1 /*
2
3 dsh-piccolo-identify Piccolo2D nodes for identifiable beans.
4 Copyright (c) 2007-2013 held jointly by the individual authors.
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 3 of the License, or (at
9 your option) any later version.
10
11 This library is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19
20 > http://www.fsf.org/licensing/licenses/lgpl.html
21 > http://www.opensource.org/licenses/lgpl-license.php
22
23 */
24 package org.dishevelled.piccolo.identify;
25
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28
29 import org.apache.commons.scxml.Context;
30 import org.apache.commons.scxml.ErrorReporter;
31 import org.apache.commons.scxml.Evaluator;
32 import org.apache.commons.scxml.EventDispatcher;
33 import org.apache.commons.scxml.SCXMLExecutor;
34 import org.apache.commons.scxml.SCXMLListener;
35 import org.apache.commons.scxml.TriggerEvent;
36
37 import org.apache.commons.scxml.env.SimpleDispatcher;
38
39 import org.apache.commons.scxml.env.jexl.JexlContext;
40 import org.apache.commons.scxml.env.jexl.JexlEvaluator;
41
42 import org.apache.commons.scxml.model.ModelException;
43 import org.apache.commons.scxml.model.SCXML;
44 import org.apache.commons.scxml.model.Transition;
45 import org.apache.commons.scxml.model.TransitionTarget;
46
47 /**
48 * State machine support class, meant to be delegated to. Provided
49 * an instance of a state machine, this class manages a state machine
50 * executor, allows delegators to fire state machine events, and responds
51 * to transition entry events by invoking methods on the delegating class
52 * via reflection. Most methods on this class fail silently instead of
53 * throwing state machine- or reflection-specific exceptions.
54 *
55 * @author Michael Heuer
56 * @version $Revision$ $Date$
57 */
58 final class StateMachineSupport
59 {
60 /** Object to delegate to. */
61 private final Object delegator;
62
63 /** State machine executor for this support class. */
64 private final SCXMLExecutor executor;
65
66
67 /**
68 * Create a new state machine support class to be delegated to
69 * by the specified delegator with the specified state machine.
70 *
71 * @param delegator object delegating to this state machine support
72 * class, must not be null
73 * @param stateMachine state machine for this support class, must
74 * not be null
75 */
76 StateMachineSupport(final Object delegator, final SCXML stateMachine)
77 {
78 if (delegator == null)
79 {
80 throw new IllegalArgumentException("delegator must not be null");
81 }
82 if (stateMachine == null)
83 {
84 throw new IllegalArgumentException("stateMachine must not be null");
85 }
86 this.delegator = delegator;
87
88 Evaluator evaluator = new JexlEvaluator();
89 EventDispatcher dispatcher = new SimpleDispatcher();
90 ErrorReporter errorReporter = new NoopErrorReporter();
91 Context rootContext = new JexlContext();
92 SCXMLListener listener = new SCXMLListener()
93 {
94 @Override
95 public void onEntry(final TransitionTarget entered)
96 {
97 invoke(entered.getId());
98 }
99
100 @Override
101 public void onExit(final TransitionTarget exited)
102 {
103 // empty
104 }
105
106 @Override
107 public void onTransition(final TransitionTarget to,
108 final TransitionTarget from,
109 final Transition transition)
110 {
111 // empty
112 }
113 };
114
115 executor = new SCXMLExecutor(evaluator, dispatcher, errorReporter);
116 executor.setStateMachine(stateMachine);
117 executor.setSuperStep(false);
118 executor.setRootContext(rootContext);
119 executor.addListener(stateMachine, listener);
120
121 try
122 {
123 executor.go();
124 }
125 catch (ModelException e)
126 {
127 // ignore
128 }
129 }
130
131 /**
132 * Reset the state machine for this state machine support class to its
133 * "initial" configuration (fails silently).
134 */
135 void resetStateMachine()
136 {
137 try
138 {
139 executor.reset();
140 }
141 catch (ModelException e)
142 {
143 // ignore
144 }
145 }
146
147 /**
148 * Fire an event with the specified event name on the state machine for
149 * this state machine support class (fails silently).
150 *
151 * @param eventName event name, must not be null
152 */
153 void fireStateMachineEvent(final String eventName)
154 {
155 if (eventName == null)
156 {
157 throw new IllegalArgumentException("eventName must not be null");
158 }
159 try
160 {
161 TriggerEvent event = new TriggerEvent(eventName, TriggerEvent.SIGNAL_EVENT, null);
162 executor.triggerEvents(new TriggerEvent[] { event });
163 }
164 catch (ModelException e)
165 {
166 // ignore
167 }
168 }
169
170 /**
171 * Invoke the no-argument method with the following name
172 * on the object delegating to this state machine support class
173 * (fails silently).
174 *
175 * @param methodName method name to invoke on the object
176 * delegating to this state machine support class
177 */
178 private void invoke(final String methodName)
179 {
180 try
181 {
182 Class<?> c = delegator.getClass();
183 Method method = c.getDeclaredMethod(methodName, new Class[0]);
184 method.setAccessible(true);
185 method.invoke(delegator, new Object[0]);
186 }
187 catch (SecurityException se)
188 {
189 // ignore
190 }
191 catch (NoSuchMethodException nsme)
192 {
193 // ignore
194 }
195 catch (IllegalArgumentException iae)
196 {
197 // ignore
198 }
199 catch (IllegalAccessException iae)
200 {
201 // ignore
202 }
203 catch (InvocationTargetException ite)
204 {
205 // ignore
206 }
207 }
208
209 /**
210 * No-op error reporter.
211 */
212 private class NoopErrorReporter
213 implements ErrorReporter
214 {
215
216 @Override
217 public void onError(final String errorCode,
218 final String errorDetail,
219 final Object errorContext)
220 {
221 // empty
222 }
223 }
224 }