/*
* TeleStax, Open Source Cloud Communications Copyright 2012.
* and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.mobicents.protocols.ss7.m3ua.impl.fsm;
import javolution.util.FastMap;
import org.apache.log4j.Logger;
import org.mobicents.protocols.ss7.m3ua.impl.scheduler.M3UATask;
/**
* @author amit bhayani
*/
public class FSM extends M3UATask {
protected static final Logger logger = Logger.getLogger(FSM.class);
public static final String ATTRIBUTE_MESSAGE = "message";
private String name;
// first and last states in fsm
protected FSMState start;
protected FSMState end;
// intermediate states
private FastMap<String, FSMState> states = new FastMap<String, FSMState>();
protected FSMState currentState;
private FastMap attributes = new FastMap();
private FSMState oldState;
public FSM(String name) {
this.name = name;
}
public FSMState getState() {
return currentState;
}
public void setStart(String name) {
// the start state already has value which differs from current state?
if (this.start != null && currentState != null) {
throw new IllegalStateException("Start state can't be changed now");
}
this.start = states.get(name);
this.currentState = start;
}
public void setEnd(String name) {
this.end = states.get(name);
}
public FSMState createState(String name) {
FSMState s = new FSMState(this, name);
states.put(name, s);
return s;
}
public void setAttribute(String name, Object value) {
attributes.put(name, value);
}
public Object getAttribute(String name) {
return attributes.get(name);
}
public void removeAttribute(String name) {
attributes.remove(name);
}
public Transition createTransition(String name, String from, String to) {
if (name.equals("timeout")) {
throw new IllegalArgumentException("timeout is illegal name for transition");
}
if (!states.containsKey(from)) {
throw new IllegalStateException("Unknown state: " + from);
}
if (!states.containsKey(to)) {
throw new IllegalStateException("Unknown state: " + to);
}
Transition t = new Transition(name, states.get(to));
states.get(from).add(t);
return t;
}
public Transition createTimeoutTransition(String from, String to, long timeout) {
if (!states.containsKey(from)) {
throw new IllegalStateException("Unknown state: " + from);
}
if (!states.containsKey(to)) {
throw new IllegalStateException("Unknown state: " + to);
}
Transition t = new Transition("timeout", states.get(to));
states.get(from).timeout = timeout;
states.get(from).add(t);
return t;
}
/**
* Processes transition.
*
* @param name the name of transition.
*/
public void signal(String name) throws UnknownTransitionException {
// check that start state defined
if (start == null) {
throw new IllegalStateException("The start sate is not defined");
}
// check that end state defined
if (end == null) {
throw new IllegalStateException("The end sate is not defined");
}
// ignore any signals if fsm reaches end state
// if (state == end) {
// return;
// }
oldState = currentState;
// switch to next state
currentState = currentState.signal(name);
if (logger.isDebugEnabled()) {
logger.debug(String.format("%s Transition to=%s", toString(), name));
}
}
public void tick(long now) {
// if (state != null && state != start && state != end) {
if (currentState != null) {
currentState.tick(now);
}
}
@Override
public String toString() {
return String.format("FSM.name=%s old state=%s, current state=%s", this.name,
(this.oldState != null) ? this.oldState.getName() : "",
(this.currentState != null) ? this.currentState.getName() : "");
}
}