View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.statemachine;
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.List;
25  
26  import org.apache.mina.statemachine.event.Event;
27  import org.apache.mina.statemachine.transition.SelfTransition;
28  import org.apache.mina.statemachine.transition.Transition;
29  
30  /**
31   * Represents a state in a {@link StateMachine}. Normally you wouldn't create 
32   * instances of this class directly but rather use the 
33   * {@link org.apache.mina.statemachine.annotation.State} annotation to define
34   * your states and then let {@link StateMachineFactory} create a 
35   * {@link StateMachine} for you.
36   * <p> 
37   * {@link State}s  inherits {@link Transition}s from
38   * their parent. A {@link State} can override any of the parents 
39   * {@link Transition}s. When an {@link Event} is processed the {@link Transition}s
40   * of the current {@link State} will be searched for a {@link Transition} which
41   * can handle the event. If none is found the {@link State}'s parent will be
42   * searched and so on.
43   * </p>
44   *
45   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
46   */
47  public class State {
48      /** The state ID */
49      private final String id;
50  
51      /** The parent state */
52      private final State parent;
53  
54      private List<TransitionHolder> transitionHolders = new ArrayList<>();
55  
56      /** The list of transitions for this state */
57      private List<Transition> transitions = Collections.emptyList();
58  
59      /** The list of entry transitions on a state */
60      private List<SelfTransition> onEntries = new ArrayList<>();
61  
62      /** The list of exit transition from a state */
63      private List<SelfTransition> onExits = new ArrayList<>();
64  
65      /**
66       * Creates a new {@link State} with the specified id.
67       * 
68       * @param id the unique id of this {@link State}.
69       */
70      public State(String id) {
71          this(id, null);
72      }
73  
74      /**
75       * Creates a new {@link State} with the specified id and parent.
76       * 
77       * @param id the unique id of this {@link State}.
78       * @param parent the parent {@link State}.
79       */
80      public State../../../../org/apache/mina/statemachine/State.html#State">State(String id, State parent) {
81          this.id = id;
82          this.parent = parent;
83      }
84  
85      /**
86       * @return the id of this {@link State}.
87       */
88      public String getId() {
89          return id;
90      }
91  
92      /**
93       * @return the parent or <code>null</code> if this {@link State} has no 
94       *         parent.
95       */
96      public State getParent() {
97          return parent;
98      }
99  
100     /**
101      * @return an unmodifiable {@link List} of {@link Transition}s going out
102      * from this {@link State}.
103      */
104     public List<Transition> getTransitions() {
105         return Collections.unmodifiableList(transitions);
106     }
107 
108     /**
109      * @return an unmodifiable {@link List} of entry {@link SelfTransition}s  
110      */
111     public List<SelfTransition> getOnEntrySelfTransitions() {
112         return Collections.unmodifiableList(onEntries);
113     }
114 
115     /**
116      * @return an unmodifiable {@link List} of exit {@link SelfTransition}s  
117      */
118     public List<SelfTransition> getOnExitSelfTransitions() {
119         return Collections.unmodifiableList(onExits);
120     }
121 
122     /**
123      * Adds an entry {@link SelfTransition} to this {@link State} 
124      * 
125      * @param selfTransition the {@link SelfTransition} to add.
126      * @return this {@link State}.
127      */
128     State addOnEntrySelfTransaction(SelfTransition onEntrySelfTransaction) {
129         if (onEntrySelfTransaction == null) {
130             throw new IllegalArgumentException("transition");
131         }
132         
133         onEntries.add(onEntrySelfTransaction);
134         
135         return this;
136     }
137 
138     /**
139      * Adds an exit {@link SelfTransition} to this {@link State} 
140      * 
141      * @param selfTransition the {@link SelfTransition} to add.
142      * @return this {@link State}.
143      */
144     State addOnExitSelfTransaction(SelfTransition onExitSelfTransaction) {
145         if (onExitSelfTransaction == null) {
146             throw new IllegalArgumentException("transition");
147         }
148         
149         onExits.add(onExitSelfTransaction);
150         
151         return this;
152     }
153 
154     private void updateTransitions() {
155         transitions = new ArrayList<>(transitionHolders.size());
156         
157         for (TransitionHolder holder : transitionHolders) {
158             transitions.add(holder.transition);
159         }
160     }
161 
162     /**
163      * Adds an outgoing {@link Transition} to this {@link State} with weight 0.
164      * 
165      * @param transition the {@link Transition} to add.
166      * @return this {@link State}.
167      * @see #addTransition(Transition, int)
168      */
169     public State addTransition(Transition transition) {
170         return addTransition(transition, 0);
171     }
172 
173     /**
174      * Adds an outgoing {@link Transition} to this {@link State} with the 
175      * specified weight. The higher the weight the less important a 
176      * {@link Transition} is. If two {@link Transition}s match the same
177      * {@link Event} the {@link Transition} with the lower weight will
178      * be executed.
179      * 
180      * @param transition the {@link Transition} to add.
181      * @param weight The weight of this transition
182      * @return this {@link State}.
183      */
184     public State addTransition(Transition transition, int weight) {
185         if (transition == null) {
186             throw new IllegalArgumentException("transition");
187         }
188 
189         transitionHolders.add(new TransitionHolder(transition, weight));
190         Collections.sort(transitionHolders);
191         updateTransitions();
192         return this;
193     }
194 
195     /**
196      * {@inheritDoc}
197      */
198     @Override
199     public boolean equals(Object o) {
200         if (o == this) {
201             return true;
202         }
203         
204         if (!(o instanceof State)) {
205             return false;
206         }
207         
208         return id.equals(((State) o).id);
209     }
210 
211     /**
212      * {@inheritDoc}
213      */
214     @Override
215     public int hashCode() {
216         int h = 37;
217         
218         return h * 17 + id.hashCode();
219     }
220 
221     /**
222      * {@inheritDoc}
223      */
224     @Override
225     public String toString() {
226         StringBuilder sb = new StringBuilder();
227         
228         sb.append("State[");
229         sb.append("id=").append(id);
230         sb.append("]");
231         
232         return sb.toString();
233     }
234 
235     private static class TransitionHolder implements Comparable<TransitionHolder> {
236         private Transition transition;
237 
238         private int weight;
239 
240         TransitionHolder(Transition transition, int weight) {
241             this.transition = transition;
242             this.weight = weight;
243         }
244 
245         @Override
246         public int compareTo(TransitionHolder o) {
247             return (weight > o.weight) ? 1 : (weight < o.weight ? -1 : 0);
248         }
249     }
250 }