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   * @version $Rev: 586108 $, $Date: 2007-10-18 22:05:07 +0200 (jeu, 18 oct 2007) $
49   */
50  public class State {
51      private final String id;
52      private final State parent;
53      private List<TransitionHolder> transitionHolders = new ArrayList<TransitionHolder>();
54      private List<Transition> transitions = Collections.emptyList();
55      
56      /**
57       * Creates a new {@link State} with the specified id.
58       * 
59       * @param id the unique id of this {@link State}.
60       */
61      public State(String id) {
62          this(id, null);
63      }
64  
65      /**
66       * Creates a new {@link State} with the specified id and parent.
67       * 
68       * @param id the unique id of this {@link State}.
69       * @param parent the parent {@link State}.
70       */
71      public State(String id, State parent) {
72          this.id = id;
73          this.parent = parent;
74      }
75  
76      /**
77       * Returns the id of this {@link State}.
78       * 
79       * @return the id.
80       */
81      public String getId() {
82          return id;
83      }
84  
85      /**
86       * Returns the parent {@link State}.
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       * Returns an unmodifiable {@link List} of {@link Transition}s going out
97       * from this {@link State}.
98       * 
99       * @return the {@link Transition}s.
100      */
101     public List<Transition> getTransitions() {
102         return Collections.unmodifiableList(transitions);
103     }
104 
105     private void updateTransitions() {
106         transitions = new ArrayList<Transition>(transitionHolders.size());
107         for (TransitionHolder holder : transitionHolders) {
108             transitions.add(holder.transition);
109         }
110     }
111     
112     /**
113      * Adds an outgoing {@link Transition} to this {@link State} with weight 0.
114      * 
115      * @param transition the {@link Transition} to add.
116      * @return this {@link State}.
117      * @see #addTransition(Transition, int)
118      */
119     public State addTransition(Transition transition) {
120         return addTransition(transition, 0);
121     }
122 
123     /**
124      * Adds an outgoing {@link Transition} to this {@link State} with the 
125      * specified weight. The higher the weight the less important a 
126      * {@link Transition} is. If two {@link Transition}s match the same
127      * {@link Event} the {@link Transition} with the lower weight will
128      * be executed.
129      * 
130      * @param transition the {@link Transition} to add.
131      * @return this {@link State}.
132      */
133     public State addTransition(Transition transition, int weight) {
134         if (transition == null) {
135             throw new NullPointerException("transition");
136         }
137 
138         transitionHolders.add(new TransitionHolder(transition, weight));
139         Collections.sort(transitionHolders);
140         updateTransitions();
141         return this;
142     }
143     
144     @Override
145     public boolean equals(Object o) {
146         if (!(o instanceof State)) {
147             return false;
148         }
149         if (o == this) {
150             return true;
151         }
152         State that = (State) o;
153         return new EqualsBuilder().append(this.id, that.id).isEquals();
154     }
155 
156     @Override
157     public int hashCode() {
158         return new HashCodeBuilder(13, 33).append(this.id).toHashCode();
159     }
160 
161     @Override
162     public String toString() {
163         return new ToStringBuilder(this).append("id", this.id).toString();
164     }
165 
166     private static class TransitionHolder implements Comparable<TransitionHolder> {
167         Transition transition;
168 
169         int weight;
170 
171         TransitionHolder(Transition transition, int weight) {
172             this.transition = transition;
173             this.weight = weight;
174         }
175 
176         public int compareTo(TransitionHolder o) {
177             return (weight > o.weight) ? 1 : (weight < o.weight ? -1 : 0);
178         }
179     }
180 }