Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / apphosting / utils / config / AppEngineWebXml.java
blobe9f088cae818e691467102b9b669054c4460bfdf
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 package com.google.apphosting.utils.config;
4 import com.google.common.base.Objects;
5 import com.google.common.base.StringUtil;
6 import com.google.common.collect.Lists;
7 import com.google.common.collect.Maps;
9 import java.security.Permissions;
10 import java.security.UnresolvedPermission;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.LinkedHashSet;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18 import java.util.regex.Pattern;
20 /**
21 * Struct describing the config data that lives in WEB-INF/appengine-web.xml.
23 * Any additions to this class should also be made to the YAML
24 * version in AppYaml.java.
27 public class AppEngineWebXml {
28 /**
29 * Enumeration of supported scaling types.
31 public static enum ScalingType {AUTOMATIC, MANUAL, BASIC}
33 private final Map<String, String> systemProperties = Maps.newHashMap();
35 private final Map<String, String> vmSettings = Maps.newLinkedHashMap();
37 private final Map<String, String> envVariables = Maps.newHashMap();
39 private final List<UserPermission> userPermissions = new ArrayList<UserPermission>();
41 public static final String WARMUP_SERVICE = "warmup";
43 public static final String URL_HANDLER_URLFETCH = "urlfetch";
44 public static final String URL_HANDLER_NATIVE= "native";
46 private String appId;
48 private String majorVersionId;
50 private String module;
51 private String instanceClass;
53 private final AutomaticScaling automaticScaling;
54 private final ManualScaling manualScaling;
55 private final BasicScaling basicScaling;
57 private String sourceLanguage;
58 private boolean sslEnabled = true;
59 private boolean useSessions = false;
60 private boolean asyncSessionPersistence = false;
61 private String asyncSessionPersistenceQueueName;
63 private final List<StaticFileInclude> staticFileIncludes;
64 private final List<String> staticFileExcludes;
65 private final List<String> resourceFileIncludes;
66 private final List<String> resourceFileExcludes;
68 private Pattern staticIncludePattern;
69 private Pattern staticExcludePattern;
70 private Pattern resourceIncludePattern;
71 private Pattern resourceExcludePattern;
73 private String publicRoot = "";
75 private String appRoot;
77 private final Set<String> inboundServices;
78 private boolean precompilationEnabled = true;
80 private final List<AdminConsolePage> adminConsolePages = new ArrayList<AdminConsolePage>();
81 private final List<ErrorHandler> errorHandlers = new ArrayList<ErrorHandler>();
83 private ClassLoaderConfig classLoaderConfig;
85 private String urlStreamHandlerType = null;
87 private boolean threadsafe = false;
88 private boolean threadsafeValueProvided = false;
90 private String autoIdPolicy;
92 private boolean codeLock = false;
93 private boolean useVm = false;
94 private ApiConfig apiConfig;
95 private final List<String> apiEndpointIds;
96 private Pagespeed pagespeed;
98 /**
99 * Represent user's choice w.r.t the usage of Google's customized connector-j.
101 public static enum UseGoogleConnectorJ {
102 NOT_STATED_BY_USER,
103 TRUE,
104 FALSE,
106 private UseGoogleConnectorJ useGoogleConnectorJ = UseGoogleConnectorJ.NOT_STATED_BY_USER;
108 public AppEngineWebXml() {
109 automaticScaling = new AutomaticScaling();
110 manualScaling = new ManualScaling();
111 basicScaling = new BasicScaling();
113 staticFileIncludes = new ArrayList<StaticFileInclude>();
114 staticFileExcludes = new ArrayList<String>();
115 staticFileExcludes.add("WEB-INF/**");
116 staticFileExcludes.add("**.jsp");
117 resourceFileIncludes = new ArrayList<String>();
118 resourceFileExcludes = new ArrayList<String>();
119 inboundServices = new LinkedHashSet<String>();
120 apiEndpointIds = new ArrayList<String>();
124 * @return An unmodifiable map whose entries correspond to the
125 * system properties defined in appengine-web.xml.
127 public Map<String, String> getSystemProperties() {
128 return Collections.unmodifiableMap(systemProperties);
131 public void addSystemProperty(String key, String value) {
132 systemProperties.put(key, value);
136 * @return An unmodifiable map whose entires correspond to the
137 * vm settings defined in appengine-web.xml.
139 public Map<String, String> getVmSettings() {
140 return Collections.unmodifiableMap(vmSettings);
143 public void addVmSetting(String key, String value) {
144 vmSettings.put(key, value);
148 * @return An unmodifiable map whose entires correspond to the
149 * environment variables defined in appengine-web.xml.
151 public Map<String, String> getEnvironmentVariables() {
152 return Collections.unmodifiableMap(envVariables);
155 public void addEnvironmentVariable(String key, String value) {
156 envVariables.put(key, value);
159 public String getAppId() {
160 return appId;
163 public void setAppId(String appId) {
164 this.appId = appId;
167 public String getMajorVersionId() {
168 return majorVersionId;
171 public void setMajorVersionId(String majorVersionId) {
172 this.majorVersionId = majorVersionId;
175 public String getSourceLanguage() {
176 return this.sourceLanguage;
179 public void setSourceLanguage(String sourceLanguage) {
180 this.sourceLanguage = sourceLanguage;
183 public String getModule() {
184 return module;
188 * Sets instanceClass (aka class in the xml/yaml files). Normalizes empty and null
189 * inputs to null.
191 public void setInstanceClass(String instanceClass) {
192 this.instanceClass = StringUtil.toNullIfEmptyOrWhitespace(instanceClass);
195 public String getInstanceClass() {
196 return instanceClass;
199 public AutomaticScaling getAutomaticScaling() {
200 return automaticScaling;
203 public ManualScaling getManualScaling() {
204 return manualScaling;
207 public BasicScaling getBasicScaling() {
208 return basicScaling;
211 public ScalingType getScalingType() {
212 if (!getBasicScaling().isEmpty()) {
213 return ScalingType.BASIC;
214 } else if (!getManualScaling().isEmpty()) {
215 return ScalingType.MANUAL;
216 } else {
217 return ScalingType.AUTOMATIC;
221 public void setModule(String module) {
222 this.module = module;
225 public void setSslEnabled(boolean ssl) {
226 sslEnabled = ssl;
229 public boolean getSslEnabled() {
230 return sslEnabled;
233 public void setSessionsEnabled(boolean sessions) {
234 useSessions = sessions;
237 public boolean getSessionsEnabled() {
238 return useSessions;
241 public void setAsyncSessionPersistence(boolean asyncSessionPersistence) {
242 this.asyncSessionPersistence = asyncSessionPersistence;
245 public boolean getAsyncSessionPersistence() {
246 return asyncSessionPersistence;
249 public void setAsyncSessionPersistenceQueueName(String asyncSessionPersistenceQueueName) {
250 this.asyncSessionPersistenceQueueName = asyncSessionPersistenceQueueName;
253 public String getAsyncSessionPersistenceQueueName() {
254 return asyncSessionPersistenceQueueName;
257 public List<StaticFileInclude> getStaticFileIncludes() {
258 return staticFileIncludes;
261 public List<String> getStaticFileExcludes() {
262 return staticFileExcludes;
265 public StaticFileInclude includeStaticPattern(String pattern, String expiration) {
266 staticIncludePattern = null;
267 StaticFileInclude staticFileInclude = new StaticFileInclude(pattern, expiration);
268 staticFileIncludes.add(staticFileInclude);
269 return staticFileInclude;
272 public void excludeStaticPattern(String url) {
273 staticExcludePattern = null;
274 staticFileExcludes.add(url);
277 public List<String> getResourcePatterns() {
278 return resourceFileIncludes;
281 public List<String> getResourceFileExcludes() {
282 return resourceFileExcludes;
285 public void includeResourcePattern(String url) {
286 resourceExcludePattern = null;
287 resourceFileIncludes.add(url);
290 public void excludeResourcePattern(String url) {
291 resourceIncludePattern = null;
292 resourceFileExcludes.add(url);
295 public void addUserPermission(String className, String name, String actions) {
296 if (className.startsWith("java.")) {
297 throw new AppEngineConfigException("Cannot specify user-permissions for " +
298 "classes in java.* packages.");
301 userPermissions.add(new UserPermission(className, name, actions));
304 public Permissions getUserPermissions() {
305 Permissions permissions = new Permissions();
306 for (UserPermission permission : userPermissions) {
307 permissions.add(new UnresolvedPermission(permission.getClassName(),
308 permission.getName(),
309 permission.getActions(),
310 null));
312 permissions.setReadOnly();
313 return permissions;
316 public void setPublicRoot(String root) {
317 if (root.indexOf('*') != -1) {
318 throw new AppEngineConfigException("public-root cannot contain wildcards");
320 if (root.endsWith("/")) {
321 root = root.substring(0, root.length() - 1);
323 if (root.length() > 0 && !root.startsWith("/")) {
324 root = "/" + root;
326 staticIncludePattern = null;
327 publicRoot = root;
330 public String getPublicRoot() {
331 return publicRoot;
334 public void addInboundService(String service) {
335 inboundServices.add(service);
338 public Set<String> getInboundServices() {
339 return inboundServices;
342 public boolean getPrecompilationEnabled() {
343 return precompilationEnabled;
346 public void setPrecompilationEnabled(boolean precompilationEnabled) {
347 this.precompilationEnabled = precompilationEnabled;
350 public boolean getWarmupRequestsEnabled() {
351 return inboundServices.contains(WARMUP_SERVICE);
354 public void setWarmupRequestsEnabled(boolean warmupRequestsEnabled) {
355 if (warmupRequestsEnabled) {
356 inboundServices.add(WARMUP_SERVICE);
357 } else {
358 inboundServices.remove(WARMUP_SERVICE);
362 public List<AdminConsolePage> getAdminConsolePages() {
363 return Collections.unmodifiableList(adminConsolePages);
366 public void addAdminConsolePage(AdminConsolePage page) {
367 adminConsolePages.add(page);
370 public List<ErrorHandler> getErrorHandlers() {
371 return Collections.unmodifiableList(errorHandlers);
374 public void addErrorHandler(ErrorHandler handler) {
375 errorHandlers.add(handler);
378 public boolean getThreadsafe() {
379 return threadsafe;
382 public boolean getThreadsafeValueProvided() {
383 return threadsafeValueProvided;
386 public void setThreadsafe(boolean threadsafe) {
387 this.threadsafe = threadsafe;
388 this.threadsafeValueProvided = true;
391 public void setAutoIdPolicy(String policy) {
392 autoIdPolicy = policy;
395 public String getAutoIdPolicy() {
396 return autoIdPolicy;
399 public boolean getCodeLock() {
400 return codeLock;
403 public void setCodeLock(boolean codeLock) {
404 this.codeLock = codeLock;
407 public void setUseVm(boolean useVm) {
408 this.useVm = useVm;
411 public boolean getUseVm() {
412 return useVm;
415 public ApiConfig getApiConfig() {
416 return apiConfig;
419 public void setApiConfig(ApiConfig config) {
420 apiConfig = config;
423 public ClassLoaderConfig getClassLoaderConfig() {
424 return classLoaderConfig;
427 public void setClassLoaderConfig(ClassLoaderConfig classLoaderConfig) {
428 if (this.classLoaderConfig != null) {
429 throw new AppEngineConfigException("class-loader-config may only be specified once.");
431 this.classLoaderConfig = classLoaderConfig;
434 public String getUrlStreamHandlerType() {
435 return urlStreamHandlerType;
438 public void setUrlStreamHandlerType(String urlStreamHandlerType) {
439 if (this.classLoaderConfig != null) {
440 throw new AppEngineConfigException("url-stream-handler may only be specified once.");
442 if (!URL_HANDLER_URLFETCH.equals(urlStreamHandlerType)
443 && !URL_HANDLER_NATIVE.equals(urlStreamHandlerType)) {
444 throw new AppEngineConfigException(
445 "url-stream-handler must be " + URL_HANDLER_URLFETCH + " or " + URL_HANDLER_NATIVE +
446 " given " + urlStreamHandlerType);
448 this.urlStreamHandlerType = urlStreamHandlerType;
452 * Returns true if {@code url} matches one of the servlets or servlet
453 * filters listed in this web.xml that has api-endpoint set to true.
455 public boolean isApiEndpoint(String id) {
456 return apiEndpointIds.contains(id);
459 public void addApiEndpoint(String id) {
460 apiEndpointIds.add(id);
463 public Pagespeed getPagespeed() {
464 return pagespeed;
467 public void setPagespeed(Pagespeed pagespeed) {
468 this.pagespeed = pagespeed;
471 public void setUseGoogleConnectorJ(boolean useGoogleConnectorJ) {
472 if (useGoogleConnectorJ) {
473 this.useGoogleConnectorJ = UseGoogleConnectorJ.TRUE;
474 } else {
475 this.useGoogleConnectorJ = UseGoogleConnectorJ.FALSE;
479 public UseGoogleConnectorJ getUseGoogleConnectorJ() {
480 return useGoogleConnectorJ;
483 @Override
484 public String toString() {
485 return "AppEngineWebXml{" +
486 "systemProperties=" + systemProperties +
487 ", envVariables=" + envVariables +
488 ", userPermissions=" + userPermissions +
489 ", appId='" + appId + '\'' +
490 ", majorVersionId='" + majorVersionId + '\'' +
491 ", sourceLanguage='" + sourceLanguage + '\'' +
492 ", module='" + module + '\'' +
493 ", instanceClass='" + instanceClass + '\'' +
494 ", automaticScaling=" + automaticScaling +
495 ", manualScaling=" + manualScaling +
496 ", basicScaling=" + basicScaling +
497 ", sslEnabled=" + sslEnabled +
498 ", useSessions=" + useSessions +
499 ", asyncSessionPersistence=" + asyncSessionPersistence +
500 ", asyncSessionPersistenceQueueName='" + asyncSessionPersistenceQueueName + '\'' +
501 ", staticFileIncludes=" + staticFileIncludes +
502 ", staticFileExcludes=" + staticFileExcludes +
503 ", resourceFileIncludes=" + resourceFileIncludes +
504 ", resourceFileExcludes=" + resourceFileExcludes +
505 ", staticIncludePattern=" + staticIncludePattern +
506 ", staticExcludePattern=" + staticExcludePattern +
507 ", resourceIncludePattern=" + resourceIncludePattern +
508 ", resourceExcludePattern=" + resourceExcludePattern +
509 ", publicRoot='" + publicRoot + '\'' +
510 ", appRoot='" + appRoot + '\'' +
511 ", inboundServices=" + inboundServices +
512 ", precompilationEnabled=" + precompilationEnabled +
513 ", adminConsolePages=" + adminConsolePages +
514 ", errorHandlers=" + errorHandlers +
515 ", threadsafe=" + threadsafe +
516 ", threadsafeValueProvided=" + threadsafeValueProvided +
517 ", autoIdPolicy=" + autoIdPolicy +
518 ", codeLock=" + codeLock +
519 ", apiConfig=" + apiConfig +
520 ", apiEndpointIds=" + apiEndpointIds +
521 ", pagespeed=" + pagespeed +
522 ", classLoaderConfig=" + classLoaderConfig +
523 ", urlStreamHandlerType=" +
524 (urlStreamHandlerType == null ? URL_HANDLER_URLFETCH : urlStreamHandlerType) +
525 ", useGoogleConnectorJ=" + useGoogleConnectorJ +
526 '}';
529 @Override
530 public boolean equals(Object o) {
531 if (this == o) {
532 return true;
534 if (o == null || getClass() != o.getClass()) {
535 return false;
538 AppEngineWebXml that = (AppEngineWebXml) o;
540 if (asyncSessionPersistence != that.asyncSessionPersistence) {
541 return false;
543 if (precompilationEnabled != that.precompilationEnabled) {
544 return false;
546 if (sslEnabled != that.sslEnabled) {
547 return false;
549 if (threadsafe != that.threadsafe) {
550 return false;
552 if (threadsafeValueProvided != that.threadsafeValueProvided) {
553 return false;
555 if (autoIdPolicy != null ? !autoIdPolicy.equals(that.autoIdPolicy)
556 : that.autoIdPolicy != null) {
557 return false;
559 if (codeLock != that.codeLock) {
560 return false;
562 if (useSessions != that.useSessions) {
563 return false;
565 if (adminConsolePages != null ? !adminConsolePages.equals(that.adminConsolePages)
566 : that.adminConsolePages != null) {
567 return false;
569 if (appId != null ? !appId.equals(that.appId) : that.appId != null) {
570 return false;
572 if (majorVersionId != null ? !majorVersionId.equals(that.majorVersionId)
573 : that.majorVersionId != null) {
574 return false;
576 if (module != null ? !module.equals(that.module) : that.module != null) {
577 return false;
579 if (instanceClass != null ? !instanceClass.equals(that.instanceClass)
580 : that.instanceClass != null) {
581 return false;
583 if (!automaticScaling.equals(that.automaticScaling)) {
584 return false;
586 if (!manualScaling.equals(that.manualScaling)) {
587 return false;
589 if (!basicScaling.equals(that.basicScaling)) {
590 return false;
592 if (appRoot != null ? !appRoot.equals(that.appRoot) : that.appRoot != null) {
593 return false;
595 if (asyncSessionPersistenceQueueName != null ? !asyncSessionPersistenceQueueName
596 .equals(that.asyncSessionPersistenceQueueName)
597 : that.asyncSessionPersistenceQueueName != null) {
598 return false;
600 if (envVariables != null ? !envVariables.equals(that.envVariables)
601 : that.envVariables != null) {
602 return false;
604 if (errorHandlers != null ? !errorHandlers.equals(that.errorHandlers)
605 : that.errorHandlers != null) {
606 return false;
608 if (inboundServices != null ? !inboundServices.equals(that.inboundServices)
609 : that.inboundServices != null) {
610 return false;
612 if (majorVersionId != null ? !majorVersionId.equals(that.majorVersionId)
613 : that.majorVersionId != null) {
614 return false;
616 if (sourceLanguage != null ? !sourceLanguage.equals(that.sourceLanguage)
617 : that.sourceLanguage != null) {
618 return false;
620 if (publicRoot != null ? !publicRoot.equals(that.publicRoot) : that.publicRoot != null) {
621 return false;
623 if (resourceExcludePattern != null ? !resourceExcludePattern.equals(that.resourceExcludePattern)
624 : that.resourceExcludePattern != null) {
625 return false;
627 if (resourceFileExcludes != null ? !resourceFileExcludes.equals(that.resourceFileExcludes)
628 : that.resourceFileExcludes != null) {
629 return false;
631 if (resourceFileIncludes != null ? !resourceFileIncludes.equals(that.resourceFileIncludes)
632 : that.resourceFileIncludes != null) {
633 return false;
635 if (resourceIncludePattern != null ? !resourceIncludePattern.equals(that.resourceIncludePattern)
636 : that.resourceIncludePattern != null) {
637 return false;
639 if (staticExcludePattern != null ? !staticExcludePattern.equals(that.staticExcludePattern)
640 : that.staticExcludePattern != null) {
641 return false;
643 if (staticFileExcludes != null ? !staticFileExcludes.equals(that.staticFileExcludes)
644 : that.staticFileExcludes != null) {
645 return false;
647 if (staticFileIncludes != null ? !staticFileIncludes.equals(that.staticFileIncludes)
648 : that.staticFileIncludes != null) {
649 return false;
651 if (staticIncludePattern != null ? !staticIncludePattern.equals(that.staticIncludePattern)
652 : that.staticIncludePattern != null) {
653 return false;
655 if (systemProperties != null ? !systemProperties.equals(that.systemProperties)
656 : that.systemProperties != null) {
657 return false;
659 if (vmSettings != null ? !vmSettings.equals(that.vmSettings) : that.vmSettings != null) {
660 return false;
663 if (userPermissions != null ? !userPermissions.equals(that.userPermissions)
664 : that.userPermissions != null) {
665 return false;
667 if (apiConfig != null ? !apiConfig.equals(that.apiConfig)
668 : that.apiConfig != null) {
669 return false;
671 if (apiEndpointIds != null ? !apiEndpointIds.equals(that.apiEndpointIds)
672 : that.apiEndpointIds != null) {
673 return false;
675 if (pagespeed != null ? !pagespeed.equals(that.pagespeed) : that.pagespeed != null) {
676 return false;
678 if (classLoaderConfig != null ? !classLoaderConfig.equals(that.classLoaderConfig) :
679 that.classLoaderConfig != null) {
680 return false;
682 if (urlStreamHandlerType != null ? !urlStreamHandlerType.equals(that.urlStreamHandlerType) :
683 that.urlStreamHandlerType != null) {
684 return false;
686 if (useGoogleConnectorJ != that.useGoogleConnectorJ) {
687 return false;
690 return true;
693 @Override
694 public int hashCode() {
695 int result = systemProperties != null ? systemProperties.hashCode() : 0;
696 result = 31 * result + (envVariables != null ? envVariables.hashCode() : 0);
697 result = 31 * result + (userPermissions != null ? userPermissions.hashCode() : 0);
698 result = 31 * result + (appId != null ? appId.hashCode() : 0);
699 result = 31 * result + (majorVersionId != null ? majorVersionId.hashCode() : 0);
700 result = 31 * result + (sourceLanguage != null ? sourceLanguage.hashCode() : 0);
701 result = 31 * result + (module != null ? module.hashCode() : 0);
702 result = 31 * result + (instanceClass != null ? instanceClass.hashCode() : 0);
703 result = 31 * result + automaticScaling.hashCode();
704 result = 31 * result + manualScaling.hashCode();
705 result = 31 * result + basicScaling.hashCode();
706 result = 31 * result + (sslEnabled ? 1 : 0);
707 result = 31 * result + (useSessions ? 1 : 0);
708 result = 31 * result + (asyncSessionPersistence ? 1 : 0);
709 result =
710 31 * result + (asyncSessionPersistenceQueueName != null ? asyncSessionPersistenceQueueName
711 .hashCode() : 0);
712 result = 31 * result + (staticFileIncludes != null ? staticFileIncludes.hashCode() : 0);
713 result = 31 * result + (staticFileExcludes != null ? staticFileExcludes.hashCode() : 0);
714 result = 31 * result + (resourceFileIncludes != null ? resourceFileIncludes.hashCode() : 0);
715 result = 31 * result + (resourceFileExcludes != null ? resourceFileExcludes.hashCode() : 0);
716 result = 31 * result + (staticIncludePattern != null ? staticIncludePattern.hashCode() : 0);
717 result = 31 * result + (staticExcludePattern != null ? staticExcludePattern.hashCode() : 0);
718 result = 31 * result + (resourceIncludePattern != null ? resourceIncludePattern.hashCode() : 0);
719 result = 31 * result + (resourceExcludePattern != null ? resourceExcludePattern.hashCode() : 0);
720 result = 31 * result + (publicRoot != null ? publicRoot.hashCode() : 0);
721 result = 31 * result + (appRoot != null ? appRoot.hashCode() : 0);
722 result = 31 * result + (inboundServices != null ? inboundServices.hashCode() : 0);
723 result = 31 * result + (precompilationEnabled ? 1 : 0);
724 result = 31 * result + (adminConsolePages != null ? adminConsolePages.hashCode() : 0);
725 result = 31 * result + (errorHandlers != null ? errorHandlers.hashCode() : 0);
726 result = 31 * result + (threadsafe ? 1 : 0);
727 result = 31 * result + (autoIdPolicy != null ? autoIdPolicy.hashCode() : 0);
728 result = 31 * result + (threadsafeValueProvided ? 1 : 0);
729 result = 31 * result + (codeLock ? 1 : 0);
730 result = 31 * result + (apiConfig != null ? apiConfig.hashCode() : 0);
731 result = 31 * result + (apiEndpointIds != null ? apiEndpointIds.hashCode() : 0);
732 result = 31 * result + (pagespeed != null ? pagespeed.hashCode() : 0);
733 result = 31 * result + (classLoaderConfig != null ? classLoaderConfig.hashCode() : 0);
734 result = 31 * result + (urlStreamHandlerType != null ? urlStreamHandlerType.hashCode() : 0);
735 result = 31 * result + (useGoogleConnectorJ.hashCode());
736 result = 31 * result + (vmSettings != null ? vmSettings.hashCode() : 0);
737 return result;
740 public boolean includesResource(String path) {
741 if (resourceIncludePattern == null) {
742 if (resourceFileIncludes.size() == 0) {
743 resourceIncludePattern = Pattern.compile(".*");
744 } else {
745 resourceIncludePattern = Pattern.compile(makeRegexp(resourceFileIncludes));
748 if (resourceExcludePattern == null && resourceFileExcludes.size() > 0) {
749 resourceExcludePattern = Pattern.compile(makeRegexp(resourceFileExcludes));
750 } else {
752 return includes(path, resourceIncludePattern, resourceExcludePattern);
755 public boolean includesStatic(String path) {
756 if (staticIncludePattern == null) {
757 if (staticFileIncludes.size() == 0) {
758 String staticRoot;
759 if (publicRoot.length() > 0) {
760 staticRoot = publicRoot + "/**";
761 } else {
762 staticRoot = "**";
764 staticIncludePattern = Pattern.compile(
765 makeRegexp(Collections.singletonList(staticRoot)));
766 } else {
767 List<String> patterns = new ArrayList<String>();
768 for (StaticFileInclude include : staticFileIncludes) {
769 patterns.add(include.getPattern());
771 staticIncludePattern = Pattern.compile(makeRegexp(patterns));
774 if (staticExcludePattern == null && staticFileExcludes.size() > 0) {
775 staticExcludePattern = Pattern.compile(makeRegexp(staticFileExcludes));
776 } else {
778 return includes(path, staticIncludePattern, staticExcludePattern);
782 * Tests whether {@code path} is covered by the pattern {@code includes}
783 * while not being blocked by matching {@code excludes}.
785 * @param path a URL to test
786 * @param includes a non-{@code null} pattern for included URLs
787 * @param excludes a pattern for exclusion, or {@code null} to not exclude
788 * anything from the {@code includes} set.
790 public boolean includes(String path, Pattern includes, Pattern excludes) {
791 assert(includes != null);
792 if (!includes.matcher(path).matches()) {
793 return false;
795 if (excludes != null && excludes.matcher(path).matches()) {
796 return false;
798 return true;
801 public String makeRegexp(List<String> patterns) {
802 StringBuilder builder = new StringBuilder();
803 boolean first = true;
804 for (String item : patterns) {
805 if (first) {
806 first = false;
807 } else {
808 builder.append('|');
811 while (item.charAt(0) == '/') {
812 item = item.substring(1);
815 builder.append('(');
816 if (appRoot != null) {
817 builder.append(makeFileRegex(appRoot));
819 builder.append("/");
820 builder.append(makeFileRegex(item));
821 builder.append(')');
823 return builder.toString();
827 * Helper method to translate from appengine-web.xml "file globs" to
828 * proper regular expressions as used in app.yaml.
830 * @param fileGlob the glob to translate
831 * @return the regular expression string matching the input {@code file} pattern.
833 static String makeFileRegex(String fileGlob) {
834 fileGlob = fileGlob.replaceAll("([^A-Za-z0-9\\-_/])", "\\\\$1");
835 fileGlob = fileGlob.replaceAll("\\\\\\*\\\\\\*", ".*");
836 fileGlob = fileGlob.replaceAll("\\\\\\*", "[^/]*");
837 return fileGlob;
840 * Sets the application root directory, as a prefix for the regexps in
841 * {@link #includeResourcePattern(String)} and friends. This is needed
842 * because we want to match complete filenames relative to root.
844 * @param appRoot
846 public void setSourcePrefix(String appRoot) {
847 this.appRoot = appRoot;
848 this.resourceIncludePattern = null;
849 this.resourceExcludePattern = null;
850 this.staticIncludePattern = null;
851 this.staticExcludePattern = null;
854 public String getSourcePrefix() {
855 return this.appRoot;
859 * Represents a {@link java.security.Permission} that needs to be
860 * granted to user code.
862 private static class UserPermission {
863 private final String className;
864 private final String name;
865 private final String actions;
867 private boolean hasHashCode = false;
868 private int hashCode;
870 public UserPermission(String className, String name, String actions) {
871 this.className = className;
872 this.name = name;
873 this.actions = actions;
876 public String getClassName() {
877 return className;
880 public String getName() {
881 return name;
884 public String getActions() {
885 return actions;
888 @Override
889 public int hashCode() {
890 if (hasHashCode) {
891 return hashCode;
894 int hash = className.hashCode();
895 hash = 31 * hash + name.hashCode();
896 if (actions != null) {
897 hash = 31 * hash + actions.hashCode();
900 hashCode = hash;
901 hasHashCode = true;
902 return hashCode;
905 @Override
906 public boolean equals(Object obj) {
907 if (obj instanceof UserPermission) {
908 UserPermission perm = (UserPermission) obj;
909 if (className.equals(perm.className) && name.equals(perm.name)) {
910 if (actions == null ? perm.actions == null : actions.equals(perm.actions)) {
911 return true;
915 return false;
920 * Represents an &lt;include&gt; element within the
921 * &lt;static-files&gt; element. Currently this includes both a
922 * pattern and an optional expiration time specification.
924 public static class StaticFileInclude {
925 private final String pattern;
926 private final String expiration;
927 private final Map<String, String> httpHeaders;
929 public StaticFileInclude(String pattern, String expiration) {
930 this.pattern = pattern;
931 this.expiration = expiration;
932 this.httpHeaders = new HashMap<String, String>();
935 public String getPattern() {
936 return pattern;
939 public Pattern getRegularExpression() {
940 return Pattern.compile(makeFileRegex(pattern));
943 public String getExpiration() {
944 return expiration;
947 public Map<String, String> getHttpHeaders() {
948 return httpHeaders;
951 @Override
952 public int hashCode() {
953 return Objects.hashCode(pattern, expiration, httpHeaders);
956 @Override
957 public boolean equals(Object obj) {
958 if (!(obj instanceof StaticFileInclude)) {
959 return false;
962 StaticFileInclude other = (StaticFileInclude) obj;
964 if (pattern != null) {
965 if (!pattern.equals(other.pattern)) {
966 return false;
968 } else {
969 if (other.pattern != null) {
970 return false;
974 if (expiration != null) {
975 if (!expiration.equals(other.expiration)) {
976 return false;
978 } else {
979 if (other.expiration != null) {
980 return false;
984 if (httpHeaders != null) {
985 if (!httpHeaders.equals(other.httpHeaders)) {
986 return false;
988 } else {
989 if (other.httpHeaders != null) {
990 return false;
994 return true;
998 public static class AdminConsolePage {
999 private final String name;
1000 private final String url;
1002 public AdminConsolePage(String name, String url) {
1003 this.name = name;
1004 this.url = url;
1007 public String getName() {
1008 return name;
1011 public String getUrl() {
1012 return url;
1015 @Override
1016 public int hashCode() {
1017 final int prime = 31;
1018 int result = 1;
1019 result = prime * result + ((name == null) ? 0 : name.hashCode());
1020 result = prime * result + ((url == null) ? 0 : url.hashCode());
1021 return result;
1024 @Override
1025 public boolean equals(Object obj) {
1026 if (this == obj) return true;
1027 if (obj == null) return false;
1028 if (getClass() != obj.getClass()) return false;
1029 AdminConsolePage other = (AdminConsolePage) obj;
1030 if (name == null) {
1031 if (other.name != null) return false;
1032 } else if (!name.equals(other.name)) return false;
1033 if (url == null) {
1034 if (other.url != null) return false;
1035 } else if (!url.equals(other.url)) return false;
1036 return true;
1041 * Represents an &lt;error-handler&gt; element. Currently this includes both
1042 * a file name and an optional error code.
1044 public static class ErrorHandler {
1045 private final String file;
1046 private final String errorCode;
1048 public ErrorHandler(String file, String errorCode) {
1049 this.file = file;
1050 this.errorCode = errorCode;
1053 public String getFile() {
1054 return file;
1057 public String getErrorCode() {
1058 return errorCode;
1061 @Override
1062 public int hashCode() {
1063 final int prime = 31;
1064 int result = 1;
1065 result = prime * result + ((file == null) ? 0 : file.hashCode());
1066 result = prime * result +
1067 ((errorCode == null) ? 0 : errorCode.hashCode());
1068 return result;
1071 @Override
1072 public boolean equals(Object obj) {
1073 if (!(obj instanceof ErrorHandler)) {
1074 return false;
1077 ErrorHandler handler = (ErrorHandler) obj;
1078 if (!file.equals(handler.file)) {
1079 return false;
1082 if (errorCode == null) {
1083 if (handler.errorCode != null) {
1084 return false;
1086 } else {
1087 if (!errorCode.equals(handler.errorCode)) {
1088 return false;
1092 return true;
1097 * Represents an &lt;api-config&gt; element. This is a singleton specifying
1098 * url-pattern and servlet-class for the api config server.
1100 public static class ApiConfig {
1101 private final String servletClass;
1102 private final String url;
1104 public ApiConfig(String servletClass, String url) {
1105 this.servletClass = servletClass;
1106 this.url = url;
1109 public String getservletClass() {
1110 return servletClass;
1113 public String getUrl() {
1114 return url;
1117 @Override
1118 public int hashCode() {
1119 final int prime = 31;
1120 int result = 1;
1121 result = prime * result + ((servletClass == null) ? 0 : servletClass.hashCode());
1122 result = prime * result + ((url == null) ? 0 : url.hashCode());
1123 return result;
1126 @Override
1127 public boolean equals(Object obj) {
1128 if (this == obj) { return true; }
1129 if (obj == null) { return false; }
1130 if (getClass() != obj.getClass()) { return false; }
1131 ApiConfig other = (ApiConfig) obj;
1132 if (servletClass == null) {
1133 if (other.servletClass != null) { return false; }
1134 } else if (!servletClass.equals(other.servletClass)) { return false; }
1135 if (url == null) {
1136 if (other.url != null) { return false; }
1137 } else if (!url.equals(other.url)) { return false; }
1138 return true;
1141 @Override
1142 public String toString() {
1143 return "ApiConfig{servletClass=\"" + servletClass + "\", url=\"" + url + "\"}";
1148 * Holder for automatic settings.
1150 public static class AutomaticScaling {
1151 private static final AutomaticScaling EMPTY_SETTINGS = new AutomaticScaling();
1153 public static final String AUTOMATIC = "automatic";
1154 private String minPendingLatency;
1155 private String maxPendingLatency;
1156 private String minIdleInstances;
1157 private String maxIdleInstances;
1158 private String maxConcurrentRequests;
1160 public String getMinPendingLatency() {
1161 return minPendingLatency;
1165 * Sets minPendingLatency. Normalizes empty and null inputs to null.
1167 public void setMinPendingLatency(String minPendingLatency) {
1168 this.minPendingLatency = StringUtil.toNullIfEmptyOrWhitespace(minPendingLatency);
1171 public String getMaxPendingLatency() {
1172 return maxPendingLatency;
1176 * Sets maxPendingLatency. Normalizes empty and null inputs to null.
1178 public void setMaxPendingLatency(String maxPendingLatency) {
1179 this.maxPendingLatency = StringUtil.toNullIfEmptyOrWhitespace(maxPendingLatency);
1182 public String getMinIdleInstances() {
1183 return minIdleInstances;
1187 * Sets minIdleInstances. Normalizes empty and null inputs to null.
1189 public void setMinIdleInstances(String minIdleInstances) {
1190 this.minIdleInstances = StringUtil.toNullIfEmptyOrWhitespace(minIdleInstances);
1193 public String getMaxIdleInstances() {
1194 return maxIdleInstances;
1198 * Sets maxIdleInstances. Normalizes empty and null inputs to null.
1200 public void setMaxIdleInstances(String maxIdleInstances) {
1201 this.maxIdleInstances = StringUtil.toNullIfEmptyOrWhitespace(maxIdleInstances);
1204 public boolean isEmpty() {
1205 return this.equals(EMPTY_SETTINGS);
1208 public String getMaxConcurrentRequests() {
1209 return maxConcurrentRequests;
1213 * Sets maxConcurrentRequests. Normalizes empty and null inputs to null.
1215 public void setMaxConcurrentRequests(String maxConcurrentRequests) {
1216 this.maxConcurrentRequests = StringUtil.toNullIfEmptyOrWhitespace(maxConcurrentRequests);
1219 @Override
1220 public int hashCode() {
1221 return Objects.hashCode(maxPendingLatency, minPendingLatency,
1222 maxIdleInstances, minIdleInstances, maxConcurrentRequests);
1225 @Override
1226 public boolean equals(Object obj) {
1227 if (this == obj) {
1228 return true;
1230 if (obj == null) {
1231 return false;
1233 if (getClass() != obj.getClass()) {
1234 return false;
1236 AutomaticScaling other = (AutomaticScaling) obj;
1237 return Objects.equal(maxPendingLatency, other.maxPendingLatency)
1238 && Objects.equal(minPendingLatency, other.minPendingLatency)
1239 && Objects.equal(maxIdleInstances, other.maxIdleInstances)
1240 && Objects.equal(minIdleInstances, other.minIdleInstances)
1241 && Objects.equal(maxConcurrentRequests, other.maxConcurrentRequests);
1244 @Override
1245 public String toString() {
1246 return "AutomaticScaling [minPendingLatency=" + minPendingLatency
1247 + ", maxPendingLatency=" + maxPendingLatency
1248 + ", minIdleInstances=" + minIdleInstances
1249 + ", maxIdleInstances=" + maxIdleInstances
1250 + ", maxConcurrentRequests=" + maxConcurrentRequests + "]";
1255 * Holder for manual settings.
1257 public static class ManualScaling {
1258 private static final ManualScaling EMPTY_SETTINGS = new ManualScaling();
1260 private String instances;
1262 public String getInstances() {
1263 return instances;
1267 * Sets instances. Normalizes empty and null inputs to null.
1269 public void setInstances(String instances) {
1270 this.instances = StringUtil.toNullIfEmptyOrWhitespace(instances);
1273 public boolean isEmpty() {
1274 return this.equals(EMPTY_SETTINGS);
1277 @Override
1278 public int hashCode() {
1279 return Objects.hashCode(instances);
1282 @Override
1283 public boolean equals(Object obj) {
1284 if (this == obj) {
1285 return true;
1287 if (obj == null) {
1288 return false;
1290 if (getClass() != obj.getClass()) {
1291 return false;
1293 ManualScaling other = (ManualScaling) obj;
1294 return Objects.equal(instances, other.instances);
1297 @Override
1298 public String toString() {
1299 return "ManualScaling [" + "instances=" + instances + "]";
1304 * Holder for basic settings.
1306 public static class BasicScaling {
1307 private static final BasicScaling EMPTY_SETTINGS = new BasicScaling();
1309 private String maxInstances;
1310 private String idleTimeout;
1312 public String getMaxInstances() {
1313 return maxInstances;
1316 public String getIdleTimeout() {
1317 return idleTimeout;
1321 * Sets maxInstances. Normalizes empty and null inputs to null.
1323 public void setMaxInstances(String maxInstances) {
1324 this.maxInstances = StringUtil.toNullIfEmptyOrWhitespace(maxInstances);
1328 * Sets idleTimeout. Normalizes empty and null inputs to null.
1330 public void setIdleTimeout(String idleTimeout) {
1331 this.idleTimeout = StringUtil.toNullIfEmptyOrWhitespace(idleTimeout);
1334 public boolean isEmpty() {
1335 return this.equals(EMPTY_SETTINGS);
1338 @Override
1339 public int hashCode() {
1340 return Objects.hashCode(maxInstances, idleTimeout);
1343 @Override
1344 public boolean equals(Object obj) {
1345 if (this == obj) {
1346 return true;
1348 if (obj == null) {
1349 return false;
1351 if (getClass() != obj.getClass()) {
1352 return false;
1354 BasicScaling other = (BasicScaling) obj;
1355 return Objects.equal(maxInstances, other.maxInstances)
1356 && Objects.equal(idleTimeout, other.idleTimeout);
1359 @Override
1360 public String toString() {
1361 return "BasicScaling [" + "maxInstances=" + maxInstances
1362 + ", idleTimeout=" + idleTimeout + "]";
1367 * Represents a &lt;pagespeed&gt; element. This is used to specify configuration for the Page
1368 * Speed Service, which can be used to automatically optimize the loading speed of app engine
1369 * sites.
1371 public static class Pagespeed {
1372 private final List<String> urlBlacklist = Lists.newArrayList();
1373 private final List<String> domainsToRewrite = Lists.newArrayList();
1374 private final List<String> enabledRewriters = Lists.newArrayList();
1375 private final List<String> disabledRewriters = Lists.newArrayList();
1377 public void addUrlBlacklist(String url) {
1378 urlBlacklist.add(url);
1381 public List<String> getUrlBlacklist() {
1382 return Collections.unmodifiableList(urlBlacklist);
1385 public void addDomainToRewrite(String domain) {
1386 domainsToRewrite.add(domain);
1389 public List<String> getDomainsToRewrite() {
1390 return Collections.unmodifiableList(domainsToRewrite);
1393 public void addEnabledRewriter(String rewriter) {
1394 enabledRewriters.add(rewriter);
1397 public List<String> getEnabledRewriters() {
1398 return Collections.unmodifiableList(enabledRewriters);
1401 public void addDisabledRewriter(String rewriter) {
1402 disabledRewriters.add(rewriter);
1405 public List<String> getDisabledRewriters() {
1406 return Collections.unmodifiableList(disabledRewriters);
1409 public boolean isEmpty() {
1410 return urlBlacklist.isEmpty() && domainsToRewrite.isEmpty() && enabledRewriters.isEmpty()
1411 && disabledRewriters.isEmpty();
1414 @Override
1415 public int hashCode() {
1416 return Objects.hashCode(urlBlacklist, domainsToRewrite, enabledRewriters, disabledRewriters);
1419 @Override
1420 public boolean equals(Object obj) {
1421 if (this == obj) {
1422 return true;
1424 if (obj == null) {
1425 return false;
1427 if (getClass() != obj.getClass()) {
1428 return false;
1430 Pagespeed other = (Pagespeed) obj;
1431 return Objects.equal(urlBlacklist, other.urlBlacklist)
1432 && Objects.equal(domainsToRewrite, other.domainsToRewrite)
1433 && Objects.equal(enabledRewriters, other.enabledRewriters)
1434 && Objects.equal(disabledRewriters, other.disabledRewriters);
1437 @Override
1438 public String toString() {
1439 return "Pagespeed [urlBlacklist=" + urlBlacklist + ", domainsToRewrite=" + domainsToRewrite
1440 + ", enabledRewriters=" + enabledRewriters + ", disabledRewriters=" + disabledRewriters
1441 + "]";
1445 public static class ClassLoaderConfig {
1446 private final List<PrioritySpecifierEntry> entries = Lists.newArrayList();
1448 public void add(PrioritySpecifierEntry entry) {
1449 entries.add(entry);
1452 public List<PrioritySpecifierEntry> getEntries() {
1453 return entries;
1456 @Override
1457 public int hashCode() {
1458 final int prime = 31;
1459 int result = 1;
1460 result = prime * result + ((entries == null) ? 0 : entries.hashCode());
1461 return result;
1464 @Override
1465 public boolean equals(Object obj) {
1466 if (this == obj) return true;
1467 if (obj == null) return false;
1468 if (getClass() != obj.getClass()) return false;
1469 ClassLoaderConfig other = (ClassLoaderConfig) obj;
1470 if (entries == null) {
1471 if (other.entries != null) return false;
1472 } else if (!entries.equals(other.entries)) return false;
1473 return true;
1476 @Override
1477 public String toString() {
1478 return "ClassLoaderConfig{entries=\"" + entries + "\"}";
1482 public static class PrioritySpecifierEntry {
1483 private String filename;
1484 private Double priority;
1486 private void checkNotAlreadySet() {
1487 if (filename != null) {
1488 throw new AppEngineConfigException("Found more that one file name matching tag. "
1489 + "Only one of 'filename' attribute allowed.");
1493 public String getFilename() {
1494 return filename;
1497 public void setFilename(String filename) {
1498 checkNotAlreadySet();
1499 this.filename = filename;
1502 public Double getPriority() {
1503 return priority;
1506 public double getPriorityValue() {
1507 if (priority == null) {
1508 return 1.0d;
1510 return priority;
1513 public void setPriority(String priority) {
1514 if (this.priority != null) {
1515 throw new AppEngineConfigException("The 'priority' tag may only be specified once.");
1518 if (priority == null) {
1519 this.priority = null;
1520 return;
1523 this.priority = Double.parseDouble(priority);
1526 public void checkClassLoaderConfig() {
1527 if (filename == null) {
1528 throw new AppEngineConfigException("Must have a filename attribute.");
1532 @Override
1533 public int hashCode() {
1534 final int prime = 31;
1535 int result = 1;
1536 result = prime * result + ((filename == null) ? 0 : filename.hashCode());
1537 result = prime * result + ((priority == null) ? 0 : priority.hashCode());
1538 return result;
1541 @Override
1542 public boolean equals(Object obj) {
1543 if (this == obj) return true;
1544 if (obj == null) return false;
1545 if (getClass() != obj.getClass()) return false;
1546 PrioritySpecifierEntry other = (PrioritySpecifierEntry) obj;
1547 if (filename == null) {
1548 if (other.filename != null) return false;
1549 } else if (!filename.equals(other.filename)) return false;
1550 if (priority == null) {
1551 if (other.priority != null) return false;
1552 } else if (!priority.equals(other.priority)) return false;
1553 return true;
1556 @Override
1557 public String toString() {
1558 return "PrioritySpecifierEntry{filename=\"" + filename + "\", priority=\"" + priority + "\"}";