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
;
15 import java
.io
.IOException
;
16 import java
.security
.GeneralSecurityException
;
17 import java
.security
.PrivateKey
;
18 import java
.util
.List
;
21 * A mutable object containing settings for installing the remote API.
23 * <p>Example for connecting to a development app server:</p>
26 * RemoteApiOptions options = new RemoteApiOptions()
27 * .server("localhost", 8888),
28 * .credentials("username", "password does not matter");
31 * <p>Example for connecting to a deployed app:</p>
34 * RemoteApiOptions options = new RemoteApiOptions()
35 * .server("myappid.appspot.com", 443),
36 * .credentials(adminUsername, adminPassword);
40 * The options should be passed to {@link RemoteApiInstaller#install}.
44 public class RemoteApiOptions
{
46 private static final List
<String
> OAUTH_SCOPES
= ImmutableList
.of(
47 "https://www.googleapis.com/auth/appengine.apis",
48 "https://www.googleapis.com/auth/userinfo.email");
50 private static final String LOCAL_USER
= "test@example.com";
51 private static final String LOCAL_PASSWORD
= "";
53 private String hostname
;
55 private String userEmail
;
56 private String password
;
57 private String credentialsToReuse
;
58 private String remoteApiPath
= "/remote_api";
59 private int maxConcurrentRequests
= 5;
60 private int datastoreQueryFetchSize
= 500;
61 private int maxHttpResponseSize
= 33 * 1024 * 1024;
63 private Credential oauthCredential
;
64 private HttpTransport httpTransport
;
66 public RemoteApiOptions() {}
68 RemoteApiOptions(RemoteApiOptions original
) {
69 this.hostname
= original
.hostname
;
70 this.port
= original
.port
;
71 this.userEmail
= original
.userEmail
;
72 this.password
= original
.password
;
73 this.credentialsToReuse
= original
.credentialsToReuse
;
74 this.remoteApiPath
= original
.remoteApiPath
;
75 this.maxConcurrentRequests
= original
.maxConcurrentRequests
;
76 this.datastoreQueryFetchSize
= original
.datastoreQueryFetchSize
;
77 this.maxHttpResponseSize
= original
.maxHttpResponseSize
;
78 this.oauthCredential
= original
.oauthCredential
;
79 this.httpTransport
= original
.httpTransport
;
83 * Sets the host and port port where we will connect.
85 public RemoteApiOptions
server(String newHostname
, int newPort
) {
86 hostname
= newHostname
;
92 * Sets a username and password to be used for logging in via the
93 * ClientLogin API. Overrides any previously-provided credentials.
95 public RemoteApiOptions
credentials(String newUserEMail
, String newPassword
) {
96 userEmail
= newUserEMail
;
97 password
= newPassword
;
98 credentialsToReuse
= null;
99 oauthCredential
= null;
104 * Reuses credentials from another AppEngineClient. Credentials can only
105 * be reused from a client with the same hostname and user. Overrides any
106 * previously-provided credentials.
107 * @param newUserEmail the email address of the user we want to log in as.
108 * @param serializedCredentials a string returned by calling
109 * {@link AppEngineClient#serializeCredentials} on the previous client
111 public RemoteApiOptions
reuseCredentials(String newUserEmail
, String serializedCredentials
) {
112 userEmail
= newUserEmail
;
114 credentialsToReuse
= serializedCredentials
;
115 oauthCredential
= null;
120 * Use a Compute Engine credential for authentication. Overrides any
121 * previously-provided credentials.
123 RemoteApiOptions
useComputeEngineCredential() {
125 HttpTransport transport
= getOrCreateHttpTransportForOAuth();
126 ComputeCredential credential
= new ComputeCredential(transport
, new JacksonFactory());
127 credential
.refreshToken();
128 setOAuthCredential(credential
);
129 } catch (IOException
|GeneralSecurityException e
) {
130 throw new RuntimeException("Failed to acquire Google Compute Engine credential.", e
);
136 * Use a service account credential. Overrides any previously-provided
139 RemoteApiOptions
useServiceAccountCredential(String serviceAccount
,
140 String p12PrivateKeyFile
) {
142 Credential credential
= getCredentialBuilder(serviceAccount
)
143 .setServiceAccountPrivateKeyFromP12File(new File(p12PrivateKeyFile
))
145 setOAuthCredential(credential
);
146 } catch (IOException
|GeneralSecurityException e
) {
147 throw new RuntimeException("Failed to build service account credential.", e
);
153 * Use a service account credential. Overrides any previously-provided
156 RemoteApiOptions
useServiceAccountCredential(String serviceAccount
,
157 PrivateKey privateKey
) {
159 Credential credential
= getCredentialBuilder(serviceAccount
)
160 .setServiceAccountPrivateKey(privateKey
)
162 setOAuthCredential(credential
);
163 } catch (IOException
|GeneralSecurityException e
) {
164 throw new RuntimeException("Failed to build service account credential.", e
);
170 * Use credentials appropriate for talking to the Development Server.
171 * Overrides any previously-provided credentials.
173 RemoteApiOptions
useDevelopmentServerCredential() {
174 credentials(LOCAL_USER
, LOCAL_PASSWORD
);
178 private GoogleCredential
.Builder
getCredentialBuilder(
179 String serviceAccount
) throws GeneralSecurityException
, IOException
{
180 HttpTransport transport
= getOrCreateHttpTransportForOAuth();
181 JacksonFactory jsonFactory
= new JacksonFactory();
182 return new GoogleCredential
.Builder()
183 .setTransport(transport
)
184 .setJsonFactory(jsonFactory
)
185 .setServiceAccountId(serviceAccount
)
186 .setServiceAccountScopes(OAUTH_SCOPES
);
189 RemoteApiOptions
oauthCredential(Credential oauthCredential
) {
190 setOAuthCredential(oauthCredential
);
194 private void setOAuthCredential(Credential oauthCredential
) {
197 credentialsToReuse
= null;
198 this.oauthCredential
= oauthCredential
;
201 RemoteApiOptions
httpTransport(HttpTransport httpTransport
) {
202 this.httpTransport
= httpTransport
;
207 * Sets the path used to access the remote API. If not set, the default
210 public RemoteApiOptions
remoteApiPath(String newPath
) {
211 remoteApiPath
= newPath
;
216 * This parameter controls the maximum number of async API requests that will be
217 * in flight at once. Each concurrent request will likely be handled by a separate
218 * <a href="http://cloud.google.com/appengine/docs/adminconsole/instances.html"
219 * >instance</a> of your App. Having more instances increases throughput but may
220 * result in errors due to exceeding quota. Defaults to 5.
222 public RemoteApiOptions
maxConcurrentRequests(int newValue
) {
223 maxConcurrentRequests
= newValue
;
228 * When executing a datastore query, this is the number of results to fetch
229 * per HTTP request. Increasing this value will reduce the number of round trips
230 * when running large queries, but too high a value can be wasteful when not
231 * all results are needed. Defaults to 500.
233 * <p>(This value can be overridden by the code using the datastore API.)</p>
235 public RemoteApiOptions
datastoreQueryFetchSize(int newValue
) {
236 datastoreQueryFetchSize
= newValue
;
241 * When making a remote call, this is the maximum size of the HTTP response.
242 * The default is 33M. Normally there's no reason to change this. This
243 * setting has no effect when running in an App Engine container.
245 public RemoteApiOptions
maxHttpResponseSize(int newValue
) {
246 maxHttpResponseSize
= newValue
;
250 public RemoteApiOptions
copy() {
251 return new RemoteApiOptions(this);
255 * Create an {@link HttpTransport} appropriate to this environment or return
256 * the one that's already been created. This method ensures that the
257 * determination of whether we're running in App Engine happens early
258 * (specifically, before the Remote API has been installed) and that said
259 * determination is remembered.
261 private HttpTransport
getOrCreateHttpTransportForOAuth()
262 throws IOException
, GeneralSecurityException
{
263 if (httpTransport
!= null) {
264 return httpTransport
;
267 if (ApiProxy
.getCurrentEnvironment() != null) {
268 throw new IllegalStateException(
269 "OAuth-based authorization not supported for clients running on App Engine");
272 httpTransport
= GoogleNetHttpTransport
.newTrustedTransport();
273 return httpTransport
;
276 HttpTransport
getHttpTransport() {
277 return httpTransport
;
280 public String
getHostname() {
284 public int getPort() {
288 public String
getUserEmail() {
292 public String
getPassword() {
296 public String
getCredentialsToReuse() {
297 return credentialsToReuse
;
300 Credential
getOAuthCredential() {
301 return oauthCredential
;
304 public String
getRemoteApiPath() {
305 return remoteApiPath
;
308 public int getMaxConcurrentRequests() {
309 return maxConcurrentRequests
;
312 public int getDatastoreQueryFetchSize() {
313 return datastoreQueryFetchSize
;
316 public int getMaxHttpResponseSize() {
317 return maxHttpResponseSize
;