com.google.appengine.tools.development.ManualInstanceHolder Maven / Gradle / Ivy
Go to download
SDK for dev_appserver (local development) with some of the dependencies shaded (repackaged)
/*
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.appengine.tools.development;
import com.google.appengine.tools.development.ApplicationConfigurationManager.ModuleConfigurationHandle;
import com.google.appengine.tools.development.InstanceStateHolder.InstanceState;
import java.io.File;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
/**
* {@link InstanceHolder} for a {@link ManualModule}.
*/
class ManualInstanceHolder extends AbstractInstanceHolder {
// maximum time a request can wait for a start request to complete
private static final int MAX_START_QUEUE_TIME_MS = 30 * 1000;
private static final Logger LOGGER = Logger.getLogger(ManualInstanceHolder.class.getName());
private final String moduleName;
private final InstanceStateHolder stateHolder;
private final InstanceHelper instanceHelper;
private volatile CountDownLatch startRequestLatch;
// Set by setConfiguration
private ModuleConfigurationHandle moduleConfigurationHandle;
private String serverInfo;
private File externalResourceDir;
private String address;
private Map containerConfigProperties;
private DevAppServer devAppServer;
// Set by createConnection after Jetty either accepts our
// choice of port or selects a port. We remember this value
// so we can retain the same port after stopServing.
Integer port;
/**
* Construct an instance holder.
* @param moduleName the module name or 'default'
* @param containerService for the instance.
* @param instance nonnegative instance number or
* {link {@link LocalEnvironment#MAIN_INSTANCE}.
* @param stateHolder holder for the instance state.
* @param instanceHelper helper for operating on the instance.
*/
ManualInstanceHolder(String moduleName, ContainerService containerService, int instance,
InstanceStateHolder stateHolder, InstanceHelper instanceHelper) {
super(containerService, instance);
this.moduleName = moduleName;
this.stateHolder = stateHolder;
this.instanceHelper = instanceHelper;
this.startRequestLatch = new CountDownLatch(1);
}
@Override
public boolean isLoadBalancingInstance() {
return isMainInstance();
}
@Override
public boolean expectsGeneratedStartRequest() {
return !isMainInstance();
}
@Override
public String toString() {
return "ManualServerInstanceHolder: containerservice=" + getContainerService() + " instance="
+ getInstance();
}
@Override
public void startUp() throws Exception {
stateHolder.testAndSet(InstanceState.INITIALIZING, InstanceState.SHUTDOWN);
getContainerService().startup();
stateHolder.testAndSet(InstanceState.STOPPED, InstanceState.INITIALIZING);
startServing();
}
@Override
public void createConnection() throws Exception {
super.createConnection();
if (port != null && port.intValue() != getContainerService().getPort()) {
throw new IllegalStateException("Port has been reassigned for"
+ " module=" + moduleName
+ " instance=" + getInstance()
+ " original port = " + port
+ " new port=" + getContainerService().getPort());
}
this.port = getContainerService().getPort();
}
void setConfiguration(ModuleConfigurationHandle moduleConfigurationHandle,
String serverInfo, File externalResourceDir, String address,
Map containerConfigProperties, DevAppServer devAppServer) {
this.moduleConfigurationHandle = moduleConfigurationHandle;
this.serverInfo = serverInfo;
this.externalResourceDir = externalResourceDir;
this.address = address;
this.containerConfigProperties = containerConfigProperties;
this.devAppServer = devAppServer;
}
LocalServerEnvironment doConfigure() {
ContainerService containerService = getContainerService();
LocalServerEnvironment result = containerService.configure(serverInfo, address,
getPortForDoConfigure(), moduleConfigurationHandle, externalResourceDir,
containerConfigProperties, getInstance(), devAppServer);
return result;
}
/**
* Returns the port to pass to doConfigure.
*
* The port is chosen as follows
*
* - If a port is already assigned we use it. This indicates we are
* re starting the instance.
*
- Otherwise if the user specified port using service properties we use that.
*
- Otherwise we use the value 0 which causes the container service to
* select a port.
*
*
*/
private int getPortForDoConfigure() {
if (port == null) {
return DevAppServerPortPropertyHelper.getPort(moduleName,
getInstance(), devAppServer.getServiceProperties());
} else {
return port;
}
}
void stopServing() throws Exception {
if (isMainInstance()) {
stateHolder.testAndSet(InstanceState.STOPPED, InstanceState.RUNNING);
} else {
instanceHelper.shutdown();
stateHolder.testAndSet(InstanceState.INITIALIZING, InstanceState.SHUTDOWN);
startRequestLatch = new CountDownLatch(1);
doConfigure();
createConnection();
// We call ContainerService.startup inside a PrivilegedExceptionAction
// so threads created by the contained Jetty instance
// will not inherit our callers protection domains. See
// http://docs.oracle.com/javase/7/docs/technotes/guides/security/spec/security-spec.doc4.html
// section 4.3 for details.
AccessController.doPrivileged(new PrivilegedExceptionAction