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

Classes in this File | Line Coverage | Branch Coverage | Complexity
SimpleScheduler |
0% |
0% |
| 2.875;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 |  |