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 */ 020package org.apache.mina.statemachine; 021 022import java.util.ArrayList; 023import java.util.Collections; 024import java.util.List; 025 026import org.apache.mina.statemachine.event.Event; 027import org.apache.mina.statemachine.transition.SelfTransition; 028import org.apache.mina.statemachine.transition.Transition; 029 030/** 031 * Represents a state in a {@link StateMachine}. Normally you wouldn't create 032 * instances of this class directly but rather use the 033 * {@link org.apache.mina.statemachine.annotation.State} annotation to define 034 * your states and then let {@link StateMachineFactory} create a 035 * {@link StateMachine} for you. 036 * <p> 037 * {@link State}s inherits {@link Transition}s from 038 * their parent. A {@link State} can override any of the parents 039 * {@link Transition}s. When an {@link Event} is processed the {@link Transition}s 040 * of the current {@link State} will be searched for a {@link Transition} which 041 * can handle the event. If none is found the {@link State}'s parent will be 042 * searched and so on. 043 * </p> 044 * 045 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 046 */ 047public class State { 048 private final String id; 049 050 private final State parent; 051 052 private List<TransitionHolder> transitionHolders = new ArrayList<TransitionHolder>(); 053 054 private List<Transition> transitions = Collections.emptyList(); 055 056 private List<SelfTransition> onEntries = new ArrayList<SelfTransition>(); 057 058 private List<SelfTransition> onExits = new ArrayList<SelfTransition>(); 059 060 /** 061 * Creates a new {@link State} with the specified id. 062 * 063 * @param id the unique id of this {@link State}. 064 */ 065 public State(String id) { 066 this(id, null); 067 } 068 069 /** 070 * Creates a new {@link State} with the specified id and parent. 071 * 072 * @param id the unique id of this {@link State}. 073 * @param parent the parent {@link State}. 074 */ 075 public State(String id, State parent) { 076 this.id = id; 077 this.parent = parent; 078 } 079 080 /** 081 * @return the id of this {@link State}. 082 */ 083 public String getId() { 084 return id; 085 } 086 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 * @return an unmodifiable {@link List} of {@link Transition}s going out 097 * from this {@link State}. 098 */ 099 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}