blob: 0068b7a73248789edf1c5515128b47298c71a329 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.mina.statemachine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.mina.statemachine.event.Event;
import org.apache.mina.statemachine.transition.SelfTransition;
import org.apache.mina.statemachine.transition.Transition;
/**
* Represents a state in a {@link StateMachine}. Normally you wouldn't create
* instances of this class directly but rather use the
* {@link org.apache.mina.statemachine.annotation.State} annotation to define
* your states and then let {@link StateMachineFactory} create a
* {@link StateMachine} for you.
* <p>
* {@link State}s inherits {@link Transition}s from
* their parent. A {@link State} can override any of the parents
* {@link Transition}s. When an {@link Event} is processed the {@link Transition}s
* of the current {@link State} will be searched for a {@link Transition} which
* can handle the event. If none is found the {@link State}'s parent will be
* searched and so on.
* </p>
*
* @author <a href="http://mina.apache.org">Apache MINA Project</a>
*/
public class State {
/** The state ID */
private final String id;
/** The parent state */
private final State parent;
private List<TransitionHolder> transitionHolders = new ArrayList<>();
/** The list of transitions for this state */
private List<Transition> transitions = Collections.emptyList();
/** The list of entry transitions on a state */
private List<SelfTransition> onEntries = new ArrayList<>();
/** The list of exit transition from a state */
private List<SelfTransition> onExits = new ArrayList<>();
/**
* Creates a new {@link State} with the specified id.
*
* @param id the unique id of this {@link State}.
*/
public State(String id) {
this(id, null);
}
/**
* Creates a new {@link State} with the specified id and parent.
*
* @param id the unique id of this {@link State}.
* @param parent the parent {@link State}.
*/
public State(String id, State parent) {
this.id = id;
this.parent = parent;
}
/**
* @return the id of this {@link State}.
*/
public String getId() {
return id;
}
/**
* @return the parent or <code>null</code> if this {@link State} has no
* parent.
*/
public State getParent() {
return parent;
}
/**
* @return an unmodifiable {@link List} of {@link Transition}s going out
* from this {@link State}.
*/
public List<Transition> getTransitions() {
return Collections.unmodifiableList(transitions);
}
/**
* @return an unmodifiable {@link List} of entry {@link SelfTransition}s
*/
public List<SelfTransition> getOnEntrySelfTransitions() {
return Collections.unmodifiableList(onEntries);
}
/**
* @return an unmodifiable {@link List} of exit {@link SelfTransition}s
*/
public List<SelfTransition> getOnExitSelfTransitions() {
return Collections.unmodifiableList(onExits);
}
/**
* Adds an entry {@link SelfTransition} to this {@link State}
*
* @param selfTransition the {@link SelfTransition} to add.
* @return this {@link State}.
*/
State addOnEntrySelfTransaction(SelfTransition onEntrySelfTransaction) {
if (onEntrySelfTransaction == null) {
throw new IllegalArgumentException("transition");
}
onEntries.add(onEntrySelfTransaction);
return this;
}
/**
* Adds an exit {@link SelfTransition} to this {@link State}
*
* @param selfTransition the {@link SelfTransition} to add.
* @return this {@link State}.
*/
State addOnExitSelfTransaction(SelfTransition onExitSelfTransaction) {
if (onExitSelfTransaction == null) {
throw new IllegalArgumentException("transition");
}
onExits.add(onExitSelfTransaction);
return this;
}
private void updateTransitions() {
transitions = new ArrayList<>(transitionHolders.size());
for (TransitionHolder holder : transitionHolders) {
transitions.add(holder.transition);
}
}
/**
* Adds an outgoing {@link Transition} to this {@link State} with weight 0.
*
* @param transition the {@link Transition} to add.
* @return this {@link State}.
* @see #addTransition(Transition, int)
*/
public State addTransition(Transition transition) {
return addTransition(transition, 0);
}
/**
* Adds an outgoing {@link Transition} to this {@link State} with the
* specified weight. The higher the weight the less important a
* {@link Transition} is. If two {@link Transition}s match the same
* {@link Event} the {@link Transition} with the lower weight will
* be executed.
*
* @param transition the {@link Transition} to add.
* @param weight The weight of this transition
* @return this {@link State}.
*/
public State addTransition(Transition transition, int weight) {
if (transition == null) {
throw new IllegalArgumentException("transition");
}
transitionHolders.add(new TransitionHolder(transition, weight));
Collections.sort(transitionHolders);
updateTransitions();
return this;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof State)) {
return false;
}
return id.equals(((State) o).id);
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int h = 37;
return h * 17 + id.hashCode();
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("State[");
sb.append("id=").append(id);
sb.append("]");
return sb.toString();
}
private static class TransitionHolder implements Comparable<TransitionHolder> {
private Transition transition;
private int weight;
TransitionHolder(Transition transition, int weight) {
this.transition = transition;
this.weight = weight;
}
@Override
public int compareTo(TransitionHolder o) {
return (weight > o.weight) ? 1 : (weight < o.weight ? -1 : 0);
}
}
}