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.commons.lang.builder.EqualsBuilder;
27  import org.apache.commons.lang.builder.HashCodeBuilder;
28  import org.apache.commons.lang.builder.ToStringBuilder;
29  import org.apache.mina.statemachine.event.Event;
30  import org.apache.mina.statemachine.transition.Transition;
31  
32  /**
33   * Represents a state in a {@link StateMachine}. Normally you wouldn't create 
34   * instances of this class directly but rather use the 
35   * {@link org.apache.mina.statemachine.annotation.State} annotation to define
36   * your states and then let {@link StateMachineFactory} create a 
37   * {@link StateMachine} for you.
38   * <p> 
39   * {@link State}s  inherits {@link Transition}s from
40   * their parent. A {@link State} can override any of the parents 
41   * {@link Transition}s. When an {@link Event} is processed the {@link Transition}s
42   * of the current {@link State} will be searched for a {@link Transition} which
43   * can handle the event. If none is found the {@link State}'s parent will be
44   * searched and so on.
45   * </p>
46   *
47   * @author The Apache MINA Project (dev@mina.apache.org)
48   */
49  public class State {
50      private final String id;
51      private final State parent;
52      private List<TransitionHolder> transitionHolders = new ArrayList<TransitionHolder>();
53      private List<Transition> transitions = Collections.emptyList();
54      
55      /**
56       * Creates a new {@link State} with the specified id.
57       * 
58       * @param id the unique id of this {@link State}.
59       */
60      public State(String id) {
61          this(id, null);
62      }
63  
64      /**
65       * Creates a new {@link State} with the specified id and parent.
66       * 
67       * @param id the unique id of this {@link State}.
68       * @param parent the parent {@link State}.
69       */
70      public State(String id, State parent) {
71          this.id = id;
72          this.parent = parent;
73      }
74  
75      /**
76       * Returns the id of this {@link State}.
77       * 
78       * @return the id.
79       */
80      public String getId() {
81          return id;
82      }
83  
84      /**
85       * Returns the parent {@link State}.
86       * 
87       * @return the parent or <code>null</code> if this {@link State} has no 
88       *         parent.
89       */
90      public State getParent() {
91          return parent;
92      }
93  
94      /**
95       * Returns an unmodifiable {@link List} of {@link Transition}s going out
96       * from this {@link State}.
97       * 
98       * @return the {@link Transition}s.
99       */
100     public List<Transition> getTransitions() {
101         return Collections.unmodifiableList(transitions);
102     }
103 
104     private void updateTransitions() {
105         transitions = new ArrayList<Transition>(transitionHolders.size());
106         for (TransitionHolder holder : transitionHolders) {
107             transitions.add(holder.transition);
108         }
109     }
110     
111     /**
112      * Adds an outgoing {@link Transition} to this {@link State} with weight 0.
113      * 
114      * @param transition the {@link Transition} to add.
115      * @return this {@link State}.
116      * @see #addTransition(Transition, int)
117      */
118     public State addTransition(Transition transition) {
119         return addTransition(transition, 0);
120     }
121 
122     /**
123      * Adds an outgoing {@link Transition} to this {@link State} with the 
124      * specified weight. The higher the weight the less important a 
125      * {@link Transition} is. If two {@link Transition}s match the same
126      * {@link Event} the {@link Transition} with the lower weight will
127      * be executed.
128      * 
129      * @param transition the {@link Transition} to add.
130      * @return this {@link State}.
131      */
132     public State addTransition(Transition transition, int weight) {
133         if (transition == null) {
134             throw new NullPointerException("transition");
135         }
136 
137         transitionHolders.add(new TransitionHolder(transition, weight));
138         Collections.sort(transitionHolders);
139         updateTransitions();
140         return this;
141     }
142     
143     @Override
144     public boolean equals(Object o) {
145         if (!(o instanceof State)) {
146             return false;
147         }
148         if (o == this) {
149             return true;
150         }
151         State that = (State) o;
152         return new EqualsBuilder().append(this.id, that.id).isEquals();
153     }
154 
155     @Override
156     public int hashCode() {
157         return new HashCodeBuilder(13, 33).append(this.id).toHashCode();
158     }
159 
160     @Override
161     public String toString() {
162         return new ToStringBuilder(this).append("id", this.id).toString();
163     }
164 
165     private static class TransitionHolder implements Comparable<TransitionHolder> {
166         Transition transition;
167 
168         int weight;
169 
170         TransitionHolder(Transition transition, int weight) {
171             this.transition = transition;
172             this.weight = weight;
173         }
174 
175         public int compareTo(TransitionHolder o) {
176             return (weight > o.weight) ? 1 : (weight < o.weight ? -1 : 0);
177         }
178     }
179 }