1 package com
.google
.appengine
.tools
.development
;
3 import com
.google
.common
.base
.Joiner
;
5 import javax
.annotation
.concurrent
.GuardedBy
;
8 * Holder for the state of a server or backend instance.
10 public class InstanceStateHolder
{
11 static enum InstanceState
{
12 INITIALIZING
, SLEEPING
, RUNNING_START_REQUEST
, RUNNING
, STOPPED
, SHUTDOWN
;
15 private static final Joiner STATE_JOINER
= Joiner
.on("|");
16 private final String serverOrBackendName
;
17 private final int instance
;
19 private InstanceState currentState
= InstanceState
.SHUTDOWN
;
22 * Constructs an {@link InstanceStateHolder}.
24 * @param serverOrBackendName For server instances the server name and for backend instances the
26 * @param instance The instance number or -1 for load balancing servers and automatic servers.
28 InstanceStateHolder(String serverOrBackendName
, int instance
) {
29 this.serverOrBackendName
= serverOrBackendName
;
30 this.instance
= instance
;
34 * Updates the current server state and verifies that the previous state is
37 * @param newState The new state to change to
38 * @param acceptablePreviousStates Acceptable previous states
39 * @throws IllegalStateException If the current state is not one of the
40 * acceptable previous states
42 void testAndSet(InstanceState newState
,
43 InstanceState
... acceptablePreviousStates
) throws IllegalStateException
{
44 InstanceState invalidState
=
45 testAndSetIf(newState
, acceptablePreviousStates
);
46 if (invalidState
!= null) {
47 reportInvalidStateChange(serverOrBackendName
, instance
, invalidState
,
48 newState
, acceptablePreviousStates
);
53 * Reports an invalid state change attempt.
55 static void reportInvalidStateChange(String serverOrBackendName
, int instance
,
56 InstanceState currentState
, InstanceState newState
,
57 InstanceState
... acceptablePreviousStates
) {
58 StringBuilder error
= new StringBuilder();
59 error
.append("Tried to change state to " + newState
);
60 error
.append(" on server " + serverOrBackendName
+ "." + instance
);
61 error
.append(" but previous state is " + currentState
);
62 error
.append(" and not ");
63 error
.append(STATE_JOINER
.join(acceptablePreviousStates
));
64 throw new IllegalStateException(error
.toString());
68 * Updates the current server state to the requested value and returns
69 * null if the previous state is an acceptable value and if not leaves the
70 * current server state unchanged and returns the current invalid state.
72 synchronized InstanceState
testAndSetIf(InstanceState newState
,
73 InstanceState
... acceptablePreviousStates
) {
74 InstanceState result
= currentState
;
75 if (test(acceptablePreviousStates
)) {
77 currentState
= newState
;
83 * Returns true if current state is one of the provided acceptable states.
85 synchronized boolean test(InstanceState
... acceptableStates
) {
86 for (InstanceState acceptable
: acceptableStates
) {
87 if (currentState
== acceptable
) {
95 * Throws an IllegalStateException if the current state is not one of the
96 * acceptable states for the designated operation.
98 synchronized void requireState(String operation
, InstanceState
... acceptableStates
) {
99 if (!test(acceptableStates
)) {
100 throw new IllegalStateException("Invalid current state operation=" + operation
101 + " currentState=" + currentState
102 + " acceptableStates=" + STATE_JOINER
.join(acceptableStates
));
107 * Checks if the server is in a state where it can accept incoming requests.
109 * @return true if the server can accept incoming requests, false otherwise.
111 synchronized boolean acceptsConnections() {
112 return (currentState
== InstanceState
.RUNNING
113 || currentState
== InstanceState
.RUNNING_START_REQUEST
114 || currentState
== InstanceState
.SLEEPING
);
118 * Returns the display name for the current state.
120 synchronized String
getDisplayName() {
121 return currentState
.name().toLowerCase();
125 * Unconditionally sets the state.
127 synchronized void set(InstanceState newState
) {
128 currentState
= newState
;