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