##### Coverage Report - org.apache.commons.scxml.SCInstance

Classes in this File | Line Coverage | Branch Coverage | Complexity
SCInstance |
86% |
100% |
| 1.619047619047619;1.619

1 |  |
     /*
2 |  |
      *
3 |  |
      *   Copyright 2006 The Apache Software Foundation.
4 |  |
      *
5 |  |
      *  Licensed under the Apache License, Version 2.0 (the "License");
6 |  |
      *  you may not use this file except in compliance with the License.
7 |  |
      *  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 |  |
      */
18 |  |
     package org.apache.commons.scxml;
19 |  |
20 |  |
     import java.util.HashMap;
21 |  |
     import java.util.HashSet;
22 |  |
     import java.util.Map;
23 |  |
     import java.util.Set;
24 |  |
25 |  |
     import org.apache.commons.scxml.invoke.Invoker;
26 |  |
     import org.apache.commons.scxml.invoke.InvokerException;
27 |  |
     import org.apache.commons.scxml.model.Datamodel;
28 |  |
     import org.apache.commons.scxml.model.History;
29 |  |
     import org.apache.commons.scxml.model.TransitionTarget;
30 |  |
31 |  |
     /**
32 |  |
      * The <code>SCInstance</code> performs book-keeping functions for
33 |  |
      * a particular execution of a state chart represented by a
34 |  |
      * <code>SCXML</code> object.
35 |  |
      */
36 |  |
     public class SCInstance {
37 |  |
38 |  |
         /**
39 |  |
          * The notification registry.
40 |  |
          */
41 |  |
         private NotificationRegistry notificationRegistry;
42 |  |
43 |  |
         /**
44 |  |
          * The <code>Map</code> of <code>Context</code>s per
45 |  |
          * <code>TransitionTarget</code>.
46 |  |
          */
47 |  |
         private Map contexts;
48 |  |
49 |  |
         /**
50 |  |
          * The <code>Map</code> of last known configurations per
51 |  |
          * <code>History</code>.
52 |  |
          */
53 |  |
         private Map histories;
54 |  |
55 |  |
         /**
56 |  |
          * The <code>Invoker</code> classes <code>Map</code>, keyed by
57 |  |
          * &lt;invoke&gt; target types (specified using "targettype" attribute).
58 |  |
          */
59 |  |
         private Map invokerClasses;
60 |  |
61 |  |
         /**
62 |  |
          * The <code>Map</code> of active <code>Invoker</code>s, keyed by
63 |  |
          * (leaf) <code>State</code>s.
64 |  |
          */
65 |  |
         private Map invokers;
66 |  |
67 |  |
         /**
68 |  |
          * The evaluator for expressions.
69 |  |
          */
70 |  |
         private Evaluator evaluator;
71 |  |
72 |  |
         /**
73 |  |
          * The root context.
74 |  |
          */
75 |  |
         private Context rootContext;
76 |  |
77 |  |
         /**
78 |  |
          * The owning state machine executor.
79 |  |
          */
80 |  |
         private SCXMLExecutor executor;
81 |  |
82 |  |
         /**
83 |  |
          * Constructor.
84 |  |
          *
85 |  |
          * @param executor The executor that this instance is attached to.
86 |  |
          */
87 | 48 |
         SCInstance(final SCXMLExecutor executor) {
88 | 48 |
             this.notificationRegistry = new NotificationRegistry();
89 | 48 |
             this.contexts = new HashMap();
90 | 48 |
             this.histories = new HashMap();
91 | 48 |
             this.invokerClasses = new HashMap();
92 | 48 |
             this.invokers = new HashMap();
93 | 48 |
             this.evaluator = null;
94 | 48 |
             this.rootContext = null;
95 | 48 |
             this.executor = executor;
96 | 48 |
         }
97 |  |
98 |  |
         /**
99 |  |
          * Get the <code>Evaluator</code>.
100 |  |
          *
101 |  |
          * @return The evaluator.
102 |  |
          */
103 |  |
         public Evaluator getEvaluator() {
104 | 293 |
             return evaluator;
105 |  |
         }
106 |  |
107 |  |
         /**
108 |  |
          * Set the <code>Evaluator</code>.
109 |  |
          *
110 |  |
          * @param evaluator The evaluator.
111 |  |
          */
112 |  |
         void setEvaluator(final Evaluator evaluator) {
113 | 40 |
             this.evaluator = evaluator;
114 | 40 |
         }
115 |  |
116 |  |
         /**
117 |  |
          * Get the root context.
118 |  |
          *
119 |  |
          * @return The root context.
120 |  |
          */
121 |  |
         public Context getRootContext() {
122 | 695 |
             if (rootContext == null && evaluator != null) {
123 | 1 |
                 rootContext = evaluator.newContext(null);
124 |  |
             }
125 | 695 |
             return rootContext;
126 |  |
         }
127 |  |
128 |  |
         /**
129 |  |
          * Set the root context.
130 |  |
          *
131 |  |
          * @param context The root context.
132 |  |
          */
133 |  |
         void setRootContext(final Context context) {
134 | 40 |
             this.rootContext = context;
135 | 40 |
         }
136 |  |
137 |  |
         /**
138 |  |
          * Get the notification registry.
139 |  |
          *
140 |  |
          * @return The notification registry.
141 |  |
          */
142 |  |
         public NotificationRegistry getNotificationRegistry() {
143 | 280 |
             return notificationRegistry;
144 |  |
         }
145 |  |
146 |  |
         /**
147 |  |
          * Set the notification registry.
148 |  |
          *
149 |  |
          * @param notifRegistry The notification registry.
150 |  |
          */
151 |  |
         void setNotificationRegistry(final NotificationRegistry notifRegistry) {
152 | 0 |
             this.notificationRegistry = notifRegistry;
153 | 0 |
         }
154 |  |
155 |  |
         /**
156 |  |
          * Get the <code>Context</code> for this <code>TransitionTarget</code>.
157 |  |
          * If one is not available it is created.
158 |  |
          *
159 |  |
          * @param transitionTarget The TransitionTarget.
160 |  |
          * @return The Context.
161 |  |
          */
162 |  |
         public Context getContext(final TransitionTarget transitionTarget) {
163 | 350 |
             Context context = (Context) contexts.get(transitionTarget);
164 | 350 |
             if (context == null) {
165 | 149 |
                 TransitionTarget parent = transitionTarget.getParent();
166 | 149 |
                 if (parent == null) {
167 |  |
                     // docroot
168 | 61 |
                     context = evaluator.newContext(getRootContext());
169 |  |
                 } else {
170 | 88 |
                     context = evaluator.newContext(getContext(parent));
171 |  |
                 }
172 | 149 |
                 Datamodel datamodel = transitionTarget.getDatamodel();
173 | 149 |
                 SCXMLHelper.cloneDatamodel(datamodel, context, evaluator, null);
174 | 149 |
                 contexts.put(transitionTarget, context);
175 |  |
             }
176 | 350 |
             return context;
177 |  |
         }
178 |  |
179 |  |
         /**
180 |  |
          * Get the <code>Context</code> for this <code>TransitionTarget</code>.
181 |  |
          * May return <code>null</code>.
182 |  |
          *
183 |  |
          * @param transitionTarget The <code>TransitionTarget</code>.
184 |  |
          * @return The Context.
185 |  |
          */
186 |  |
         Context lookupContext(final TransitionTarget transitionTarget) {
187 | 189 |
             return (Context) contexts.get(transitionTarget);
188 |  |
         }
189 |  |
190 |  |
         /**
191 |  |
          * Set the <code>Context</code> for this <code>TransitionTarget</code>.
192 |  |
          *
193 |  |
          * @param transitionTarget The TransitionTarget.
194 |  |
          * @param context The Context.
195 |  |
          */
196 |  |
         void setContext(final TransitionTarget transitionTarget,
197 |  |
                 final Context context) {
198 | 1 |
             contexts.put(transitionTarget, context);
199 | 1 |
         }
200 |  |
201 |  |
         /**
202 |  |
          * Get the last configuration for this history.
203 |  |
          *
204 |  |
          * @param history The history.
205 |  |
          * @return Returns the lastConfiguration.
206 |  |
          */
207 |  |
         public Set getLastConfiguration(final History history) {
208 | 23 |
             Set lastConfiguration = (Set) histories.get(history);
209 | 23 |
             if (lastConfiguration == null) {
210 | 8 |
                 lastConfiguration = new HashSet();
211 | 8 |
                 histories.put(history, lastConfiguration);
212 |  |
             }
213 | 23 |
             return lastConfiguration;
214 |  |
         }
215 |  |
216 |  |
         /**
217 |  |
          * Set the last configuration for this history.
218 |  |
          *
219 |  |
          * @param history The history.
220 |  |
          * @param lc The lastConfiguration to set.
221 |  |
          */
222 |  |
         public void setLastConfiguration(final History history,
223 |  |
                 final Set lc) {
224 | 13 |
             Set lastConfiguration = getLastConfiguration(history);
225 | 13 |
             lastConfiguration.clear();
226 | 13 |
             lastConfiguration.addAll(lc);
227 | 13 |
         }
228 |  |
229 |  |
         /**
230 |  |
          * Check whether we have prior history.
231 |  |
          *
232 |  |
          * @param history The history.
233 |  |
          * @return Whether we have a non-empty last configuration
234 |  |
          */
235 |  |
         public boolean isEmpty(final History history) {
236 | 14 |
             Set lastConfiguration = (Set) histories.get(history);
237 | 14 |
             if (lastConfiguration == null || lastConfiguration.isEmpty()) {
238 | 5 |
                 return true;
239 |  |
             }
240 | 9 |
             return false;
241 |  |
         }
242 |  |
243 |  |
         /**
244 |  |
          * Resets the history state.
245 |  |
          *
246 |  |
          * @param history The history.
247 |  |
          * @see org.apache.commons.scxml.SCXMLExecutor#reset()
248 |  |
          */
249 |  |
         public void reset(final History history) {
250 | 8 |
             Set lastConfiguration = (Set) histories.get(history);
251 | 8 |
             if (lastConfiguration != null) {
252 | 3 |
                 lastConfiguration.clear();
253 |  |
             }
254 | 8 |
         }
255 |  |
256 |  |
         /**
257 |  |
          * Get the {@link SCXMLExecutor} this instance is attached to.
258 |  |
          *
259 |  |
          * @return The SCXMLExecutor this instance is attached to.
260 |  |
          * @see org.apache.commons.scxml.SCXMLExecutor
261 |  |
          */
262 |  |
         public SCXMLExecutor getExecutor() {
263 | 0 |
             return executor;
264 |  |
         }
265 |  |
266 |  |
         /**
267 |  |
          * Register an {@link Invoker} class for this target type.
268 |  |
          *
269 |  |
          * @param targettype The target type (specified by "targettype"
270 |  |
          *                   attribute of &lt;invoke&gt; tag).
271 |  |
          * @param invokerClass The <code>Invoker</code> <code>Class</code>.
272 |  |
          */
273 |  |
         void registerInvokerClass(final String targettype,
274 |  |
                 final Class invokerClass) {
275 | 1 |
             invokerClasses.put(targettype, invokerClass);
276 | 1 |
         }
277 |  |
278 |  |
         /**
279 |  |
          * Remove the {@link Invoker} class registered for this target
280 |  |
          * type (if there is one registered).
281 |  |
          *
282 |  |
          * @param targettype The target type (specified by "targettype"
283 |  |
          *                   attribute of &lt;invoke&gt; tag).
284 |  |
          */
285 |  |
         void unregisterInvokerClass(final String targettype) {
286 | 0 |
             invokerClasses.remove(targettype);
287 | 0 |
         }
288 |  |
289 |  |
         /**
290 |  |
          * Get the {@link Invoker} for this {@link TransitionTarget}.
291 |  |
          * May return <code>null</code>. A non-null <code>Invoker</code> will be
292 |  |
          * returned if and only if the <code>TransitionTarget</code> is
293 |  |
          * currently active and contains an &lt;invoke&gt; child.
294 |  |
          *
295 |  |
          * @param targettype The type of the target being invoked.
296 |  |
          * @return An {@link Invoker} for the specified type, if an
297 |  |
          *         invoker class is registered against that type,
298 |  |
          *         <code>null</code> otherwise.
299 |  |
          * @throws InvokerException When a suitable {@link Invoker} cannot
300 |  |
          *                          be instantiated.
301 |  |
          */
302 |  |
         public Invoker newInvoker(final String targettype)
303 |  |
         throws InvokerException {
304 | 1 |
             Class invokerClass = (Class) invokerClasses.get(targettype);
305 | 1 |
             if (invokerClass == null) {
306 | 0 |
                 throw new InvokerException("No Invoker registered for "
307 |  |
                     + "targettype \"" + targettype + "\"");
308 |  |
             }
309 | 1 |
             Invoker invoker = null;
310 |  |
             try {
311 | 1 |
                 invoker = (Invoker) invokerClass.newInstance();
312 | 0 |
             } catch (InstantiationException ie) {
313 | 0 |
                 throw new InvokerException(ie.getMessage(), ie.getCause());
314 | 0 |
             } catch (IllegalAccessException iae) {
315 | 0 |
                 throw new InvokerException(iae.getMessage(), iae.getCause());
316 | 1 |
             }
317 | 1 |
             return invoker;
318 |  |
         }
319 |  |
320 |  |
         /**
321 |  |
         * Get the {@link Invoker} for this {@link TransitionTarget}.
322 |  |
          * May return <code>null</code>. A non-null {@link Invoker} will be
323 |  |
          * returned if and only if the {@link TransitionTarget} is
324 |  |
          * currently active and contains an &lt;invoke&gt; child.
325 |  |
          *
326 |  |
          * @param transitionTarget The <code>TransitionTarget</code>.
327 |  |
          * @return The Invoker.
328 |  |
          */
329 |  |
         public Invoker getInvoker(final TransitionTarget transitionTarget) {
330 | 1 |
             return (Invoker) invokers.get(transitionTarget);
331 |  |
         }
332 |  |
333 |  |
         /**
334 |  |
          * Set the {@link Invoker} for this {@link TransitionTarget}.
335 |  |
          *
336 |  |
          * @param transitionTarget The TransitionTarget.
337 |  |
          * @param invoker The Invoker.
338 |  |
          */
339 |  |
         public void setInvoker(final TransitionTarget transitionTarget,
340 |  |
                 final Invoker invoker) {
341 | 1 |
             invokers.put(transitionTarget, invoker);
342 | 1 |
         }
343 |  |
344 |  |
         /**
345 |  |
          * Return the Map of {@link Invoker}s currently "active".
346 |  |
          *
347 |  |
          * @return The map of invokers.
348 |  |
          */
349 |  |
         public Map getInvokers() {
350 | 565 |
             return invokers;
351 |  |
         }
352 |  |
353 |  |
     }
354 |  |