Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / apphosting / utils / config / AppEngineWebXml.java
blobd9763066548e0957770fc65372a17157ca0f6dc6
1 // Copyright 2008 Google Inc. All Rights Reserved.
2 package com.google.apphosting.utils.config;
4 import com.google.common.base.StringUtil;
5 import com.google.common.collect.Lists;
6 import com.google.common.collect.Maps;
8 import java.security.Permissions;
9 import java.security.UnresolvedPermission;
10 import java.util.ArrayList;
11 import java.util.Collections;
12 import java.util.LinkedHashMap;
13 import java.util.LinkedHashSet;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Objects;
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 implements Cloneable {
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> betaSettings = Maps.newLinkedHashMap();
37 private final HealthCheck healthCheck;
39 private final Resources resources;
41 private final Network network;
43 private final Map<String, String> envVariables = Maps.newHashMap();
45 private final List<UserPermission> userPermissions = new ArrayList<UserPermission>();
47 public static final String WARMUP_SERVICE = "warmup";
49 public static final String URL_HANDLER_URLFETCH = "urlfetch";
50 public static final String URL_HANDLER_NATIVE= "native";
52 private String appId;
54 private String majorVersionId;
56 private String module;
57 private String instanceClass;
59 private final AutomaticScaling automaticScaling;
60 private final ManualScaling manualScaling;
61 private final BasicScaling basicScaling;
63 private String sourceLanguage;
64 private boolean sslEnabled = true;
65 private boolean useSessions = false;
66 private boolean asyncSessionPersistence = false;
67 private String asyncSessionPersistenceQueueName;
69 private final List<StaticFileInclude> staticFileIncludes;
70 private final List<String> staticFileExcludes;
71 private final List<String> resourceFileIncludes;
72 private final List<String> resourceFileExcludes;
74 private Pattern staticIncludePattern;
75 private Pattern staticExcludePattern;
76 private Pattern resourceIncludePattern;
77 private Pattern resourceExcludePattern;
79 private String publicRoot = "";
81 private String appRoot;
83 private final Set<String> inboundServices;
84 private boolean precompilationEnabled = true;
86 private final List<AdminConsolePage> adminConsolePages = new ArrayList<AdminConsolePage>();
87 private final List<ErrorHandler> errorHandlers = new ArrayList<ErrorHandler>();
89 private ClassLoaderConfig classLoaderConfig;
91 private String urlStreamHandlerType = null;
93 private boolean threadsafe = false;
94 private boolean threadsafeValueProvided = false;
96 private String autoIdPolicy;
98 private boolean codeLock = false;
99 private boolean useVm = false;
100 private ApiConfig apiConfig;
101 private final List<String> apiEndpointIds;
102 private Pagespeed pagespeed;
105 * Represent user's choice w.r.t the usage of Google's customized connector-j.
107 public static enum UseGoogleConnectorJ {
108 NOT_STATED_BY_USER,
109 TRUE,
110 FALSE,
112 private UseGoogleConnectorJ useGoogleConnectorJ = UseGoogleConnectorJ.NOT_STATED_BY_USER;
114 public AppEngineWebXml() {
115 automaticScaling = new AutomaticScaling();
116 manualScaling = new ManualScaling();
117 basicScaling = new BasicScaling();
118 healthCheck = new HealthCheck();
119 resources = new Resources();
120 network = new Network();
122 staticFileIncludes = new ArrayList<StaticFileInclude>();
123 staticFileExcludes = new ArrayList<String>();
124 staticFileExcludes.add("WEB-INF/**");
125 staticFileExcludes.add("**.jsp");
126 resourceFileIncludes = new ArrayList<String>();
127 resourceFileExcludes = new ArrayList<String>();
128 inboundServices = new LinkedHashSet<String>();
129 apiEndpointIds = new ArrayList<String>();
132 public AppEngineWebXml clone() {
133 try {
134 return (AppEngineWebXml) super.clone();
135 } catch (CloneNotSupportedException ce) {
136 throw new RuntimeException("Could not clone AppEngineWebXml", ce);
141 * @return An unmodifiable map whose entries correspond to the
142 * system properties defined in appengine-web.xml.
144 public Map<String, String> getSystemProperties() {
145 return Collections.unmodifiableMap(systemProperties);
148 public void addSystemProperty(String key, String value) {
149 systemProperties.put(key, value);
153 * @return An unmodifiable map whose entires correspond to the
154 * vm settings defined in appengine-web.xml.
156 public Map<String, String> getBetaSettings() {
157 return Collections.unmodifiableMap(betaSettings);
160 public void addBetaSetting(String key, String value) {
161 betaSettings.put(key, value);
164 public HealthCheck getHealthCheck() {
165 return healthCheck;
168 public Resources getResources() {
169 return resources;
172 public Network getNetwork() {
173 return network;
177 * @return An unmodifiable map whose entires correspond to the
178 * environment variables defined in appengine-web.xml.
180 public Map<String, String> getEnvironmentVariables() {
181 return Collections.unmodifiableMap(envVariables);
184 public void addEnvironmentVariable(String key, String value) {
185 envVariables.put(key, value);
188 public String getAppId() {
189 return appId;
192 public void setAppId(String appId) {
193 this.appId = appId;
196 public String getMajorVersionId() {
197 return majorVersionId;
200 public void setMajorVersionId(String majorVersionId) {
201 this.majorVersionId = majorVersionId;
204 public String getSourceLanguage() {
205 return this.sourceLanguage;
208 public void setSourceLanguage(String sourceLanguage) {
209 this.sourceLanguage = sourceLanguage;
212 public String getModule() {
213 return module;
217 * Sets instanceClass (aka class in the xml/yaml files). Normalizes empty and null
218 * inputs to null.
220 public void setInstanceClass(String instanceClass) {
221 this.instanceClass = StringUtil.toNullIfEmptyOrWhitespace(instanceClass);
224 public String getInstanceClass() {
225 return instanceClass;
228 public AutomaticScaling getAutomaticScaling() {
229 return automaticScaling;
232 public ManualScaling getManualScaling() {
233 return manualScaling;
236 public BasicScaling getBasicScaling() {
237 return basicScaling;
240 public ScalingType getScalingType() {
241 if (!getBasicScaling().isEmpty()) {
242 return ScalingType.BASIC;
243 } else if (!getManualScaling().isEmpty()) {
244 return ScalingType.MANUAL;
245 } else {
246 return ScalingType.AUTOMATIC;
250 public void setModule(String module) {
251 this.module = module;
254 public void setSslEnabled(boolean ssl) {
255 sslEnabled = ssl;
258 public boolean getSslEnabled() {
259 return sslEnabled;
262 public void setSessionsEnabled(boolean sessions) {
263 useSessions = sessions;
266 public boolean getSessionsEnabled() {
267 return useSessions;
270 public void setAsyncSessionPersistence(boolean asyncSessionPersistence) {
271 this.asyncSessionPersistence = asyncSessionPersistence;
274 public boolean getAsyncSessionPersistence() {
275 return asyncSessionPersistence;
278 public void setAsyncSessionPersistenceQueueName(String asyncSessionPersistenceQueueName) {
279 this.asyncSessionPersistenceQueueName = asyncSessionPersistenceQueueName;
282 public String getAsyncSessionPersistenceQueueName() {
283 return asyncSessionPersistenceQueueName;
286 public List<StaticFileInclude> getStaticFileIncludes() {
287 return staticFileIncludes;
290 public List<String> getStaticFileExcludes() {
291 return staticFileExcludes;
294 public StaticFileInclude includeStaticPattern(String pattern, String expiration) {
295 staticIncludePattern = null;
296 StaticFileInclude staticFileInclude = new StaticFileInclude(pattern, expiration);
297 staticFileIncludes.add(staticFileInclude);
298 return staticFileInclude;
301 public void excludeStaticPattern(String url) {
302 staticExcludePattern = null;
303 staticFileExcludes.add(url);
306 public List<String> getResourcePatterns() {
307 return resourceFileIncludes;
310 public List<String> getResourceFileExcludes() {
311 return resourceFileExcludes;
314 public void includeResourcePattern(String url) {
315 resourceExcludePattern = null;
316 resourceFileIncludes.add(url);
319 public void excludeResourcePattern(String url) {
320 resourceIncludePattern = null;
321 resourceFileExcludes.add(url);
324 public void addUserPermission(String className, String name, String actions) {
325 if (className.startsWith("java.")) {
326 throw new AppEngineConfigException("Cannot specify user-permissions for " +
327 "classes in java.* packages.");
330 userPermissions.add(new UserPermission(className, name, actions));
333 public Permissions getUserPermissions() {
334 Permissions permissions = new Permissions();
335 for (UserPermission permission : userPermissions) {
336 permissions.add(new UnresolvedPermission(permission.getClassName(),
337 permission.getName(),
338 permission.getActions(),
339 null));
341 permissions.setReadOnly();
342 return permissions;
345 public void setPublicRoot(String root) {
346 if (root.indexOf('*') != -1) {
347 throw new AppEngineConfigException("public-root cannot contain wildcards");
349 if (root.endsWith("/")) {
350 root = root.substring(0, root.length() - 1);
352 if (root.length() > 0 && !root.startsWith("/")) {
353 root = "/" + root;
355 staticIncludePattern = null;
356 publicRoot = root;
359 public String getPublicRoot() {
360 return publicRoot;
363 public void addInboundService(String service) {
364 inboundServices.add(service);
367 public Set<String> getInboundServices() {
368 return inboundServices;
371 public boolean getPrecompilationEnabled() {
372 return precompilationEnabled;
375 public void setPrecompilationEnabled(boolean precompilationEnabled) {
376 this.precompilationEnabled = precompilationEnabled;
379 public boolean getWarmupRequestsEnabled() {
380 return inboundServices.contains(WARMUP_SERVICE);
383 public void setWarmupRequestsEnabled(boolean warmupRequestsEnabled) {
384 if (warmupRequestsEnabled) {
385 inboundServices.add(WARMUP_SERVICE);
386 } else {
387 inboundServices.remove(WARMUP_SERVICE);
391 public List<AdminConsolePage> getAdminConsolePages() {
392 return Collections.unmodifiableList(adminConsolePages);
395 public void addAdminConsolePage(AdminConsolePage page) {
396 adminConsolePages.add(page);
399 public List<ErrorHandler> getErrorHandlers() {
400 return Collections.unmodifiableList(errorHandlers);
403 public void addErrorHandler(ErrorHandler handler) {
404 errorHandlers.add(handler);
407 public boolean getThreadsafe() {
408 return threadsafe;
411 public boolean getThreadsafeValueProvided() {
412 return threadsafeValueProvided;
415 public void setThreadsafe(boolean threadsafe) {
416 this.threadsafe = threadsafe;
417 this.threadsafeValueProvided = true;
420 public void setAutoIdPolicy(String policy) {
421 autoIdPolicy = policy;
424 public String getAutoIdPolicy() {
425 return autoIdPolicy;
428 public boolean getCodeLock() {
429 return codeLock;
432 public void setCodeLock(boolean codeLock) {
433 this.codeLock = codeLock;
436 public void setUseVm(boolean useVm) {
437 this.useVm = useVm;
440 public boolean getUseVm() {
441 return useVm;
444 public ApiConfig getApiConfig() {
445 return apiConfig;
448 public void setApiConfig(ApiConfig config) {
449 apiConfig = config;
452 public ClassLoaderConfig getClassLoaderConfig() {
453 return classLoaderConfig;
456 public void setClassLoaderConfig(ClassLoaderConfig classLoaderConfig) {
457 if (this.classLoaderConfig != null) {
458 throw new AppEngineConfigException("class-loader-config may only be specified once.");
460 this.classLoaderConfig = classLoaderConfig;
463 public String getUrlStreamHandlerType() {
464 return urlStreamHandlerType;
467 public void setUrlStreamHandlerType(String urlStreamHandlerType) {
468 if (this.classLoaderConfig != null) {
469 throw new AppEngineConfigException("url-stream-handler may only be specified once.");
471 if (!URL_HANDLER_URLFETCH.equals(urlStreamHandlerType)
472 && !URL_HANDLER_NATIVE.equals(urlStreamHandlerType)) {
473 throw new AppEngineConfigException(
474 "url-stream-handler must be " + URL_HANDLER_URLFETCH + " or " + URL_HANDLER_NATIVE +
475 " given " + urlStreamHandlerType);
477 this.urlStreamHandlerType = urlStreamHandlerType;
481 * Returns true if {@code url} matches one of the servlets or servlet
482 * filters listed in this web.xml that has api-endpoint set to true.
484 public boolean isApiEndpoint(String id) {
485 return apiEndpointIds.contains(id);
488 public void addApiEndpoint(String id) {
489 apiEndpointIds.add(id);
492 public Pagespeed getPagespeed() {
493 return pagespeed;
496 public void setPagespeed(Pagespeed pagespeed) {
497 this.pagespeed = pagespeed;
500 public void setUseGoogleConnectorJ(boolean useGoogleConnectorJ) {
501 if (useGoogleConnectorJ) {
502 this.useGoogleConnectorJ = UseGoogleConnectorJ.TRUE;
503 } else {
504 this.useGoogleConnectorJ = UseGoogleConnectorJ.FALSE;
508 public UseGoogleConnectorJ getUseGoogleConnectorJ() {
509 return useGoogleConnectorJ;
512 @Override
513 public String toString() {
514 return "AppEngineWebXml{" +
515 "systemProperties=" + systemProperties +
516 ", envVariables=" + envVariables +
517 ", userPermissions=" + userPermissions +
518 ", appId='" + appId + '\'' +
519 ", majorVersionId='" + majorVersionId + '\'' +
520 ", sourceLanguage='" + sourceLanguage + '\'' +
521 ", module='" + module + '\'' +
522 ", instanceClass='" + instanceClass + '\'' +
523 ", automaticScaling=" + automaticScaling +
524 ", manualScaling=" + manualScaling +
525 ", basicScaling=" + basicScaling +
526 ", healthCheck=" + healthCheck +
527 ", resources=" + resources +
528 ", network=" + network +
529 ", sslEnabled=" + sslEnabled +
530 ", useSessions=" + useSessions +
531 ", asyncSessionPersistence=" + asyncSessionPersistence +
532 ", asyncSessionPersistenceQueueName='" + asyncSessionPersistenceQueueName + '\'' +
533 ", staticFileIncludes=" + staticFileIncludes +
534 ", staticFileExcludes=" + staticFileExcludes +
535 ", resourceFileIncludes=" + resourceFileIncludes +
536 ", resourceFileExcludes=" + resourceFileExcludes +
537 ", staticIncludePattern=" + staticIncludePattern +
538 ", staticExcludePattern=" + staticExcludePattern +
539 ", resourceIncludePattern=" + resourceIncludePattern +
540 ", resourceExcludePattern=" + resourceExcludePattern +
541 ", publicRoot='" + publicRoot + '\'' +
542 ", appRoot='" + appRoot + '\'' +
543 ", inboundServices=" + inboundServices +
544 ", precompilationEnabled=" + precompilationEnabled +
545 ", adminConsolePages=" + adminConsolePages +
546 ", errorHandlers=" + errorHandlers +
547 ", threadsafe=" + threadsafe +
548 ", threadsafeValueProvided=" + threadsafeValueProvided +
549 ", autoIdPolicy=" + autoIdPolicy +
550 ", codeLock=" + codeLock +
551 ", apiConfig=" + apiConfig +
552 ", apiEndpointIds=" + apiEndpointIds +
553 ", pagespeed=" + pagespeed +
554 ", classLoaderConfig=" + classLoaderConfig +
555 ", urlStreamHandlerType=" +
556 (urlStreamHandlerType == null ? URL_HANDLER_URLFETCH : urlStreamHandlerType) +
557 ", useGoogleConnectorJ=" + useGoogleConnectorJ +
558 '}';
561 @Override
562 public boolean equals(Object o) {
563 if (this == o) {
564 return true;
566 if (o == null || getClass() != o.getClass()) {
567 return false;
570 AppEngineWebXml that = (AppEngineWebXml) o;
572 if (asyncSessionPersistence != that.asyncSessionPersistence) {
573 return false;
575 if (precompilationEnabled != that.precompilationEnabled) {
576 return false;
578 if (sslEnabled != that.sslEnabled) {
579 return false;
581 if (threadsafe != that.threadsafe) {
582 return false;
584 if (threadsafeValueProvided != that.threadsafeValueProvided) {
585 return false;
587 if (autoIdPolicy != null ? !autoIdPolicy.equals(that.autoIdPolicy)
588 : that.autoIdPolicy != null) {
589 return false;
591 if (codeLock != that.codeLock) {
592 return false;
594 if (useSessions != that.useSessions) {
595 return false;
597 if (adminConsolePages != null ? !adminConsolePages.equals(that.adminConsolePages)
598 : that.adminConsolePages != null) {
599 return false;
601 if (appId != null ? !appId.equals(that.appId) : that.appId != null) {
602 return false;
604 if (majorVersionId != null ? !majorVersionId.equals(that.majorVersionId)
605 : that.majorVersionId != null) {
606 return false;
608 if (module != null ? !module.equals(that.module) : that.module != null) {
609 return false;
611 if (instanceClass != null ? !instanceClass.equals(that.instanceClass)
612 : that.instanceClass != null) {
613 return false;
615 if (!automaticScaling.equals(that.automaticScaling)) {
616 return false;
618 if (!manualScaling.equals(that.manualScaling)) {
619 return false;
621 if (!basicScaling.equals(that.basicScaling)) {
622 return false;
624 if (appRoot != null ? !appRoot.equals(that.appRoot) : that.appRoot != null) {
625 return false;
627 if (asyncSessionPersistenceQueueName != null ? !asyncSessionPersistenceQueueName
628 .equals(that.asyncSessionPersistenceQueueName)
629 : that.asyncSessionPersistenceQueueName != null) {
630 return false;
632 if (envVariables != null ? !envVariables.equals(that.envVariables)
633 : that.envVariables != null) {
634 return false;
636 if (errorHandlers != null ? !errorHandlers.equals(that.errorHandlers)
637 : that.errorHandlers != null) {
638 return false;
640 if (inboundServices != null ? !inboundServices.equals(that.inboundServices)
641 : that.inboundServices != null) {
642 return false;
644 if (majorVersionId != null ? !majorVersionId.equals(that.majorVersionId)
645 : that.majorVersionId != null) {
646 return false;
648 if (sourceLanguage != null ? !sourceLanguage.equals(that.sourceLanguage)
649 : that.sourceLanguage != null) {
650 return false;
652 if (publicRoot != null ? !publicRoot.equals(that.publicRoot) : that.publicRoot != null) {
653 return false;
655 if (resourceExcludePattern != null ? !resourceExcludePattern.equals(that.resourceExcludePattern)
656 : that.resourceExcludePattern != null) {
657 return false;
659 if (resourceFileExcludes != null ? !resourceFileExcludes.equals(that.resourceFileExcludes)
660 : that.resourceFileExcludes != null) {
661 return false;
663 if (resourceFileIncludes != null ? !resourceFileIncludes.equals(that.resourceFileIncludes)
664 : that.resourceFileIncludes != null) {
665 return false;
667 if (resourceIncludePattern != null ? !resourceIncludePattern.equals(that.resourceIncludePattern)
668 : that.resourceIncludePattern != null) {
669 return false;
671 if (staticExcludePattern != null ? !staticExcludePattern.equals(that.staticExcludePattern)
672 : that.staticExcludePattern != null) {
673 return false;
675 if (staticFileExcludes != null ? !staticFileExcludes.equals(that.staticFileExcludes)
676 : that.staticFileExcludes != null) {
677 return false;
679 if (staticFileIncludes != null ? !staticFileIncludes.equals(that.staticFileIncludes)
680 : that.staticFileIncludes != null) {
681 return false;
683 if (staticIncludePattern != null ? !staticIncludePattern.equals(that.staticIncludePattern)
684 : that.staticIncludePattern != null) {
685 return false;
687 if (systemProperties != null ? !systemProperties.equals(that.systemProperties)
688 : that.systemProperties != null) {
689 return false;
691 if (betaSettings != null ? !betaSettings.equals(that.betaSettings) : that.betaSettings != null) {
692 return false;
694 if (healthCheck != null ? !healthCheck.equals(that.healthCheck)
695 : that.healthCheck != null) {
696 return false;
698 if (resources != null ? !resources.equals(that.resources) : that.resources != null) {
699 return false;
701 if (network != null ? !network.equals(that.network) : that.network != null) {
702 return false;
704 if (userPermissions != null ? !userPermissions.equals(that.userPermissions)
705 : that.userPermissions != null) {
706 return false;
708 if (apiConfig != null ? !apiConfig.equals(that.apiConfig)
709 : that.apiConfig != null) {
710 return false;
712 if (apiEndpointIds != null ? !apiEndpointIds.equals(that.apiEndpointIds)
713 : that.apiEndpointIds != null) {
714 return false;
716 if (pagespeed != null ? !pagespeed.equals(that.pagespeed) : that.pagespeed != null) {
717 return false;
719 if (classLoaderConfig != null ? !classLoaderConfig.equals(that.classLoaderConfig) :
720 that.classLoaderConfig != null) {
721 return false;
723 if (urlStreamHandlerType != null ? !urlStreamHandlerType.equals(that.urlStreamHandlerType) :
724 that.urlStreamHandlerType != null) {
725 return false;
727 if (useGoogleConnectorJ != that.useGoogleConnectorJ) {
728 return false;
731 return true;
734 @Override
735 public int hashCode() {
736 int result = systemProperties != null ? systemProperties.hashCode() : 0;
737 result = 31 * result + (envVariables != null ? envVariables.hashCode() : 0);
738 result = 31 * result + (userPermissions != null ? userPermissions.hashCode() : 0);
739 result = 31 * result + (appId != null ? appId.hashCode() : 0);
740 result = 31 * result + (majorVersionId != null ? majorVersionId.hashCode() : 0);
741 result = 31 * result + (sourceLanguage != null ? sourceLanguage.hashCode() : 0);
742 result = 31 * result + (module != null ? module.hashCode() : 0);
743 result = 31 * result + (instanceClass != null ? instanceClass.hashCode() : 0);
744 result = 31 * result + automaticScaling.hashCode();
745 result = 31 * result + manualScaling.hashCode();
746 result = 31 * result + basicScaling.hashCode();
747 result = 31 * result + (sslEnabled ? 1 : 0);
748 result = 31 * result + (useSessions ? 1 : 0);
749 result = 31 * result + (asyncSessionPersistence ? 1 : 0);
750 result =
751 31 * result + (asyncSessionPersistenceQueueName != null ? asyncSessionPersistenceQueueName
752 .hashCode() : 0);
753 result = 31 * result + (staticFileIncludes != null ? staticFileIncludes.hashCode() : 0);
754 result = 31 * result + (staticFileExcludes != null ? staticFileExcludes.hashCode() : 0);
755 result = 31 * result + (resourceFileIncludes != null ? resourceFileIncludes.hashCode() : 0);
756 result = 31 * result + (resourceFileExcludes != null ? resourceFileExcludes.hashCode() : 0);
757 result = 31 * result + (staticIncludePattern != null ? staticIncludePattern.hashCode() : 0);
758 result = 31 * result + (staticExcludePattern != null ? staticExcludePattern.hashCode() : 0);
759 result = 31 * result + (resourceIncludePattern != null ? resourceIncludePattern.hashCode() : 0);
760 result = 31 * result + (resourceExcludePattern != null ? resourceExcludePattern.hashCode() : 0);
761 result = 31 * result + (publicRoot != null ? publicRoot.hashCode() : 0);
762 result = 31 * result + (appRoot != null ? appRoot.hashCode() : 0);
763 result = 31 * result + (inboundServices != null ? inboundServices.hashCode() : 0);
764 result = 31 * result + (precompilationEnabled ? 1 : 0);
765 result = 31 * result + (adminConsolePages != null ? adminConsolePages.hashCode() : 0);
766 result = 31 * result + (errorHandlers != null ? errorHandlers.hashCode() : 0);
767 result = 31 * result + (threadsafe ? 1 : 0);
768 result = 31 * result + (autoIdPolicy != null ? autoIdPolicy.hashCode() : 0);
769 result = 31 * result + (threadsafeValueProvided ? 1 : 0);
770 result = 31 * result + (codeLock ? 1 : 0);
771 result = 31 * result + (apiConfig != null ? apiConfig.hashCode() : 0);
772 result = 31 * result + (apiEndpointIds != null ? apiEndpointIds.hashCode() : 0);
773 result = 31 * result + (pagespeed != null ? pagespeed.hashCode() : 0);
774 result = 31 * result + (classLoaderConfig != null ? classLoaderConfig.hashCode() : 0);
775 result = 31 * result + (urlStreamHandlerType != null ? urlStreamHandlerType.hashCode() : 0);
776 result = 31 * result + (useGoogleConnectorJ.hashCode());
777 result = 31 * result + (betaSettings != null ? betaSettings.hashCode() : 0);
778 result = 31 * result + (healthCheck != null ? healthCheck.hashCode() : 0);
779 result = 31 * result + (resources != null ? resources.hashCode() : 0);
780 result = 31 * result + (network != null ? network.hashCode() : 0);
781 return result;
784 public boolean includesResource(String path) {
785 if (resourceIncludePattern == null) {
786 if (resourceFileIncludes.size() == 0) {
787 resourceIncludePattern = Pattern.compile(".*");
788 } else {
789 resourceIncludePattern = Pattern.compile(makeRegexp(resourceFileIncludes));
792 if (resourceExcludePattern == null && resourceFileExcludes.size() > 0) {
793 resourceExcludePattern = Pattern.compile(makeRegexp(resourceFileExcludes));
794 } else {
796 return includes(path, resourceIncludePattern, resourceExcludePattern);
799 public boolean includesStatic(String path) {
800 if (staticIncludePattern == null) {
801 if (staticFileIncludes.size() == 0) {
802 String staticRoot;
803 if (publicRoot.length() > 0) {
804 staticRoot = publicRoot + "/**";
805 } else {
806 staticRoot = "**";
808 staticIncludePattern = Pattern.compile(
809 makeRegexp(Collections.singletonList(staticRoot)));
810 } else {
811 List<String> patterns = new ArrayList<String>();
812 for (StaticFileInclude include : staticFileIncludes) {
813 patterns.add(include.getPattern());
815 staticIncludePattern = Pattern.compile(makeRegexp(patterns));
818 if (staticExcludePattern == null && staticFileExcludes.size() > 0) {
819 staticExcludePattern = Pattern.compile(makeRegexp(staticFileExcludes));
820 } else {
822 return includes(path, staticIncludePattern, staticExcludePattern);
826 * Tests whether {@code path} is covered by the pattern {@code includes}
827 * while not being blocked by matching {@code excludes}.
829 * @param path a URL to test
830 * @param includes a non-{@code null} pattern for included URLs
831 * @param excludes a pattern for exclusion, or {@code null} to not exclude
832 * anything from the {@code includes} set.
834 public boolean includes(String path, Pattern includes, Pattern excludes) {
835 assert(includes != null);
836 if (!includes.matcher(path).matches()) {
837 return false;
839 if (excludes != null && excludes.matcher(path).matches()) {
840 return false;
842 return true;
845 public String makeRegexp(List<String> patterns) {
846 StringBuilder builder = new StringBuilder();
847 boolean first = true;
848 for (String item : patterns) {
849 if (first) {
850 first = false;
851 } else {
852 builder.append('|');
855 while (item.charAt(0) == '/') {
856 item = item.substring(1);
859 builder.append('(');
860 if (appRoot != null) {
861 builder.append(makeFileRegex(appRoot));
863 builder.append("/");
864 builder.append(makeFileRegex(item));
865 builder.append(')');
867 return builder.toString();
871 * Helper method to translate from appengine-web.xml "file globs" to
872 * proper regular expressions as used in app.yaml.
874 * @param fileGlob the glob to translate
875 * @return the regular expression string matching the input {@code file} pattern.
877 static String makeFileRegex(String fileGlob) {
878 fileGlob = fileGlob.replaceAll("([^A-Za-z0-9\\-_/])", "\\\\$1");
879 fileGlob = fileGlob.replaceAll("\\\\\\*\\\\\\*", ".*");
880 fileGlob = fileGlob.replaceAll("\\\\\\*", "[^/]*");
881 return fileGlob;
884 * Sets the application root directory, as a prefix for the regexps in
885 * {@link #includeResourcePattern(String)} and friends. This is needed
886 * because we want to match complete filenames relative to root.
888 * @param appRoot
890 public void setSourcePrefix(String appRoot) {
891 this.appRoot = appRoot;
892 this.resourceIncludePattern = null;
893 this.resourceExcludePattern = null;
894 this.staticIncludePattern = null;
895 this.staticExcludePattern = null;
898 public String getSourcePrefix() {
899 return this.appRoot;
903 * Represents a {@link java.security.Permission} that needs to be
904 * granted to user code.
906 private static class UserPermission {
907 private final String className;
908 private final String name;
909 private final String actions;
911 private boolean hasHashCode = false;
912 private int hashCode;
914 public UserPermission(String className, String name, String actions) {
915 this.className = className;
916 this.name = name;
917 this.actions = actions;
920 public String getClassName() {
921 return className;
924 public String getName() {
925 return name;
928 public String getActions() {
929 return actions;
932 @Override
933 public int hashCode() {
934 if (hasHashCode) {
935 return hashCode;
938 int hash = className.hashCode();
939 hash = 31 * hash + name.hashCode();
940 if (actions != null) {
941 hash = 31 * hash + actions.hashCode();
944 hashCode = hash;
945 hasHashCode = true;
946 return hashCode;
949 @Override
950 public boolean equals(Object obj) {
951 if (obj instanceof UserPermission) {
952 UserPermission perm = (UserPermission) obj;
953 if (className.equals(perm.className) && name.equals(perm.name)) {
954 if (actions == null ? perm.actions == null : actions.equals(perm.actions)) {
955 return true;
959 return false;
964 * Represents an &lt;include&gt; element within the
965 * &lt;static-files&gt; element. Currently this includes both a
966 * pattern and an optional expiration time specification.
968 public static class StaticFileInclude {
969 private final String pattern;
970 private final String expiration;
971 private final Map<String, String> httpHeaders;
973 public StaticFileInclude(String pattern, String expiration) {
974 this.pattern = pattern;
975 this.expiration = expiration;
976 this.httpHeaders = new LinkedHashMap<>();
979 public String getPattern() {
980 return pattern;
983 public Pattern getRegularExpression() {
984 return Pattern.compile(makeFileRegex(pattern));
987 public String getExpiration() {
988 return expiration;
991 public Map<String, String> getHttpHeaders() {
992 return httpHeaders;
995 @Override
996 public int hashCode() {
997 return Objects.hash(pattern, expiration, httpHeaders);
1000 @Override
1001 public boolean equals(Object obj) {
1002 if (!(obj instanceof StaticFileInclude)) {
1003 return false;
1006 StaticFileInclude other = (StaticFileInclude) obj;
1008 if (pattern != null) {
1009 if (!pattern.equals(other.pattern)) {
1010 return false;
1012 } else {
1013 if (other.pattern != null) {
1014 return false;
1018 if (expiration != null) {
1019 if (!expiration.equals(other.expiration)) {
1020 return false;
1022 } else {
1023 if (other.expiration != null) {
1024 return false;
1028 if (httpHeaders != null) {
1029 if (!httpHeaders.equals(other.httpHeaders)) {
1030 return false;
1032 } else {
1033 if (other.httpHeaders != null) {
1034 return false;
1038 return true;
1042 public static class AdminConsolePage {
1043 private final String name;
1044 private final String url;
1046 public AdminConsolePage(String name, String url) {
1047 this.name = name;
1048 this.url = url;
1051 public String getName() {
1052 return name;
1055 public String getUrl() {
1056 return url;
1059 @Override
1060 public int hashCode() {
1061 final int prime = 31;
1062 int result = 1;
1063 result = prime * result + ((name == null) ? 0 : name.hashCode());
1064 result = prime * result + ((url == null) ? 0 : url.hashCode());
1065 return result;
1068 @Override
1069 public boolean equals(Object obj) {
1070 if (this == obj) return true;
1071 if (obj == null) return false;
1072 if (getClass() != obj.getClass()) return false;
1073 AdminConsolePage other = (AdminConsolePage) obj;
1074 if (name == null) {
1075 if (other.name != null) return false;
1076 } else if (!name.equals(other.name)) return false;
1077 if (url == null) {
1078 if (other.url != null) return false;
1079 } else if (!url.equals(other.url)) return false;
1080 return true;
1085 * Represents an &lt;error-handler&gt; element. Currently this includes both
1086 * a file name and an optional error code.
1088 public static class ErrorHandler {
1089 private final String file;
1090 private final String errorCode;
1092 public ErrorHandler(String file, String errorCode) {
1093 this.file = file;
1094 this.errorCode = errorCode;
1097 public String getFile() {
1098 return file;
1101 public String getErrorCode() {
1102 return errorCode;
1105 @Override
1106 public int hashCode() {
1107 final int prime = 31;
1108 int result = 1;
1109 result = prime * result + ((file == null) ? 0 : file.hashCode());
1110 result = prime * result +
1111 ((errorCode == null) ? 0 : errorCode.hashCode());
1112 return result;
1115 @Override
1116 public boolean equals(Object obj) {
1117 if (!(obj instanceof ErrorHandler)) {
1118 return false;
1121 ErrorHandler handler = (ErrorHandler) obj;
1122 if (!file.equals(handler.file)) {
1123 return false;
1126 if (errorCode == null) {
1127 if (handler.errorCode != null) {
1128 return false;
1130 } else {
1131 if (!errorCode.equals(handler.errorCode)) {
1132 return false;
1136 return true;
1141 * Represents an &lt;api-config&gt; element. This is a singleton specifying
1142 * url-pattern and servlet-class for the api config server.
1144 public static class ApiConfig {
1145 private final String servletClass;
1146 private final String url;
1148 public ApiConfig(String servletClass, String url) {
1149 this.servletClass = servletClass;
1150 this.url = url;
1153 public String getservletClass() {
1154 return servletClass;
1157 public String getUrl() {
1158 return url;
1161 @Override
1162 public int hashCode() {
1163 final int prime = 31;
1164 int result = 1;
1165 result = prime * result + ((servletClass == null) ? 0 : servletClass.hashCode());
1166 result = prime * result + ((url == null) ? 0 : url.hashCode());
1167 return result;
1170 @Override
1171 public boolean equals(Object obj) {
1172 if (this == obj) { return true; }
1173 if (obj == null) { return false; }
1174 if (getClass() != obj.getClass()) { return false; }
1175 ApiConfig other = (ApiConfig) obj;
1176 if (servletClass == null) {
1177 if (other.servletClass != null) { return false; }
1178 } else if (!servletClass.equals(other.servletClass)) { return false; }
1179 if (url == null) {
1180 if (other.url != null) { return false; }
1181 } else if (!url.equals(other.url)) { return false; }
1182 return true;
1185 @Override
1186 public String toString() {
1187 return "ApiConfig{servletClass=\"" + servletClass + "\", url=\"" + url + "\"}";
1192 * Holder for automatic settings.
1194 public static class AutomaticScaling {
1195 private static final AutomaticScaling EMPTY_SETTINGS = new AutomaticScaling();
1197 public static final String AUTOMATIC = "automatic";
1198 private String minPendingLatency;
1199 private String maxPendingLatency;
1200 private String minIdleInstances;
1201 private String maxIdleInstances;
1202 private String maxConcurrentRequests;
1204 private Integer minNumInstances;
1205 private Integer maxNumInstances;
1206 private Integer coolDownPeriodSec;
1207 private CpuUtilization cpuUtilization;
1209 public String getMinPendingLatency() {
1210 return minPendingLatency;
1214 * Sets minPendingLatency. Normalizes empty and null inputs to null.
1216 public void setMinPendingLatency(String minPendingLatency) {
1217 this.minPendingLatency = StringUtil.toNullIfEmptyOrWhitespace(minPendingLatency);
1220 public String getMaxPendingLatency() {
1221 return maxPendingLatency;
1225 * Sets maxPendingLatency. Normalizes empty and null inputs to null.
1227 public void setMaxPendingLatency(String maxPendingLatency) {
1228 this.maxPendingLatency = StringUtil.toNullIfEmptyOrWhitespace(maxPendingLatency);
1231 public String getMinIdleInstances() {
1232 return minIdleInstances;
1236 * Sets minIdleInstances. Normalizes empty and null inputs to null.
1238 public void setMinIdleInstances(String minIdleInstances) {
1239 this.minIdleInstances = StringUtil.toNullIfEmptyOrWhitespace(minIdleInstances);
1242 public String getMaxIdleInstances() {
1243 return maxIdleInstances;
1247 * Sets maxIdleInstances. Normalizes empty and null inputs to null.
1249 public void setMaxIdleInstances(String maxIdleInstances) {
1250 this.maxIdleInstances = StringUtil.toNullIfEmptyOrWhitespace(maxIdleInstances);
1253 public boolean isEmpty() {
1254 return this.equals(EMPTY_SETTINGS);
1257 public String getMaxConcurrentRequests() {
1258 return maxConcurrentRequests;
1262 * Sets maxConcurrentRequests. Normalizes empty and null inputs to null.
1264 public void setMaxConcurrentRequests(String maxConcurrentRequests) {
1265 this.maxConcurrentRequests = StringUtil.toNullIfEmptyOrWhitespace(maxConcurrentRequests);
1268 public Integer getMinNumInstances() {
1269 return minNumInstances;
1272 public void setMinNumInstances(Integer minNumInstances) {
1273 this.minNumInstances = minNumInstances;
1276 public Integer getMaxNumInstances() {
1277 return maxNumInstances;
1280 public void setMaxNumInstances(Integer maxNumInstances) {
1281 this.maxNumInstances = maxNumInstances;
1284 public Integer getCoolDownPeriodSec() {
1285 return coolDownPeriodSec;
1288 public void setCoolDownPeriodSec(Integer coolDownPeriodSec) {
1289 this.coolDownPeriodSec = coolDownPeriodSec;
1292 public CpuUtilization getCpuUtilization() {
1293 return cpuUtilization;
1296 public void setCpuUtilization(CpuUtilization cpuUtilization) {
1297 this.cpuUtilization = cpuUtilization;
1300 @Override
1301 public int hashCode() {
1302 return Objects.hash(maxPendingLatency, minPendingLatency, maxIdleInstances,
1303 minIdleInstances, maxConcurrentRequests, minNumInstances,
1304 maxNumInstances, coolDownPeriodSec, cpuUtilization);
1307 @Override
1308 public boolean equals(Object obj) {
1309 if (this == obj) {
1310 return true;
1312 if (obj == null) {
1313 return false;
1315 if (getClass() != obj.getClass()) {
1316 return false;
1318 AutomaticScaling other = (AutomaticScaling) obj;
1319 return Objects.equals(maxPendingLatency, other.maxPendingLatency)
1320 && Objects.equals(minPendingLatency, other.minPendingLatency)
1321 && Objects.equals(maxIdleInstances, other.maxIdleInstances)
1322 && Objects.equals(minIdleInstances, other.minIdleInstances)
1323 && Objects.equals(maxConcurrentRequests, other.maxConcurrentRequests)
1324 && Objects.equals(minNumInstances, other.minNumInstances)
1325 && Objects.equals(maxNumInstances, other.maxNumInstances)
1326 && Objects.equals(coolDownPeriodSec, other.coolDownPeriodSec)
1327 && Objects.equals(cpuUtilization, other.cpuUtilization);
1330 @Override
1331 public String toString() {
1332 return "AutomaticScaling [minPendingLatency=" + minPendingLatency
1333 + ", maxPendingLatency=" + maxPendingLatency
1334 + ", minIdleInstances=" + minIdleInstances
1335 + ", maxIdleInstances=" + maxIdleInstances
1336 + ", maxConcurrentRequests=" + maxConcurrentRequests
1337 + ", minNumInstances=" + minNumInstances
1338 + ", maxNumInstances=" + maxNumInstances
1339 + ", coolDownPeriodSec=" + coolDownPeriodSec
1340 + ", cpuUtilization=" + cpuUtilization + "]";
1345 * Holder for CPU utilization.
1347 public static class CpuUtilization {
1348 private static final CpuUtilization EMPTY_SETTINGS = new CpuUtilization();
1349 private Double targetUtilization;
1350 private Integer aggregationWindowLengthSec;
1352 public Double getTargetUtilization() {
1353 return targetUtilization;
1356 public void setTargetUtilization(Double targetUtilization) {
1357 this.targetUtilization = targetUtilization;
1360 public Integer getAggregationWindowLengthSec() {
1361 return aggregationWindowLengthSec;
1364 public void setAggregationWindowLengthSec(Integer aggregationWindowLengthSec) {
1365 this.aggregationWindowLengthSec = aggregationWindowLengthSec;
1368 public boolean isEmpty() {
1369 return this.equals(EMPTY_SETTINGS);
1372 @Override
1373 public int hashCode() {
1374 return Objects.hash(targetUtilization, aggregationWindowLengthSec);
1377 @Override
1378 public boolean equals(Object obj) {
1379 if (this == obj) {
1380 return true;
1382 if (obj == null) {
1383 return false;
1385 if (getClass() != obj.getClass()) {
1386 return false;
1388 CpuUtilization other = (CpuUtilization) obj;
1389 return Objects.equals(targetUtilization, other.targetUtilization)
1390 && Objects.equals(aggregationWindowLengthSec, other.aggregationWindowLengthSec);
1393 @Override
1394 public String toString() {
1395 return "CpuUtilization [targetUtilization=" + targetUtilization
1396 + ", aggregationWindowLengthSec=" + aggregationWindowLengthSec + "]";
1401 * Holder for health check.
1403 public static class HealthCheck {
1404 private static final HealthCheck EMPTY_SETTINGS = new HealthCheck();
1406 private boolean enableHealthCheck = true;
1407 private Integer checkIntervalSec;
1408 private Integer timeoutSec;
1409 private Integer unhealthyThreshold;
1410 private Integer healthyThreshold;
1411 private Integer restartThreshold;
1412 private String host;
1414 public boolean getEnableHealthCheck() {
1415 return enableHealthCheck;
1418 * Sets enableHealthCheck.
1420 public void setEnableHealthCheck(boolean enableHealthCheck) {
1421 this.enableHealthCheck = enableHealthCheck;
1424 public Integer getCheckIntervalSec() {
1425 return checkIntervalSec;
1428 * Sets checkIntervalSec.
1430 public void setCheckIntervalSec(Integer checkIntervalSec) {
1431 this.checkIntervalSec = checkIntervalSec;
1434 public Integer getTimeoutSec() {
1435 return timeoutSec;
1438 * Sets timeoutSec.
1440 public void setTimeoutSec(Integer timeoutSec) {
1441 this.timeoutSec = timeoutSec;
1444 public Integer getUnhealthyThreshold() {
1445 return unhealthyThreshold;
1449 * Sets unhealthyThreshold.
1451 public void setUnhealthyThreshold(Integer unhealthyThreshold) {
1452 this.unhealthyThreshold = unhealthyThreshold;
1455 public Integer getHealthyThreshold() {
1456 return healthyThreshold;
1460 * Sets healthyThreshold.
1463 public void setHealthyThreshold(Integer healthyThreshold) {
1464 this.healthyThreshold = healthyThreshold;
1467 public Integer getRestartThreshold() {
1468 return restartThreshold;
1472 * Sets restartThreshold.
1474 public void setRestartThreshold(Integer restartThreshold) {
1475 this.restartThreshold = restartThreshold;
1478 public String getHost() {
1479 return host;
1483 * Sets host. Normalizes empty and null inputs to null.
1485 public void setHost(String host) {
1486 this.host = StringUtil.toNullIfEmptyOrWhitespace(host);
1489 public boolean isEmpty() {
1490 return this.equals(EMPTY_SETTINGS);
1493 @Override
1494 public int hashCode() {
1495 return Objects.hash(enableHealthCheck, checkIntervalSec, timeoutSec, unhealthyThreshold,
1496 healthyThreshold, restartThreshold, host);
1499 @Override
1500 public boolean equals(Object obj) {
1501 if (this == obj) {
1502 return true;
1504 if (obj == null) {
1505 return false;
1507 if (getClass() != obj.getClass()) {
1508 return false;
1510 HealthCheck other = (HealthCheck) obj;
1511 return Objects.equals(enableHealthCheck, other.enableHealthCheck)
1512 && Objects.equals(checkIntervalSec, other.checkIntervalSec)
1513 && Objects.equals(timeoutSec, other.timeoutSec)
1514 && Objects.equals(unhealthyThreshold, other.unhealthyThreshold)
1515 && Objects.equals(healthyThreshold, other.healthyThreshold)
1516 && Objects.equals(restartThreshold, other.restartThreshold)
1517 && Objects.equals(host, other.host);
1520 @Override
1521 public String toString() {
1522 return "HealthCheck [enableHealthCheck=" + enableHealthCheck
1523 + ", checkIntervalSec=" + checkIntervalSec
1524 + ", timeoutSec=" + timeoutSec
1525 + ", unhealthyThreshold=" + unhealthyThreshold
1526 + ", healthyThreshold=" + healthyThreshold
1527 + ", restartThreshold=" + restartThreshold
1528 + ", host=" + host + "]";
1533 * Holder for Resources
1535 public static class Resources {
1536 private static final Resources EMPTY_SETTINGS = new Resources();
1538 private double cpu;
1540 public double getCpu() {
1541 return cpu;
1544 public void setCpu(double cpu) {
1545 this.cpu = cpu;
1548 private double memory_gb;
1550 public double getMemoryGb() {
1551 return memory_gb;
1554 public void setMemoryGb(double memory_gb) {
1555 this.memory_gb = memory_gb;
1558 private int disk_size_gb;
1560 public int getDiskSizeGb() {
1561 return disk_size_gb;
1564 public void setDiskSizeGb(int disk_size_gb) {
1565 this.disk_size_gb = disk_size_gb;
1568 public boolean isEmpty() {
1569 return this.equals(EMPTY_SETTINGS);
1572 @Override
1573 public int hashCode() {
1574 return Objects.hash(cpu, memory_gb, disk_size_gb);
1577 @Override
1578 public boolean equals(Object obj) {
1579 if (this == obj) {
1580 return true;
1582 if (obj == null) {
1583 return false;
1585 if (getClass() != obj.getClass()) {
1586 return false;
1588 Resources other = (Resources) obj;
1589 return Objects.equals(cpu, other.cpu) &&
1590 Objects.equals(memory_gb, other.memory_gb) &&
1591 Objects.equals(disk_size_gb, other.disk_size_gb);
1594 @Override
1595 public String toString() {
1596 return "Resources [" + "cpu=" + cpu +
1597 ", memory_gb=" + memory_gb +
1598 ", disk_size_gb=" + disk_size_gb + "]";
1603 * Holder for network.
1605 public static class Network {
1606 private static final Network EMPTY_SETTINGS = new Network();
1608 private String instanceTag;
1610 public String getInstanceTag() {
1611 return instanceTag;
1614 public void setInstanceTag(String instanceTag) {
1615 this.instanceTag = instanceTag;
1618 private final List<String> forwardedPorts = Lists.newArrayList();
1620 public List<String> getForwardedPorts() {
1621 return Collections.unmodifiableList(forwardedPorts);
1624 public void addForwardedPort(String forwardedPort) {
1625 forwardedPorts.add(forwardedPort);
1628 private String name;
1630 public String getName() {
1631 return name;
1634 public void setName(String name) {
1635 this.name = name;
1638 public boolean isEmpty() {
1639 return this.equals(EMPTY_SETTINGS);
1642 @Override
1643 public int hashCode() {
1644 return Objects.hash(forwardedPorts, instanceTag);
1647 @Override
1648 public boolean equals(Object obj) {
1649 if (this == obj) {
1650 return true;
1652 if (obj == null) {
1653 return false;
1655 if (getClass() != obj.getClass()) {
1656 return false;
1658 Network other = (Network) obj;
1659 return Objects.equals(forwardedPorts, other.forwardedPorts)
1660 && Objects.equals(instanceTag, other.instanceTag);
1663 @Override
1664 public String toString() {
1665 return "Network [forwardedPorts=" + forwardedPorts + ", instanceTag=" + instanceTag + "]";
1670 * Holder for manual settings.
1672 public static class ManualScaling {
1673 private static final ManualScaling EMPTY_SETTINGS = new ManualScaling();
1675 private String instances;
1677 public String getInstances() {
1678 return instances;
1682 * Sets instances. Normalizes empty and null inputs to null.
1684 public void setInstances(String instances) {
1685 this.instances = StringUtil.toNullIfEmptyOrWhitespace(instances);
1688 public boolean isEmpty() {
1689 return this.equals(EMPTY_SETTINGS);
1692 @Override
1693 public int hashCode() {
1694 return Objects.hash(instances);
1697 @Override
1698 public boolean equals(Object obj) {
1699 if (this == obj) {
1700 return true;
1702 if (obj == null) {
1703 return false;
1705 if (getClass() != obj.getClass()) {
1706 return false;
1708 ManualScaling other = (ManualScaling) obj;
1709 return Objects.equals(instances, other.instances);
1712 @Override
1713 public String toString() {
1714 return "ManualScaling [" + "instances=" + instances + "]";
1719 * Holder for basic settings.
1721 public static class BasicScaling {
1722 private static final BasicScaling EMPTY_SETTINGS = new BasicScaling();
1724 private String maxInstances;
1725 private String idleTimeout;
1727 public String getMaxInstances() {
1728 return maxInstances;
1731 public String getIdleTimeout() {
1732 return idleTimeout;
1736 * Sets maxInstances. Normalizes empty and null inputs to null.
1738 public void setMaxInstances(String maxInstances) {
1739 this.maxInstances = StringUtil.toNullIfEmptyOrWhitespace(maxInstances);
1743 * Sets idleTimeout. Normalizes empty and null inputs to null.
1745 public void setIdleTimeout(String idleTimeout) {
1746 this.idleTimeout = StringUtil.toNullIfEmptyOrWhitespace(idleTimeout);
1749 public boolean isEmpty() {
1750 return this.equals(EMPTY_SETTINGS);
1753 @Override
1754 public int hashCode() {
1755 return Objects.hash(maxInstances, idleTimeout);
1758 @Override
1759 public boolean equals(Object obj) {
1760 if (this == obj) {
1761 return true;
1763 if (obj == null) {
1764 return false;
1766 if (getClass() != obj.getClass()) {
1767 return false;
1769 BasicScaling other = (BasicScaling) obj;
1770 return Objects.equals(maxInstances, other.maxInstances)
1771 && Objects.equals(idleTimeout, other.idleTimeout);
1774 @Override
1775 public String toString() {
1776 return "BasicScaling [" + "maxInstances=" + maxInstances
1777 + ", idleTimeout=" + idleTimeout + "]";
1782 * Represents a &lt;pagespeed&gt; element. This is used to specify configuration for the Page
1783 * Speed Service, which can be used to automatically optimize the loading speed of app engine
1784 * sites.
1786 public static class Pagespeed {
1787 private final List<String> urlBlacklist = Lists.newArrayList();
1788 private final List<String> domainsToRewrite = Lists.newArrayList();
1789 private final List<String> enabledRewriters = Lists.newArrayList();
1790 private final List<String> disabledRewriters = Lists.newArrayList();
1792 public void addUrlBlacklist(String url) {
1793 urlBlacklist.add(url);
1796 public List<String> getUrlBlacklist() {
1797 return Collections.unmodifiableList(urlBlacklist);
1800 public void addDomainToRewrite(String domain) {
1801 domainsToRewrite.add(domain);
1804 public List<String> getDomainsToRewrite() {
1805 return Collections.unmodifiableList(domainsToRewrite);
1808 public void addEnabledRewriter(String rewriter) {
1809 enabledRewriters.add(rewriter);
1812 public List<String> getEnabledRewriters() {
1813 return Collections.unmodifiableList(enabledRewriters);
1816 public void addDisabledRewriter(String rewriter) {
1817 disabledRewriters.add(rewriter);
1820 public List<String> getDisabledRewriters() {
1821 return Collections.unmodifiableList(disabledRewriters);
1824 public boolean isEmpty() {
1825 return urlBlacklist.isEmpty() && domainsToRewrite.isEmpty() && enabledRewriters.isEmpty()
1826 && disabledRewriters.isEmpty();
1829 @Override
1830 public int hashCode() {
1831 return Objects.hash(urlBlacklist, domainsToRewrite, enabledRewriters, disabledRewriters);
1834 @Override
1835 public boolean equals(Object obj) {
1836 if (this == obj) {
1837 return true;
1839 if (obj == null) {
1840 return false;
1842 if (getClass() != obj.getClass()) {
1843 return false;
1845 Pagespeed other = (Pagespeed) obj;
1846 return Objects.equals(urlBlacklist, other.urlBlacklist)
1847 && Objects.equals(domainsToRewrite, other.domainsToRewrite)
1848 && Objects.equals(enabledRewriters, other.enabledRewriters)
1849 && Objects.equals(disabledRewriters, other.disabledRewriters);
1852 @Override
1853 public String toString() {
1854 return "Pagespeed [urlBlacklist=" + urlBlacklist + ", domainsToRewrite=" + domainsToRewrite
1855 + ", enabledRewriters=" + enabledRewriters + ", disabledRewriters=" + disabledRewriters
1856 + "]";
1860 public static class ClassLoaderConfig {
1861 private final List<PrioritySpecifierEntry> entries = Lists.newArrayList();
1863 public void add(PrioritySpecifierEntry entry) {
1864 entries.add(entry);
1867 public List<PrioritySpecifierEntry> getEntries() {
1868 return entries;
1871 @Override
1872 public int hashCode() {
1873 final int prime = 31;
1874 int result = 1;
1875 result = prime * result + ((entries == null) ? 0 : entries.hashCode());
1876 return result;
1879 @Override
1880 public boolean equals(Object obj) {
1881 if (this == obj) return true;
1882 if (obj == null) return false;
1883 if (getClass() != obj.getClass()) return false;
1884 ClassLoaderConfig other = (ClassLoaderConfig) obj;
1885 if (entries == null) {
1886 if (other.entries != null) return false;
1887 } else if (!entries.equals(other.entries)) return false;
1888 return true;
1891 @Override
1892 public String toString() {
1893 return "ClassLoaderConfig{entries=\"" + entries + "\"}";
1897 public static class PrioritySpecifierEntry {
1898 private String filename;
1899 private Double priority;
1901 private void checkNotAlreadySet() {
1902 if (filename != null) {
1903 throw new AppEngineConfigException("Found more that one file name matching tag. "
1904 + "Only one of 'filename' attribute allowed.");
1908 public String getFilename() {
1909 return filename;
1912 public void setFilename(String filename) {
1913 checkNotAlreadySet();
1914 this.filename = filename;
1917 public Double getPriority() {
1918 return priority;
1921 public double getPriorityValue() {
1922 if (priority == null) {
1923 return 1.0d;
1925 return priority;
1928 public void setPriority(String priority) {
1929 if (this.priority != null) {
1930 throw new AppEngineConfigException("The 'priority' tag may only be specified once.");
1933 if (priority == null) {
1934 this.priority = null;
1935 return;
1938 this.priority = Double.parseDouble(priority);
1941 public void checkClassLoaderConfig() {
1942 if (filename == null) {
1943 throw new AppEngineConfigException("Must have a filename attribute.");
1947 @Override
1948 public int hashCode() {
1949 final int prime = 31;
1950 int result = 1;
1951 result = prime * result + ((filename == null) ? 0 : filename.hashCode());
1952 result = prime * result + ((priority == null) ? 0 : priority.hashCode());
1953 return result;
1956 @Override
1957 public boolean equals(Object obj) {
1958 if (this == obj) return true;
1959 if (obj == null) return false;
1960 if (getClass() != obj.getClass()) return false;
1961 PrioritySpecifierEntry other = (PrioritySpecifierEntry) obj;
1962 if (filename == null) {
1963 if (other.filename != null) return false;
1964 } else if (!filename.equals(other.filename)) return false;
1965 if (priority == null) {
1966 if (other.priority != null) return false;
1967 } else if (!priority.equals(other.priority)) return false;
1968 return true;
1971 @Override
1972 public String toString() {
1973 return "PrioritySpecifierEntry{filename=\"" + filename + "\", priority=\"" + priority + "\"}";