001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *
019: */
020: package org.apache.mina.statemachine;
021:
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.List;
025:
026: import org.apache.commons.lang.builder.EqualsBuilder;
027: import org.apache.commons.lang.builder.HashCodeBuilder;
028: import org.apache.commons.lang.builder.ToStringBuilder;
029: import org.apache.mina.statemachine.event.Event;
030: import org.apache.mina.statemachine.transition.Transition;
031:
032: /**
033: * Represents a state in a {@link StateMachine}. Normally you wouldn't create
034: * instances of this class directly but rather use the
035: * {@link org.apache.mina.statemachine.annotation.State} annotation to define
036: * your states and then let {@link StateMachineFactory} create a
037: * {@link StateMachine} for you.
038: * <p>
039: * {@link State}s inherits {@link Transition}s from
040: * their parent. A {@link State} can override any of the parents
041: * {@link Transition}s. When an {@link Event} is processed the {@link Transition}s
042: * of the current {@link State} will be searched for a {@link Transition} which
043: * can handle the event. If none is found the {@link State}'s parent will be
044: * searched and so on.
045: * </p>
046: *
047: * @author The Apache MINA Project (dev@mina.apache.org)
048: * @version $Rev: 586108 $, $Date: 2007-10-18 14:05:07 -0600 (Thu, 18 Oct 2007) $
049: */
050: public class State {
051: private final String id;
052: private final State parent;
053: private List<TransitionHolder> transitionHolders = new ArrayList<TransitionHolder>();
054: private List<Transition> transitions = Collections.emptyList();
055:
056: /**
057: * Creates a new {@link State} with the specified id.
058: *
059: * @param id the unique id of this {@link State}.
060: */
061: public State(String id) {
062: this (id, null);
063: }
064:
065: /**
066: * Creates a new {@link State} with the specified id and parent.
067: *
068: * @param id the unique id of this {@link State}.
069: * @param parent the parent {@link State}.
070: */
071: public State(String id, State parent) {
072: this .id = id;
073: this .parent = parent;
074: }
075:
076: /**
077: * Returns the id of this {@link State}.
078: *
079: * @return the id.
080: */
081: public String getId() {
082: return id;
083: }
084:
085: /**
086: * Returns the parent {@link State}.
087: *
088: * @return the parent or <code>null</code> if this {@link State} has no
089: * parent.
090: */
091: public State getParent() {
092: return parent;
093: }
094:
095: /**
096: * Returns an unmodifiable {@link List} of {@link Transition}s going out
097: * from this {@link State}.
098: *
099: * @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
107: .size());
108: for (TransitionHolder holder : transitionHolders) {
109: transitions.add(holder.transition);
110: }
111: }
112:
113: /**
114: * Adds an outgoing {@link Transition} to this {@link State} with weight 0.
115: *
116: * @param transition the {@link Transition} to add.
117: * @return this {@link State}.
118: * @see #addTransition(Transition, int)
119: */
120: public State addTransition(Transition transition) {
121: return addTransition(transition, 0);
122: }
123:
124: /**
125: * Adds an outgoing {@link Transition} to this {@link State} with the
126: * specified weight. The higher the weight the less important a
127: * {@link Transition} is. If two {@link Transition}s match the same
128: * {@link Event} the {@link Transition} with the lower weight will
129: * be executed.
130: *
131: * @param transition the {@link Transition} to add.
132: * @return this {@link State}.
133: */
134: public State addTransition(Transition transition, int weight) {
135: if (transition == null) {
136: throw new NullPointerException("transition");
137: }
138:
139: transitionHolders.add(new TransitionHolder(transition, weight));
140: Collections.sort(transitionHolders);
141: updateTransitions();
142: return this ;
143: }
144:
145: @Override
146: public boolean equals(Object o) {
147: if (!(o instanceof State)) {
148: return false;
149: }
150: if (o == this ) {
151: return true;
152: }
153: State that = (State) o;
154: return new EqualsBuilder().append(this .id, that.id).isEquals();
155: }
156:
157: @Override
158: public int hashCode() {
159: return new HashCodeBuilder(13, 33).append(this .id).toHashCode();
160: }
161:
162: @Override
163: public String toString() {
164: return new ToStringBuilder(this ).append("id", this .id)
165: .toString();
166: }
167:
168: private static class TransitionHolder implements
169: Comparable<TransitionHolder> {
170: Transition transition;
171:
172: int weight;
173:
174: TransitionHolder(Transition transition, int weight) {
175: this .transition = transition;
176: this .weight = weight;
177: }
178:
179: public int compareTo(TransitionHolder o) {
180: return (weight > o.weight) ? 1 : (weight < o.weight ? -1
181: : 0);
182: }
183: }
184: }
|