All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.coos.javaframe.StateMachineCS Maven / Gradle / Ivy

/**
 * 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 org.coos.actorframe.ActorPartSpec;
import org.coos.actorframe.ActorReport;
import org.coos.actorframe.ActorSM;
import org.coos.actorframe.messages.AFConstants;
import org.coos.javaframe.messages.AFPropertyMsg;
import org.coos.javaframe.messages.ActorMsg;
import org.coos.javaframe.messages.JFConstants;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;

/**
 * The behavior for for an actor. It mainly consists of the ActorFrame protocol.
 * 
 * @author Geir Melby Tellu AS
 * @author Knut Eilif Husa, Tellu AS
 */
public class StateMachineCS extends RoleCS implements JFConstants {

	/**
	 * The constructor
	 * 
	 * @param sn
	 *            The name of the state
	 * @param cs
	 *            The enclosing state
	 */
	public StateMachineCS(String sn, CompositeState cs) {
		super(sn, cs);
	}

	public StateMachineCS() {
		super("StateMachineCS");
	}

	public StateMachineCS(String sn) {
		super(sn);
	}

	protected State waitCreateAck = new State("waitCreateAck", this);
	protected State init = new State("init", this);

	public static final int CREATION_TIMER_SPEC = 15 * 1000; // timer used first
	// to set the
	// first timeout
	// length (10
	// seconds)
	public static final String CREATION_TIMER_ID = "CreationTimer";
	public static final int NO_OF_RETRIALS = 3;

	public static String ROUTER_UPDATE_INTERVAL_ID = "ROUTER_UPDATE_INTERVAL";

	// private static long ROUTER_UPDATE_INTERVAL_LENGTH = 40 * 1000; //each
	// 4*10 seconds

	/**
	 * Makes the current statemachine enter idle
	 * 
	 * @param curfsm
	 *            The current statemachine
	 */
	public void enterState(StateMachine curfsm) {
		curfsm.setInitialState(init);
		init.enterState(curfsm);
	}

	/**
	 * Is called when the state machine enter the state where the actorspecific
	 * behavior is defined. At this time is all its inner parts created. This
	 * routine my be overridden by the sub class to start actor specifc behavior
	 * as requesting other roles, start timers etc.
	 * 
	 * @param curfsm
	 *            The reference to state machine
	 * @deprecated use the StartPlayingMsg as a trigger
	 */
	protected void startPlaying(StateMachine curfsm) {
		if (curfsm.isVisible())
			curfsm.getScheduler().upDateVisibleActors(curfsm);
	}

	/**
	 * Is called when the state machine is deleted. This routine my be
	 * overridden by the sub class to stop actor specifc behavior deleting start
	 * timers etc.
	 * 
	 * @param curfsm
	 *            The reference to state machine
	 * @deprecated use the StopPlayingMsg as a trigger
	 */
	protected void stopPlaying(StateMachine curfsm) {
		if (curfsm.isVisible())
			curfsm.getScheduler().unRegVisibleActor(curfsm.getMyActorAddress());
	}

	// deligate methods to avoid unnessary parameters

	/**
	 * Execute transition (if defined) for ActorMsg sig and State st. For each
	 * CompositeState class execTrans has to be defined. It defines the
	 * transitions (and saves) handled by its inner States (not included those
	 * inside inner CompositeStates). NB: execTrans is not called from user
	 * code.
	 * 
	 * @param sig
	 *            The consumed ActorMsg.
	 * @param st
	 *            The State to search for defined transition.
	 * @param curfsm
	 *            The performing StateMachine.
	 */
	public void execTrans(ActorMsg sig, State st, StateMachine curfsm) {
		if (st == init) {
			if (sig.equals(ROLE_PLAY_MSG)) {
				AFPropertyMsg rrm = (AFPropertyMsg) sig.getProperty("rrm");
				curfsm.context.setRootPlayMsg(sig); // Actor that starts
				// creation hiearchy
				curfsm.context.setMyParentAddress(sig.getSenderRole());
				curfsm.context.setMyAddress(sig.getReceiverRole());
				curfsm.context.addRequestorRole(rrm.getSenderRole().getActorID(), rrm.getSenderRole());
				Vector ports = (Vector) sig.getProperty("ports");
				if (ports != null && !ports.isEmpty()) {
					// create my own ports
					Vector connectors = (Vector) sig.getProperty(ROLE_CREATE_MSG_CONNECTORS);
					if (connectors != null) {
						curfsm.createPorts(connectors); // create the ports as
						// defined.
					}
					// curfsm.context.setTmpPorts(ports, null);
				}

				// Send ack to parent.
				curfsm.sendMessage(new AFPropertyMsg(ROLE_PLAY_ACK_MSG, true), sig.getSenderRole());

				// check if ports should be bounded
				Vector connectors = (Vector) sig.getProperty(ROLE_PLAY_MSG_CONNECTORS);
				if (connectors != null && !ports.isEmpty()) {
					curfsm.createPorts(connectors); // create the ports as
					// defined.
				}

				if (curfsm.createParts()) {
					// create inner parts
					performExit(curfsm);
					curfsm.startTimer(CREATION_TIMER_SPEC, CREATION_TIMER_ID); // create
					// timer
					// for
					// inner
					// parts
					curfsm.setNoOfTrialsLeft(NO_OF_RETRIALS - 1);
					curfsm.context.setHistoryStateId(idle.stateName());
					nextState(waitCreateAck, curfsm);
				} else {
					// no parts or inner ports to confirm.
					transStartPlaying(curfsm, idle);
				}
				return;
			} else if (sig.equals(ROLE_CREATE_MSG)) {
				curfsm.context.setRootPlayMsg(null); // no confirm to be send
				curfsm.setPersistent(true);
				curfsm.context.setMyParentAddress(sig.getSenderRole());
				curfsm.context.setMyAddress(sig.getReceiverRole());

				Vector ports = (Vector) sig.getProperty(ROLE_CREATE_MSG_PORTS);
				if (ports != null && !ports.isEmpty()) {
					// create my own ports
					Vector connectors = (Vector) sig.getProperty(ROLE_CREATE_MSG_CONNECTORS);
					if (connectors != null) {
						curfsm.createPorts(connectors); // create the ports as
						// defined.
					}
				}

				// Send ack to parent.
				ActorAddress aa = sig.getSenderRole();
				if (aa.getActorDomain() == null && curfsm.getContainer() != null) {
					aa.setActorDomain(curfsm.getScheduler().getSchedulerData().getActorDomainName());
				}
				curfsm.sendMessage(new AFPropertyMsg(ROLE_CREATE_ACK_MSG, true), aa);

				if (curfsm.createParts()) {
					// create inner parts
					performExit(curfsm);
					nextState(waitCreateAck, curfsm);
					return;
				} else {
					// no parts or inner ports to confirm.
					transStartPlaying(curfsm, idle);
					return;
				}
			}

		} else if (st == waitCreateAck) {
			if (sig.equals(ROLE_CREATE_ACK_MSG)) {
				curfsm.context.removeCreationChild(sig.getSenderRole());
				curfsm.context.addPersistentChildrenRole(sig.getSenderRole());
				Vector v = curfsm.context.getCreationOfChildren();
				if (v.isEmpty()) {
					// all inner parts are created, check if we need to
					// create any port-connectors for these inner parts.
					if (curfsm.context.getRootPlayMsg() != null) {
						curfsm.stopTimer(CREATION_TIMER_ID);
					}
					transStartPlaying(curfsm, idle);
					return;
				} else {
					sameState(curfsm);
					return;
				}
			} else if (sig.equals(ROLE_CREATE_NACK_MSG)) {
				curfsm.trace.traceError("ActorCS: Inner part rejected request -- creation of inner parts aborted");
				if (curfsm.context.getParentAddress().getActorID() != null) {
					curfsm
							.sendMessage(new AFPropertyMsg(ROLE_CREATE_NACK_MSG, true), curfsm.context
									.getParentAddress());
				}
				// if root node, the requestor of the RolePlayMsg should be
				// informed
				AFPropertyMsg rpm = (AFPropertyMsg) curfsm.context.getRootPlayMsg();
				if (rpm != null) {
					// root for the RolePlayMsg
					curfsm.stopTimer(CREATION_TIMER_ID);
					AFPropertyMsg rrm = (AFPropertyMsg) rpm.getProperty("rrm");
					AFPropertyMsg m = new AFPropertyMsg(ROLE_REQUEST_MSG, true);
					m.setProperty("rrm", rrm);
					curfsm.sendMessage(m, rpm.getSenderRole());
					curfsm.sendMessage(new AFPropertyMsg(ROLE_PLAY_NACK_MSG, true), curfsm.context.getActorAddress());

				}
				sameState(curfsm);
				return;
				// } else if (sig instanceof RoleCreateMsg) {
			} else if (sig.equals(ROLE_CREATE_MSG)) {
				// creation failed, repeat 3 times, this message is send from
				// the actor that initiated the
				// part creation and it is only that actor that has started a
				// timer. So this actor receives
				// a new RoleCreateMsg.

				// First get the not acknowledged children
				Vector v = curfsm.context.getCreationOfChildren();
				if (!v.isEmpty()) {
					// some children remains that are not acked, try some times
					// before giving up
					if (curfsm.createParts(v)) {
						curfsm.trace.traceError("ActorCS: Creation Timeout, new creation message received");
					} else {
						curfsm.trace.traceError("ActorCS: Creation Timeout, new creation message received, but no "
								+ "RoleCreateMsg is sent out");
					}
				}
				sameState(curfsm);
				return;
			} else if (sig.equals(TIMER_MSG) && ((AFPropertyMsg) sig).getProperty(TIMER_ID).equals(CREATION_TIMER_ID)) {
				// creation of inner parts failed, repeat
				// First get the not acknowledged children
				Vector v = curfsm.context.getCreationOfChildren();
				if (!v.isEmpty()) {
					// some children remains that are not acked, try some times
					// before giving up
					if (curfsm.getNoOfTrialsLeft() > 0) {
						// send new message to the parts again
						// and decrement no of trials
						curfsm.setNoOfTrialsLeft(curfsm.getNoOfTrialsLeft() - 1);
						if (curfsm.createParts(v)) {
							curfsm.startTimer(CREATION_TIMER_SPEC, CREATION_TIMER_ID);
						}
						sameState(curfsm);
						return;
					} else {
						// give up, tried some times without successful response
						curfsm.trace.traceError("ActorCS: Creation timeout, creation of inner parts aborted");
						// if root node, the requestor of the RolePlayMsg should
						// be informed
						sendResponsToRequestor(curfsm, ROLE_PLAY_NACK_MSG);
						sameState(curfsm);
						curfsm.sendMessage(new AFPropertyMsg(ROLE_REMOVE_MSG, true), curfsm.context.getActorAddress());
						return;
					}
				} else {
					// todo: this shouldn't happen?
					sameState(curfsm);
					return;

				}

			}
			// suspending the state machine save all input signals
		}

		// Behavior that is common for the some states, multiple state names in
		// UML
		if (st == waitCreateAck) {
			// Other messages are handled in st != init (used for compacting the
			// code)
			if (!(sig.equals(ROLE_REMOVE_MSG) || sig.equals(ROLE_RELEASE_MSG) || sig.equals(ROLE_PLAY_ENDED_MSG)
					|| sig.equals(SET_ACTOR_TRACE_MSG) || sig.equals(REPORT_REQUEST_MSG)
					|| sig.equals(REPORT_RESPONS_MSG) || sig.equals(ACTOR_REPORT_TIMER_MSG))) {
				// save the message until other state is reached.
				save(sig, curfsm);
				sameState(curfsm);
				return;
			}
		}

		// Common for all states except specified, that equal to "all, but"
		// concept for this state machine
		if (st != init) {
			if (sig.equals(ROLE_REQUEST_MSG)) {
				AFPropertyMsg rrm = (AFPropertyMsg) sig;
				String roleType = (String) rrm.getProperty(ActorAddress.ROLE_TYPE);
				String roleId = (String) rrm.getProperty(ActorAddress.ROLE_ID);
				PartSpec partSpec = curfsm.findRoleSpec(roleType, curfsm.actorSpec.getPartDesc());
				if (partSpec == null) {
					sendRoleDeniedMsg(rrm, curfsm, RoleError.ROLE_TYPE_NOT_CONTAINABLE);
					sameState(curfsm);
					return;
				}
				if (partSpec.isCredentialsRequired()) {
					if (!curfsm.validateCredentials(rrm)) {
						sendRoleDeniedMsg(rrm, curfsm, RoleError.NOT_AUTHORIZED);
						sameState(curfsm);
						return;
					}
				}

				AFPropertyMsg msg = createRolePlayMsg(rrm, partSpec, curfsm);

				// RolePlayMsg rpm = new RolePlayMsg(rrm, p.getPortNames(),
				// p.getActorDomain(), p.getRoleClassName());
				Vector v = curfsm.context.getChildrenRoles((String) rrm.getProperty(ROLE_REQUEST_MSG_ROLE_TYPE)); // v
				// >
				// 0
				// ->
				// children
				// roles
				// exists
				// of
				// right
				// type

				if (roleId != null && !roleId.equals("") || v.isEmpty()) {
					// ActorId is specified and children roles may exists
					String contextId = curfsm.getContextString();
					if (roleId != null && !roleId.equals("")) {
						contextId += roleId;
					} else {
						// lowercase first.
						String id = roleType.substring(0, 1).toLowerCase() + roleType.substring(1);
						contextId += id + StateMachine.UNIQ_ID++ + "Set" + partSpec.getSetNo();
					}
					ActorAddress aa = curfsm.context.getChildrenRole(contextId);
					if (aa != null) {
						// The requested role actor exists
						curfsm.sendMessage(msg, aa); // Send RolePlay message to
						// the existing actor
					} else if (curfsm.checkMaxLimit(partSpec)) {
						// new actor roles are allowed to be created
						ActorAddress newaa = new ActorAddress(contextId, roleType);

						/*
						 * if (aa.getActorDomain() == null &&
						 * curfsm.getContainer() != null) {
						 * aa.setActorDomain(curfsm
						 * .getContainer().getDomainName()); }
						 */
						if (curfsm.getContainer() != null) {
							newaa.setActorDomain(curfsm.getScheduler().getSchedulerData().getActorDomainName());
						}
						// todo check this Geir 9.11.2008 ask Morten, Knut Eilif
						// Husa, Tellu As
						/*
						 * ActorAddress a = partSpec.getActorDomain(); if (a !=
						 * null) newaa.setActorDomain(a.getActorID());
						 */
						curfsm.sendMessage(msg, newaa);
						curfsm.context.addChildrenRole(newaa);
					} else {
						// not allowed to be created
						sendRoleDeniedMsg(rrm, curfsm, RoleError.ACTOR_CONTAINING_CARDINALITY_EXCEEDED);
					}
					sameState(curfsm);
					return;
				} else {
					// assign a random (first in the vector) actor role
					curfsm.sendMessage(msg, (ActorAddress) v.firstElement()); // return
					// the
					// first
					// one
					// //etogme
					// 18.12.2003
					sameState(curfsm);
					return;
				}
				// } else if (sig instanceof RoleConfirmMsg) {
			} else if (sig.equals(ROLE_CONFIRM_MSG)) {
				// RoleConfirmMsg rcm = (RoleConfirmMsg) sig;
				AFPropertyMsg rrm = (AFPropertyMsg) sig.getProperty(ROLE_CONFIRM_RRM);
				curfsm.context.addRequestedRole(rrm.getSenderRole().getActorID(), sig.getSenderRole());
				sameState(curfsm);
				return;
			} else if (sig.equals(ROLE_CREATE_MSG)) {
				sameState(curfsm);
				return;
				// } else if (sig instanceof RolePlayNackMsg) {
			} else if (sig.equals(ROLE_PLAY_NACK_MSG)) {
				// RolePlayNackMsg rpnm = (RolePlayNackMsg) sig;
				curfsm.context.remove(sig.getSenderRole());
				if (curfsm.removeIfPossible()) {
					performExit(curfsm);
					curfsm.setReadyToBeDeleted(); // delete this instance when
					// transition is finished
					stopPlaying(curfsm);
					if (curfsm.isVisible()) {
						curfsm.stopTimer(ROUTER_UPDATE_INTERVAL_ID);
					}
					nextState(init, curfsm);
					return;
				}
				AFPropertyMsg rrm = (AFPropertyMsg) sig.getProperty(ROLE_REQUEST_MSG);
				// sends role denied message to original role requestor
				AFPropertyMsg m = new AFPropertyMsg(ROLE_DENIED_MSG, true);
				m.setProperty(ROLE_REQUEST_MSG, rrm);
				m.setInt("reasonCode", RoleError.ROLE_TYPE_CREATION_ERROR);
				curfsm.sendMessage(m, rrm.getSenderRole());
				// curfsm.sendMessage(new RoleDeniedMsg(rrm,
				// RoleError.ROLE_TYPE_CREATION_ERROR),
				// sig.rrm.getSenderRole());
				sameState(curfsm);
				return;
				// } else if (sig instanceof RoleCreateAckMsg) {
			} else if (sig.equals(ROLE_CREATE_ACK_MSG)) {
				// RoleCreateAckMsg am = (RoleCreateAckMsg) sig;
				// sig.getSenderRole().setActorDomain(curfsm.getContainer().getDomainName());
				curfsm.context.addChildrenRole(sig.getSenderRole());
				sameState(curfsm);
				return;
				// } else if (sig instanceof RoleCreateNackMsg) {
			} else if (sig.equals(ROLE_CREATE_NACK_MSG)) {
				// RoleCreateNackMsg am = (RoleCreateNackMsg) sig;
				curfsm.trace.traceError("Actor creation error: " + sig.getSenderRole());
				sameState(curfsm);
				return;
				// } else if (sig instanceof RoleReleaseMsg) {
			} else if (sig.equals(ROLE_RELEASE_MSG)) {
				// RoleReleaseMsg rrm = (RoleReleaseMsg) sig;
				curfsm.context.remove(sig.getSenderRole());
				if (curfsm.removeIfPossible()) {
					performExit(curfsm);
					curfsm.setReadyToBeDeleted(); // delete this instance when
					// transition is finished
					stopPlaying(curfsm);
					if (curfsm.isVisible()) {
						curfsm.stopTimer(ROUTER_UPDATE_INTERVAL_ID);
					}
					nextState(init, curfsm);
					return;
				}
				sameState(curfsm);
				return;
				// } else if (sig instanceof RolePlayEndedMsg) {
			} else if (sig.equals(ROLE_PLAY_ENDED_MSG)) {
				// RolePlayEndedMsg rpem = (RolePlayEndedMsg) sig;
				curfsm.context.remove(sig.getSenderRole());
				if (curfsm.removeIfPossible()) {
					performExit(curfsm);
					curfsm.setReadyToBeDeleted(); // delete this instance when
					// transition is finished
					stopPlaying(curfsm);
					if (curfsm.isVisible()) {
						curfsm.stopTimer(ROUTER_UPDATE_INTERVAL_ID);
					}
					nextState(init, curfsm);
					return;
				}
				sameState(curfsm);
				return;

				// } else if (sig instanceof RoleDeniedMsg) {
			} else if (sig.equals(ROLE_DENIED_MSG)) {
				// todo should this transition be deleted
				sameState(curfsm);
				return;
				// } else if (sig instanceof RolePlayMsg) {
			} else if (sig.equals(ROLE_PLAY_MSG)) {
				// sends RoleConfirm to the requestor, and RolePlayAck to the
				// senderAddress of RolePlay
				ActorAddress requestorId = sendResponsToRequestor(curfsm, ROLE_CONFIRM_MSG);
				curfsm.context.addRequestorRole(requestorId.getActorID(), requestorId);
				curfsm.sendMessage(new AFPropertyMsg(ROLE_PLAY_ACK_MSG, true), sig.getSenderRole());
				/*
				 * RoleConfirmMsg rcm = new
				 * RoleConfirmMsg(rpm.getRoleRequestMsg());
				 * rcm.setReceiverRole(rpm.getRoleRequestMsg().getSenderRole());
				 * curfsm.sendMessage(rcm); curfsm.sendMessage(new
				 * RolePlayAckMsg(), rpm.getSenderRole());
				 */
				sameState(curfsm);
				return;
				// } else if (sig instanceof RoleResetMsg) {
			}

			/**
			 * The role is reset. All associations are cleareddddd
			 */
			else if (sig.equals(ROLE_RESET_MSG)) {
				curfsm.releaseAllAssociations(); // send RoleReleaseMsg to all
				// associations which
				// involves this actor
				curfsm.releaseChildren(); // send RoleReset to all children
				// enter idle state, or the same state
				if (curfsm.context.isEmpty()) {
					performExit(curfsm);
					if (curfsm.isVisible()) {
						curfsm.stopTimer(ROUTER_UPDATE_INTERVAL_ID);
					}
					nextState(init, curfsm);
				} else {
					sameState(curfsm);
				}
				return;
				// } else if (sig instanceof RoleRemoveMsg) {
			} else if (sig.equals(ROLE_REMOVE_MSG)) {
				curfsm.releaseAllAssociations(); // send RoleReleaseMsg to all
				// associations which
				// involves this actor
				curfsm.setPersistent(false); // Used when actor received
				// RoleRemoveMsg to force
				// deletion of actor
				curfsm.context.removeAll(curfsm.context.getRequestedRoles()); // remove
				// from
				// context
				curfsm.context.removeAll(curfsm.context.getRequestorRoles()); // remove
				// from
				// context

				Vector v = curfsm.context.getChildrenRoles();
				if (v != null) {
					curfsm.sendMessage(sig.getCopy(curfsm.getScheduler().getClassLoader()), curfsm.context
							.getChildrenRoles()); // included persistentSession
					// children
				}

				if (curfsm.removeIfPossible()) {
					performExit(curfsm);
					curfsm.setReadyToBeDeleted(); // delete this instance when
					// transition is finished
					stopPlaying(curfsm);
					if (curfsm.isVisible()) {
						curfsm.scheduler.unRegVisibleActor(curfsm.getMyActorAddress());
						curfsm.stopTimer(ROUTER_UPDATE_INTERVAL_ID);
					}
					nextState(init, curfsm);
				} else {
					sameState(curfsm);
				}
				return;
				// } else if (sig instanceof RoleCreateMsg) {
			} else if (sig.equals(ROLE_CREATE_MSG)) {
				// RoleCreateMsg rcm = (RoleCreateMsg) sig;
				curfsm.trace.traceError("ActorCS: Instance already created");
				// curfsm.sendMessage(new RoleCreateNackMsg(),
				// rcm.getSenderRole());
				curfsm.sendMessage(new AFPropertyMsg(ROLE_CREATE_NACK_MSG, true), sig.getSenderRole());
				sameState(curfsm);
				return;
				// } else if (sig instanceof SetActorTraceMsg) {
			} else if (sig.equals(START_PLAYING_MSG)) {
				curfsm.routerUpdate();
				return;
				// } else if (sig instanceof DeleteActorMsg) {
			} else if (sig.equals(ROUTER_UPDATE_TIMER_MSG)) {
				curfsm.routerUpdate();
				return;
				// } else if (sig.equals(AFConstants.START_PLAYING_MSG)) {
			}
		}
		// code that implements management functionality for all actors. This
		// includes adding and deleting children.
		// The actor type has to be specified in the PartSpec specified with
		// Actor descriptor files or set in the
		// initInstance() method. These functions are only valid in user-defined
		// states, which means that they
		// are saved in all actor specific states.
		if (st == init && st == waitCreateAck) {
			// in actor specific states, save all management messages
			if (sig.equals(DELETE_ACTOR_MSG) || sig.equals(ADD_ACTOR_MSG)) {
				save(sig, curfsm);
				return;
			}

		}

		// All state

		/**
		 * Soft restart of the role. No assosiations are kept. Default behavior
		 * is to set the state machine in idle state. The application shpould
		 * respond with actions such as the client will behavour like starting
		 * the application again.
		 */
		if (sig.equals(ROLE_RESTART_MSG)) {
			performExit();
			sendMessage(ROLE_RESTART_MSG, curfsm.getContext().getChildrenRoles());
			traceTask("Role is reset");

			sendMessage(START_PLAYING_MSG, getMyActorAddress());

			nextState(idle);
			return;
		}

		/**
		 * This a message to check whether a role is active or not
		 */
		if (sig.equals(AFConstants.ARE_YOU_THERE)) {
			sendMessage(AFConstants.YES_I_AM, sig.getSenderRole());
			sameState();
			return;
		}

		if (sig.equals(REPORT_REQUEST_MSG)) {
			transReportRequest(curfsm, sig);
			sameState(curfsm);
			return;
		} else if (sig.equals(REPORT_RESPONS_MSG)) {
			transReportRespond(curfsm, sig);
			sameState(curfsm);
			return;
		} else if (sig.equals(ACTOR_REPORT_TIMER_MSG)) {
			// time out, some actors have not responded
			if (curfsm.noOfRRMessages > 0) {
				curfsm.context.actorReport.status = writeStatus(curfsm);
				curfsm.trace.traceWarning(curfsm.context.actorReport.status);
				curfsm.sendMessage(new AFPropertyMsg(REPORT_RESPONS_MSG, true).setProperty(ACTOR_REPORT_PROP,
						curfsm.context.actorReport), curfsm.senderOfReportRequest);
			}

			sameState(curfsm);

			return;
		}

	}

	private String writeStatus(StateMachine asm) {
		String s = null;

		if (asm.noOfRRMessages > 0) {
			s = "\n" + "Actor: " + asm.getMyActorAddress() + " - " + asm.noOfRRMessages + " - children of actor: "
					+ asm.getMyActorAddress() + " has not responded";
		}

		return s;
	}

	protected AFPropertyMsg createRolePlayMsg(AFPropertyMsg rrm, PartSpec p, StateMachine curfsm) {
		AFPropertyMsg msg = new AFPropertyMsg(ROLE_PLAY_MSG, true);
		msg.setProperty(ROLE_PLAY_MSG_RRM, rrm);
		msg.setProperty(ROLE_PLAY_MSG_PORTS, curfsm.getApplicationSpec().getActorSpec(p.getRoleType()).getPortNames());
		msg.setProperty(ROLE_PLAY_MSG_TARGET_ACTOR, p.getActorDomain());
		msg.setProperty(ROLE_PLAY_MSG_CONNECTORS, curfsm.actorSpec.getConnectorDesc(p.getRoleType(), null));
		msg.setBoolean(ROLE_PLAY_MSG_VISIBLE, p.isVisible());
		msg.setInt(TRACE_LEVEL_PROP, p.getTraceLev());
		return msg;
	}

	protected void sendRoleDeniedMsg(AFPropertyMsg rrm, StateMachine curfsm, int reasonCode) {
		AFPropertyMsg m = new AFPropertyMsg(ROLE_DENIED_MSG, true);
		m.setInt("reasonCode", reasonCode);
		m.setProperty("rrm", rrm);
		curfsm.sendMessage(m, rrm.getSenderRole());
	}

	protected ActorAddress sendResponsToRequestor(StateMachine curfsm, String msgType) {
		AFPropertyMsg rpm = (AFPropertyMsg) curfsm.context.getRootPlayMsg();
		if (rpm != null) {
			// root for the RolePlayMsg
			AFPropertyMsg rrm = (AFPropertyMsg) rpm.getProperty("rrm");
			AFPropertyMsg m = new AFPropertyMsg(msgType, true);
			m.setProperty("rrm", rrm);
			curfsm.sendMessage(m, rrm.getSenderRole());
			return rrm.getSenderRole();
			// curfsm.sendMessage(new RolePlayNackMsg(rpm.getRoleRequestMsg()),
			// rpm.getSenderRole());
		}
		return null;
	}

	/**
	 * Executes the common transition to start chatting -- with the nec.
	 * acknowlegdements. If the state machine contains roles, the startplaying
	 * msg is also send to the roles.
	 * 
	 * @param curfsm
	 * @param nxtState
	 *            State to transition to.
	 */
	protected void transStartPlaying(StateMachine curfsm, State nxtState) {
		performExit(curfsm);
		// root for creating inner parts
		sendResponsToRequestor(curfsm, ROLE_CONFIRM_MSG);

		AFPropertyMsg msg = new AFPropertyMsg(START_PLAYING_MSG, true);

		ActorSpec aspec = curfsm.getApplicationSpec().getActorSpec(curfsm.context.getParentAddress().getActorType());
		if (aspec != null) {
			PartSpec spec = aspec.getPartSpec(curfsm.myActorType);
			if (spec instanceof ActorPartSpec) {
				ActorPartSpec apspec = (ActorPartSpec) spec;
				String myRoleName = curfsm.myActorId.substring(curfsm.myActorId.lastIndexOf('/') + 1);
				String[] roleNames = spec.getRoleNames();
				Hashtable properties = null;
				if (apspec.getActorProperties() != null) {
					properties = (Hashtable) apspec.getActorProperties().get("default");
					if (properties != null)
						msg.setProperties(properties);
				}
				for (int i = 0; i < roleNames.length; i++) {
					if (roleNames[i].equals(myRoleName)) {
						if (apspec.getActorProperties() != null) {
							Hashtable props = (Hashtable) apspec.getActorProperties().get(myRoleName);
							if (props != null) {
								if (properties != null) {
									Enumeration en = properties.keys();
									while (en.hasMoreElements()) {
										Object o = en.nextElement();
										if (props.get(o) == null) {
											props.put(o, properties.get(o));
										}
									}
								}
								msg.setProperties(props);
							} else if (properties != null) {
								msg.setProperties(properties);
							}

						}
						// break;
					}
				}
			}
		}

		ActorAddress reciever = curfsm.getMyActorAddress();

		Enumeration en = curfsm.getStateMachines().keys();

		while (en.hasMoreElements()) {
			String actorId = (String) en.nextElement();
			CompositeState cs = (CompositeState) curfsm.getCurrentStates().get(actorId);
			if (cs != null) {
				// Asume that this is the main state machine
				curfsm.sendMessage(msg, reciever);
				nextState(nxtState, curfsm);
			}
		}

		en = curfsm.getStateMachines().keys();
		while (en.hasMoreElements()) {
			String actorId = (String) en.nextElement();
			CompositeState cs = (CompositeState) curfsm.getCurrentStates().get(actorId);
			if (cs == null) {
				// Asume that this is a role
				actorId = curfsm.getMyActorAddress().getActorID() + "." + actorId;
				reciever.setActorID(actorId);
				curfsm.sendMessage(msg.cloneAFPropertyMsg(curfsm.getContainer()), reciever); // send
				// start
				// idle
				// msg
				// to
				// self
			}
		}

		startPlaying(curfsm);
		curfsm.context.setRootPlayMsg(null);

	}

	/**
	 * Check if a state is in the States as defined by generic actor behavior
	 * sm.
	 * 
	 * @param st
	 *            State to check.
	 * @return true iff the state is part of the generic actor behavior sm.
	 */
	protected boolean isStateIsInSuper(State st) {
		return (st == init || st == waitCreateAck);
	}

	protected void sendRolePlayNackMsg(StateMachine curfsm) {
		AFPropertyMsg rpm = (AFPropertyMsg) curfsm.context.getRootPlayMsg();
		if (rpm != null) {
			// root for the RolePlayMsg
			// curfsm.sendMessage(new RolePlayNackMsg(rpm.getRoleRequestMsg()),
			// rpm.getSenderRole());
			AFPropertyMsg msg = new AFPropertyMsg(ROLE_PLAY_NACK_MSG, true);
			msg.setProperty(ROLE_REQUEST_MSG, rpm.getProperty(ROLE_REQUEST_MSG));
			curfsm.sendMessage(msg, rpm.getSenderRole());
		}
	}

	protected void transReportRequest(StateMachine asm, ActorMsg sig) {
		AFPropertyMsg rrmsg = (AFPropertyMsg) sig;
		asm.senderOfReportRequest = rrmsg.getSenderRole();
		asm.noOfRRMessages = asm.context.getChildrenRoles().size(); // initial
		// value
		asm.context.actorReport = new ActorReport();
		asm.context.actorReport.myId = asm.context.getActorAddress();
		asm.context.actorReport.myParrentId = asm.context.getParentAddress();
		asm.context.actorReport.myState = asm.getCurrentState().getFullStateName();
		asm.context.actorReport.RequestType = rrmsg.getString(REQUEST_TYPE_PROP);
		asm.context.actorReport.myStateData = asm.printStateData(); // state
		// data
		asm.context.actorReport.myRequestedRoles = asm.context.getRequestedRoles();
		asm.context.actorReport.yourRequestedRoles = asm.context.getRequestorRoles();
		asm.context.actorReport.active = asm.isPersistent(); // todo check this
		// one
		asm.context.actorReport.traceLevel = asm.getTraceLevel();
		asm.context.actorReport.myRoles = null;
		asm.context.actorReport.status = null;
		asm.context.actorReport.ports = asm.ports;
		if (asm.context.getActorProperties() != null)
			asm.context.actorReport.setMyProperties(asm.context.getActorProperties());

		if ((asm.noOfRRMessages == 0) || rrmsg.getString(REQUEST_TYPE_PROP).equals("this")) {
			asm.sendMessage(new AFPropertyMsg(REPORT_RESPONS_MSG, true).setProperty(ACTOR_REPORT_PROP,
					asm.context.actorReport), asm.senderOfReportRequest);
			asm.context.actorReport = null;
		} else if (rrmsg.getString(REQUEST_TYPE_PROP).equals("all")) {
			asm.sendMessage(new AFPropertyMsg(REPORT_REQUEST_MSG, true).setProperty(REQUEST_TYPE_PROP, rrmsg
					.getString(REQUEST_TYPE_PROP)), asm.context.getChildrenRoles());
			asm.startTimer(ActorSM.ACTOR_REPORT_TIMEOUT, ActorSM.ACTOR_REPORT_TIMER);
		} else if (rrmsg.getString(REQUEST_TYPE_PROP).equals("this")) {
			asm.sendMessage(new AFPropertyMsg(REPORT_RESPONS_MSG, true).setProperty(ACTOR_REPORT_PROP,
					asm.context.actorReport), asm.senderOfReportRequest);
			asm.context.actorReport = null;
		}
	}

	private void transReportRespond(StateMachine asm, ActorMsg sig) {
		AFPropertyMsg rrmsg = (AFPropertyMsg) sig;
		asm.context.actorReport.myChildren.addElement(rrmsg.getProperty(ACTOR_REPORT_PROP));
		asm.noOfRRMessages = asm.noOfRRMessages - 1;

		if (asm.noOfRRMessages <= 0) {
			asm.sendMessage(new AFPropertyMsg(REPORT_RESPONS_MSG, true).setProperty(ACTOR_REPORT_PROP,
					asm.context.actorReport), asm.senderOfReportRequest);
			asm.stopTimer(ActorSM.ACTOR_REPORT_TIMER);
		}
	}

	/**
	 * Creates a Role Request message
	 * 
	 * @param actorid
	 *            the instance id of the new actor, may be null
	 * @param actorType
	 *            is the type of actor
	 * @return the property message
	 */
	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;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy