View Javadoc

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 }