Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / tools / development / ManualServerInstanceHolder.java
blobcf3d3923529237aa16f95dbe439de598351e5480
1 package com.google.appengine.tools.development;
3 import com.google.appengine.tools.development.ApplicationConfigurationManager.ServerConfigurationHandle;
4 import com.google.appengine.tools.development.InstanceStateHolder.InstanceState;
6 import java.io.File;
7 import java.security.AccessController;
8 import java.security.PrivilegedExceptionAction;
9 import java.util.Map;
10 import java.util.concurrent.CountDownLatch;
11 import java.util.concurrent.TimeUnit;
12 import java.util.logging.Logger;
14 /**
15 * {@link InstanceHolder} for a {@link ManualServer}.
17 class ManualServerInstanceHolder extends AbstractServerInstanceHolder {
18 private static final int MAX_START_QUEUE_TIME_MS = 30 * 1000;
19 private static final Logger LOGGER = Logger.getLogger(ManualServerInstanceHolder.class.getName());
21 private final String serverName;
22 private final InstanceStateHolder stateHolder;
23 private final InstanceHelper instanceHelper;
24 private volatile CountDownLatch startRequestLatch;
26 private ServerConfigurationHandle serverConfigurationHandle;
27 private String serverInfo;
28 private File externalResourceDir;
29 private String address;
30 private Map<String, Object> containerConfigProperties;
31 private DevAppServerImpl devAppServer;
33 Integer port;
35 /**
36 * Construct an instance holder.
37 * @param serverName the server's name or 'default'
38 * @param containerService for the instance.
39 * @param instance nonnegative instance number or
40 * {link {@link LocalEnvironment#MAIN_INSTANCE}.
41 * @param stateHolder holder for the instance state.
42 * @param instanceHelper helper for operating on the instance.
44 ManualServerInstanceHolder(String serverName, ContainerService containerService, int instance,
45 InstanceStateHolder stateHolder, InstanceHelper instanceHelper) {
46 super(containerService, instance);
47 this.serverName = serverName;
48 this.stateHolder = stateHolder;
49 this.instanceHelper = instanceHelper;
50 this.startRequestLatch = new CountDownLatch(1);
53 @Override
54 public boolean isServerLoadBalancingServer() {
55 return isMainInstance();
58 @Override
59 public boolean expectsGeneratedStartRequest() {
60 return !isMainInstance();
63 @Override
64 public String toString() {
65 return "ManualServerInstanceHolder: containerservice=" + getContainerService() + " instance="
66 + getInstance();
69 @Override
70 public void startUp() throws Exception {
71 stateHolder.testAndSet(InstanceState.INITIALIZING, InstanceState.SHUTDOWN);
72 getContainerService().startup();
73 stateHolder.testAndSet(InstanceState.STOPPED, InstanceState.INITIALIZING);
74 startServing();
77 @Override
78 public void createConnection() throws Exception {
79 super.createConnection();
80 if (port != null && port.intValue() != getContainerService().getPort()) {
81 throw new IllegalStateException("Port has been reassigned for"
82 + " server=" + serverName
83 + " instance=" + getInstance()
84 + " original port = " + port
85 + " new port=" + getContainerService().getPort());
87 this.port = getContainerService().getPort();
90 void setConfiguration(ServerConfigurationHandle serverConfigurationHandle,
91 String serverInfo, File externalResourceDir, String address,
92 Map<String, Object> containerConfigProperties, DevAppServerImpl devAppServer) {
93 this.serverConfigurationHandle = serverConfigurationHandle;
94 this.serverInfo = serverInfo;
95 this.externalResourceDir = externalResourceDir;
96 this.address = address;
97 this.containerConfigProperties = containerConfigProperties;
98 this.devAppServer = devAppServer;
101 LocalServerEnvironment doConfigure() {
102 ContainerService containerService = getContainerService();
103 LocalServerEnvironment result = containerService.configure(serverInfo, address,
104 getPortForDoConfigure(), serverConfigurationHandle, externalResourceDir,
105 containerConfigProperties, getInstance(), devAppServer);
106 return result;
110 * Returns the port to pass to doConfigure.
111 * <p>
112 * The port is chosen as follows
113 * <ol>
114 * <li> If a port is already assigned we use it. This indicates we are
115 * re starting the instance.
116 * <li> Otherwise if the user specified port using service properties we use that.
117 * <li> Otherwise we use the value 0 which causes the container service to
118 * select a port.
119 * </li>
120 * </ol>
122 private int getPortForDoConfigure() {
123 if (port == null) {
124 return DevAppServerPortPropertyHelper.getPort(serverName,
125 getInstance(), devAppServer.getServiceProperties());
126 } else {
127 return port;
131 void stopServing() throws Exception {
132 if (isMainInstance()) {
133 stateHolder.testAndSet(InstanceState.STOPPED, InstanceState.RUNNING);
134 } else {
135 instanceHelper.shutdown();
136 stateHolder.testAndSet(InstanceState.INITIALIZING, InstanceState.SHUTDOWN);
137 startRequestLatch = new CountDownLatch(1);
138 doConfigure();
139 createConnection();
140 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
141 @Override
142 public Object run() throws Exception {
143 getContainerService().startup();
144 return null;
147 stateHolder.testAndSet(InstanceState.STOPPED, InstanceState.INITIALIZING);
151 void startServing() throws Exception {
152 if (!stateHolder.test(InstanceState.STOPPED)) {
153 throw new IllegalStateException("stopServer state=" + stateHolder + " server=" + serverName);
155 if (isMainInstance()) {
156 stateHolder.testAndSet(InstanceState.RUNNING, InstanceState.STOPPED);
157 } else {
158 stateHolder.testAndSet(InstanceState.SLEEPING, InstanceState.STOPPED);
159 sendStartRequest();
163 void requireState(String operation, InstanceState requiredState) {
164 stateHolder.requireState(operation, requiredState);
167 private void sendStartRequest() {
168 instanceHelper.sendStartRequest(new Runnable() {
170 @Override
171 public void run() {
172 startRequestLatch.countDown();
177 @Override
178 public boolean acquireServingPermit() {
179 LOGGER.finest(String.format("trying to get serving permit for server %d.%s", getInstance(),
180 serverName));
181 int maxWaitTime = 0;
182 synchronized (stateHolder) {
183 if (!stateHolder.acceptsConnections()) {
184 LOGGER.finest(serverName + ": got request but server is not in a serving state");
185 return false;
188 if (stateHolder.test(InstanceState.SLEEPING)) {
189 LOGGER.finest(serverName + ": waking up sleeping server");
190 sendStartRequest();
193 if (stateHolder.test(InstanceState.RUNNING_START_REQUEST)) {
194 maxWaitTime = MAX_START_QUEUE_TIME_MS;
197 try {
198 boolean gotPermit = startRequestLatch.await(maxWaitTime, TimeUnit.MILLISECONDS);
199 LOGGER.finest(getInstance() + "." + serverName + ": tried to get server permit, timeout="
200 + maxWaitTime + " success=" + gotPermit);
201 return gotPermit;
202 } catch (InterruptedException e) {
203 LOGGER.finest(
204 getInstance() + "." + serverName + ": got interrupted while waiting for serving permit");
205 return false;
209 @Override
210 public boolean isStopped() {
211 return stateHolder.test(InstanceState.STOPPED);