1 package com
.google
.apphosting
.utils
.config
;
3 import com
.google
.apphosting
.utils
.config
.DispatchXml
.DispatchEntry
;
5 import org
.mortbay
.xml
.XmlParser
.Node
;
8 import java
.io
.InputStream
;
9 import java
.util
.Stack
;
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
19 private final String relativeFilename
;
21 public DispatchXmlReader(String warDirectory
, String relativeFilename
) {
22 super(warDirectory
, false);
23 this.relativeFilename
= relativeFilename
;
27 * Parses the dispatch.xml file if one exists into an {@link DispatchXml} and otherwise
30 public DispatchXml
readDispatchXml() {
31 return readConfigXml();
35 protected DispatchXml
processXml(InputStream is
) {
36 DispatchXmlParserCallback dispatchParserCallback
= new DispatchXmlParserCallback();
37 parse(dispatchParserCallback
, is
);
38 return dispatchParserCallback
.getDispatchXml();
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() {
62 throw new IllegalStateException(
63 "getDispatchXml() called before parsing a valid dispatch.xml");
65 checkForIncompleteDispatchElement();
66 return dispatchXmlBuilder
.build();
70 public void newNode(Node node
, Stack
<Node
> ancestors
) {
71 switch (ancestors
.size()) {
73 if (!DISPATCH_ENTRIES_TAG
.equalsIgnoreCase(node
.getTag())) {
74 throwExpectingTag(DISPATCH_ENTRIES_TAG
, node
.getTag());
77 throwDuplicateTag(DISPATCH_ENTRIES_TAG
, null);
83 if (DISPATCH_TAG
.equalsIgnoreCase(node
.getTag())) {
84 checkForIncompleteDispatchElement();
85 dispatchComplete
= false;
87 throwExpectingTag(DISPATCH_TAG
, node
.getTag());
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);
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);
106 throwBadElementContents(MODULE_TAG
);
109 throwUnsupportedTag(node
.getTag(), DISPATCH_TAG
);
111 if (url
!= null && module
!= null) {
112 dispatchXmlBuilder
.addDispatchEntry(new DispatchEntry(url
, module
));
115 dispatchComplete
= true;
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");
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()));
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()));