App Engine Python SDK version 1.8.4
[gae.git] / java / src / main / com / google / apphosting / utils / config / DispatchXmlReader.java
blobf15aed01841dda5e71b2d7f4a5a4aa87690d5876
1 package com.google.apphosting.utils.config;
3 import com.google.apphosting.utils.config.DispatchXml.DispatchEntry;
5 import org.mortbay.xml.XmlParser.Node;
7 import java.io.File;
8 import java.io.InputStream;
9 import java.util.Stack;
11 /**
12 * Creates a {@link DispatchXml} from dispatch.yaml.
14 public class DispatchXmlReader extends AbstractConfigXmlReader<DispatchXml> {
16 public static final String DEFAULT_RELATIVE_FILENAME = "WEB-INF" + File.separatorChar
17 + "dispatch.xml";
19 private final String relativeFilename;
21 public DispatchXmlReader(String warDirectory, String relativeFilename) {
22 super(warDirectory, false);
23 this.relativeFilename = relativeFilename;
26 /**
27 * Parses the dispatch.xml file if one exists into an {@link DispatchXml} and otherwise
28 * returns null.
30 public DispatchXml readDispatchXml() {
31 return readConfigXml();
34 @Override
35 protected DispatchXml processXml(InputStream is) {
36 DispatchXmlParserCallback dispatchParserCallback = new DispatchXmlParserCallback();
37 parse(dispatchParserCallback, is);
38 return dispatchParserCallback.getDispatchXml();
41 @Override
42 protected String getRelativeFilename() {
43 return relativeFilename;
46 private class DispatchXmlParserCallback implements ParserCallback {
47 private final DispatchXml.Builder dispatchXmlBuilder = DispatchXml.builder();
49 private static final String DISPATCH_ENTRIES_TAG = "dispatch-entries";
50 private static final String DISPATCH_TAG = "dispatch";
51 private static final String URL_TAG = "url";
52 private static final String MODULE_TAG = "module";
54 private boolean first = true;
56 private boolean dispatchComplete;
57 private String url = null;
58 private String module = null;
60 DispatchXml getDispatchXml() {
61 if (first) {
62 throw new IllegalStateException(
63 "getDispatchXml() called before parsing a valid dispatch.xml");
65 checkForIncompleteDispatchElement();
66 return dispatchXmlBuilder.build();
69 @Override
70 public void newNode(Node node, Stack<Node> ancestors) {
71 switch (ancestors.size()) {
72 case 0:
73 if (!DISPATCH_ENTRIES_TAG.equalsIgnoreCase(node.getTag())) {
74 throwExpectingTag(DISPATCH_ENTRIES_TAG, node.getTag());
76 if (!first) {
77 throwDuplicateTag(DISPATCH_ENTRIES_TAG, null);
79 first = false;
80 break;
82 case 1:
83 if (DISPATCH_TAG.equalsIgnoreCase(node.getTag())) {
84 checkForIncompleteDispatchElement();
85 dispatchComplete = false;
86 } else {
87 throwExpectingTag(DISPATCH_TAG, node.getTag());
89 break;
91 case 2:
92 if (URL_TAG.equalsIgnoreCase(node.getTag())) {
93 if (dispatchComplete || url != null) {
94 throwDuplicateTag(URL_TAG, DISPATCH_TAG);
95 } else if (node.size() == 1 && node.get(0) instanceof String) {
96 url = (String) node.get(0);
97 } else {
98 throwBadElementContents(URL_TAG);
100 } else if (MODULE_TAG.equalsIgnoreCase(node.getTag())) {
101 if (dispatchComplete || module != null) {
102 throwDuplicateTag(MODULE_TAG, DISPATCH_TAG);
103 } else if (node.size() == 1 && node.get(0) instanceof String) {
104 module = (String) node.get(0);
105 } else {
106 throwBadElementContents(MODULE_TAG);
108 } else {
109 throwUnsupportedTag(node.getTag(), DISPATCH_TAG);
111 if (url != null && module != null) {
112 dispatchXmlBuilder.addDispatchEntry(new DispatchEntry(url, module));
113 url = null;
114 module = null;
115 dispatchComplete = true;
117 break;
119 default:
120 throw new AppEngineConfigException(
121 String.format("Syntax error; node <%s> is too deeply nested in file %s",
122 node.getTag(), getFilename()));
126 private void checkForIncompleteDispatchElement() {
127 if (module != null) {
128 throwExpectingTag("url", "/dispatch");
130 if (url != null) {
131 throwExpectingTag("module", "/dispatch");
135 private void throwExpectingTag(String expecting, String got) {
136 throw new AppEngineConfigException(String.format("Expecting <%s> but got <%s> in file %s",
137 expecting, got, getFilename()));
140 private void throwUnsupportedTag(String tag, String parent) {
141 throw new AppEngineConfigException(String.format(
142 "Tag <%s> not supported in element <%s> in file %s", tag, parent, getFilename()));
145 private void throwDuplicateTag(String duplicateTag, String parentTag) {
146 if (parentTag == null) {
147 throw new AppEngineConfigException(String.format("Duplicate <%s> in file %s",
148 duplicateTag, getFilename()));
149 } else {
150 throw new AppEngineConfigException(String.format("Duplicate <%s> inside <%s> in file %s",
151 duplicateTag, parentTag, getFilename()));
155 private void throwBadElementContents(String badTag) {
156 throw new AppEngineConfigException(String.format(
157 "Invalid contents in element <%s> in file %s", badTag, getFilename()));