|
29 | 29 | import java.io.IOException; |
30 | 30 | import java.io.InputStream; |
31 | 31 | import java.lang.reflect.Constructor; |
| 32 | +import java.lang.reflect.Field; |
32 | 33 | import java.lang.reflect.InvocationTargetException; |
| 34 | +import java.lang.reflect.Method; |
33 | 35 | import java.security.AccessControlException; |
34 | 36 | import java.util.Locale; |
35 | 37 |
|
@@ -169,7 +171,7 @@ private final Environment detectEnvironment(HttpTransport transport) throws IOEx |
169 | 171 | return Environment.WELL_KNOWN_FILE; |
170 | 172 |
|
171 | 173 | // Try App Engine |
172 | | - } else if (runningOnAppEngine()) { |
| 174 | + } else if (useGAEStandardAPI()) { |
173 | 175 | return Environment.APP_ENGINE; |
174 | 176 |
|
175 | 177 | // Then try Cloud Shell. This must be done BEFORE checking |
@@ -256,19 +258,56 @@ private GoogleCredential getCredentialUsingWellKnownFile( |
256 | 258 | } |
257 | 259 | } |
258 | 260 |
|
259 | | - |
260 | | - private boolean runningOnAppEngine() { |
| 261 | + private boolean useGAEStandardAPI() { |
| 262 | + // We should specifically return false in some cases in order to shortcircuit checking for |
| 263 | + // appengine classpath resources. This lets us flow into metadata server logic rather than |
| 264 | + // continuing to rely on jars on the classpath. |
261 | 265 | if (getEnvEquals("GAE_ENV", "standard")) { |
262 | | - return true; |
| 266 | + return getEnvEquals("GAE_RUNTIME", "java7"); |
263 | 267 | } |
264 | | - if (getEnvEquals("GAE_RUNTIME", "java7")) { |
265 | | - return true; |
| 268 | + if (getEnvEquals("GAE_VM", "true")) { |
| 269 | + return false; |
266 | 270 | } |
267 | | - if (getEnvEquals("GAE_RUNTIME", "java8")) { |
268 | | - return true; |
| 271 | + |
| 272 | + // Check the classpath for the existence of classes. |
| 273 | + Class<?> systemPropertyClass; |
| 274 | + try { |
| 275 | + systemPropertyClass = forName("com.google.appengine.api.utils.SystemProperty"); |
| 276 | + } catch (ClassNotFoundException expected) { |
| 277 | + // We didn't find the class - move on. |
| 278 | + return false; |
269 | 279 | } |
270 | | - if (getEnvEquals("GAE_VM", "true")) { |
271 | | - return true; |
| 280 | + |
| 281 | + Exception cause = null; |
| 282 | + Field environmentField; |
| 283 | + try { |
| 284 | + // Use reflection to call com.google.appengine.api.utils.SystemProperty::environment.value(). |
| 285 | + environmentField = systemPropertyClass.getField("environment"); |
| 286 | + Object environmentValue = environmentField.get(null); |
| 287 | + Class<?> environmentType = environmentField.getType(); |
| 288 | + Method valueMethod = environmentType.getMethod("value"); |
| 289 | + Object environmentValueValue = valueMethod.invoke(environmentValue); |
| 290 | + |
| 291 | + // Any value will be treated as "running on app engine standard". |
| 292 | + return (environmentValueValue != null); |
| 293 | + } catch (NoSuchFieldException ignored) { |
| 294 | + // If the field does not exist then we treat it as false. |
| 295 | + } catch (SecurityException exception) { |
| 296 | + cause = exception; |
| 297 | + } catch (IllegalArgumentException exception) { |
| 298 | + cause = exception; |
| 299 | + } catch (IllegalAccessException exception) { |
| 300 | + cause = exception; |
| 301 | + } catch (NoSuchMethodException exception) { |
| 302 | + cause = exception; |
| 303 | + } catch (InvocationTargetException exception) { |
| 304 | + cause = exception; |
| 305 | + } |
| 306 | + |
| 307 | + if (cause != null) { |
| 308 | + throw new RuntimeException(String.format( |
| 309 | + "Unexpected error trying to determine if runnning on Google App Engine: %s", |
| 310 | + cause.getMessage()), cause); |
272 | 311 | } |
273 | 312 |
|
274 | 313 | return false; |
|
0 commit comments