View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.state;
21  
22  import org.waarp.common.exception.IllegalFiniteStateException;
23  import org.waarp.common.logging.WaarpLogger;
24  import org.waarp.common.logging.WaarpLoggerFactory;
25  
26  import java.util.EnumSet;
27  import java.util.concurrent.ConcurrentHashMap;
28  import java.util.concurrent.ConcurrentMap;
29  
30  /**
31   * This is the base class for the basic support of Finite State Machine in
32   * GoldenGate. One need to implement
33   * an Enum class to use with it. <br>
34   * <br>
35   * Note: the type EnumSet< ? > is in fact of type EnumSet< EnumState >
36   *
37   * @param <E>
38   */
39  public class MachineState<E extends Enum<E>> {
40    /**
41     * Internal Logger
42     */
43    private static final WaarpLogger logger =
44        WaarpLoggerFactory.getLogger(MachineState.class);
45  
46    private ConcurrentMap<E, EnumSet<E>> statemap;
47    private E currentState;
48  
49    /**
50     * Initialize with an initialState
51     *
52     * @param initialState initial MachineState
53     * @param map the association of state and set of acceptable
54     *     following
55     *     states
56     */
57    public MachineState(final E initialState,
58                        final ConcurrentMap<E, EnumSet<E>> map) {
59      statemap = map;
60      currentState = initialState;
61    }
62  
63    /**
64     * Initialize with an initialState but no association (Machine State is
65     * empty)
66     *
67     * @param initialState initial MachineState
68     */
69    public MachineState(final E initialState) {
70      statemap = new ConcurrentHashMap<E, EnumSet<E>>();
71      currentState = initialState;
72    }
73  
74    /**
75     * Add a new association from one state to a set of acceptable following
76     * states (can replace an existing
77     * association)
78     *
79     * @param state
80     * @param set the new association
81     *
82     * @return the previous association if any
83     */
84    public final EnumSet<E> addNewAssociation(final E state,
85                                              final EnumSet<E> set) {
86      return statemap.put(state, set);
87    }
88  
89    /**
90     * Add a new association from one state to a set of acceptable following
91     * states (can replace an existing
92     * association)
93     *
94     * @param elt
95     *
96     * @return the previous association if any
97     */
98    public final EnumSet<E> addNewAssociation(final Transition<E> elt) {
99      return statemap.put(elt.getState(), elt.getSet());
100   }
101 
102   /**
103    * Remove an association from one state to any acceptable following states
104    *
105    * @param state the state to remove any acceptable following states
106    *
107    * @return the previous association if any
108    */
109   public final EnumSet<E> removeAssociation(final E state) {
110     return statemap.remove(state);
111   }
112 
113   /**
114    * Return the current application state.
115    *
116    * @return the current State
117    */
118   public final E getCurrent() {
119     return currentState;
120   }
121 
122   /**
123    * Sets the current application state.
124    *
125    * @param desiredState
126    *
127    * @return the requested state, if it was reachable
128    *
129    * @throws IllegalFiniteStateException if the state is not allowed
130    */
131   public final E setCurrent(final E desiredState)
132       throws IllegalFiniteStateException {
133     if (!isReachable(desiredState)) {
134       logger.debug("State {} not reachable from: {}", desiredState,
135                    currentState);
136       throw new IllegalFiniteStateException(
137           desiredState + " not allowed from " + currentState);
138     }
139     return setAsFinal(desiredState);
140   }
141 
142   /**
143    * Sets the current application state, but no exception if not compatible.
144    *
145    * @param desiredState
146    *
147    * @return the requested state, even if it was not reachable
148    */
149   public final E setDryCurrent(final E desiredState) {
150     return setAsFinal(desiredState);
151   }
152 
153   /**
154    * Determine if the given state is allowed to be next.
155    *
156    * @param desiredState desired MachineState
157    *
158    * @return True if the desiredState is valid from currentState
159    */
160   private boolean isReachable(final E desiredState) {
161     if (currentState == null || statemap == null) {
162       return false;
163     }
164     final EnumSet<?> set = statemap.get(currentState);
165     if (set != null) {
166       return set.contains(desiredState);
167     }
168     return false;
169   }
170 
171   /**
172    * Finalizes the new requested state
173    *
174    * @param desiredState
175    *
176    * @return the requested state
177    */
178   private E setAsFinal(final E desiredState) {
179     logger.debug("New State: {} from {}", desiredState, currentState);
180     currentState = desiredState;
181     return currentState;
182   }
183 
184   /**
185    * Release the Machine State
186    */
187   public final void release() {
188     currentState = null;
189     statemap = null;
190   }
191 }