Coverage Report - org.apache.commons.scxml.env.SimpleScheduler

Classes in this File Line Coverage Branch Coverage Complexity
SimpleScheduler
0% 
0% 
2.875

 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.scxml.env;
 18  
 
 19  
 import java.io.Serializable;
 20  
 import java.util.Collections;
 21  
 import java.util.HashMap;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 import java.util.Timer;
 25  
 import java.util.TimerTask;
 26  
 
 27  
 import org.apache.commons.logging.Log;
 28  
 import org.apache.commons.logging.LogFactory;
 29  
 import org.apache.commons.scxml.EventDispatcher;
 30  
 import org.apache.commons.scxml.SCXMLExecutor;
 31  
 import org.apache.commons.scxml.SCXMLHelper;
 32  
 import org.apache.commons.scxml.TriggerEvent;
 33  
 import org.apache.commons.scxml.model.ModelException;
 34  
 
 35  
 /**
 36  
  * <p>EventDispatcher implementation that can schedule <code>delay</code>ed
 37  
  * &lt;send&gt; events for the &quot;scxml&quot; <code>targettype</code>
 38  
  * attribute value (which is also the default). This implementation uses
 39  
  * J2SE <code>Timer</code>s.</p>
 40  
  *
 41  
  * <p>No other <code>targettype</code>s are processed. Subclasses may support
 42  
  * additional <code>targettype</code>s by overriding the
 43  
  * <code>send(...)</code> and <code>cancel(...)</code> methods and
 44  
  * delegating to their <code>super</code> counterparts for the
 45  
  * &quot;scxml&quot; <code>targettype</code>.</p>
 46  
  *
 47  
  */
 48  0
 public class SimpleScheduler implements EventDispatcher, Serializable {
 49  
 
 50  
     /** Serial version UID. */
 51  
     private static final long serialVersionUID = 1L;
 52  
 
 53  
     /** Log instance. */
 54  0
     private Log log = LogFactory.getLog(SimpleScheduler.class);
 55  
 
 56  
     /**
 57  
      * The <code>Map</code> of active <code>Timer</code>s, keyed by
 58  
      * &lt;send&gt; element <code>id</code>s.
 59  
      */
 60  
     private Map timers;
 61  
 
 62  
     /**
 63  
      * The state chart execution instance we schedule events for.
 64  
      */
 65  
     private SCXMLExecutor executor;
 66  
 
 67  
     /**
 68  
      * Constructor.
 69  
      *
 70  
      * @param executor The owning {@link SCXMLExecutor} instance.
 71  
      */
 72  
     public SimpleScheduler(final SCXMLExecutor executor) {
 73  0
         super();
 74  0
         this.executor = executor;
 75  0
         this.timers = Collections.synchronizedMap(new HashMap());
 76  0
     }
 77  
 
 78  
     /**
 79  
      * @see EventDispatcher#cancel(String)
 80  
      */
 81  
     public void cancel(final String sendId) {
 82  
         // Log callback
 83  0
         if (log.isInfoEnabled()) {
 84  0
             log.info("cancel( sendId: " + sendId + ")");
 85  
         }
 86  0
         if (!timers.containsKey(sendId)) {
 87  0
             return; // done, we don't track this one or its already expired
 88  
         }
 89  0
         Timer timer = (Timer) timers.get(sendId);
 90  0
         if (timer != null) {
 91  0
             timer.cancel();
 92  0
             if (log.isDebugEnabled()) {
 93  0
                 log.debug("Cancelled event scheduled by <send> with id '"
 94  
                     + sendId + "'");
 95  
             }
 96  
         }
 97  0
         timers.remove(sendId);
 98  0
     }
 99  
 
 100  
     /**
 101  
     @see EventDispatcher#send(String,String,String,String,Map,Object,long,List)
 102  
      */
 103  
     public void send(final String sendId, final String target,
 104  
             final String targettype, final String event, final Map params,
 105  
             final Object hints, final long delay, final List externalNodes) {
 106  
         // Log callback
 107  0
         if (log.isInfoEnabled()) {
 108  0
             StringBuffer buf = new StringBuffer();
 109  0
             buf.append("send ( sendId: ").append(sendId);
 110  0
             buf.append(", target: ").append(target);
 111  0
             buf.append(", targetType: ").append(targettype);
 112  0
             buf.append(", event: ").append(event);
 113  0
             buf.append(", params: ").append(String.valueOf(params));
 114  0
             buf.append(", hints: ").append(String.valueOf(hints));
 115  0
             buf.append(", delay: ").append(delay);
 116  0
             buf.append(')');
 117  0
             log.info(buf.toString());
 118  
         }
 119  
 
 120  
         // We only handle the "scxml" targettype (which is the default too)
 121  0
         if (SCXMLHelper.isStringEmpty(targettype)
 122  
                 || targettype.trim().equalsIgnoreCase(TARGETTYPE_SCXML)) {
 123  
 
 124  0
             if (!SCXMLHelper.isStringEmpty(target)) {
 125  
                 // We know of no other target
 126  0
                 if (log.isWarnEnabled()) {
 127  0
                     log.warn("<send>: Unavailable target - " + target);
 128  
                 }
 129  
                 try {
 130  0
                     this.executor.triggerEvent(new TriggerEvent(
 131  
                         EVENT_ERR_SEND_TARGETUNAVAILABLE,
 132  
                         TriggerEvent.ERROR_EVENT));
 133  0
                 } catch (ModelException me) {
 134  0
                     log.error(me.getMessage(), me);
 135  0
                 }
 136  0
                 return; // done
 137  
             }
 138  
 
 139  0
             if (delay > 0L) {
 140  
                 // Need to schedule this one
 141  0
                 Timer timer = new Timer(true);
 142  0
                 timer.schedule(new DelayedEventTask(sendId, event), delay);
 143  0
                 timers.put(sendId, timer);
 144  0
                 if (log.isDebugEnabled()) {
 145  0
                     log.debug("Scheduled event '" + event + "' with delay "
 146  
                         + delay + "ms, as specified by <send> with id '"
 147  
                         + sendId + "'");
 148  
                 }
 149  
             }
 150  
             // else short-circuited by Send#execute()
 151  
             // TODO: Pass through in v1.0
 152  
 
 153  
         }
 154  
 
 155  0
     }
 156  
 
 157  
     /**
 158  
      * Get the log instance.
 159  
      *
 160  
      * @return The current log instance
 161  
      */
 162  
     protected Log getLog() {
 163  0
         return log;
 164  
     }
 165  
 
 166  
     /**
 167  
      * Get the current timers.
 168  
      *
 169  
      * @return The currently scheduled timers
 170  
      */
 171  
     protected Map getTimers() {
 172  0
         return timers;
 173  
     }
 174  
 
 175  
     /**
 176  
      * Get the executor we're attached to.
 177  
      *
 178  
      * @return The owning executor instance
 179  
      */
 180  
     protected SCXMLExecutor getExecutor() {
 181  0
         return executor;
 182  
     }
 183  
 
 184  
     /**
 185  
      * TimerTask implementation.
 186  
      */
 187  
     class DelayedEventTask extends TimerTask {
 188  
 
 189  
         /**
 190  
          * The ID of the &lt;send&gt; element.
 191  
          */
 192  
         private String sendId;
 193  
 
 194  
         /**
 195  
          * The event name.
 196  
          */
 197  
         private String event;
 198  
 
 199  
         /**
 200  
          * Constructor.
 201  
          *
 202  
          * @param sendId The ID of the send element.
 203  
          * @param event The name of the event to be triggered.
 204  
          */
 205  0
         DelayedEventTask(final String sendId, final String event) {
 206  0
             super();
 207  0
             this.sendId = sendId;
 208  0
             this.event = event;
 209  0
         }
 210  
 
 211  
         /**
 212  
          * What to do when timer expires.
 213  
          */
 214  
         public void run() {
 215  
             try {
 216  0
                 executor.triggerEvent(new TriggerEvent(event,
 217  
                     TriggerEvent.SIGNAL_EVENT));
 218  0
             } catch (ModelException me) {
 219  0
                 log.error(me.getMessage(), me);
 220  0
             }
 221  0
             timers.remove(sendId);
 222  0
             if (log.isDebugEnabled()) {
 223  0
                 log.debug("Fired event '" + event + "' as scheduled by "
 224  
                     + "<send> with id '" + sendId + "'");
 225  
             }
 226  0
         }
 227  
 
 228  
     }
 229  
 
 230  
     /**
 231  
      * The default targettype.
 232  
      */
 233  
     private static final String TARGETTYPE_SCXML = "scxml";
 234  
 
 235  
     /**
 236  
      * The spec mandated derived event when target cannot be reached.
 237  
      */
 238  
     private static final String EVENT_ERR_SEND_TARGETUNAVAILABLE =
 239  
         "error.send.targetunavailable";
 240  
 
 241  
 }
 242