Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / apphosting / utils / config / AppEngineWebXmlProcessor.java
blob3655cf0755da267619827a494ab47555dc5e0ef6
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());
44 /**
45 * Construct an {@link AppEngineWebXml} from the xml document
46 * identified by the provided {@link InputStream}.
48 * @param is The InputStream containing the xml we want to parse and process.
50 * @return Object representation of the xml document.
51 * @throws AppEngineConfigException If the input stream cannot be parsed.
53 public AppEngineWebXml processXml(InputStream is) {
54 XmlParser.Node config = getTopLevelNode(is);
55 AppEngineWebXml appEngineWebXml = new AppEngineWebXml();
56 appEngineWebXml.setWarmupRequestsEnabled(true);
57 for (Object o : config) {
58 if (!(o instanceof XmlParser.Node)) {
59 continue;
61 XmlParser.Node node = (XmlParser.Node) o;
62 processSecondLevelNode(node, appEngineWebXml);
64 checkScalingConstraints(appEngineWebXml);
65 return appEngineWebXml;
68 /**
69 * Given an AppEngineWebXml, ensure it has no more than one of the scaling options available.
71 * @throws AppEngineConfigException If there is more than one scaling option selected.
73 private static void checkScalingConstraints(AppEngineWebXml appEngineWebXml) {
74 int count = appEngineWebXml.getManualScaling().isEmpty() ? 0 : 1;
75 count += appEngineWebXml.getBasicScaling().isEmpty() ? 0 : 1;
76 count += appEngineWebXml.getAutomaticScaling().isEmpty() ? 0 : 1;
77 if (count > 1) {
78 throw new AppEngineConfigException(
79 "There may be only one of 'automatic-scaling', 'manual-scaling' or " +
80 "'basic-scaling' elements.");
84 /**
85 * Given an InputStream, create a Node corresponding to the top level xml
86 * element.
88 * @throws AppEngineConfigException If the input stream cannot be parsed.
90 XmlParser.Node getTopLevelNode(InputStream is) {
91 XmlParser xmlParser = new XmlParser();
92 try {
93 return xmlParser.parse(is);
94 } catch (IOException e) {
95 String msg = "Received IOException parsing the input stream.";
96 logger.log(Level.SEVERE, msg, e);
97 throw new AppEngineConfigException(msg, e);
98 } catch (SAXException e) {
99 String msg = "Received SAXException parsing the input stream.";
100 logger.log(Level.SEVERE, msg, e);
101 throw new AppEngineConfigException(msg, e);
105 private void processSecondLevelNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
106 String elementName = node.getTag();
107 if (elementName.equals("system-properties")) {
108 processSystemPropertiesNode(node, appEngineWebXml);
109 } else if (elementName.equals("vm-settings") || elementName.equals("beta-settings")) {
110 processBetaSettingsNode(node, appEngineWebXml);
111 } else if (elementName.equals("vm-health-check") || elementName.equals("health-check")) {
112 processHealthCheckNode(node, appEngineWebXml);
113 } else if (elementName.equals("resources")) {
114 processResourcesNode(node, appEngineWebXml);
115 } else if (elementName.equals("network")) {
116 processNetworkNode(node, appEngineWebXml);
117 } else if (elementName.equals("env-variables")) {
118 processEnvironmentVariablesNode(node, appEngineWebXml);
119 } else if (elementName.equals("application")) {
120 processApplicationNode(node, appEngineWebXml);
121 } else if (elementName.equals("version")) {
122 processVersionNode(node, appEngineWebXml);
123 } else if (elementName.equals("source-language")) {
124 processSourceLanguageNode(node, appEngineWebXml);
125 } else if (elementName.equals("module")) {
126 processModuleNode(node, appEngineWebXml);
127 } else if (elementName.equals("instance-class")) {
128 processInstanceClassNode(node, appEngineWebXml);
129 } else if (elementName.equals("automatic-scaling")) {
130 processAutomaticScalingNode(node, appEngineWebXml);
131 } else if (elementName.equals("manual-scaling")) {
132 processManualScalingNode(node, appEngineWebXml);
133 } else if (elementName.equals("basic-scaling")) {
134 processBasicScalingNode(node, appEngineWebXml);
135 } else if (elementName.equals("static-files")) {
136 processFilesetNode(node, appEngineWebXml, FileType.STATIC);
137 } else if (elementName.equals("resource-files")) {
138 processFilesetNode(node, appEngineWebXml, FileType.RESOURCE);
139 } else if (elementName.equals("ssl-enabled")) {
140 processSslEnabledNode(node, appEngineWebXml);
141 } else if (elementName.equals("sessions-enabled")) {
142 processSessionsEnabledNode(node, appEngineWebXml);
143 } else if (elementName.equals("async-session-persistence")) {
144 processAsyncSessionPersistenceNode(node, appEngineWebXml);
145 } else if (elementName.equals("user-permissions")) {
146 processPermissionsNode(node, appEngineWebXml);
147 } else if (elementName.equals("public-root")) {
148 processPublicRootNode(node, appEngineWebXml);
149 } else if (elementName.equals("inbound-services")) {
150 processInboundServicesNode(node, appEngineWebXml);
151 } else if (elementName.equals("precompilation-enabled")) {
152 processPrecompilationEnabledNode(node, appEngineWebXml);
153 } else if (elementName.equals("admin-console")) {
154 processAdminConsoleNode(node, appEngineWebXml);
155 } else if (elementName.equals("static-error-handlers")) {
156 processErrorHandlerNode(node, appEngineWebXml);
157 } else if (elementName.equals("warmup-requests-enabled")) {
158 processWarmupRequestsEnabledNode(node, appEngineWebXml);
159 } else if (elementName.equals("threadsafe")) {
160 processThreadsafeNode(node, appEngineWebXml);
161 } else if (elementName.equals("auto-id-policy")) {
162 processAutoIdPolicyNode(node, appEngineWebXml);
163 } else if (elementName.equals("code-lock")) {
164 processCodeLockNode(node, appEngineWebXml);
165 } else if (elementName.equals("vm")) {
166 processVmNode(node, appEngineWebXml);
167 } else if (elementName.equals("api-config")) {
168 processApiConfigNode(node, appEngineWebXml);
169 } else if (elementName.equals("pagespeed")) {
170 processPagespeedNode(node, appEngineWebXml);
171 } else if (elementName.equals("class-loader-config")) {
172 processClassLoaderConfig(node, appEngineWebXml);
173 } else if (elementName.equals("url-stream-handler")) {
174 processUrlStreamHandler(node, appEngineWebXml);
175 } else if (elementName.equals("use-google-connector-j")) {
176 processUseGoogleConnectorJNode(node, appEngineWebXml);
177 } else {
178 throw new AppEngineConfigException("Unrecognized element <" + elementName + ">");
182 private void processApplicationNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
183 appEngineWebXml.setAppId(getTextNode(node));
186 private void processPublicRootNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
187 appEngineWebXml.setPublicRoot(getTextNode(node));
190 private void processVersionNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
191 appEngineWebXml.setMajorVersionId(getTextNode(node));
194 private void processSourceLanguageNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
195 appEngineWebXml.setSourceLanguage(getTextNode(node));
198 private void processModuleNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
199 appEngineWebXml.setModule(getTextNode(node));
202 private void processInstanceClassNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
203 appEngineWebXml.setInstanceClass(getTextNode(node));
206 private String getChildNodeText(XmlParser.Node parentNode, String childTag) {
207 String result = null;
208 XmlParser.Node node = parentNode.get(childTag);
209 if (node != null) {
210 result = (String) node.get(0);
212 return result;
215 private Integer getChildNodePositiveInteger(XmlParser.Node parentNode, String childTag) {
216 Integer result = null;
217 XmlParser.Node node = parentNode.get(childTag);
218 if (node != null && node.get(0) != null) {
219 String trimmedText = ((String) node.get(0)).trim();
220 if (!trimmedText.isEmpty()) {
221 try {
222 result = Integer.parseInt(trimmedText);
223 } catch (NumberFormatException ex) {
224 throw new AppEngineConfigException(childTag + " should only contain integers.");
227 if (result <= 0) {
228 throw new AppEngineConfigException(childTag + " should only contain positive integers.");
232 return result;
235 private Double getChildNodeDouble(XmlParser.Node parentNode, String childTag) {
236 Double result = null;
237 XmlParser.Node node = parentNode.get(childTag);
238 if (node != null && node.get(0) != null) {
239 String trimmedText = ((String) node.get(0)).trim();
240 if (!trimmedText.isEmpty()) {
241 try {
242 result = Double.parseDouble(trimmedText);
243 } catch (NumberFormatException ex) {
244 throw new AppEngineConfigException(childTag + " should only contain doubles.");
245 } catch (NullPointerException ex) {
246 throw new AppEngineConfigException(childTag + " should NOT be empty.");
250 return result;
253 private void processAutomaticScalingNode(XmlParser.Node settingsNode,
254 AppEngineWebXml appEngineWebXml) {
255 AutomaticScaling automaticScaling = appEngineWebXml.getAutomaticScaling();
256 automaticScaling.setMinPendingLatency(getChildNodeText(settingsNode, "min-pending-latency"));
257 automaticScaling.setMaxPendingLatency(getChildNodeText(settingsNode, "max-pending-latency"));
258 automaticScaling.setMinIdleInstances(getChildNodeText(settingsNode, "min-idle-instances"));
259 automaticScaling.setMaxIdleInstances(getChildNodeText(settingsNode, "max-idle-instances"));
260 automaticScaling.setMaxConcurrentRequests(
261 getChildNodeText(settingsNode, "max-concurrent-requests"));
262 automaticScaling.setMinNumInstances(
263 getChildNodePositiveInteger(settingsNode, "min-num-instances"));
264 automaticScaling.setMaxNumInstances(
265 getChildNodePositiveInteger(settingsNode, "max-num-instances"));
266 automaticScaling.setCoolDownPeriodSec(
267 getChildNodePositiveInteger(settingsNode, "cool-down-period-sec"));
268 processCpuUtilizationNode(settingsNode, automaticScaling);
271 private void processCpuUtilizationNode(
272 XmlParser.Node settingsNode, AutomaticScaling automaticScaling) {
273 XmlParser.Node childNode = settingsNode.get("cpu-utilization");
274 if (childNode != null) {
275 CpuUtilization cpuUtilization = new CpuUtilization();
276 Double targetUtilization = getChildNodeDouble(childNode, "target-utilization");
277 if (targetUtilization != null) {
278 if (targetUtilization <= 0 || targetUtilization > 1) {
279 throw new AppEngineConfigException("target-utilization should be in range (0, 1].");
281 cpuUtilization.setTargetUtilization(targetUtilization);
284 cpuUtilization.setAggregationWindowLengthSec(
285 getChildNodePositiveInteger(childNode, "aggregation-window-length-sec"));
286 if (!cpuUtilization.isEmpty()) {
287 automaticScaling.setCpuUtilization(cpuUtilization);
292 private void processManualScalingNode(XmlParser.Node settingsNode,
293 AppEngineWebXml appEngineWebXml) {
294 ManualScaling manualScaling = appEngineWebXml.getManualScaling();
295 manualScaling.setInstances(getChildNodeText(settingsNode, "instances"));
298 private void processBasicScalingNode(XmlParser.Node settingsNode,
299 AppEngineWebXml appEngineWebXml) {
300 BasicScaling basicScaling = appEngineWebXml.getBasicScaling();
301 basicScaling.setMaxInstances(getChildNodeText(settingsNode, "max-instances"));
302 basicScaling.setIdleTimeout(getChildNodeText(settingsNode, "idle-timeout"));
305 private void processSslEnabledNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
306 appEngineWebXml.setSslEnabled(getBooleanValue(node));
309 private void processSessionsEnabledNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
310 appEngineWebXml.setSessionsEnabled(getBooleanValue(node));
313 private void processAsyncSessionPersistenceNode(
314 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
315 boolean enabled = getBooleanAttributeValue(node, "enabled");
316 appEngineWebXml.setAsyncSessionPersistence(enabled);
317 String queueName = trim(node.getAttribute("queue-name"));
318 appEngineWebXml.setAsyncSessionPersistenceQueueName(queueName);
321 private void processPrecompilationEnabledNode(XmlParser.Node node,
322 AppEngineWebXml appEngineWebXml) {
323 appEngineWebXml.setPrecompilationEnabled(getBooleanValue(node));
326 private void processWarmupRequestsEnabledNode(XmlParser.Node node,
327 AppEngineWebXml appEngineWebXml) {
328 appEngineWebXml.setWarmupRequestsEnabled(getBooleanValue(node));
331 private void processThreadsafeNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
332 appEngineWebXml.setThreadsafe(getBooleanValue(node));
335 private void processAutoIdPolicyNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
336 appEngineWebXml.setAutoIdPolicy(getTextNode(node));
339 private void processCodeLockNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
340 appEngineWebXml.setCodeLock(getBooleanValue(node));
343 private void processVmNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
344 appEngineWebXml.setUseVm(getBooleanValue(node));
347 private void processFilesetNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml,
348 FileType type) {
349 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "include");
350 while (nodeIter.hasNext()) {
351 XmlParser.Node includeNode = nodeIter.next();
352 String path = trim(includeNode.getAttribute("path"));
353 if (type == FileType.STATIC) {
354 String expiration = trim(includeNode.getAttribute("expiration"));
355 AppEngineWebXml.StaticFileInclude staticFileInclude =
356 appEngineWebXml.includeStaticPattern(path, expiration);
358 Map<String, String> httpHeaders = staticFileInclude.getHttpHeaders();
359 Iterator<XmlParser.Node> httpHeaderIter = getNodeIterator(includeNode, "http-header");
360 while (httpHeaderIter.hasNext()) {
361 XmlParser.Node httpHeaderNode = httpHeaderIter.next();
362 String name = httpHeaderNode.getAttribute("name");
363 String value = httpHeaderNode.getAttribute("value");
365 if (httpHeaders.containsKey(name)) {
366 throw new AppEngineConfigException("Two http-header elements have the same name.");
369 httpHeaders.put(name, value);
371 } else {
372 appEngineWebXml.includeResourcePattern(path);
376 nodeIter = getNodeIterator(node, "exclude");
377 while (nodeIter.hasNext()) {
378 XmlParser.Node subNode = nodeIter.next();
379 String path = trim(subNode.getAttribute("path"));
380 if (type == FileType.STATIC) {
381 appEngineWebXml.excludeStaticPattern(path);
382 } else {
383 appEngineWebXml.excludeResourcePattern(path);
388 private Iterator<XmlParser.Node> getNodeIterator(XmlParser.Node node, String filter) {
389 @SuppressWarnings("unchecked")
390 Iterator<XmlParser.Node> iterator = node.iterator(filter);
391 return iterator;
394 private void processSystemPropertiesNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
395 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "property");
396 while (nodeIter.hasNext()) {
397 XmlParser.Node subNode = nodeIter.next();
398 String propertyName = trim(subNode.getAttribute("name"));
399 String propertyValue = trim(subNode.getAttribute("value"));
400 appEngineWebXml.addSystemProperty(propertyName, propertyValue);
404 private void processBetaSettingsNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
405 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "setting");
406 while (nodeIter.hasNext()) {
407 XmlParser.Node subNode = nodeIter.next();
408 String name = trim(subNode.getAttribute("name"));
409 String value = trim(subNode.getAttribute("value"));
410 appEngineWebXml.addBetaSetting(name, value);
414 private void processHealthCheckNode(XmlParser.Node settingsNode,
415 AppEngineWebXml appEngineWebXml) {
416 HealthCheck healthCheck = appEngineWebXml.getHealthCheck();
417 String enableHealthCheck = trim(getChildNodeText(settingsNode, "enable-health-check"));
418 if (enableHealthCheck != null && !enableHealthCheck.isEmpty()) {
419 healthCheck.setEnableHealthCheck(toBoolean(enableHealthCheck));
421 healthCheck.setCheckIntervalSec(
422 getChildNodePositiveInteger(settingsNode, "check-interval-sec"));
423 healthCheck.setTimeoutSec(getChildNodePositiveInteger(settingsNode, "timeout-sec"));
424 healthCheck.setUnhealthyThreshold(
425 getChildNodePositiveInteger(settingsNode, "unhealthy-threshold"));
426 healthCheck.setHealthyThreshold(
427 getChildNodePositiveInteger(settingsNode, "healthy-threshold"));
428 healthCheck.setRestartThreshold(
429 getChildNodePositiveInteger(settingsNode, "restart-threshold"));
430 healthCheck.setHost(getChildNodeText(settingsNode, "host"));
433 private void processResourcesNode(XmlParser.Node settingsNode,
434 AppEngineWebXml appEngineWebXml) {
435 Resources resources = appEngineWebXml.getResources();
436 Double cpu = getChildNodeDouble(settingsNode, "cpu");
437 if (cpu != null) {
438 resources.setCpu(cpu);
440 Double memory_gb = getChildNodeDouble(settingsNode, "memory-gb");
441 if (memory_gb != null) {
442 resources.setMemoryGb(memory_gb);
444 Integer disk_size_gb = getChildNodePositiveInteger(settingsNode, "disk-size-gb");
445 if (disk_size_gb != null) {
446 resources.setDiskSizeGb(disk_size_gb);
450 private void processNetworkNode(XmlParser.Node settingsNode,
451 AppEngineWebXml appEngineWebXml) {
452 Network network = appEngineWebXml.getNetwork();
453 String instance_tag = trim(getChildNodeText(settingsNode, "instance-tag"));
454 if (instance_tag != null && !instance_tag.isEmpty()) {
455 network.setInstanceTag(instance_tag);
457 Iterator<XmlParser.Node> nodeIter = getNodeIterator(settingsNode, "forwarded-port");
458 while (nodeIter.hasNext()) {
459 XmlParser.Node subNode = nodeIter.next();
460 String forwardedPort = getTextNode(subNode);
461 network.addForwardedPort(forwardedPort);
463 String name = trim(getChildNodeText(settingsNode, "name"));
464 if (name != null && !name.isEmpty()) {
465 network.setName(name);
469 private void processEnvironmentVariablesNode(
470 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
471 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "env-var");
472 while (nodeIter.hasNext()) {
473 XmlParser.Node subNode = nodeIter.next();
474 String propertyName = trim(subNode.getAttribute("name"));
475 String propertyValue = trim(subNode.getAttribute("value"));
476 appEngineWebXml.addEnvironmentVariable(propertyName, propertyValue);
480 private void processPermissionsNode(
481 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
482 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "permission");
483 while (nodeIter.hasNext()) {
484 XmlParser.Node subNode = nodeIter.next();
485 String className = trim(subNode.getAttribute("class"));
486 String name = trim(subNode.getAttribute("name"));
487 String actions = trim(subNode.getAttribute("actions"));
488 appEngineWebXml.addUserPermission(className, name, actions);
492 private void processInboundServicesNode(
493 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
494 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "service");
495 while (nodeIter.hasNext()) {
496 XmlParser.Node subNode = nodeIter.next();
497 String service = getTextNode(subNode);
498 appEngineWebXml.addInboundService(service);
502 private void processAdminConsoleNode(
503 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
504 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "page");
505 while (nodeIter.hasNext()) {
506 XmlParser.Node subNode = nodeIter.next();
507 String name = trim(subNode.getAttribute("name"));
508 String url = trim(subNode.getAttribute("url"));
509 appEngineWebXml.addAdminConsolePage(new AdminConsolePage(name, url));
513 private void processErrorHandlerNode(
514 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
515 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "handler");
516 while (nodeIter.hasNext()) {
517 XmlParser.Node subNode = nodeIter.next();
518 String file = trim(subNode.getAttribute("file"));
519 String errorCode = trim(subNode.getAttribute("error-code"));
520 appEngineWebXml.addErrorHandler(new ErrorHandler(file, errorCode));
524 private void processApiConfigNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
525 String servlet = trim(node.getAttribute("servlet-class"));
526 String url = trim(node.getAttribute("url-pattern"));
527 appEngineWebXml.setApiConfig(new ApiConfig(servlet, url));
529 String id = null;
530 Iterator<XmlParser.Node> subNodeIter = getNodeIterator(node, "endpoint-servlet-mapping-id");
531 while (subNodeIter.hasNext()) {
532 XmlParser.Node subNode = subNodeIter.next();
533 id = trim(getTextNode(subNode));
534 if (id != null && id.length() > 0) {
535 appEngineWebXml.addApiEndpoint(id);
540 private void processPagespeedNode(XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
541 Pagespeed pagespeed = new Pagespeed();
542 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "url-blacklist");
543 while (nodeIter.hasNext()) {
544 XmlParser.Node subNode = nodeIter.next();
545 String urlMatcher = getTextNode(subNode);
546 pagespeed.addUrlBlacklist(urlMatcher);
548 nodeIter = getNodeIterator(node, "domain-to-rewrite");
549 while (nodeIter.hasNext()) {
550 XmlParser.Node subNode = nodeIter.next();
551 String domain = getTextNode(subNode);
552 pagespeed.addDomainToRewrite(domain);
554 nodeIter = getNodeIterator(node, "enabled-rewriter");
555 while (nodeIter.hasNext()) {
556 XmlParser.Node subNode = nodeIter.next();
557 String rewriter = getTextNode(subNode);
558 pagespeed.addEnabledRewriter(rewriter);
560 nodeIter = getNodeIterator(node, "disabled-rewriter");
561 while (nodeIter.hasNext()) {
562 XmlParser.Node subNode = nodeIter.next();
563 String rewriter = getTextNode(subNode);
564 pagespeed.addDisabledRewriter(rewriter);
566 appEngineWebXml.setPagespeed(pagespeed);
569 private void processClassLoaderConfig(
570 XmlParser.Node node, AppEngineWebXml appEngineWebXml) {
571 ClassLoaderConfig config = new ClassLoaderConfig();
572 appEngineWebXml.setClassLoaderConfig(config);
573 Iterator<XmlParser.Node> nodeIter = getNodeIterator(node, "priority-specifier");
574 while (nodeIter.hasNext()) {
575 processClassPathPrioritySpecifier(nodeIter.next(), config);
579 private void processClassPathPrioritySpecifier(Node node, ClassLoaderConfig config) {
580 PrioritySpecifierEntry entry = new PrioritySpecifierEntry();
581 entry.setFilename(node.getAttribute("filename"));
582 entry.setPriority(node.getAttribute("priority"));
583 entry.checkClassLoaderConfig();
584 config.add(entry);
587 private void processUrlStreamHandler(Node node, AppEngineWebXml appEngineWebXml) {
588 appEngineWebXml.setUrlStreamHandlerType(getTextNode(node));
591 private boolean getBooleanValue(XmlParser.Node node) {
592 return toBoolean(getTextNode(node));
595 private boolean getBooleanAttributeValue(XmlParser.Node node, String attribute) {
596 return toBoolean(node.getAttribute(attribute));
599 private boolean toBoolean(String value) {
600 value = value.trim();
601 return (value.equalsIgnoreCase("true") || value.equals("1"));
604 private String getTextNode(XmlParser.Node node) {
605 String value = (String) node.get(0);
606 if (value == null) {
607 value = "";
609 return value.trim();
612 private String trim(String attribute) {
613 return attribute == null ? null : attribute.trim();
616 private void processUseGoogleConnectorJNode(XmlParser.Node node,
617 AppEngineWebXml appEngineWebXml) {
618 appEngineWebXml.setUseGoogleConnectorJ(getBooleanValue(node));