View Javadoc
1   package com.atlassian.plugin.manager;
2   
3   import java.util.concurrent.atomic.AtomicReference;
4   
5   /**
6    * Simple thread-safe state machine that prevents illegal transitions.
7    * <p>
8    * Could be easily extended to allow custom workflows by interfacing
9    * out the State type and having this class generified with that.
10   */
11  class StateTracker {
12      enum State {
13          NOT_STARTED {
14              @Override
15              void check(final State newState) {
16                  if (newState != STARTING && newState != SHUTTING_DOWN) {
17                      illegalState(newState);
18                  }
19              }
20          },
21          STARTING,
22          DELAYED {
23              @Override
24              void check(final State newState) {
25                  if (newState != RESUMING && newState != SHUTTING_DOWN) {
26                      illegalState(newState);
27                  }
28              }
29          },
30          RESUMING,
31          STARTED {
32              @Override
33              void check(final State newState) {
34                  if (newState != WARM_RESTARTING && newState != SHUTTING_DOWN) {
35                      illegalState(newState);
36                  }
37              }
38          },
39          WARM_RESTARTING {
40              @Override
41              void check(final State newState) {
42                  if (newState != STARTED) {
43                      illegalState(newState);
44                  }
45              }
46          },
47          SHUTTING_DOWN,
48          SHUTDOWN {
49              @Override
50              void check(final State newState) {
51                  if (newState != STARTING) {
52                      illegalState(newState);
53                  }
54              }
55          };
56  
57          void check(final State newState) {
58              if ((ordinal() + 1) != newState.ordinal()) {
59                  illegalState(newState);
60              }
61          }
62  
63          void illegalState(final State newState) {
64              throw new IllegalStateException("Cannot go from State: " + this + " to: " + newState);
65          }
66      }
67  
68      private final AtomicReference<State> state = new AtomicReference<>(State.NOT_STARTED);
69  
70      public State get() {
71          return state.get();
72      }
73  
74      StateTracker setState(final State newState) throws IllegalStateException {
75          for (; ; ) {
76              final State oldState = get();
77              oldState.check(newState);
78              if (state.compareAndSet(oldState, newState)) {
79                  return this;
80              }
81          }
82      }
83  
84      @Override
85      public String toString() {
86          return get().toString();
87      }
88  }