Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* COOS - Connected Objects Operating System (www.connectedobjects.org).
*
* Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This library 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 program. If not, see .
*
* You may also contact one of the following for additional information:
* Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
* Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
*/
package org.coos.javaframe;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import org.coos.actorframe.application.Container;
import org.coos.javaframe.messages.AFPropertyMsg;
import org.coos.javaframe.messages.ActorMsg;
import org.coos.javaframe.messages.JFConstants;
/**
* The StateMachine is an implementation of finite machine on the EJB platform.
* This class is an abstract super class, that should not be changed by the
* application developer (AD). The main function for this class is to receive
* JMS messages from an attached JMS queue, read the state data for the receving
* state machine instance from the entity bean, execute the transition, write
* back the state data and at last make an trace object of the transition.
*
*
* The class contains a set of methods that must be implemented by the subclass:
*
*
*
* Following methods may be used by the application designer
*
*
{@link #sendMessage(ActorMsg,ActorAddress)}
*
{@link #stopTimer(String)}
*
*
* Following methods may be overloaded by the application designer. The
* overloaded methods must call its super.method
*
*
{@link #initStateMachine()}
*
{@link #initInstance()}
*
*
*
* @author Geir Melby, Tellu AS
* @see State
* @see CompositeState
*/
// to change actor class
public class StateMachine implements Schedulable, Actor, JFConstants {
public int noOfRRMessages = 3;
public ActorAddress senderOfReportRequest;
// Start of definition of persistentSession state data that needs to be
// stored in entity beans
public String myActorId; // the name of actor instance, used also as the
// primary key for the corresponding entity bean
public String myActorType; // The type of the state macghine
public String myActorDomain;
public MailBox saveQueue; // Queue of signals saved in currentState.
// When State::nextState() is called, the signals in saveQueue are
// moved back in front of the messageBox.
protected String currentStateId;
// An unique id of the state machine instance
public Hashtable activeTimers;
// Reference to each active timer is stored in this table hashed with an id
// that the
// user can use to cancel a timer
// Temporary variables
// protected State currentState; // current state of the startPage actor
// instance
protected State nextState;
protected ActorMsg currentMessage;
// keeps the reference to the entity bean that keeps the state data for
// current state machine
protected State initialState;
// the initial state that all instances of this state machine share set in
// the State class "enterstate" method
public TraceObject trace; // trace of the transistion
public Scheduler scheduler; // reference to the scheduler
boolean readyToBeDeleted = false;
// set during the transition if the state machine shall be deleted after the
// transition is finished
public boolean performExitIsDone = false; // Set in performExit method and
// used in exec() method to
// check inconsistency
public boolean sameStateIsDone = false; // Set in sameState() method and
// used in save() method to check if
// it shall not save
public boolean exitStateIsDone = false; // set in the exitState method to
// flag that this method has been
// called, used by framework
public boolean saveDone = false; // this flagf is set during the save
// operation to avoid further signal
// trigging in sub types
public int entryNo = 0; // used in the entering the next state
// Variables that are common for all instances of the State Machine. These
// are set at initiation time of the
// message bean and are therefore equal for all mesage beans of the same
// type.
protected CompositeState myCompositeState; // my outermost composite state
// context for the message bean, set in the {@link
// #setMessageDrivenContext(MessageDrivenContext)}
// Queue of signals used by the simulator, is set the {@link
// #setMailBox(MailBox)} called by the {@link Scheduler}
public MailBox mailbox;
private static Timer jfTimer;
// private boolean visible = false;
// added properties from ActorSM
public ActorSpec actorSpec;
public Hashtable ports = new Hashtable(); // contains the port address that
// this ActorStateMachine may
// contain
public static int UNIQ_ID = 0; // unique actor id used when new actors are
// generating with no id specified
public ActorContext context; // ActorContext object of this ActorSM
// properties copied from Context class
// private ActorAddress myAddress;
private boolean isPersistent = false;
// used for creation of parts and ports
private int noOfTrialsLeft = 3; // initially set to 3
private boolean visible;
private int traceLevel;
private boolean traceParts;
/**
* Containes the references to the composite states installed.
*/
private Hashtable stateMachines;
/**
* Contains current state for each composite machine installed.
*/
private Hashtable currentStates;
/**
* True if the state machine is under Junit test. This because then output
* messages are send also when no connectors are set. Makes the testing
* easier
*/
private boolean testing = false;
private static ActorAddress proxyAddress = null;
/**
* Constructor to create an state machine
*/
public StateMachine() {
currentStates = new Hashtable();
stateMachines = new Hashtable();
currentMessage = null;
currentStateId = null;
saveQueue = new MailBox();
mailbox = new MailBox();
activeTimers = new Hashtable();
}
public StateMachine(CompositeState compositeState) {
this();
setBehaviorClass(compositeState);
}
// ************************ System utitillity methods , not used by the
// programmer
public boolean useProxy() {
return proxyAddress != null;
}
public void setProxyAddress(ActorAddress proxyAddress) {
this.proxyAddress = proxyAddress;
}
public ActorAddress getProxyAddress() {
return proxyAddress;
}
public void setBehaviorClass(CompositeState myCompositeState) {
this.myCompositeState = myCompositeState;
}
public CompositeState getBehaviorClass() {
return myCompositeState;
}
public boolean isTesting() {
return testing;
}
public void setTesting(boolean testing) {
this.testing = testing;
}
public ActorSpec getActorSpec() {
return actorSpec;
}
public void setActorSpec(ActorSpec actorSpec) {
this.actorSpec = actorSpec;
}
public ActorAddress getMyActorAddress() {
ActorAddress adr = new ActorAddress(myActorId, myActorType);
if (adr.getActorDomain() == null)
adr.setActorDomain(myActorDomain);
return adr;
}
protected static Timer createTimer() {
if (jfTimer == null) {
jfTimer = new Timer();
}
return jfTimer;
}
/**
* Returns the id used as key in the statemachines and currentStates
*
* @param actorId is the actor id of this state machine
* @return the key
*/
protected String getStateMachineId(String actorId) {
int index = actorId.indexOf(".");
if (index == -1) {
return actorId;
}
return actorId.substring(index + 1);
}
public boolean containsStateMachine(String id) {
return stateMachines.containsKey(id);
}
protected boolean isRole(String actorId) {
return actorId.indexOf(".") != -1;
}
public CompositeState getStateMachine() {
String str = getStateMachineId(myActorId);
CompositeState cs = (CompositeState) stateMachines.get(str);
if (cs == null) {
throw new RuntimeException("CompositeState (behaviour class) not set. ActorId = " + myActorId);
}
return (CompositeState) stateMachines.get(str);
}
public CompositeState getStateMachine(String stateMachineId) {
return (CompositeState) stateMachines.get(stateMachineId);
}
public void addStateMachine(String stateMachineId, RoleCS stateMachine) {
if (!stateMachines.containsKey(stateMachineId)) {
stateMachine.setParentAddress(getMyActorAddress());
stateMachines.put(stateMachineId, stateMachine);
}
}
public String getMyActorDomain() {
return myActorDomain;
}
public void setMyActorDomain(String myActorDomain) {
this.myActorDomain = myActorDomain;
}
public void setMyActorId(String myActorId) {
this.myActorId = myActorId;
}
public void setMyActorType(String myActorType) {
this.myActorType = myActorType;
}
public TraceObject getTrace() {
return trace;
}
public void setVisible(boolean visible) {
this.visible = visible;
}
public void setNextState(State state) {
currentStates.put(getStateMachineId(myActorId), state);
}
public void setCurrentState(CompositeState state) {
currentStates.put(getStateMachineId(myActorId), state);
}
public Hashtable getStateMachines() {
return stateMachines;
}
public Container getContainer() {
return scheduler.getSchedulerData().getContainer();
}
/**
* Returns the specification of the application
*
* @return the application spec for this application
*/
public ApplicationSpec getApplicationSpec() {
return scheduler.getSchedulerData().getApplicationSpec();
}
/**
* /** Create the context for an instance of this state machine in current
* context.
*
* @return A context string that makes the actorid unique
*/
public String getContextString() {
if (this.context.getActorAddress() != null)
// return this.context.getActorAddress().getActorID() + "/";
return myActorId + "/";
else
return "/";
}
protected boolean isCreateMsg(ActorMsg msg) {
return msg instanceof AFPropertyMsg && msg.equals(ROLE_CREATE_MSG) || msg.equals(ROLE_PLAY_MSG);
}
public ActorContext getContext() {
return context;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
this.trace = scheduler.getTraceObject();
}
public MailBox getMailbox() {
return mailbox; // To change body of implemented methods use File |
// Settings | File Templates.
}
public Scheduler getScheduler() {
return scheduler; // To change body of implemented methods use File |
// Settings | File Templates.
}
public boolean isSaveDone() {
return saveDone;
}
public boolean isReadyToBeDeleted() {
return readyToBeDeleted;
}
/**
* This methos is called from createActor method in SchedulerImpl. The basic
* properties are set as actorId, actorType
*/
public void init() {
ApplicationSpec appSpec = scheduler.getSchedulerData().getApplicationSpec();
actorSpec = appSpec.getClonedActorSpec(getType());
scheduler.setTrace(appSpec.isTraceEnabled());
if (myCompositeState != null && myCompositeState instanceof RoleCS) {
addStateMachine(myActorId, (RoleCS) myCompositeState);
}
initStateMachine(); // Initiate State machine
execStartTransition(); // execute the start transition as enter state
initNewInstance(); // initiate local variables unique for each instance
}
/**
* Called from the scheduler, when the application is deleted. May be
* overridden to to take special actions such as closing resources, deleting
* threads etc.
*/
public void destroy() {
stopAllTimers();
}
/**
* Called from the scheduler, when the application is paused. May be
* overridden to to take special actions such as pausing threads etc.
*/
public void pause() {
}
public CompositeState getCompositeState() {
return getStateMachine();
}
/**
* Reads the trace level which specifies what level of information that
* shall be reported. The trace level is debug, info, warning and error.
*
* @return
* @see org.coos.javaframe.TraceObject
*/
public int getTraceLevel() {
return traceLevel;
}
/**
* Sets the traceLevel as explained in {@link #getTraceLevel}
*
* @param traceLevel
*/
public void setTraceLevel(int traceLevel) {
this.traceLevel = traceLevel;
}
/**
* Writes out the instance identification and the the actor type as
* "ole@user"
*/
public String toString() {
return myActorId + "@" + myActorType;
}
public class JFTimerTask extends TimerTask {
AFPropertyMsg thisMsg;
public JFTimerTask(AFPropertyMsg thisMsg) {
super();
// ActorAddress aa = new ActorAddress(myActorId, myActorType);
// thisMsg.setReceiverRole(aa);
this.thisMsg = thisMsg;
}
public void run() {
sendMessage(thisMsg);
if (thisMsg instanceof AFPropertyMsg) {
activeTimers.remove(thisMsg.getString(JFConstants.TIMER_ID));
}
}
}
public void startTimer(long duration, String timerId, ActorAddress receiver) {
AFPropertyMsg tm = new AFPropertyMsg(TIMER_MSG, true);
// todo forlag til endring AFPropertyMsg tm = new
// AFPropertyMsg(timerId);
tm.setProperty(JFConstants.TIMER_ID, timerId);
tm.setReceiverRole(receiver);
tm.setLong(JFConstants.DURATION, duration);
startTimer(tm, duration, timerId);
}
public void startTimer(AFPropertyMsg tm, long duration, String timerId) {
if (timerId == null || timerId.equals("")) {
timerId = tm.toString();
}
tm.setReceiverRole(getMyActorAddress());
tm.setProperty(JFConstants.TIMER_ID, timerId);
if (activeTimers.containsKey(timerId)) {
stopTimer(timerId);
}
JFTimerTask jfTT = new JFTimerTask(tm);
activeTimers.put(timerId, jfTT);
Timer timer = createTimer();
timer.schedule(jfTT, duration);
trace.traceTask("Timer: " + timerId + " Duration: " + duration / 1000 + " seconds");
return;
}
public void startTimer(long duration, String timerId) {
startTimer(new AFPropertyMsg(TIMER_MSG, true), duration, timerId);
// todo forlag til endring startTimer(new AFPropertyMsg(timerId),
// duration, timerId);
return;
}
public boolean stopTimer(String timerId) {
boolean returnValue = false;
if (timerId == null || timerId.equals("")) {
trace.traceWarning("Scheduler.JFTimerTask.stopTimer: Timer: " + timerId
+ " illegal timerId, timer not removed");
} else {
// tider id ok
JFTimerTask t = (JFTimerTask) activeTimers.remove(timerId);
if (t == null) {
trace.traceTask("Scheduler.JFTimerTask.stopTimer: Timer: " + timerId + " timer does exist");
} else {
// timer task exists
if (t.cancel()) {
trace.traceTask("Timer: " + timerId.trim() + " removed");
returnValue = true;
} else {
trace.traceTask("Scheduler.JFTimerTask.stopTimer: Timer: " + timerId.trim() + " not removed");
}
}
}
return returnValue;
}
public Hashtable getActiveTimers() {
return activeTimers;
}
/**
* All messages in the savequeue are resent to the state machine instance if
* the savequeue is not empty and the state is changed.
*/
void runSaveQueue() {
if (nextState != null) {
MailBox tmp = new MailBox();
if (saveQueue != null) {
tmp.moveMailBox(saveQueue); // move all messages to this this
// tmp queue
}
ActorMsg am = (ActorMsg) tmp.removeFirst(); // get first message
while (am != null) {
processMessage(am);
am = (ActorMsg) tmp.removeFirst();
}
}
}
/**
* Process an incomming message to an incomming port for this actor. The
* message is send to the actor address. The hashtable ports contains an
* actoradress for each port. Each port can only have one address, that
* means only one connector.
*
* @param msg is the message to be send
*/
protected boolean processPortMessage(ActorMsg msg) {
boolean ok = false;
myActorId = msg.getReceiverRole().getActorID();
myActorType = msg.getReceiverRole().getActorType();
String portName = msg.getReceiverRole().getActorPort();
ActorAddress receiverAddress = (ActorAddress) ports.get(portName);
// if (receiverAddress != null &&
// context.getChildrenRole(msg.getReceiverRole().getActorID()) != null)
// {
if (receiverAddress != null) {
// ActorAddress aa =
// context.getChildrenRole(receiverAddress.getActorID());
msg.setReceiverRole(receiverAddress);
ok = output(msg);
} else {
trace
.traceOut(TraceConstants.tlError, trace.getTraceHeader() + "The port " + portName
+ " does not exists");
}
return ok;
}
/**
* Process the incoming message. If the actor message RoleCreateMsg is
* received, an new actor instance is created before the exec method is
* called which will treat the message.
*
* @param msg is the actor message.
* @see ActorMsg
*/
public boolean processMessage(ActorMsg msg) {
currentMessage = msg;
myActorId = msg.getReceiverRole().getActorID(); // tHe instance variable
myActorType = msg.getReceiverRole().getActorType();
readyToBeDeleted = false; // reset to false before transition Changed
// 08.10.2003
trace.traceInit(this);
trace.setInputSignal(msg);
/* Added trace requests here */
// check if receiver is a role / state machine
State ps = getCurrentState();
if (ps == null) {
CompositeState cs = getStateMachine(getStateMachineId(myActorId));
if (cs != null) {
cs.enterState(this);
} else {
if (scheduler.isTraceOn())
trace.traceError("No state machine found for id: <" + myActorId + ">");
return false;
}
}
ps = getCurrentState();
if (ps != null) {
try {
exec(msg, this); // execute the transition
} catch (Exception e) {
if (scheduler.isTraceOn())
trace.traceError("Something went seriously wrong during execution. Performing Rollback: "
+ e.toString() + " " + e.getMessage());
getContainer().displayError(e);
if (performExitIsDone) {
// Exception occurred after the perforExit was called, Then
// the curr state will be wrong, and exception next time
// will occur
setNextState(ps);
}
return false;
}
if (scheduler.isTraceOn() && trace.traceLevel <= TraceConstants.tlDebug) {
trace.traceOut(TraceConstants.tlDebug, trace.toString());
}
} else {
if (scheduler.isTraceOn())
trace.traceError(" Current state is not set");
return false;
}
currentMessage = null;
runSaveQueue();
return true;
}
/**
* Checks if the Statemachine is visible. The sub type of State machine
* shoud override this method. An actor has a visible flag that is set to
* true if the actors shoiuld be visblie otside current domain
*
* @return true if the actor shall be visible in the router system
*/
public boolean isVisible() {
return visible;
}
/**
* Overloaded by substate machine to initialize specific attributes of a new
* instance. This method is called when a new instance is created.
*/
protected void initInstance() {
}
protected void destroyInstance() {
}
/**
* Called from process message when new instance is created
*/
private void initNewInstance() {
this.context = new ActorContext(new ActorAddress(myActorId, myActorType));
this.context.setMyParentAddress(new ActorAddress(myActorId, myActorType)); // set
// the
// parent
// address
// gn
initInstance();
}
public String getType() {
return this.myActorType;
}
public String getID() {
return this.myActorId;
}
/**
* Prints out the state data of an instance excluded the framework data
*
* @return a string of the state data
*/
public String printStateData() {
return "";
}
/**
* Initiate this syte machine, may be overridden by the sub states
*/
protected void initStateMachine() {
}
/**
* Get the current State of this StateMachine.
*
* @return The current State
*/
public final State getCurrentState() {
return (State) currentStates.get(getStateMachineId(myActorId));
}
protected Hashtable getCurrentStates() {
return currentStates;
}
protected final void setInitialState(State state) {
currentStates.put(getStateMachineId(myActorId), state);
}
public void setCurrentMessage(ActorMsg currentMessage) {
this.currentMessage = currentMessage;
}
/**
* Get the current ActorMsg of this StateMachine.
*
* @return The current ActorMsg
*/
public final ActorMsg getCurrentMessage() {
return currentMessage;
}
public void setPartSpecs(Vector partSpecs) {
this.actorSpec.setPartDesc(partSpecs);
}
public void setPortSpecs(Vector portSpecs) {
this.actorSpec.setPortDesc(portSpecs);
}
/**
* Code to be executed at startup of this StateMachine.
*/
protected void execStartTransition() {
getStateMachine().enterState(this);
initialState = getCurrentState(); // initiate the default initial state
currentStateId = initialState.stateName();
}
/**
* Restart this StateMachine. Note: the content of the messageBox is kept.
*/
public void restart() {
do {
getCurrentState().exit(this);
setNextState(getCurrentState().enclosingState);
} while (null != getCurrentState());
}
/**
* The treatment by this StateMachine of the next message from the mailbox.
* Default action is skipping of the signal. An invariant is that the signal
* != null
*
* @param sig is the input message to this state machine instance.
*/
protected void exec(ActorMsg sig, StateMachine curfsm) {
nextState = null;
entryNo = 0; // set default entry no, if nor changed by nextState(),
// default enterState is called
State currState = getCurrentState();
State st = currState;
trace.setCurrentState(currState.stateName());
CompositeState enclSt = currState.enclosingState;
if (enclSt == null) {
if (scheduler.isTraceError())
trace.traceOut(TraceConstants.tlError, trace.getTraceHeader() + "State is null!");
return;
}
saveDone = false;
do {
performExitIsDone = false;
sameStateIsDone = false;
exitStateIsDone = false;
enclSt.curfsm = this;
enclSt.execTrans(sig, currState, curfsm); // execute the transition
// check first if exitState has been called, if so call the exit()
// method
if (exitStateIsDone) {
if (performExitIsDone) {
currState.exit(curfsm);
} else {
throw new ActorFrameException("CurState: " + currState.getFullStateName()
+ " PerformExit() is not called before exitState() is called in execTrans()");
}
}
// check if nextState has been set
if (nextState != null && performExitIsDone) {
// call the enterstate method dependent of type of the next
// state
// setNextState(nextState);
if (nextState instanceof CompositeState && entryNo != 0) {
((CompositeState) nextState).enterState(entryNo, this);
} else {
nextState.enterState(this);
}
if (currState == null || currState instanceof CompositeState) {
if (scheduler.isTraceOn())
throw new ActorFrameException("Inconsisent current state of state machine id: "
+ (sig.getReceiverRole()).toString()
+ " Probably a mismatch of performExit() and enterState()");
}
if (scheduler.isTraceOn())
trace.setNewState(nextState.stateName());
if (isPersistent())
try {
storePersistentData();
} catch (IOException e) {
trace.traceOut(TraceConstants.tlError, "IOException while storing persistent data");
}
return; // sig has triggered a transistion (or save)
} else {
if (nextState == null && performExitIsDone) {
trace.setNewState(currState.stateName());
throw new ActorFrameException("CurState: " + currState.getFullStateName()
+ " NextState != null, but performExit is not run");
} else if (nextState != null && !performExitIsDone) {
String str = "CurState: " + currState.getFullStateName()
+ " NextState != null, but performExit is not run";
if (scheduler.isTraceOn())
trace.traceOut(TraceConstants.tlInfo, trace.getTraceHeader() + str);
trace.setNewState(currState.stateName());
throw new ActorFrameException(str);
} else if (sameStateIsDone) {
trace.setNewState(currState.stateName());
return;
}
// the sigal has not triggered a transition
st = enclSt;
enclSt = st.enclosingState;
}
} while (enclSt != null && !saveDone);
trace.setNewState(currState.stateName());
}
/**
* Sends the message to an ActorStateMachine. The actor address of the
* sending actor is set in the message
*
* @param sig
*/
public final boolean output(ActorMsg sig) {
if (sig.getReceiverRole() != null && sig.getReceiverRole().getActorType() != null) {
if (sig.getSenderRole() == null) {
sig.setSenderRole(getMyActorAddress()); // set the senderAddress
// of this message
}
/* if (useProxy()) {
sig.getReceiverRole().setProxyAddress(getProxyAddress());
//sig.setProxyAddress(getProxyAddress());
}*/
scheduler.clearLastMsgFromRouter();
return scheduler.output(sig, this);
} else {
trace.traceWarning("Illegal Receiver: " + sig.messageContent());
scheduler.output(sig, this);
}
return false;
}
/**
* Sends a message to the receiver address of the message. Utility routine
* to be used by the action specification in the state machine.
*
* @param sig invariant: The receiver and sender addresses of sig are set
*/
public boolean sendMessage(ActorMsg sig) {
return output(sig);
}
/**
* Sends a message to the specified actor address. Utility routine to be
* used by the action specification in the state machine.
*
* @param sig
* @param aa The actor address that the message is sent to
*/
public boolean sendMessage(ActorMsg sig, ActorAddress aa) {
if (aa == null) {
throw new RuntimeException("ActorAddress is null");
} else {
sig.setReceiverRole((ActorAddress) aa.clone()); // set the
// senderAddress of
// this message
sig.setSenderRole(getMyActorAddress()); // set the senderAddress of
// this
return output(sig);
}
}
/**
* Sends a message to the specified actor address. Utility routine to be
* used by the action specification in the state machine.
*
* @param signaName is the name of the message
* @param aa The actor address that the message is sent to
*/
public boolean sendMessage(String signaName, ActorAddress aa) {
AFPropertyMsg sig = new AFPropertyMsg(signaName);
sig.setReceiverRole((ActorAddress) aa.clone()); // set the senderAddress
// of this message
sig.setSenderRole(getMyActorAddress()); // set the senderAddress of this
return output(sig);
}
/**
* Sends a message to the specified actor address. Utilility routine to be
* used by the action specification in the state machine.
*
* @param sig
* @param aa The actor address that the message is sent to
* @param protocol specifies the transport protocol UDP or TCP to be used
*/
public boolean sendMessage(ActorMsg sig, ActorAddress aa, String protocol) {
sig.setReceiverRole((ActorAddress) aa.clone()); // set the senderAddress
// of this message
sig.getReceiverRole().setProtocol(protocol);
sig.setSenderRole(getMyActorAddress()); // set the senderAddress of this
sig.getSenderRole().setProtocol(protocol);
return output(sig);
}
/**
* Sends the message to a vector of actor addresses.
*
* @param sigName is the name of actor message that hall be send
* @param receiver is the receiver address. if not valid assume that the
* receiver is a port
*/
public boolean sendMessage(String sigName, String receiver) {
if (receiver.indexOf("@") != -1) {
return sendMessage(new AFPropertyMsg(sigName), new ActorAddress(receiver));
} else {
return sendMessage(new AFPropertyMsg(sigName), receiver);
}
}
/**
* Sends the message to a vector of actor addresses.
*
* @param sigName is the name of actor message that hall be send
* @param v is the vector of actor addresses
*/
public boolean sendMessage(String sigName, Vector v) {
return sendMessage(new AFPropertyMsg(sigName), v);
}
/**
* Sends the message to a vector of actor addresses.
*
* @param sig is the actor message that hall be send
* @param v is the vector of actor addresses
*/
public boolean sendMessage(ActorMsg sig, Vector v) {
boolean res = true;
if (v != null && v.size() > 0) {
if (v.size() == 1) {
ActorAddress aa = (ActorAddress) v.firstElement();
sig.setReceiverRole(aa);
res = output(sig);
} else {
Enumeration e = v.elements();
while (e.hasMoreElements()) {
ActorAddress aa = (ActorAddress) e.nextElement();
ActorMsg msg = sig.getCopy(scheduler.getClassLoader());
msg.setReceiverRole(aa);
boolean ok = output(msg);
res = res || ok;
}
}
}
return res;
}
/**
* Sends the message to an arry of actor addresses.
*
* @param sig is the actor message that hall be send
* @param actorAddresses is an arry of actor addresses
*/
public boolean sendMessage(ActorMsg sig, ActorAddress[] actorAddresses) {
boolean res = true;
if (actorAddresses != null) {
if (actorAddresses.length == 1) {
ActorAddress aa = actorAddresses[0];
sig.setReceiverRole(aa);
res = output(sig);
} else {
for (int i = 0; i < actorAddresses.length; i++) {
ActorAddress address = actorAddresses[i];
ActorMsg msg = sig.getCopy(scheduler.getClassLoader());
msg.setReceiverRole(address);
boolean ok = output(msg);
res = res || ok;
}
}
} else res = false;
return res;
}
/**
* Sends the message to an arry of actor addresses.
*
* @param sig is the actor message that hall be send
* @param actorAddresses is an arry of actor addresses
*/
public boolean sendMessage(ActorMsg sig, Object[] actorAddresses) {
boolean res = true;
try {
for (int i = 0; i < actorAddresses.length; i++) {
ActorAddress actorAddress = (ActorAddress) actorAddresses[i];
boolean ok = sendMessage(sig.getCopy(getScheduler().getClassLoader()), actorAddress);
;
res = res || ok;
}
} catch (ClassCastException e) {
throw new ClassCastException("Array of objects is not Actor addresses" + e.getMessage());
}
return res;
}
/**
* Sends the message to an arry of actor addresses.
*
* @param name is the name of message that hall be send
* @param actorAddresses is an arry of actor addresses
*/
public boolean sendMessage(String name, Object[] actorAddresses) {
return sendMessage(new AFPropertyMsg(name), actorAddresses);
}
/**
* Sends a message to another actor via a port name. The port is set up at
* initiation of actor, normaly using actor deployment descriptors.
*
* @param am ActorMsg to send.
* @param portName the port id. This has to be the same name as defined in the
* descriptor file.
*/
public boolean sendMessage(ActorMsg am, String portName) {
ActorAddress portAddress = getPortAddress(portName);
if (portAddress == null) {
if (scheduler.isTraceOn())
trace.traceError("Illegal port name: " + portName + " Message: " + am.getMsgId());
return false;
}
if (portAddress.getActorID() == null) {
// no specific instance specified, get the first instance of the
// specified type
// get all instances
Enumeration en = scheduler.getSchedulerData().getMySystem().elements();
while (en.hasMoreElements()) {
Schedulable sm = (Schedulable) en.nextElement();
String type = sm.getMyActorAddress().getActorType();
if (type.equals(portAddress.getActorType())) {
portAddress.setActorID(sm.getMyActorAddress().getActorID());
break;
}
}
}
// send the mesaeg only if the receiver address is legal
if (portAddress.isValied()) {
am.setSenderRole(getMyActorAddress());
return sendMessage(am, portAddress);
}
return false;
}
/**
* Sets a flag ton indeicate that this instance of the state machine shall
* be deleted when the transition is finished.
*/
public void setReadyToBeDeleted() {
readyToBeDeleted = true;
}
/**
* Reads the parts specification for this actor
*
* @return the actor description
*/
public ActorSpec readActorDescription() {
if (getType() != null) {
return scheduler.getSchedulerData().getApplicationSpec().getActorSpec(getType());
}
return null;
}
/**
* Search the PartSpecs table for a specific part. If it exist the partSpec
* is returned. This method is called from the ActorStateMachine protocol
* when new roles are requested. Not used by the application developer.
*
* @param roleType The actor type to be serched for.
* @param roleSpecs Contains the specification of inner parts for a specific actor
* type
* @return The partspec for this roleType.
*/
public PartSpec findRoleSpec(String roleType, Vector roleSpecs) {
for (int i = 0; i < roleSpecs.size(); i++) {
PartSpec parttemp = (PartSpec) roleSpecs.elementAt(i);
String tmp = parttemp.getRoleType();
if (roleType.equals(tmp)) {
return parttemp;
}
}
return null;
}
public Vector getPartSpecs() {
return actorSpec.getPartDesc();
}
public Vector getPortSpecs() {
return actorSpec.getPortDesc();
}
/**
* Creates the inner parts (actors) that shall exists at creation time of
* the enclosing actor. Not used by the application developers. Create the
* part only if it
*/
public boolean createParts() {
boolean childrenCreated = false;
String s = "INNER PARTS: ";
Vector partSpecs = actorSpec.getPartDesc();
for (int i = 0; i < partSpecs.size(); i++) {
PartSpec ps = (PartSpec) partSpecs.elementAt(i);
s = s + ", " + ps.toString();
ActorAddress aa;
// Check if the actor spec exists
ActorSpec spec = getApplicationSpec().getActorSpec(ps.getRoleType());
if (spec == null) {
if (scheduler.isTraceOn())
trace.traceOut(TraceConstants.tlError, " Scheduler.createParts:" + " ActorStateMachine spec"
+ ps.getRoleType() + " does not exists");
continue;
}
// if the bind property is set (Instance id for the actor that
// implements this part),
// an instance of the actor shall not be created
if (ps.getBind() != null) {
if (scheduler.isTraceOn())
trace.traceOut(TraceConstants.tlInfo, " Scheduler.createParts:" + " ActorStateMachine spec: "
+ ps.getRoleType() + " is bind to: " + ps.getBind());
continue;
}
int noOfExistingRoles = context.getChildrenRoles(ps.getRoleType()).size();
if (ps.getLow() - noOfExistingRoles > 0) {
for (int j = noOfExistingRoles; j < ps.getLow(); j++) {
Vector ports = getApplicationSpec().getActorSpec(ps.getRoleType()).getPortNames();
AFPropertyMsg pm = createRoleCreateMsg(ps, ports);
// check also if it exists a role name for that particular
// role instance
if (ps.getRoleNames() == null || ps.getRoleNames().length <= j) {
aa = new ActorAddress(
getContextString() + ps.getRoleType() + UNIQ_ID++ + "Set" + ps.getSetNo(), ps
.getRoleType());
} else {
aa = new ActorAddress(getContextString() + ps.getRoleNames()[j], ps.getRoleType());
}
// added GM 18.11.04
// set remote actor, null if it not exists, read from the
// actor descriptors
// Send only the creation msg to actors that
if (ps.getActorDomain() != null) {
aa = ps.getActorDomain();
String id = getContextString() + ps.getRoleNames()[j];
ActorAddress targetActor = new ActorAddress(id, ps.getRoleType());
pm.setProperty(ROLE_CREATE_MSG_TARGET_ACTOR, targetActor);
context.getCreationOfChildren().addElement(targetActor);
} else {
context.getCreationOfChildren().addElement(aa);
}
Vector v = actorSpec.getConnectorDesc(ps.getRoleType(), null);
v = rewriteContextualConnectors(v);
pm.setProperty(ROLE_CREATE_MSG_CONNECTORS, v);
this.sendMessage(pm, aa); // send the message
childrenCreated = true;
}
}
}
if (scheduler.isTraceOn())
trace.traceOut(TraceConstants.tlInfo, trace.getTraceHeader() + s);
return childrenCreated;
}
/**
* Create parts listed as strings of format in
* vector v. The actor id and actor type has to be read from this string.
*
* @param v contains strings of format which is
* the key of ActorAddresses of actors that has not responed on
* RoleCreate message
* @return true if parts has been created
*/
public boolean createParts(Vector v) {
boolean childrenCreated = false;
for (int i = 0; i < actorSpec.getPartDesc().size(); i++) {
PartSpec ps = (PartSpec) actorSpec.getPartDesc().elementAt(i);
// check if v contains this actor type
for (int j = 0; j < v.size(); j++) {
// Read the key string, which has to be converted to
// ActorAddress
Vector ports = getApplicationSpec().getActorSpec(ps.getRoleType()).getPortNames();
ActorAddress aa;
AFPropertyMsg pm = createRoleCreateMsg(ps, ports);
aa = (ActorAddress) v.elementAt(j);
String s = aa.key();
String actorId;
if (s.endsWith(ps.getRoleType())) {
// the key ends with actortype, calculate the id string
actorId = s.substring(0, s.indexOf("@"));
aa = new ActorAddress(actorId, ps.getRoleType());
if (ps.getActorDomain() != null) {
aa = ps.getActorDomain();
String id = getContextString() + ps.getRoleNames()[j];
ActorAddress targetActor = new ActorAddress(id, ps.getRoleType());
pm.setProperty(ROLE_CREATE_MSG_TARGET_ACTOR, targetActor);
// add the actor only if it is not there again
// context.getCreationOfChildren().addElement(targetActor);
}
Vector con = actorSpec.getConnectorDesc(ps.getRoleType(), null);
v = rewriteContextualConnectors(con);
pm.setProperty(ROLE_CREATE_MSG_CONNECTORS, con);
sendMessage(pm, aa); // send the message
childrenCreated = true;
}
}
}
return childrenCreated;
}
/**
* Creates an RoleCreateMsg
*
* @param ps is the part spec of the part
* @param ports is the port names for the part
* @return an RoleCreateMsg
*/
protected AFPropertyMsg createRoleCreateMsg(PartSpec ps, Vector ports) {
AFPropertyMsg pm = new AFPropertyMsg(ROLE_CREATE_MSG, true);
pm.setProperty(ROLE_CREATE_MSG_PORTS, ports);
pm.setProperty(ROLE_CREATE_MSG_CONNECTORS, actorSpec.getConnectorDesc(ps.getRoleType(), null));
pm.setBoolean(ROLE_CREATE_MSG_VISIBLE, ps.isVisible());
pm.setInt(TRACE_LEVEL_PROP, ps.getTraceLev());
return pm;
}
/**
* Create the Port instances belonging to a StateMachine and add addresses
* to target Port/actor for each of them. If the port exists already the
* port is not changed
*
* @param connectors
*/
public boolean createPorts(Vector connectors) {
if (ports == null) {
ports = new Hashtable();
}
// Vector con = rewriteContextualConnectors(connectors);
boolean createdPorts = false;
// this.ports.clear();
// Create all port instances with their configuration
Enumeration enumer = connectors.elements();
while (enumer.hasMoreElements()) {
ConnectorSpec connectorSpec = (ConnectorSpec) enumer.nextElement();
// Add it to the port list [from StateMachine]
if (!ports.containsKey(connectorSpec.getFrom())) {
if (connectorSpec.getFrom().getActorPort() != null) {
ports.put(connectorSpec.getFrom().getActorPort(), connectorSpec.getTo());
createdPorts = true;
}
}
}
return createdPorts;
}
/**
* Rewrite an actor address to be correct in this context
*
* @param connAddr the addrss to be rewritten to right context
* @param childrenAddrs are all the children inside this context
* @return
*/
protected ActorAddress getContextAddress(ActorAddress connAddr, Vector childrenAddrs) {
ActorAddress res = (ActorAddress) connAddr.clone();
if (res.getActorID() == null) {
// Undefined ActorID, try to find one.
if (connAddr.getActorType().equals(myActorType)) {
// bind to this actor.
res.setActorID(myActorId);
} else {
// search through the children to be created
// to find a correct instance.
Enumeration children = childrenAddrs.elements();
while (children.hasMoreElements()) {
ActorAddress child = (ActorAddress) children.nextElement();
if (child.getActorType().equals(connAddr.getActorType())) {
// found matching actor. use this actorId
res.setActorID(child.getActorID());
break;
}
}
}
} else {
// include the context
res.setActorID(getContextString() + connAddr.getActorID());
}
if (res.getActorPort() == null || res.getActorPort().equals("")) {
res.setActorPort(null); // "defaultInPort"
}
return res;
}
/**
* Rewrites the ActorAddresses in the Vector to include contextual
* information in the ActorID field. If the ActorID is null it searches a
* list of inner parts for this actor with correct ActorType.
*
* @param connectors Vector of CONNECTORS for connector requests
* @return conectors bound to this context
*/
public Vector rewriteContextualConnectors(Vector connectors) {
Vector childrenAddrs = getAllChildrenOfThisType(myActorType);
Vector res = new Vector();
for (int i = 0; i < connectors.size(); i++) {
ConnectorSpec cs = (ConnectorSpec) connectors.elementAt(i);
// check if the bind property is set. If so, use this as the target
// actor instance id
ActorAddress to = cs.getTo();
PartSpec toPart = actorSpec.getPartSpec(to.getActorType());
if (toPart != null && toPart.getBind() != null) {
// use the bind poroperty. The receiving part is already running
to.setActorID(toPart.getBind());
} else {
to = getContextAddress(cs.getTo(), childrenAddrs);
}
ActorAddress from = getContextAddress(cs.getFrom(), childrenAddrs);
ConnectorSpec newSpec = new ConnectorSpec(from, to, cs.isBidirectional());
res.addElement(newSpec);
}
return res;
}
private Vector getAllChildrenOfThisType(String actorType) {
// get all children of this type.
Vector all = context.getChildrenRoles();
Enumeration enumer = context.getCreationOfChildren().elements();
while (enumer.hasMoreElements()) {
all.addElement(enumer.nextElement());
}
return all;
}
// Check if creation of a new instance is permitted
public boolean checkMaxLimit(PartSpec p) {
if (context.sizeOfChildrenRoles(p.getRoleType()) < p.getHigh())
return true;
else
return false;
}
/**
* releaseAllAssociations releases all association which involves this role.
* A RoleReleaseMsg is sent on each association.
*/
public void releaseAllAssociations() {
Vector req = context.getRequestorRoles();
for (Enumeration e = req.elements(); e.hasMoreElements();) {
ActorAddress aa = (ActorAddress) e.nextElement();
this.sendMessage(new AFPropertyMsg(ROLE_RELEASE_MSG, true), aa);
}
req = context.getRequestedRoles();
for (Enumeration e = req.elements(); e.hasMoreElements();) {
ActorAddress aa = (ActorAddress) e.nextElement();
this.sendMessage(new AFPropertyMsg(ROLE_RELEASE_MSG, true), aa);
}
context.getRequestedRoles().removeAllElements();
}
/**
* releaseChildren releases all children roles of this ActorSM. A
* RoleResetMsg is sent to each children role, and unless the children role
* is persistent, it is removed from the ActorContext of this actor.
*/
public void releaseChildren() {
Vector children = context.getChildrenRoles();
for (Enumeration e = children.elements(); e.hasMoreElements();) {
ActorAddress childAA = (ActorAddress) e.nextElement();
if (context.isPersistentChildrenRole(childAA)) {
AFPropertyMsg pm = new AFPropertyMsg(ROLE_RESET_MSG, true);
pm.setSenderRole(new ActorAddress(myActorId, myActorType));
this.sendMessage(pm, childAA);
/*
* RoleResetMsg resm = new RoleResetMsg(); pm.setSenderRole(new
* ActorAddress(myActorId, myActorType)); this.sendMessage(resm,
* childAA);
*/
} else {
AFPropertyMsg pm = new AFPropertyMsg(ROLE_REMOVE_MSG, true);
this.sendMessage(pm, childAA);
// RoleRemoveMsg resm = new RoleRemoveMsg();
pm.setSenderRole(new ActorAddress(myActorId, myActorType));
this.sendMessage(pm, childAA);
context.remove(childAA);
}
}
}
/**
* Sends RoleRequestMsg to an actor for chatting a role with shall be named
* roleType and shall be of type roleType. If is does not exist, it will be
* created. Called by application developer.
*
* @param aa ActorAddress to send the request to
* @param roleId The actor id to request.
* @param roleType The actor type that shall play the role.
* @throws Exception
*/
public void sendRoleRequest(ActorAddress aa, String roleId, String roleType) throws Exception {
AFPropertyMsg rrm = new AFPropertyMsg(ROLE_REQUEST_MSG, true);
rrm.setProperty(ActorAddress.ROLE_ID, roleId);
rrm.setProperty(ActorAddress.ROLE_TYPE, roleType);
this.sendMessage(rrm, aa);
}
/**
* Check if this actor can be removed. If it is not a persistent actor or it
* contains no other associations, it can be deleted
*/
public boolean removeIfPossible() {
if (context.isEmpty() && !isPersistent()) {
destroyInstance();
sendMessage(new AFPropertyMsg(ROLE_PLAY_ENDED_MSG, true), context.getParentAddress());
stopAllTimers();
return true;
}
return false;
}
public void stopAllTimers() {
if (!(activeTimers.isEmpty())) {
Enumeration tmp = activeTimers.keys();
while (tmp.hasMoreElements()) {
String s = (String) tmp.nextElement();
stopTimer(s);
}
}
}
/**
* puts the message into the input queue of this state machine and notify
* the sheduler to start the state machine
*
* @param am is the message send by the window "manager"
*/
public void executeTheEvent(ActorMsg am) {
am.setReceiverRole(context.getActorAddress());
if (am.getSenderRole() == null) {
am.setSenderRole(context.getActorAddress());
}
synchronized (getScheduler()) {
getMailbox().addMessage(am);
getScheduler().notifyScheduler();
}
}
/**
* puts the message into the input queue of this state machine and notify
* the sheduler to start the state machine
*
* @param msgName is the message name send by the window "manager"
*/
public void executeTheEvent(String msgName) {
executeTheEvent(new AFPropertyMsg(msgName));
}
/**
* Gets the history state.
*
* @param cs is the composite state
* @return cs
*/
public State getHistoryState(CompositeState cs) {
return cs.findCurrentState(context.getHistoryStateId());
}
/**
* Sets the historyState to be the provided State
*/
public void setHistoryState(State st) {
if (st == null) {
context.setHistoryStateId(null);
} else {
context.setHistoryStateId(st.stateName());
}
}
public String stripContext(String s) {
return s.substring(s.lastIndexOf('/') + 1);
}
public boolean validateCredentials(AFPropertyMsg rrm) {
return false;
}
// added methods from Context
public boolean isPersistent() {
return isPersistent;
}
/**
* Sets this actor instance to be persistent or not. This method is called
* by the {@link StateMachineCS} to force it to be deleted by setting the
* persistent flag to false. This actor instance will then be deleted.
*
* @param persistent is true if the actor instance is persistent
*/
public void setPersistent(boolean persistent) {
isPersistent = persistent;
}
private ActorAddress getPortAddress(String portName) {
return (ActorAddress) ports.get(portName);
}
public int getNoOfTrialsLeft() {
return noOfTrialsLeft;
}
public void setNoOfTrialsLeft(int noOfTrialsLeft) {
this.noOfTrialsLeft = noOfTrialsLeft;
}
public void routerUpdate() {
// This validateLicense through the midlet router, that search trough
// the Sheduler.mySystem table for
// visible actors
/*
* if (isVisible()) { Vector actors = new Vector();
* actors.addElement(getMyActorAddress()); sendMessage(new
* ActorRouterRegMsg(actors, 0), new RouterAddress("ar", "ActorRouter",
* "udp")); startTimer(new RouterUpdateTimerMsg(),
* ROUTER_UPDATE_INTERVAL_LENGTH, ROUTER_UPDATE_INTERVAL_ID); }
*/
}
public boolean isTraceParts() {
return traceParts;
}
public void setTraceParts(boolean traceParts) {
this.traceParts = traceParts;
}
protected byte[] storePersistentData() throws IOException {
return new byte[0];
}
protected ByteArrayInputStream restorePersistentData(byte[] data) throws IOException {
return new ByteArrayInputStream(data);
}
public boolean isTraceOn() {
return scheduler.isTraceOn();
}
public boolean isTraceError() {
return scheduler.isTraceError();
}
/**
* Sends the messages to children with acor addfress
* @param am is the actor message
* @param child is the actor address without the context
* @return true if success
*/
public boolean sendToChild(ActorMsg am, ActorAddress child) {
ActorAddress aa = context.getChildrenRoleIgnoreContext(child);
if (aa != null) {
sendMessage(am, aa);
return true;
} else {
return false;
}
}
/**
* Sends the messages to all children
* @param am is the actor message
* @return true if success
*/
public boolean sendToChildren(ActorMsg am) {
if (!context.getChildrenRoles().isEmpty()) {
return sendMessage(am, context.getChildrenRoles());
} else {
return false;
}
}
public boolean sendToChild(ActorMsg am, String childType) {
Vector v = context.getChildrenRoles(childType);
if (v.size() == 1) {
sendMessage(am, (ActorAddress) v.elementAt(0));
return true;
} else {
return false;
}
}
public ActorMsg getCopyMsg(ActorMsg msg) {
return msg.getCopy(getScheduler().getClassLoader());
}
public AFPropertyMsg createRoleRequestMsg(String actorid, String actorType) {
AFPropertyMsg pm = new AFPropertyMsg(ROLE_REQUEST_MSG, true);
pm.setProperty(ROLE_REQUEST_MSG_ROLE_ID, actorid);
pm.setProperty(ROLE_REQUEST_MSG_ROLE_TYPE, actorType);
return pm;
}
}