1.9.30 sync.
[gae.git] / java / src / main / com / google / appengine / tools / remoteapi / RemoteApiOptions.java
blobc6323de9712f1891f4d02823eec76dbd9104db02
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.appengine.tools.remoteapi;
5 import com.google.api.client.auth.oauth2.Credential;
6 import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
7 import com.google.api.client.googleapis.compute.ComputeCredential;
8 import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
9 import com.google.api.client.http.HttpTransport;
10 import com.google.api.client.json.jackson.JacksonFactory;
11 import com.google.apphosting.api.ApiProxy;
12 import com.google.common.collect.ImmutableList;
14 import java.io.File;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.security.GeneralSecurityException;
18 import java.security.PrivateKey;
19 import java.util.List;
21 /**
22 * A mutable object containing settings for installing the remote API.
24 * <p>Example for connecting to a development app server:</p>
26 * <pre>
27 * RemoteApiOptions options = new RemoteApiOptions()
28 * .server("localhost", 8888),
29 * .useDevelopmentServerCredential();
30 * </pre>
32 * <p>Example for connecting to a deployed app:</p>
34 * <pre>
35 * RemoteApiOptions options = new RemoteApiOptions()
36 * .server("myappid.appspot.com", 443),
37 * .useApplicationDefaultCredential();
38 * </pre>
40 * <p>
41 * The options should be passed to {@link RemoteApiInstaller#install}.
42 * </p>
45 public class RemoteApiOptions {
47 private static final List<String> OAUTH_SCOPES = ImmutableList.of(
48 "https://www.googleapis.com/auth/appengine.apis",
49 "https://www.googleapis.com/auth/userinfo.email");
51 private static final String LOCAL_USER = "test@example.com";
52 private static final String LOCAL_PASSWORD = "";
54 private String hostname;
55 private int port;
56 private String userEmail;
57 private String password;
58 private String credentialsToReuse;
59 private String remoteApiPath = "/remote_api";
60 private int maxConcurrentRequests = 5;
61 private int datastoreQueryFetchSize = 500;
62 private int maxHttpResponseSize = 33 * 1024 * 1024;
64 private Credential oauthCredential;
65 private HttpTransport httpTransport;
67 public RemoteApiOptions() {}
69 RemoteApiOptions(RemoteApiOptions original) {
70 this.hostname = original.hostname;
71 this.port = original.port;
72 this.userEmail = original.userEmail;
73 this.password = original.password;
74 this.credentialsToReuse = original.credentialsToReuse;
75 this.remoteApiPath = original.remoteApiPath;
76 this.maxConcurrentRequests = original.maxConcurrentRequests;
77 this.datastoreQueryFetchSize = original.datastoreQueryFetchSize;
78 this.maxHttpResponseSize = original.maxHttpResponseSize;
79 this.oauthCredential = original.oauthCredential;
80 this.httpTransport = original.httpTransport;
83 /**
84 * Sets the host and port port where we will connect.
86 public RemoteApiOptions server(String newHostname, int newPort) {
87 hostname = newHostname;
88 port = newPort;
89 return this;
92 /**
93 * Sets a username and password to be used for logging in via the
94 * ClientLogin API. Overrides any previously-provided credentials.
96 * @deprecated Use {@link #useApplicationDefaultCredential} or
97 * {@link useServiceAccountCredential} instead.
99 @Deprecated
100 public RemoteApiOptions credentials(String newUserEMail, String newPassword) {
101 userEmail = newUserEMail;
102 password = newPassword;
103 credentialsToReuse = null;
104 oauthCredential = null;
105 return this;
109 * Reuses credentials from another AppEngineClient. Credentials can only
110 * be reused from a client with the same hostname and user. Overrides any
111 * previously-provided credentials.
112 * @param newUserEmail the email address of the user we want to log in as.
113 * @param serializedCredentials a string returned by calling
114 * {@link AppEngineClient#serializeCredentials} on the previous client
116 public RemoteApiOptions reuseCredentials(String newUserEmail, String serializedCredentials) {
117 userEmail = newUserEmail;
118 password = null;
119 credentialsToReuse = serializedCredentials;
120 oauthCredential = null;
121 return this;
125 * Use a Compute Engine credential for authentication. Overrides any
126 * previously-provided credentials.
128 * @return this {@code RemoteApiOptions} instance
129 * @deprecated Use {@link #useApplicationDefaultCredential}.
131 @Deprecated
132 public RemoteApiOptions useComputeEngineCredential() {
133 try {
134 HttpTransport transport = getOrCreateHttpTransportForOAuth();
135 ComputeCredential credential = new ComputeCredential(transport, new JacksonFactory());
136 credential.refreshToken();
137 setOAuthCredential(credential);
138 } catch (IOException|GeneralSecurityException e) {
139 throw new RuntimeException("Failed to acquire Google Compute Engine credential.", e);
141 return this;
145 * Use a Google Application Default credential for authentication. Overrides any
146 * previously-provided credentials.
148 * @return this {@code RemoteApiOptions} instance.
149 * @see <a href="developers.google.com/identity/protocols/application-default-credentials">
150 * Application Default Credentials</a>
152 public RemoteApiOptions useApplicationDefaultCredential() {
153 try {
154 getOrCreateHttpTransportForOAuth();
155 GoogleCredential credential = GoogleCredential.getApplicationDefault();
156 credential = credential.createScoped(OAUTH_SCOPES);
157 credential.refreshToken();
158 setOAuthCredential(credential);
159 } catch (IOException|GeneralSecurityException e) {
160 throw new RuntimeException("Failed to acquire Google Application Default credential.", e);
162 return this;
166 * Use a service account credential. Overrides any previously-provided
167 * credentials.
169 * @param serviceAccountId service account ID (typically an e-mail address)
170 * @param p12PrivateKeyFile p12 file containing a private key to use with the service account
172 * @return this {@code RemoteApiOptions} instance
174 public RemoteApiOptions useServiceAccountCredential(String serviceAccountId,
175 String p12PrivateKeyFile) {
176 try {
177 Credential credential = getCredentialBuilder(serviceAccountId)
178 .setServiceAccountPrivateKeyFromP12File(new File(p12PrivateKeyFile))
179 .build();
180 setOAuthCredential(credential);
181 } catch (IOException|GeneralSecurityException e) {
182 throw new RuntimeException("Failed to build service account credential.", e);
184 return this;
188 * Use a service account credential. Overrides any previously-provided
189 * credentials.
191 * @param serviceAccountId service account ID (typically an e-mail address)
192 * @param privateKey private key to use with the service account
194 * @return this {@code RemoteApiOptions} instance
196 public RemoteApiOptions useServiceAccountCredential(String serviceAccountId,
197 PrivateKey privateKey) {
198 try {
199 Credential credential = getCredentialBuilder(serviceAccountId)
200 .setServiceAccountPrivateKey(privateKey)
201 .build();
202 setOAuthCredential(credential);
203 } catch (IOException|GeneralSecurityException e) {
204 throw new RuntimeException("Failed to build service account credential.", e);
206 return this;
210 * Use credentials appropriate for talking to the Development Server.
211 * Overrides any previously-provided credentials.
213 * @return this {@code RemoteApiOptions} instance
215 public RemoteApiOptions useDevelopmentServerCredential() {
216 credentials(LOCAL_USER, LOCAL_PASSWORD);
217 return this;
220 private GoogleCredential.Builder getCredentialBuilder(
221 String serviceAccountId) throws GeneralSecurityException, IOException {
222 HttpTransport transport = getOrCreateHttpTransportForOAuth();
223 JacksonFactory jsonFactory = new JacksonFactory();
224 return new GoogleCredential.Builder()
225 .setTransport(transport)
226 .setJsonFactory(jsonFactory)
227 .setServiceAccountId(serviceAccountId)
228 .setServiceAccountScopes(OAUTH_SCOPES);
231 RemoteApiOptions useGoogleCredentialStream(InputStream stream) {
232 try {
233 getOrCreateHttpTransportForOAuth();
234 GoogleCredential credential = GoogleCredential.fromStream(stream);
235 credential = credential.createScoped(OAUTH_SCOPES);
236 credential.refreshToken();
237 setOAuthCredential(credential);
238 } catch (IOException|GeneralSecurityException e) {
239 throw new RuntimeException("Failed to acquire Google credential.", e);
241 return this;
244 RemoteApiOptions oauthCredential(Credential oauthCredential) {
245 setOAuthCredential(oauthCredential);
246 return this;
249 private void setOAuthCredential(Credential oauthCredential) {
250 userEmail = null;
251 password = null;
252 credentialsToReuse = null;
253 this.oauthCredential = oauthCredential;
256 RemoteApiOptions httpTransport(HttpTransport httpTransport) {
257 this.httpTransport = httpTransport;
258 return this;
262 * Sets the path used to access the remote API. If not set, the default
263 * is /remote_api.
265 public RemoteApiOptions remoteApiPath(String newPath) {
266 remoteApiPath = newPath;
267 return this;
271 * This parameter controls the maximum number of async API requests that will be
272 * in flight at once. Each concurrent request will likely be handled by a separate
273 * <a href="http://cloud.google.com/appengine/docs/adminconsole/instances.html"
274 * >instance</a> of your App. Having more instances increases throughput but may
275 * result in errors due to exceeding quota. Defaults to 5.
277 public RemoteApiOptions maxConcurrentRequests(int newValue) {
278 maxConcurrentRequests = newValue;
279 return this;
283 * When executing a datastore query, this is the number of results to fetch
284 * per HTTP request. Increasing this value will reduce the number of round trips
285 * when running large queries, but too high a value can be wasteful when not
286 * all results are needed. Defaults to 500.
288 * <p>(This value can be overridden by the code using the datastore API.)</p>
290 public RemoteApiOptions datastoreQueryFetchSize(int newValue) {
291 datastoreQueryFetchSize = newValue;
292 return this;
296 * When making a remote call, this is the maximum size of the HTTP response.
297 * The default is 33M. Normally there's no reason to change this. This
298 * setting has no effect when running in an App Engine container.
300 public RemoteApiOptions maxHttpResponseSize(int newValue) {
301 maxHttpResponseSize = newValue;
302 return this;
305 public RemoteApiOptions copy() {
306 return new RemoteApiOptions(this);
310 * Create an {@link HttpTransport} appropriate to this environment or return
311 * the one that's already been created. This method ensures that the
312 * determination of whether we're running in App Engine happens early
313 * (specifically, before the Remote API has been installed) and that said
314 * determination is remembered.
316 private HttpTransport getOrCreateHttpTransportForOAuth()
317 throws IOException, GeneralSecurityException {
318 if (httpTransport != null) {
319 return httpTransport;
322 if (ApiProxy.getCurrentEnvironment() != null) {
323 throw new IllegalStateException(
324 "OAuth-based authorization not supported for clients running on App Engine");
327 httpTransport = GoogleNetHttpTransport.newTrustedTransport();
328 return httpTransport;
331 HttpTransport getHttpTransport() {
332 return httpTransport;
335 public String getHostname() {
336 return hostname;
339 public int getPort() {
340 return port;
343 public String getUserEmail() {
344 return userEmail;
347 public String getPassword() {
348 return password;
351 public String getCredentialsToReuse() {
352 return credentialsToReuse;
355 Credential getOAuthCredential() {
356 return oauthCredential;
359 public String getRemoteApiPath() {
360 return remoteApiPath;
363 public int getMaxConcurrentRequests() {
364 return maxConcurrentRequests;
367 public int getDatastoreQueryFetchSize() {
368 return datastoreQueryFetchSize;
371 public int getMaxHttpResponseSize() {
372 return maxHttpResponseSize;