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      private final String id;
49  
50      private final State parent;
51  
52      private List<TransitionHolder> transitionHolders = new ArrayList<TransitionHolder>();
53  
54      private List<Transition> transitions = Collections.emptyList();
55  
56      private List<SelfTransition> onEntries = new ArrayList<SelfTransition>();
57  
58      private List<SelfTransition> onExits = new ArrayList<SelfTransition>();
59  
60      /**
61       * Creates a new {@link State} with the specified id.
62       * 
63       * @param id the unique id of this {@link State}.
64       */
65      public State(String id) {
66          this(id, null);
67      }
68  
69      /**
70       * Creates a new {@link State} with the specified id and parent.
71       * 
72       * @param id the unique id of this {@link State}.
73       * @param parent the parent {@link State}.
74       */
75      public State(String id, State parent) {
76          this.id = id;
77          this.parent = parent;
78      }
79  
80      /**
81       * @return the id of this {@link State}.
82       */
83      public String getId() {
84          return id;
85      }
86  
87      /**
88       * @return the parent or <code>null</code> if this {@link State} has no 
89       *         parent.
90       */
91      public State getParent() {
92          return parent;
93      }
94  
95      /**
96       * @return an unmodifiable {@link List} of {@link Transition}s going out
97       * from this {@link State}.
98       */
99      public List<Transition> getTransitions() {
100         return Collections.unmodifiableList(transitions);
101     }
102 
103     /**
104      * @return an unmodifiable {@link List} of entry {@link SelfTransition}s  
105      */
106     public List<SelfTransition> getOnEntrySelfTransitions() {
107         return Collections.unmodifiableList(onEntries);
108     }
109 
110     /**
111      * @return an unmodifiable {@link List} of exit {@link SelfTransition}s  
112      */
113     public List<SelfTransition> getOnExitSelfTransitions() {
114         return Collections.unmodifiableList(onExits);
115     }
116 
117     /**
118      * Adds an entry {@link SelfTransition} to this {@link State} 
119      * 
120      * @param selfTransition the {@link SelfTransition} to add.
121      * @return this {@link State}.
122      */
123     State addOnEntrySelfTransaction(SelfTransition onEntrySelfTransaction) {
124         if (onEntrySelfTransaction == null) {
125             throw new IllegalArgumentException("transition");
126         }
127         onEntries.add(onEntrySelfTransaction);
128         return this;
129     }
130 
131     /**
132      * Adds an exit {@link SelfTransition} to this {@link State} 
133      * 
134      * @param selfTransition the {@link SelfTransition} to add.
135      * @return this {@link State}.
136      */
137     State addOnExitSelfTransaction(SelfTransition onExitSelfTransaction) {
138         if (onExitSelfTransaction == null) {
139             throw new IllegalArgumentException("transition");
140         }
141         onExits.add(onExitSelfTransaction);
142         return this;
143     }
144 
145     private void updateTransitions() {
146         transitions = new ArrayList<Transition>(transitionHolders.size());
147         for (TransitionHolder holder : transitionHolders) {
148             transitions.add(holder.transition);
149         }
150     }
151 
152     /**
153      * Adds an outgoing {@link Transition} to this {@link State} with weight 0.
154      * 
155      * @param transition the {@link Transition} to add.
156      * @return this {@link State}.
157      * @see #addTransition(Transition, int)
158      */
159     public State addTransition(Transition transition) {
160         return addTransition(transition, 0);
161     }
162 
163     /**
164      * Adds an outgoing {@link Transition} to this {@link State} with the 
165      * specified weight. The higher the weight the less important a 
166      * {@link Transition} is. If two {@link Transition}s match the same
167      * {@link Event} the {@link Transition} with the lower weight will
168      * be executed.
169      * 
170      * @param transition the {@link Transition} to add.
171      * @param weight The weight of this transition
172      * @return this {@link State}.
173      */
174     public State addTransition(Transition transition, int weight) {
175         if (transition == null) {
176             throw new IllegalArgumentException("transition");
177         }
178 
179         transitionHolders.add(new TransitionHolder(transition, weight));
180         Collections.sort(transitionHolders);
181         updateTransitions();
182         return this;
183     }
184 
185     /**
186      * {@inheritDoc}
187      */
188     @Override
189     public boolean equals(Object o) {
190         if (o == this) {
191             return true;
192         }
193         
194         if (!(o instanceof State)) {
195             return false;
196         }
197         
198         return id.equals(((State) o).id);
199     }
200 
201     /**
202      * {@inheritDoc}
203      */
204     @Override
205     public int hashCode() {
206         int h = 37;
207         
208         return h * 17 + id.hashCode();
209     }
210 
211     /**
212      * {@inheritDoc}
213      */
214     @Override
215     public String toString() {
216         StringBuilder sb = new StringBuilder();
217         
218         sb.append("State[");
219         sb.append("id=").append(id);
220         sb.append("]");
221         
222         return sb.toString();
223     }
224 
225     private static class TransitionHolder implements Comparable<TransitionHolder> {
226         private Transition transition;
227 
228         private int weight;
229 
230         TransitionHolder(Transition transition, int weight) {
231             this.transition = transition;
232             this.weight = weight;
233         }
234 
235         public int compareTo(TransitionHolder o) {
236             return (weight > o.weight) ? 1 : (weight < o.weight ? -1 : 0);
237         }
238     }
239 }