1.9.30 sync.
[gae.git] / java / src / main / com / google / apphosting / utils / config / QueueXmlReader.java
blob87a1480cdcaaee90341402d77d58ca505e8f8995
1 // Copyright 2009 Google Inc. All Rights Reserved.
2 package com.google.apphosting.utils.config;
4 import org.mortbay.xml.XmlParser.Node;
6 import java.io.InputStream;
7 import java.util.ArrayList;
8 import java.util.Stack;
10 /**
11 * Creates an {@link QueueXml} instance from
12 * <appdir>WEB-INF/queue.xml. If you want to read the configuration
13 * from a different file, subclass and override {@link #getFilename()}. If you
14 * want to read the configuration from something that isn't a file, subclass
15 * and override {@link #getInputStream()}.
18 public class QueueXmlReader extends AbstractConfigXmlReader<QueueXml> {
20 private static final String FILENAME = "WEB-INF/queue.xml";
22 private static final String TOTAL_STORAGE_LIMIT_TAG = "total-storage-limit";
23 private static final String QUEUEENTRIES_TAG = "queue-entries";
24 private static final String QUEUE_TAG = "queue";
25 private static final String NAME_TAG = "name";
26 private static final String RATE_TAG = "rate";
27 private static final String BUCKET_SIZE = "bucket-size";
28 private static final String MAX_CONCURRENT_REQUESTS = "max-concurrent-requests";
29 private static final String MODE_TAG = "mode";
31 private static final String RETRY_PARAMETERS_TAG = "retry-parameters";
32 private static final String TASK_RETRY_LIMIT_TAG = "task-retry-limit";
33 private static final String TASK_AGE_LIMIT_TAG = "task-age-limit";
34 private static final String MIN_BACKOFF_SECONDS_TAG = "min-backoff-seconds";
35 private static final String MAX_BACKOFF_SECONDS_TAG = "max-backoff-seconds";
36 private static final String MAX_DOUBLINGS_TAG = "max-doublings";
37 private static final String TARGET_TAG = "target";
39 private static final String ACL_TAG = "acl";
40 private static final String USER_EMAIL_TAG = "user-email";
41 private static final String WRITER_EMAIL_TAG = "writer-email";
43 /**
44 * Constructs the reader for {@code queue.xml} in a given application directory.
45 * @param appDir the application directory
47 public QueueXmlReader(String appDir) {
48 super(appDir, false);
51 /**
52 * Parses the config file.
53 * @return A {@link QueueXml} object representing the parsed configuration.
55 public QueueXml readQueueXml() {
56 return readConfigXml();
59 @Override
60 protected QueueXml processXml(InputStream is) {
61 final QueueXml queueXml = new QueueXml();
62 parse(new ParserCallback() {
63 boolean firstQueueEntriesTag = true;
64 boolean firstTotalStorageLimitTag = true;
65 boolean insideRetryParametersTag = false;
66 boolean insideAclTag = false;
67 QueueXml.Entry entry;
69 @Override
70 public void newNode(Node node, Stack<Node> ancestors) {
71 switch (ancestors.size()) {
72 case 0:
73 if (QUEUEENTRIES_TAG.equalsIgnoreCase(node.getTag())) {
74 if (!firstQueueEntriesTag) {
75 throw new AppEngineConfigException(getFilename() + " contains multiple <"
76 + QUEUEENTRIES_TAG + ">");
78 firstQueueEntriesTag = false;
80 break;
82 case 1:
83 if (firstQueueEntriesTag) {
84 throw new AppEngineConfigException(getFilename() + " does not contain <"
85 + QUEUEENTRIES_TAG + ">");
87 if (TOTAL_STORAGE_LIMIT_TAG.equalsIgnoreCase(node.getTag())) {
88 if (!firstTotalStorageLimitTag) {
89 throw new AppEngineConfigException(getFilename() + " contains multiple <"
90 + TOTAL_STORAGE_LIMIT_TAG + ">");
92 if (node.size() == 1 && node.get(0) instanceof String) {
93 queueXml.setTotalStorageLimit(getString(node));
94 } else {
95 throw new AppEngineConfigException(getFilename() + "has invalid <"
96 +TOTAL_STORAGE_LIMIT_TAG + ">");
98 firstTotalStorageLimitTag = false;
99 } else if (QUEUE_TAG.equalsIgnoreCase(node.getTag())) {
100 entry = queueXml.addNewEntry();
101 } else {
102 throw new AppEngineConfigException(getFilename() + " contains <"
103 + node.getTag() + "> instead of <" + QUEUE_TAG + "/> or <" +
104 TOTAL_STORAGE_LIMIT_TAG + ">");
106 break;
108 case 2:
109 assert(entry != null);
110 if (NAME_TAG.equalsIgnoreCase(node.getTag())) {
111 if (node.size() == 1 && node.get(0) instanceof String) {
112 entry.setName(getString(node));
113 } else {
114 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
115 + NAME_TAG + ">");
117 } else if (BUCKET_SIZE.equalsIgnoreCase(node.getTag())) {
118 if (node.size() == 1 && node.get(0) instanceof String) {
119 entry.setBucketSize(getString(node));
120 } else {
121 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
122 + BUCKET_SIZE + ">");
124 } else if (RATE_TAG.equalsIgnoreCase(node.getTag())) {
125 if (node.size() == 1 && node.get(0) instanceof String) {
126 entry.setRate(getString(node));
127 } else {
128 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
129 + RATE_TAG + ">");
131 } else if (MAX_CONCURRENT_REQUESTS.equalsIgnoreCase(node.getTag())) {
132 if (node.size() == 1 && node.get(0) instanceof String) {
133 entry.setMaxConcurrentRequests(getString(node));
134 } else {
135 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
136 + MAX_CONCURRENT_REQUESTS + ">");
138 } else if (MODE_TAG.equalsIgnoreCase(node.getTag())) {
139 if (node.size() == 1 && node.get(0) instanceof String) {
140 entry.setMode(getString(node));
141 } else {
142 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
143 + MODE_TAG + ">");
145 } else if (TARGET_TAG.equalsIgnoreCase(node.getTag())) {
146 if (node.size() == 1 && node.get(0) instanceof String) {
147 entry.setTarget(getString(node));
148 } else {
149 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
150 + TARGET_TAG + ">");
152 } else if (RETRY_PARAMETERS_TAG.equalsIgnoreCase(node.getTag())) {
153 entry.setRetryParameters(new QueueXml.RetryParameters());
154 insideRetryParametersTag = true;
155 insideAclTag = false;
156 } else if (ACL_TAG.equalsIgnoreCase(node.getTag())) {
157 entry.setAcl(new ArrayList<QueueXml.AclEntry>());
158 insideAclTag = true;
159 insideRetryParametersTag = false;
160 } else {
161 throw new AppEngineConfigException(getFilename() + " contains unknown <"
162 + node.getTag() + "> inside <" + QUEUE_TAG + "/>");
164 break;
166 case 3:
167 assert(insideRetryParametersTag ^ insideAclTag);
168 assert(entry != null);
169 boolean brokenTag = !(node.size() == 1 && node.get(0) instanceof String);
171 if (insideRetryParametersTag) {
172 assert(entry.getRetryParameters() != null);
173 QueueXml.RetryParameters retryParameters = entry.getRetryParameters();
175 if (TASK_RETRY_LIMIT_TAG.equalsIgnoreCase(node.getTag())) {
176 if (!brokenTag) {
177 retryParameters.setRetryLimit(getString(node));
179 } else if (TASK_AGE_LIMIT_TAG.equalsIgnoreCase(node.getTag())) {
180 if (!brokenTag) {
181 retryParameters.setAgeLimitSec(getString(node));
183 } else if (MIN_BACKOFF_SECONDS_TAG.equalsIgnoreCase(node.getTag())) {
184 if (!brokenTag) {
185 retryParameters.setMinBackoffSec(getString(node));
187 } else if (MAX_BACKOFF_SECONDS_TAG.equalsIgnoreCase(node.getTag())) {
188 if (!brokenTag) {
189 retryParameters.setMaxBackoffSec(getString(node));
191 } else if (MAX_DOUBLINGS_TAG.equalsIgnoreCase(node.getTag())) {
192 if (!brokenTag) {
193 retryParameters.setMaxDoublings(getString(node));
195 } else {
196 throw new AppEngineConfigException(getFilename() + " contains unknown <"
197 + node.getTag() + "> inside <" + RETRY_PARAMETERS_TAG + "/>");
201 if (insideAclTag) {
202 assert(entry.getAcl() != null);
203 if (USER_EMAIL_TAG.equalsIgnoreCase(node.getTag())) {
204 if (!brokenTag) {
205 QueueXml.AclEntry acl = new QueueXml.AclEntry();
206 acl.setUserEmail(getString(node));
207 entry.getAcl().add(acl);
209 } else if (WRITER_EMAIL_TAG.equalsIgnoreCase(node.getTag())) {
210 if (!brokenTag) {
211 QueueXml.AclEntry acl = new QueueXml.AclEntry();
212 acl.setWriterEmail(getString(node));
213 entry.getAcl().add(acl);
215 } else {
216 throw new AppEngineConfigException(getFilename() + " contains unknown <"
217 + node.getTag() + "> inside <" + ACL_TAG + "/>");
221 if (brokenTag) {
222 throw new AppEngineConfigException(getFilename() + " has bad contents in <"
223 + node.getTag() + ">");
225 break;
227 default:
228 throw new AppEngineConfigException(getFilename()
229 + " has a syntax error; node <"
230 + node.getTag() + "> is too deeply nested to be valid.");
233 }, is);
234 queueXml.validateLastEntry();
235 return queueXml;
238 @Override
239 protected String getRelativeFilename() {
240 return FILENAME;