1.9.30 sync.
[gae.git] / java / src / main / com / google / apphosting / utils / config / AppEngineWebXmlProcessor.java
blob8ad3ba51d03e42cc3a874140118a2e567f7d2b4d
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 package com.google.apphosting.utils.config;
4 import com.google.apphosting.utils.config.AppEngineWebXml.AdminConsolePage;
5 import com.google.apphosting.utils.config.AppEngineWebXml.ApiConfig;
6 import com.google.apphosting.utils.config.AppEngineWebXml.AutomaticScaling;
7 import com.google.apphosting.utils.config.AppEngineWebXml.BasicScaling;
8 import com.google.apphosting.utils.config.AppEngineWebXml.ClassLoaderConfig;
9 import com.google.apphosting.utils.config.AppEngineWebXml.CpuUtilization;
10 import com.google.apphosting.utils.config.AppEngineWebXml.ErrorHandler;
11 import com.google.apphosting.utils.config.AppEngineWebXml.ManualScaling;
12 import com.google.apphosting.utils.config.AppEngineWebXml.Pagespeed;
13 import com.google.apphosting.utils.config.AppEngineWebXml.PrioritySpecifierEntry;
14 import com.google.apphosting.utils.config.AppEngineWebXml.HealthCheck;
15 import com.google.apphosting.utils.config.AppEngineWebXml.Resources;
16 import com.google.apphosting.utils.config.AppEngineWebXml.Network;
18 import org.mortbay.xml.XmlParser;
19 import org.mortbay.xml.XmlParser.Node;
20 import org.xml.sax.SAXException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.logging.Level;
27 import java.util.logging.Logger;
29 /**
30 * Constructs an {@link AppEngineWebXml} from an xml document corresponding to
31 * appengine-web.xsd. We use Jetty's {@link XmlParser} utility for
32 * convenience.
34 * @TODO(user): Add a real link to the xsd once it exists and do schema
35 * validation.
38 class AppEngineWebXmlProcessor {
40 enum FileType { STATIC, RESOURCE }
42 private static final Logger logger = Logger.getLogger(AppEngineWebXmlProcessor.class.getName());
43 private boolean moduleNodeFound;
44 private boolean serviceNodeFound;
46 /**
47 * Construct an {@link AppEngineWebXml} from the xml document
48 * identified by the provided {@link InputStream}.
50 * @param is The InputStream containing the xml we want to parse and process.
52 * @return Object representation of the xml document.
53 * @throws AppEngineConfigException If the input stream cannot be parsed.
55 public AppEngineWebXml processXml(InputStream is) {
56 XmlParser.Node config = getTopLevelNode(is);
57 AppEngineWebXml appEngineWebXml = new AppEngineWebXml();
58 appEngineWebXml.setWarmupRequestsEnabled(true);
59 for (Object o : config) {
60 if (!(o instanceof XmlParser.Node)) {
61 continue;
63 XmlParser.Node node = (XmlParser.Node) o;
64 processSecondLevelNode(node, appEngineWebXml);
66 checkScalingConstraints(appEngineWebXml);
67 if (serviceNodeFound && moduleNodeFound) {
68 throw new AppEngineConfigException(
69 "The <service> and <module> elements are conflicting. "
70 + "Please remove the deprecated <module> element.");
72 return appEngineWebXml;
75 /**
76 * Given an AppEngineWebXml, ensure it has no more than one of the scaling options available.
78 * @throws AppEngineConfigException If there is more than one scaling option selected.
80 private static void checkScalingConstraints(AppEngineWebXml appEngineWebXml) {
81 int count = appEngineWebXml.getManualScaling().isEmpty() ? 0 : 1;
82 count += appEngineWebXml.getBasicScaling().isEmpty() ? 0 : 1;
83 count += appEngineWebXml.getAutomaticScaling().isEmpty() ? 0 : 1;
84 if (count > 1) {
85 throw new AppEngineConfigException(
86 "There may be only one of 'automatic-scaling', 'manual-scaling' or " +
87 "'basic-scaling' elements.");
91 /**
92 * Given an InputStream, create a Node corresponding to the top level xml
93 * element.
95 * @throws AppEngineConfigException If the input stream cannot be parsed.
97 XmlParser.Node getTopLevelNode(InputStream is) {
98 XmlParser xmlParser = new XmlParser();
99 try {
100 return xmlParser.parse(is);
101 } catch (IOException e) {
102 String msg = "Received IOException parsing the input stream.";
103 logger.log(Level.SEVERE, msg, e);
104 throw new AppEngineConfigException(msg, e);
105 } catch (SAXException e) {
106 String msg = "Received SAXException parsing the input stream.";
107 logger.log(Level.SEVERE, msg, e);
108 throw new AppEngineConfigException(msg, e);
112 private void processSecondLevelNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
113 String elementName = node.getTag();
114 if (elementName.equals("system-properties")) {
115 processSystemPropertiesNode(node, appEngineWebXml);
116 } else if (elementName.equals("vm-settings") || elementName.equals("beta-settings")) {
117 processBetaSettingsNode(node, appEngineWebXml);
118 } else if (elementName.equals("vm-health-check") || elementName.equals("health-check")) {
119 processHealthCheckNode(node, appEngineWebXml);
120 } else if (elementName.equals("resources")) {
121 processResourcesNode(node, appEngineWebXml);
122 } else if (elementName.equals("network")) {
123 processNetworkNode(node, appEngineWebXml);
124 } else if (elementName.equals("env-variables")) {
125 processEnvironmentVariablesNode(node, appEngineWebXml);
126 } else if (elementName.equals("application")) {
127 processApplicationNode(node, appEngineWebXml);
128 } else if (elementName.equals("version")) {
129 processVersionNode(node, appEngineWebXml);
130 } else if (elementName.equals("source-language")) {
131 processSourceLanguageNode(node, appEngineWebXml);
132 } else if (elementName.equals("module")) {
133 moduleNodeFound = true;
134 processModuleNode(node, appEngineWebXml);
135 } else if (elementName.equals("service")) {
136 serviceNodeFound = true;
137 processServiceNode(node, appEngineWebXml);
138 } else if (elementName.equals("instance-class")) {
139 processInstanceClassNode(node, appEngineWebXml);
140 } else if (elementName.equals("automatic-scaling")) {
141 processAutomaticScalingNode(node, appEngineWebXml);
142 } else if (elementName.equals("manual-scaling")) {
143 processManualScalingNode(node, appEngineWebXml);
144 } else if (elementName.equals("basic-scaling")) {
145 processBasicScalingNode(node, appEngineWebXml);
146 } else if (elementName.equals("static-files")) {
147 processFilesetNode(node, appEngineWebXml, FileType.STATIC);
148 } else if (elementName.equals("resource-files")) {
149 processFilesetNode(node, appEngineWebXml, FileType.RESOURCE);
150 } else if (elementName.equals("ssl-enabled")) {
151 processSslEnabledNode(node, appEngineWebXml);
152 } else if (elementName.equals("sessions-enabled")) {
153 processSessionsEnabledNode(node, appEngineWebXml);
154 } else if (elementName.equals("async-session-persistence")) {
155 processAsyncSessionPersistenceNode(node, appEngineWebXml);
156 } else if (elementName.equals("user-permissions")) {
157 processPermissionsNode(node, appEngineWebXml);
158 } else if (elementName.equals("public-root")) {
159 processPublicRootNode(node, appEngineWebXml);
160 } else if (elementName.equals("inbound-services")) {
161 processInboundServicesNode(node, appEngineWebXml);
162 } else if (elementName.equals("precompilation-enabled")) {
163 processPrecompilationEnabledNode(node, appEngineWebXml);
164 } else if (elementName.equals("admin-console")) {
165 processAdminConsoleNode(node, appEngineWebXml);
166 } else if (elementName.equals("static-error-handlers")) {
167 processErrorHandlerNode(node, appEngineWebXml);
168 } else if (elementName.equals("warmup-requests-enabled")) {
169 processWarmupRequestsEnabledNode(node, appEngineWebXml);
170 } else if (elementName.equals("threadsafe")) {
171 processThreadsafeNode(node, appEngineWebXml);
172 } else if (elementName.equals("auto-id-policy")) {
173 processAutoIdPolicyNode(node, appEngineWebXml);
174 } else if (elementName.equals("code-lock")) {
175 processCodeLockNode(node, appEngineWebXml);
176 } else if (elementName.equals("vm")) {
177 processVmNode(node, appEngineWebXml);
178 } else if (elementName.equals("env")) {
179 processEnvNode(node, appEngineWebXml);
180 } else if (elementName.equals("api-config")) {
181 processApiConfigNode(node, appEngineWebXml);
182 } else if (elementName.equals("pagespeed")) {
183 processPagespeedNode(node, appEngineWebXml);
184 } else if (elementName.equals("class-loader-config")) {
185 processClassLoaderConfig(node, appEngineWebXml);
186 } else if (elementName.equals("url-stream-handler")) {
187 processUrlStreamHandler(node, appEngineWebXml);
188 } else if (elementName.equals("use-google-connector-j")) {
189 processUseGoogleConnectorJNode(node, appEngineWebXml);
190 } else {
191 throw new AppEngineConfigException("Unrecognized element <" + elementName + ">");
195 private void processApplicationNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
196 appEngineWebXml.setAppId(getTextNode(node));
199 private void processPublicRootNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
200 appEngineWebXml.setPublicRoot(getTextNode(node));
203 private void processVersionNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
204 appEngineWebXml.setMajorVersionId(getTextNode(node));
207 private void processSourceLanguageNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
208 appEngineWebXml.setSourceLanguage(getTextNode(node));
211 private void processModuleNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
212 appEngineWebXml.setModule(getTextNode(node));
215 private void processServiceNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
216 appEngineWebXml.setService(getTextNode(node));
219 private void processInstanceClassNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
220 appEngineWebXml.setInstanceClass(getTextNode(node));
223 private String getChildNodeText(XmlParser.Node parentNode, String childTag) {
224 String result = null;
225 XmlParser.Node node = parentNode.get(childTag);
226 if (node != null) {
227 result = (String) node.get(0);
229 return result;
232 private Integer getChildNodePositiveInteger(XmlParser.Node parentNode, String childTag) {
233 Integer result = null;
234 XmlParser.Node node = parentNode.get(childTag);
235 if (node != null && node.get(0) != null) {
236 String trimmedText = ((String) node.get(0)).trim();
237 if (!trimmedText.isEmpty()) {
238 try {
239 result = Integer.parseInt(trimmedText);
240 } catch (NumberFormatException ex) {
241 throw new AppEngineConfigException(childTag + " should only contain integers.");
244 if (result <= 0) {
245 throw new AppEngineConfigException(childTag + " should only contain positive integers.");
249 return result;
252 private Double getChildNodeDouble(XmlParser.Node parentNode, String childTag) {
253 Double result = null;
254 XmlParser.Node node = parentNode.get(childTag);
255 if (node != null && node.get(0) != null) {
256 String trimmedText = ((String) node.get(0)).trim();
257 if (!trimmedText.isEmpty()) {
258 try {
259 result = Double.parseDouble(trimmedText);
260 } catch (NumberFormatException ex) {
261 throw new AppEngineConfigException(childTag + " should only contain doubles.");
262 } catch (NullPointerException ex) {
263 throw new AppEngineConfigException(childTag + " should NOT be empty.");
267 return result;
270 private void processAutomaticScalingNode(XmlParser.Node settingsNode,
271 AppEngineWebXml appEngineWebXml) {
272 AutomaticScaling automaticScaling = appEngineWebXml.getAutomaticScaling();
273 automaticScaling.setMinPendingLatency(getChildNodeText(settingsNode, "min-pending-latency"));
274 automaticScaling.setMaxPendingLatency(getChildNodeText(settingsNode, "max-pending-latency"));
275 automaticScaling.setMinIdleInstances(getChildNodeText(settingsNode, "min-idle-instances"));
276 automaticScaling.setMaxIdleInstances(getChildNodeText(settingsNode, "max-idle-instances"));
277 automaticScaling.setMaxConcurrentRequests(
278 getChildNodeText(settingsNode, "max-concurrent-requests"));
279 automaticScaling.setMinNumInstances(
280 getChildNodePositiveInteger(settingsNode, "min-num-instances"));
281 automaticScaling.setMaxNumInstances(
282 getChildNodePositiveInteger(settingsNode, "max-num-instances"));
283 automaticScaling.setCoolDownPeriodSec(
284 getChildNodePositiveInteger(settingsNode, "cool-down-period-sec"));
285 processCpuUtilizationNode(settingsNode, automaticScaling);
286 automaticScaling.setTargetNetworkSentBytesPerSec(
287 getChildNodePositiveInteger(settingsNode, "target-network-sent-bytes-per-sec"));
288 automaticScaling.setTargetNetworkSentPacketsPerSec(
289 getChildNodePositiveInteger(settingsNode, "target-network-sent-packets-per-sec"));
290 automaticScaling.setTargetNetworkReceivedBytesPerSec(
291 getChildNodePositiveInteger(settingsNode, "target-network-received-bytes-per-sec"));
292 automaticScaling.setTargetNetworkReceivedPacketsPerSec(
293 getChildNodePositiveInteger(settingsNode, "target-network-received-packets-per-sec"));
294 automaticScaling.setTargetDiskWriteBytesPerSec(
295 getChildNodePositiveInteger(settingsNode, "target-disk-write-bytes-per-sec"));
296 automaticScaling.setTargetDiskWriteOpsPerSec(
297 getChildNodePositiveInteger(settingsNode, "target-disk-write-ops-per-sec"));
298 automaticScaling.setTargetDiskReadBytesPerSec(
299 getChildNodePositiveInteger(settingsNode, "target-disk-read-bytes-per-sec"));
300 automaticScaling.setTargetDiskReadOpsPerSec(
301 getChildNodePositiveInteger(settingsNode, "target-disk-read-ops-per-sec"));
302 automaticScaling.setTargetRequestCountPerSec(
303 getChildNodePositiveInteger(settingsNode, "target-request-count-per-sec"));
304 automaticScaling.setTargetConcurrentRequests(
305 getChildNodePositiveInteger(settingsNode, "target-concurrent-requests"));
308 private void processCpuUtilizationNode(
309 XmlParser.Node settingsNode, AutomaticScaling automaticScaling) {
310 XmlParser.Node childNode = settingsNode.get("cpu-utilization");
311 if (childNode != null) {
312 CpuUtilization cpuUtilization = new CpuUtilization();
313 Double targetUtilization = getChildNodeDouble(childNode, "target-utilization");
314 if (targetUtilization != null) {
315 if (targetUtilization <= 0 || targetUtilization > 1) {
316 throw new AppEngineConfigException("target-utilization should be in range (0, 1].");
318 cpuUtilization.setTargetUtilization(targetUtilization);
321 cpuUtilization.setAggregationWindowLengthSec(
322 getChildNodePositiveInteger(childNode, "aggregation-window-length-sec"));
323 if (!cpuUtilization.isEmpty()) {
324 automaticScaling.setCpuUtilization(cpuUtilization);
329 private void processManualScalingNode(XmlParser.Node settingsNode,
330 AppEngineWebXml appEngineWebXml) {
331 ManualScaling manualScaling = appEngineWebXml.getManualScaling();
332 manualScaling.setInstances(getChildNodeText(settingsNode, "instances"));
335 private void processBasicScalingNode(XmlParser.Node settingsNode,
336 AppEngineWebXml appEngineWebXml) {
337 BasicScaling basicScaling = appEngineWebXml.getBasicScaling();
338 basicScaling.setMaxInstances(getChildNodeText(settingsNode, "max-instances"));
339 basicScaling.setIdleTimeout(getChildNodeText(settingsNode, "idle-timeout"));
342 private void processSslEnabledNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
343 appEngineWebXml.setSslEnabled(getBooleanValue(node));
346 private void processSessionsEnabledNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
347 appEngineWebXml.setSessionsEnabled(getBooleanValue(node));
350 private void processAsyncSessionPersistenceNode(
351 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
352 boolean enabled = getBooleanAttributeValue(node, "enabled");
353 appEngineWebXml.setAsyncSessionPersistence(enabled);
354 String queueName = trim(node.getAttribute("queue-name"));
355 appEngineWebXml.setAsyncSessionPersistenceQueueName(queueName);
358 private void processPrecompilationEnabledNode(XmlParser.Node node,
359 AppEngineWebXml appEngineWebXml) {
360 appEngineWebXml.setPrecompilationEnabled(getBooleanValue(node));
363 private void processWarmupRequestsEnabledNode(XmlParser.Node node,
364 AppEngineWebXml appEngineWebXml) {
365 appEngineWebXml.setWarmupRequestsEnabled(getBooleanValue(node));
368 private void processThreadsafeNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
369 appEngineWebXml.setThreadsafe(getBooleanValue(node));
372 private void processAutoIdPolicyNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
373 appEngineWebXml.setAutoIdPolicy(getTextNode(node));
376 private void processCodeLockNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
377 appEngineWebXml.setCodeLock(getBooleanValue(node));
380 private void processVmNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
381 appEngineWebXml.setUseVm(getBooleanValue(node));
384 private void processEnvNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
385 appEngineWebXml.setEnv(getTextNode(node));
388 private void processFilesetNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml,
389 FileType type) {
390 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "include");
391 while (nodeIter.hasNext()) {
392 XmlParser.Node includeNode = nodeIter.next();
393 String path = trim(includeNode.getAttribute("path"));
394 if (type == FileType.STATIC) {
395 String expiration = trim(includeNode.getAttribute("expiration"));
396 AppEngineWebXml.StaticFileInclude staticFileInclude =
397 appEngineWebXml.includeStaticPattern(path, expiration);
399 Map<String, String> httpHeaders = staticFileInclude.getHttpHeaders();
400 Iterator<XmlParser.Node> httpHeaderIter = getNodeIterator(includeNode, "http-header");
401 while (httpHeaderIter.hasNext()) {
402 XmlParser.Node httpHeaderNode = httpHeaderIter.next();
403 String name = httpHeaderNode.getAttribute("name");
404 String value = httpHeaderNode.getAttribute("value");
406 if (httpHeaders.containsKey(name)) {
407 throw new AppEngineConfigException("Two http-header elements have the same name.");
410 httpHeaders.put(name, value);
412 } else {
413 appEngineWebXml.includeResourcePattern(path);
417 nodeIter = getNodeIterator(node, "exclude");
418 while (nodeIter.hasNext()) {
419 XmlParser.Node subNode = nodeIter.next();
420 String path = trim(subNode.getAttribute("path"));
421 if (type == FileType.STATIC) {
422 appEngineWebXml.excludeStaticPattern(path);
423 } else {
424 appEngineWebXml.excludeResourcePattern(path);
429 private Iterator<XmlParser.Node> getNodeIterator(XmlParser.Node node, String filter) {
430 @SuppressWarnings("unchecked")
431 Iterator<XmlParser.Node> iterator = node.iterator(filter);
432 return iterator;
435 private void processSystemPropertiesNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
436 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "property");
437 while (nodeIter.hasNext()) {
438 XmlParser.Node subNode = nodeIter.next();
439 String propertyName = trim(subNode.getAttribute("name"));
440 String propertyValue = trim(subNode.getAttribute("value"));
441 appEngineWebXml.addSystemProperty(propertyName, propertyValue);
445 private void processBetaSettingsNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
446 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "setting");
447 while (nodeIter.hasNext()) {
448 XmlParser.Node subNode = nodeIter.next();
449 String name = trim(subNode.getAttribute("name"));
450 String value = trim(subNode.getAttribute("value"));
451 appEngineWebXml.addBetaSetting(name, value);
455 private void processHealthCheckNode(XmlParser.Node settingsNode,
456 AppEngineWebXml appEngineWebXml) {
457 HealthCheck healthCheck = appEngineWebXml.getHealthCheck();
458 String enableHealthCheck = trim(getChildNodeText(settingsNode, "enable-health-check"));
459 if (enableHealthCheck != null && !enableHealthCheck.isEmpty()) {
460 healthCheck.setEnableHealthCheck(toBoolean(enableHealthCheck));
462 healthCheck.setCheckIntervalSec(
463 getChildNodePositiveInteger(settingsNode, "check-interval-sec"));
464 healthCheck.setTimeoutSec(getChildNodePositiveInteger(settingsNode, "timeout-sec"));
465 healthCheck.setUnhealthyThreshold(
466 getChildNodePositiveInteger(settingsNode, "unhealthy-threshold"));
467 healthCheck.setHealthyThreshold(
468 getChildNodePositiveInteger(settingsNode, "healthy-threshold"));
469 healthCheck.setRestartThreshold(
470 getChildNodePositiveInteger(settingsNode, "restart-threshold"));
471 healthCheck.setHost(getChildNodeText(settingsNode, "host"));
474 private void processResourcesNode(XmlParser.Node settingsNode,
475 AppEngineWebXml appEngineWebXml) {
476 Resources resources = appEngineWebXml.getResources();
477 Double cpu = getChildNodeDouble(settingsNode, "cpu");
478 if (cpu != null) {
479 resources.setCpu(cpu);
481 Double memory_gb = getChildNodeDouble(settingsNode, "memory-gb");
482 if (memory_gb != null) {
483 resources.setMemoryGb(memory_gb);
485 Integer disk_size_gb = getChildNodePositiveInteger(settingsNode, "disk-size-gb");
486 if (disk_size_gb != null) {
487 resources.setDiskSizeGb(disk_size_gb);
491 private void processNetworkNode(XmlParser.Node settingsNode,
492 AppEngineWebXml appEngineWebXml) {
493 Network network = appEngineWebXml.getNetwork();
494 String instance_tag = trim(getChildNodeText(settingsNode, "instance-tag"));
495 if (instance_tag != null && !instance_tag.isEmpty()) {
496 network.setInstanceTag(instance_tag);
498 Iterator<XmlParser.Node> nodeIter = getNodeIterator(settingsNode, "forwarded-port");
499 while (nodeIter.hasNext()) {
500 XmlParser.Node subNode = nodeIter.next();
501 String forwardedPort = getTextNode(subNode);
502 network.addForwardedPort(forwardedPort);
504 String name = trim(getChildNodeText(settingsNode, "name"));
505 if (name != null && !name.isEmpty()) {
506 network.setName(name);
510 private void processEnvironmentVariablesNode(
511 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
512 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "env-var");
513 while (nodeIter.hasNext()) {
514 XmlParser.Node subNode = nodeIter.next();
515 String propertyName = trim(subNode.getAttribute("name"));
516 String propertyValue = trim(subNode.getAttribute("value"));
517 appEngineWebXml.addEnvironmentVariable(propertyName, propertyValue);
521 private void processPermissionsNode(
522 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
523 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "permission");
524 while (nodeIter.hasNext()) {
525 XmlParser.Node subNode = nodeIter.next();
526 String className = trim(subNode.getAttribute("class"));
527 String name = trim(subNode.getAttribute("name"));
528 String actions = trim(subNode.getAttribute("actions"));
529 appEngineWebXml.addUserPermission(className, name, actions);
533 private void processInboundServicesNode(
534 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
535 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "service");
536 while (nodeIter.hasNext()) {
537 XmlParser.Node subNode = nodeIter.next();
538 String service = getTextNode(subNode);
539 appEngineWebXml.addInboundService(service);
543 private void processAdminConsoleNode(
544 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
545 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "page");
546 while (nodeIter.hasNext()) {
547 XmlParser.Node subNode = nodeIter.next();
548 String name = trim(subNode.getAttribute("name"));
549 String url = trim(subNode.getAttribute("url"));
550 appEngineWebXml.addAdminConsolePage(new AdminConsolePage(name, url));
554 private void processErrorHandlerNode(
555 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
556 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "handler");
557 while (nodeIter.hasNext()) {
558 XmlParser.Node subNode = nodeIter.next();
559 String file = trim(subNode.getAttribute("file"));
560 String errorCode = trim(subNode.getAttribute("error-code"));
561 appEngineWebXml.addErrorHandler(new ErrorHandler(file, errorCode));
565 private void processApiConfigNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
566 String servlet = trim(node.getAttribute("servlet-class"));
567 String url = trim(node.getAttribute("url-pattern"));
568 appEngineWebXml.setApiConfig(new ApiConfig(servlet, url));
570 String id = null;
571 Iterator<XmlParser.Node> subNodeIter = getNodeIterator(node, "endpoint-servlet-mapping-id");
572 while (subNodeIter.hasNext()) {
573 XmlParser.Node subNode = subNodeIter.next();
574 id = trim(getTextNode(subNode));
575 if (id != null && id.length() > 0) {
576 appEngineWebXml.addApiEndpoint(id);
581 private void processPagespeedNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
582 Pagespeed pagespeed = new Pagespeed();
583 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "url-blacklist");
584 while (nodeIter.hasNext()) {
585 XmlParser.Node subNode = nodeIter.next();
586 String urlMatcher = getTextNode(subNode);
587 pagespeed.addUrlBlacklist(urlMatcher);
589 nodeIter = getNodeIterator(node, "domain-to-rewrite");
590 while (nodeIter.hasNext()) {
591 XmlParser.Node subNode = nodeIter.next();
592 String domain = getTextNode(subNode);
593 pagespeed.addDomainToRewrite(domain);
595 nodeIter = getNodeIterator(node, "enabled-rewriter");
596 while (nodeIter.hasNext()) {
597 XmlParser.Node subNode = nodeIter.next();
598 String rewriter = getTextNode(subNode);
599 pagespeed.addEnabledRewriter(rewriter);
601 nodeIter = getNodeIterator(node, "disabled-rewriter");
602 while (nodeIter.hasNext()) {
603 XmlParser.Node subNode = nodeIter.next();
604 String rewriter = getTextNode(subNode);
605 pagespeed.addDisabledRewriter(rewriter);
607 appEngineWebXml.setPagespeed(pagespeed);
610 private void processClassLoaderConfig(
611 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
612 ClassLoaderConfig config = new ClassLoaderConfig();
613 appEngineWebXml.setClassLoaderConfig(config);
614 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "priority-specifier");
615 while (nodeIter.hasNext()) {
616 processClassPathPrioritySpecifier(nodeIter.next(), config);
620 private void processClassPathPrioritySpecifier(Node node, ClassLoaderConfig config) {
621 PrioritySpecifierEntry entry = new PrioritySpecifierEntry();
622 entry.setFilename(node.getAttribute("filename"));
623 entry.setPriority(node.getAttribute("priority"));
624 entry.checkClassLoaderConfig();
625 config.add(entry);
628 private void processUrlStreamHandler(Node node, AppEngineWebXml appEngineWebXml) {
629 appEngineWebXml.setUrlStreamHandlerType(getTextNode(node));
632 private boolean getBooleanValue(XmlParser.Node node) {
633 return toBoolean(getTextNode(node));
636 private boolean getBooleanAttributeValue(XmlParser.Node node, String attribute) {
637 return toBoolean(node.getAttribute(attribute));
640 private boolean toBoolean(String value) {
641 value = value.trim();
642 return (value.equalsIgnoreCase("true") || value.equals("1"));
645 private String getTextNode(XmlParser.Node node) {
646 String value = (String) node.get(0);
647 if (value == null) {
648 value = "";
650 return value.trim();
653 private String trim(String attribute) {
654 return attribute == null ? null : attribute.trim();
657 private void processUseGoogleConnectorJNode(XmlParser.Node node,
658 AppEngineWebXml appEngineWebXml) {
659 appEngineWebXml.setUseGoogleConnectorJ(getBooleanValue(node));