You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by ra...@apache.org on 2006/10/17 19:07:56 UTC
svn commit: r464965 - in
/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml:
env/SimpleScheduler.java model/Send.java test/StandaloneUtils.java
Author: rahul
Date: Tue Oct 17 10:07:55 2006
New Revision: 464965
URL: http://svn.apache.org/viewvc?view=rev&rev=464965
Log:
Provide a new EventDispatcher implementation (SimpleScheduler) that provides the ability to deal with delayed events of the "scxml" <send> targettype. The delay attribute now supports the following suffixes (ms-milliseconds, s-seconds, m-minutes; the default being milliseconds).
SCXML-21
Added:
jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java (with props)
Modified:
jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Send.java
jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java
Added: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java?view=auto&rev=464965
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java (added)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java Tue Oct 17 10:07:55 2006
@@ -0,0 +1,239 @@
+/*
+ * 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.commons.scxml.env;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.scxml.EventDispatcher;
+import org.apache.commons.scxml.SCXMLExecutor;
+import org.apache.commons.scxml.SCXMLHelper;
+import org.apache.commons.scxml.TriggerEvent;
+import org.apache.commons.scxml.model.ModelException;
+
+/**
+ * <p>EventDispatcher implementation that can schedule <code>delay</code>ed
+ * <send> events for the "scxml" <code>targettype</code>
+ * attribute value (which is also the default). This implementation uses
+ * J2SE <code>Timer</code>s.</p>
+ *
+ * <p>No other <code>targettype</code>s are processed. Subclasses may support
+ * additional <code>targettype</code>s by overriding the
+ * <code>send(...)</code> and <code>cancel(...)</code> methods and
+ * delegating to their <code>super</code> counterparts for the
+ * "scxml" <code>targettype</code>.</p>
+ *
+ */
+public class SimpleScheduler implements EventDispatcher, Serializable {
+
+ /** Log instance. */
+ private Log log = LogFactory.getLog(SimpleScheduler.class);
+
+ /**
+ * The <code>Map</code> of active <code>Timer</code>s, keyed by
+ * <send> element <code>id</code>s.
+ */
+ private Map timers;
+
+ /**
+ * The state chart execution instance we schedule events for.
+ */
+ private SCXMLExecutor executor;
+
+ /**
+ * Constructor.
+ *
+ * @param executor The owning {@link SCXMLExecutor} instance.
+ */
+ public SimpleScheduler(final SCXMLExecutor executor) {
+ super();
+ this.executor = executor;
+ this.timers = Collections.synchronizedMap(new HashMap());
+ }
+
+ /**
+ * @see EventDispatcher#cancel(String)
+ */
+ public void cancel(final String sendId) {
+ // Log callback
+ if (log.isInfoEnabled()) {
+ log.info("cancel( sendId: " + sendId + ")");
+ }
+ if (!timers.containsKey(sendId)) {
+ return; // done, we don't track this one or its already expired
+ }
+ Timer timer = (Timer) timers.get(sendId);
+ if (timer != null) {
+ timer.cancel();
+ if (log.isDebugEnabled()) {
+ log.debug("Cancelled event scheduled by <send> with id '"
+ + sendId + "'");
+ }
+ }
+ timers.remove(sendId);
+ }
+
+ /**
+ @see EventDispatcher#send(String,String,String,String,Map,Object,long,List)
+ */
+ public void send(final String sendId, final String target,
+ final String targettype, final String event, final Map params,
+ final Object hints, final long delay, final List externalNodes) {
+ // Log callback
+ if (log.isInfoEnabled()) {
+ StringBuffer buf = new StringBuffer();
+ buf.append("send ( sendId: ").append(sendId);
+ buf.append(", target: ").append(target);
+ buf.append(", targetType: ").append(targettype);
+ buf.append(", event: ").append(event);
+ buf.append(", params: ").append(String.valueOf(params));
+ buf.append(", hints: ").append(String.valueOf(hints));
+ buf.append(", delay: ").append(delay);
+ buf.append(')');
+ log.info(buf.toString());
+ }
+
+ // We only handle the "scxml" targettype (which is the default too)
+ if (SCXMLHelper.isStringEmpty(targettype)
+ || targettype.trim().equalsIgnoreCase(TARGETTYPE_SCXML)) {
+
+ if (!SCXMLHelper.isStringEmpty(target)) {
+ // We know of no other target
+ if (log.isWarnEnabled()) {
+ log.warn("<send>: Unavailable target - " + target);
+ }
+ try {
+ this.executor.triggerEvent(new TriggerEvent(
+ EVENT_ERR_SEND_TARGETUNAVAILABLE,
+ TriggerEvent.ERROR_EVENT));
+ } catch (ModelException me) {
+ log.error(me.getMessage(), me);
+ }
+ return; // done
+ }
+
+ if (delay > 0L) {
+ // Need to schedule this one
+ Timer timer = new Timer(true);
+ timer.schedule(new DelayedEventTask(sendId, event), delay);
+ timers.put(sendId, timer);
+ if (log.isDebugEnabled()) {
+ log.debug("Scheduled event '" + event + "' with delay "
+ + delay + "ms, as specified by <send> with id '"
+ + sendId + "'");
+ }
+ }
+ // else short-circuited by Send#execute()
+ // TODO: Pass through in v1.0
+
+ }
+
+ }
+
+ /**
+ * Get the log instance.
+ *
+ * @return The current log instance
+ */
+ protected Log getLog() {
+ return log;
+ }
+
+ /**
+ * Get the current timers.
+ *
+ * @return The currently scheduled timers
+ */
+ protected Map getTimers() {
+ return timers;
+ }
+
+ /**
+ * Get the executor we're attached to.
+ *
+ * @return The owning executor instance
+ */
+ protected SCXMLExecutor getExecutor() {
+ return executor;
+ }
+
+ /**
+ * TimerTask implementation.
+ */
+ class DelayedEventTask extends TimerTask {
+
+ /**
+ * The ID of the <send> element.
+ */
+ private String sendId;
+
+ /**
+ * The event name.
+ */
+ private String event;
+
+ /**
+ * Constructor.
+ *
+ * @param sendId The ID of the send element.
+ * @param event The name of the event to be triggered.
+ */
+ DelayedEventTask(final String sendId, final String event) {
+ super();
+ this.sendId = sendId;
+ this.event = event;
+ }
+
+ /**
+ * What to do when timer expires.
+ */
+ public void run() {
+ try {
+ executor.triggerEvent(new TriggerEvent(event,
+ TriggerEvent.SIGNAL_EVENT));
+ } catch (ModelException me) {
+ log.error(me.getMessage(), me);
+ }
+ timers.remove(sendId);
+ if (log.isDebugEnabled()) {
+ log.debug("Fired event '" + event + "' as scheduled by "
+ + "<send> with id '" + sendId + "'");
+ }
+ }
+
+ }
+
+ /**
+ * The default targettype.
+ */
+ private static final String TARGETTYPE_SCXML = "scxml";
+
+ /**
+ * The spec mandated derived event when target cannot be reached.
+ */
+ private static final String EVENT_ERR_SEND_TARGETUNAVAILABLE =
+ "error.send.targetunavailable";
+
+}
+
Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/env/SimpleScheduler.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL
Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Send.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Send.java?view=diff&rev=464965&r1=464964&r2=464965
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Send.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/model/Send.java Tue Oct 17 10:07:55 2006
@@ -265,23 +265,7 @@
final ErrorReporter errRep, final SCInstance scInstance,
final Log appLog, final Collection derivedEvents)
throws ModelException, SCXMLExpressionException {
- // Lets see if we should handle it ourselves
- if (targettype != null && targettype.trim().toLowerCase().
- equals(TARGETTYPE_SCXML)) {
- if (SCXMLHelper.isStringEmpty(target)) {
- derivedEvents.add(new TriggerEvent(event,
- TriggerEvent.SIGNAL_EVENT));
- } else {
- // We know of no other
- appLog.warn("<send>: Unavailable target - " + target);
- derivedEvents.add(new TriggerEvent(
- EVENT_ERR_SEND_TARGETUNAVAILABLE,
- TriggerEvent.ERROR_EVENT));
- }
- // short-circuit the EventDispatcher
- return;
- }
- // Else, let the EventDispatcher take care of it
+ // Send attributes evaluation
State parentState = getParentState();
Context ctx = scInstance.getContext(parentState);
Evaluator eval = scInstance.getEvaluator();
@@ -304,18 +288,87 @@
params.put(varName, varObj);
}
}
+ long wait = parseDelay(appLog);
+ // Lets see if we should handle it ourselves
+ if (SCXMLHelper.isStringEmpty(targettype)
+ || targettype.trim().equalsIgnoreCase(TARGETTYPE_SCXML)) {
+ if (SCXMLHelper.isStringEmpty(target)) {
+ // TODO: Remove both short-circuit passes in v1.0
+ if (wait == 0L) {
+ derivedEvents.add(new TriggerEvent(event,
+ TriggerEvent.SIGNAL_EVENT));
+ return;
+ }
+ } else {
+ // We know of no other
+ appLog.warn("<send>: Unavailable target - " + target);
+ derivedEvents.add(new TriggerEvent(
+ EVENT_ERR_SEND_TARGETUNAVAILABLE,
+ TriggerEvent.ERROR_EVENT));
+ // short-circuit the EventDispatcher
+ return;
+ }
+ }
+ // Else, let the EventDispatcher take care of it
+ evtDispatcher.send(sendid, target, targettype, event, params,
+ hintsValue, wait, externalNodes);
+ }
+
+ /**
+ * Parse delay.
+ *
+ * @param appLog The application log
+ * @return The parsed delay in milliseconds
+ * @throws SCXMLExpressionException If the delay cannot be parsed
+ */
+ private long parseDelay(final Log appLog)
+ throws SCXMLExpressionException {
+
long wait = 0L;
- if (delay != null && delay.length() > 0) {
+ long multiplier = 1L;
+
+ if (!SCXMLHelper.isStringEmpty(delay)) {
+
+ String trimDelay = delay.trim();
+ String numericDelay = trimDelay;
+ if (trimDelay.endsWith(MILLIS)) {
+ numericDelay = trimDelay.substring(0, trimDelay.length() - 2);
+ } else if (trimDelay.endsWith(SECONDS)) {
+ multiplier = MILLIS_IN_A_SECOND;
+ numericDelay = trimDelay.substring(0, trimDelay.length() - 1);
+ } else if (trimDelay.endsWith(MINUTES)) {
+ multiplier = MILLIS_IN_A_MINUTE;
+ numericDelay = trimDelay.substring(0, trimDelay.length() - 1);
+ }
+
try {
- wait = Long.parseLong(delay.trim());
+ wait = Long.parseLong(numericDelay);
} catch (NumberFormatException nfe) {
- appLog.warn("Could not parse delay for <send>, "
- + "it will be treated as immediate", nfe);
+ appLog.error(nfe.getMessage(), nfe);
+ throw new SCXMLExpressionException(nfe.getMessage(), nfe);
}
+ wait *= multiplier;
+
}
- evtDispatcher.send(sendid, target, targettype, event, params,
- hintsValue, wait, externalNodes);
+
+ return wait;
+
}
+
+ /** The suffix in the delay string for milliseconds. */
+ private static final String MILLIS = "ms";
+
+ /** The suffix in the delay string for seconds. */
+ private static final String SECONDS = "s";
+
+ /** The suffix in the delay string for minutes. */
+ private static final String MINUTES = "m";
+
+ /** The number of milliseconds in a second. */
+ private static final long MILLIS_IN_A_SECOND = 1000L;
+
+ /** The number of milliseconds in a minute. */
+ private static final long MILLIS_IN_A_MINUTE = 60000L;
}
Modified: jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java?view=diff&rev=464965&r1=464964&r2=464965
==============================================================================
--- jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java (original)
+++ jakarta/commons/proper/scxml/trunk/src/main/java/org/apache/commons/scxml/test/StandaloneUtils.java Tue Oct 17 10:07:55 2006
@@ -29,7 +29,7 @@
import org.apache.commons.scxml.SCXMLExecutor;
import org.apache.commons.scxml.SCXMLHelper;
import org.apache.commons.scxml.TriggerEvent;
-import org.apache.commons.scxml.env.SimpleDispatcher;
+import org.apache.commons.scxml.env.SimpleScheduler;
import org.apache.commons.scxml.env.Tracer;
import org.apache.commons.scxml.invoke.SimpleSCXMLInvoker;
import org.apache.commons.scxml.io.SCXMLDigester;
@@ -75,7 +75,6 @@
try {
String documentURI = getCanonicalURI(uri);
Context rootCtx = evaluator.newContext(null);
- EventDispatcher ed = new SimpleDispatcher();
Tracer trc = new Tracer();
SCXML doc = SCXMLDigester.digest(new URL(documentURI), trc);
if (doc == null) {
@@ -84,11 +83,13 @@
System.exit(-1);
}
System.out.println(SCXMLSerializer.serialize(doc));
- SCXMLExecutor exec = new SCXMLExecutor(evaluator, ed, trc);
+ SCXMLExecutor exec = new SCXMLExecutor(evaluator, null, trc);
+ EventDispatcher ed = new SimpleScheduler(exec);
+ exec.setEventdispatcher(ed);
+ exec.setStateMachine(doc);
exec.addListener(doc, trc);
exec.registerInvokerClass("scxml", SimpleSCXMLInvoker.class);
exec.setRootContext(rootCtx);
- exec.setStateMachine(doc);
exec.go();
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org