1 // Copyright 2008 Google Inc. All Rights Reserved.
3 package com
.google
.appengine
.tools
.admin
;
5 import com
.google
.appengine
.tools
.info
.SdkInfo
;
6 import com
.google
.appengine
.tools
.util
.ClientCookieManager
;
9 import java
.io
.PrintWriter
;
10 import java
.nio
.charset
.Charset
;
11 import java
.util
.Collections
;
15 * Creates a new {@link AppAdmin} for a designated App Engine application.
18 public class AppAdminFactory
{
20 private static final String JAVA_CMD_PROP
= "appengine.java";
21 private static final String JAVAC_CMD_PROP
= "appengine.javac";
23 private ApplicationProcessingOptions appOptions
= new ApplicationProcessingOptions();
25 private Class
<?
extends AppVersionUpload
> appVersionUploadClass
= AppVersionUpload
.class;
28 * Creates a new {@link AppAdmin} that can be used to administer the
29 * designated App Engine application.
31 * @param options The options used to connect to the remote server. Must not
33 * @param app The application to be administered. May be {@code null}.
34 * @param errorWriter A writer to which error logs can be written. The logs
35 * can be used for diagnosis if a failure occurs during operation. May
37 * @return a not {@code null} AppAdmin
39 public AppAdmin
createAppAdmin(ConnectOptions options
, Application app
, PrintWriter errorWriter
) {
40 return new AppAdminImpl(options
, app
, errorWriter
, appOptions
, appVersionUploadClass
);
44 * Creates a new {@link AppAdmin} that can be used to administer the
45 * designated App Engine application.
47 * @param options The options used to connect to the remote server. Must not
49 * @param app The application to be administered. May be {@code null}.
50 * @param errorWriter A writer to which error logs can be written. The logs
51 * can be used for diagnosis if a failure occurs during operation. May
53 * @return a not {@code null} AppAdmin
55 public AppAdmin
createAppAdmin(ConnectOptions options
, GenericApplication app
,
56 PrintWriter errorWriter
) {
57 return new AppAdminImpl(options
, app
, errorWriter
, appOptions
, appVersionUploadClass
);
60 public ApplicationProcessingOptions
getAppOptions() {
64 public Class
<?
extends AppVersionUpload
> getAppVersionUploadClass() {
65 return appVersionUploadClass
;
69 * Sets the class used for uploading the application to the server. Should
70 * only be used for advanced customization of the upload process.
72 public void setAppVersionUploadClass(Class
<?
extends AppVersionUpload
> klass
) {
73 appVersionUploadClass
= klass
;
77 * Callback that is invoked to prompt the user to enter a password.
79 public interface PasswordPrompt
{
84 * The options used to connect to the remote App Engine administration server.
87 public static class ConnectOptions
{
90 * Retrieves the user's email address used to authenticate to the server.
92 * @return user identity
94 public String
getUserId() {
99 * The user id for the App Engine account. This should be the same e-mail
100 * address used to register the account owning the App Engine application.
102 * @param userId the not {@code null} e-mail address
104 public void setUserId(String userId
) {
105 this.userId
= userId
;
109 * Retrieves the prompter used to get the user's password.
111 * @return the {@link PasswordPrompt} to be used
113 public PasswordPrompt
getPasswordPrompt() {
114 return passwordPrompt
;
118 * The password prompt to get the user's password.
120 * @param prompt the {@link PasswordPrompt} that's being used
122 public void setPasswordPrompt(PasswordPrompt prompt
) {
123 this.passwordPrompt
= prompt
;
126 /** Returns the server address to connect to. */
127 public String
getServer() {
132 * The remote administration server to connect to. This is an advanced
133 * option that should rarely be set by users.
135 * @param server May be set to {@code null} to use the default server.
137 public void setServer(String server
) {
138 this.server
= server
;
142 * Returns the value used for the Host header sent to the server with RPCs.
144 * @return hostname to insert into request headers
146 public String
getHost() {
151 * The host name to supply to the remote server. This is an advanced option
152 * that should rarely be set by users.
154 * @param host May be set to {@code null} to use the default host name.
156 public void setHost(String host
) {
161 * Controls whether we clean up our temporary files, or leave it for
164 public void setRetainUploadDir(boolean flag
) {
165 this.keepUpload
= flag
;
168 /** Returns {@code true} if the upload directory should not be deleted. */
169 public boolean getRetainUploadDir() {
173 /** Returns the location of the AppEngine SDK directory. */
174 public String
getSdkRoot() {
179 * A file path to the top directory of the Google App Engine SDK.
181 * @param sdkRoot the not {@code null} path to the SDK
183 public void setSdkRoot(String sdkRoot
) {
184 this.sdkRoot
= sdkRoot
;
188 * Retrieves the current cookie manager.
190 * @return the cookie manager set with
191 * {@link #setCookies(ClientCookieManager)}.
193 public ClientCookieManager
getCookies() {
198 * Associates a {@link ClientCookieManager} to store cookies received from
199 * the server, for later reuse in other requests.
201 * @param cookies the cookie manager to use
203 public void setCookies(ClientCookieManager cookies
) {
204 this.cookies
= cookies
;
208 * Returns whether to use HTTPS for communicating with the Admin Console. By
209 * default, this returns true.
211 public boolean getSecure() {
216 * Sets whether to use HTTPS for communicating with the Admin Console.
218 * @param secure true for HTTPS, false for HTTP
220 public void setSecure(boolean secure
) {
221 this.secure
= secure
;
225 * Sets the OAuth 2.0 token to use for authentication (instead of requiring
226 * a username and password).
228 public void setOauthToken(String oauthToken
) {
229 this.oauthToken
= oauthToken
;
233 * Returns the OAuth 2.0 token being used for authentication, or {@code
236 public String
getOauthToken() {
241 * Sets whether to use persisted credentials (load/save to/from disk).
243 public void setUsePersistedCredentials(boolean usePersistedCredentials
) {
244 this.usePersistedCredentials
= usePersistedCredentials
;
248 * Returns whether to use persisted credentials (load/save to/from disk).
250 public boolean getUsePersistedCredentials() {
251 return usePersistedCredentials
;
254 private String userId
;
255 private String server
= SdkInfo
.getDefaultServer();
257 private String sdkRoot
;
259 private ClientCookieManager cookies
;
260 private PasswordPrompt passwordPrompt
;
261 private boolean secure
= true;
262 private String oauthToken
;
263 private boolean usePersistedCredentials
= true;
266 public boolean equals(Object o
) {
270 if (o
== null || getClass() != o
.getClass()) {
273 ConnectOptions that
= (ConnectOptions
) o
;
275 if (host
!= null ?
!host
.equals(that
.host
) : that
.host
!= null) {
278 if (server
!= null ?
!server
.equals(that
.server
) : that
.server
!= null) {
281 if (userId
!= null ?
!userId
.equals(that
.userId
) : that
.userId
!= null) {
284 if (sdkRoot
!= null ?
!sdkRoot
.equals(that
.sdkRoot
) : that
.sdkRoot
!= null) {
292 public int hashCode() {
294 result
= (userId
!= null ? userId
.hashCode() : 0);
295 result
= 31 * result
+ (server
!= null ? server
.hashCode() : 0);
296 result
= 31 * result
+ (host
!= null ? host
.hashCode() : 0);
297 result
= 31 * result
+ (sdkRoot
!= null ? sdkRoot
.hashCode() : 0);
303 * Options used in preparing an application directory for upload.
305 public static class ApplicationProcessingOptions
{
308 private boolean compileJsps
= true;
309 private boolean doBatch
= true;
310 private String compileEncoding
= "UTF-8";
311 private boolean splitJars
= false;
312 private boolean jarJSPs
= true;
313 private boolean jarClasses
= false;
314 private boolean deleteJSPs
= false;
315 private Set
<String
> splitExcludes
= Collections
.emptySet();
316 private String runtime
;
317 private boolean allowAnyRuntime
= false;
318 private boolean failOnPrecompilationError
= false;
321 * Returns an appropriate "java" executable. If a prior call to
322 * {@link #setJavaExecutable(File)} was made, that value is returned (on
323 * windows, the algorithm is forgiving if ".exe" was omitted, and will add
324 * it). If not, the system property {@code java.home} is used to identify
325 * the currently-running JVM, and if that directory contains a file named
326 * {@code bin/java} (Unix) or {@code bin\\java.exe} (Windows), that is
329 * @return the Java executable, as a {@link File}.
330 * @throws IllegalStateException if the java cannot be found by the
331 * heuristic above, but {@link #setJavaExecutable(File)} has not
332 * been called, or if it has been called, but the specified file
335 public File
getJavaExecutable() {
340 String javaProp
= System
.getProperty(JAVA_CMD_PROP
);
341 if (javaProp
!= null) {
342 java
= new File(javaProp
);
343 if (!java
.exists()) {
344 if (Utility
.isOsWindows() && !javaProp
.endsWith(".exe")
345 && (new File(javaProp
+ ".exe")).exists()) {
346 java
= new File(javaProp
+ ".exe");
348 throw new IllegalStateException("cannot find java executable \"" + javaProp
+ "\"");
352 String javaHome
= System
.getProperty("java.home");
354 javaHome
+ File
.separator
+ "bin" + File
.separator
+ "java"
355 + (Utility
.isOsWindows() ?
".exe" : "");
356 java
= new File(javaCmd
);
357 if (!java
.exists()) {
359 throw new IllegalStateException("cannot find java executable "
360 + "based on java.home, tried \"" + javaCmd
+ "\"");
367 * Explicitly requests a specific {@code java} program be used for launched
368 * tasks, such as compiling JSP files.
370 * @param java the executable file to run.
372 void setJavaExecutable(File java
) {
377 * Returns an appropriate "javac" executable. If a prior call to
378 * {@link #setJavaCompiler(File)} was made, that value is returned (on
379 * windows, the algorithm is forgiving if ".exe" was omitted, and will add
380 * it). If not, the system property {@code java.home} is used to identify
381 * the currently-running JVM. If that pathname ends with "jre", then its
382 * parent is used instead as a hoped-for JDK root. If that directory
383 * contains a file named {@code bin/javac} (Unix) or {@code bin\\javac.exe}
384 * (Windows), that is returned.
386 * @return the Java compiler, as a {@link File}.
387 * @throws IllegalStateException if the javac cannot be found by the
388 * heuristic above, but {@link #setJavaCompiler(File)} has not be
389 * called, or if it has been called but the file does not exist.
391 public File
getJavaCompiler() {
396 String javacProp
= System
.getProperty(JAVAC_CMD_PROP
);
397 if (javacProp
!= null) {
398 javac
= new File(javacProp
);
399 if (!javac
.exists()) {
400 if (Utility
.isOsWindows() && !javacProp
.endsWith(".exe")
401 && (new File(javacProp
+ ".exe")).exists()) {
402 javac
= new File(javacProp
+ ".exe");
404 throw new IllegalStateException("cannot find javac executable \"" + javacProp
+ "\"");
408 String javaHome
= System
.getProperty("java.home");
409 String javacDir
= javaHome
;
411 javacDir
+ File
.separator
+ "bin" + File
.separator
+ "javac"
412 + (Utility
.isOsWindows() ?
".exe" : "");
413 javac
= new File(javacCmd
);
414 if (!javac
.exists()) {
416 javacDir
= (new File(javaHome
)).getParentFile().getPath();
418 javacDir
+ File
.separator
+ "bin" + File
.separator
+ "javac"
419 + (Utility
.isOsWindows() ?
".exe" : "");
420 javac
= new File(javacCmd2
);
421 if (!javac
.exists()) {
423 throw new IllegalStateException("cannot find javac executable "
424 + "based on java.home, tried \"" + javacCmd
+ "\" and \"" + javacCmd2
+ "\"");
432 * Explicitly requests a specific {@code javac} program be used for launched
433 * Java compilations, such as compiling JSP files into classes.
435 * @param javac the executable file to run.
437 void setJavaCompiler(File javac
) {
441 /** Returns whether we should attempt to compile JSPs */
442 public boolean isCompileJspsSet() {
447 * Requests that *.jsp files should be compiled into Java byte code, or if
448 * false should be left untouched.
450 * @param doJsps {@code true} to compile .jsp files
452 void setCompileJsps(boolean doJsps
) {
453 this.compileJsps
= doJsps
;
457 * Returns whether we should use batch upload
459 public boolean isBatchModeSet() {
464 * Requests we use the upload batch mode
466 * @param doBatch {@code true} to use batch mode
468 void setBatchMode(boolean doBatch
) {
469 this.doBatch
= doBatch
;
472 public String
getCompileEncoding() {
473 return compileEncoding
;
476 public void setCompileEncoding(String compileEncoding
) {
477 this.compileEncoding
= compileEncoding
;
480 /** Returns whether we should split large jar files. */
481 public boolean isSplitJarsSet() {
485 /** Sets whether we should split large jar files. */
486 public void splitJars(boolean b
) {
490 /** Sets whether we should jar the classes generated from JSPs. */
491 public void setJarJSPs(boolean b
) {
495 /** Returns whether we should jar the classes generated from JSPs. */
496 public boolean isJarJSPsSet() {
500 /** Sets whether we should jar the WEB-INF/classes content. */
501 public void setJarClasses(boolean b
) {
505 /** Returns whether we should jar the WEB-INF/classes content. */
506 public boolean isJarClassesSet() {
510 /** Sets whether we should delete the JSP source files. */
511 public void setDeleteJSPs(boolean b
) {
515 /** Returns whether we should delete the JSP source files. */
516 public boolean isDeleteJSPs() {
521 * Sets suffixes of filenames to exclude when splitting jars.
523 * @param jarSplittingExcludeSuffixes suffixes of filenames to exclude when
526 void setJarSplittingExcludes(Set
<String
> jarSplittingExcludeSuffixes
) {
527 splitExcludes
= jarSplittingExcludeSuffixes
;
531 * Returns the set of suffixes of filenames that should be excluded when
534 * @return a set of suffixes of filenames to exclude.
536 public Set
<String
> getJarSplittingExcludes() {
537 return splitExcludes
;
540 /** Sets the runtime id. */
541 public void setRuntime(String s
) {
545 /** Returns the runtime id. */
546 public String
getRuntime() {
550 /** Sets whether to skip validation of the runtime id provided by the user. */
551 public void setAllowAnyRuntime(boolean b
) {
555 /** Returns whether to skip validation of the runtime id provided by the user. */
556 public boolean isAllowAnyRuntime() {
557 return allowAnyRuntime
;
560 /** Sets whether to abort an update in case precompilation fails. */
561 public void setFailOnPrecompilationError(boolean b
) {
562 failOnPrecompilationError
= b
;
565 /** Returns whether to abort an update in case precompilation fails. */
566 public boolean isFailOnPrecompilationError() {
567 return failOnPrecompilationError
;
572 * Specifies the location of a java executable, used when compiling JSPs. By
573 * default, the system property {@code java.home} is used to identify the
574 * currently-running JVM, and if that directory contains a file named {@code
575 * bin/java} (Unix) or {@code bin\\java.exe} (Windows), that is returned.
577 * @param java the Java executable to be used.
579 public void setJavaExecutable(File java
) {
580 appOptions
.setJavaExecutable(java
);
584 * Specifies the location of a javac executable, used when compiling JSPs. By
585 * default, the system property {@code java.home} is used to identify the
586 * currently-running JVM. If that pathname ends with "jre", then its parent is
587 * used instead as a hoped-for JDK root. If that directory contains a file
588 * named {@code bin/javac} (Unix) or {@code bin\\javac.exe} (Windows), that is
591 * @param javac the Java compiler executable to be used.
593 public void setJavaCompiler(File javac
) {
594 appOptions
.setJavaCompiler(javac
);
598 * Requests that *.jsp files should be compiled into Java byte code, or if
599 * false should be left untouched.
601 * @param flag {@code true} to compile .jsp files
603 public void setCompileJsps(boolean flag
) {
604 appOptions
.setCompileJsps(flag
);
608 * Requests we do upload using batch
610 * @param flag {@code true} to use batch mode for upload
612 public void setBatchMode(boolean flag
) {
613 appOptions
.setBatchMode(flag
);
617 * Enables or disables jar splitting.
619 * @param doSplit {@code false} to leave jars unsplit, and perhaps fail to
620 * upload due to large files, {@code true} to split into chunks of some
623 public void setJarSplittingEnabled(boolean doSplit
) {
624 appOptions
.splitJars(doSplit
);
628 * Enables or disables jarring classes generated from JSPs.
630 * @param doJarJSPs {@code true} to jar the generated classes from JSPs.
632 public void setJarJSPsEnabled(boolean doJarJSPs
) {
633 appOptions
.setJarJSPs(doJarJSPs
);
637 * Enables or disables jarring WEB-INF/classes content.
639 * @param doJarClasses {@code true} to jar the WEB-INF/classes content.
641 public void setJarClassessEnabled(boolean doJarClasses
) {
642 appOptions
.setJarClasses(doJarClasses
);
646 * Deletes or not the JSPs source files.
648 * @param deleteJSPs {@code true} remove all JSPs source (not needed after compilation).
650 public void setDeleteJSPs(boolean deleteJSPs
) {
651 appOptions
.setDeleteJSPs(deleteJSPs
);
655 * Sets suffixes for files to exclude when performing jar splitting.
657 * @param jarSplittingExcludeSuffixes a set of filename suffixes to exclude
658 * when performing jar splitting.
660 public void setJarSplittingExcludes(Set
<String
> jarSplittingExcludeSuffixes
) {
661 appOptions
.setJarSplittingExcludes(jarSplittingExcludeSuffixes
);
665 * Sets the character encoding to use when compiling JSP files.
667 * @throws IllegalArgumentException If the specified encoding is illegal or
670 public void setCompileEncoding(String compileEncoding
) {
671 Charset
.forName(compileEncoding
);
672 appOptions
.setCompileEncoding(compileEncoding
);
676 * Sets the runtime id to use in the generated app.yaml descriptor.
678 * @param runtime the runtime id to use.
680 public void setRuntime(String runtime
) {
681 appOptions
.setRuntime(runtime
);
685 * Enables or disables validation of the runtime id provided by the user.
687 * @param allowAnyRuntime {@code true} to allow an arbitrary runtime id value,
688 * {@code false} to validate it against the list of supported runtimes.
690 public void setAllowAnyRuntime(boolean allowAnyRuntime
) {
691 appOptions
.setAllowAnyRuntime(allowAnyRuntime
);
695 * Enables or disables treating (repeated) precompilation errors as fatal when
696 * updating an application.
698 * @param fail {@code true} to abort an update if precompilation fails,
699 * {@code false} to treat it as a warning and continue updating the application.
701 public void setFailOnPrecompilationError(boolean fail
) {
702 appOptions
.setFailOnPrecompilationError(fail
);