KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > servicemix > beanflow > Workflow


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.servicemix.beanflow;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.apache.servicemix.beanflow.support.EnumHelper;
22 import org.apache.servicemix.beanflow.support.Interpreter;
23 import org.apache.servicemix.beanflow.support.ReflectionInterpreter;
24
25 import java.util.Timer JavaDoc;
26 import java.util.concurrent.BlockingQueue JavaDoc;
27 import java.util.concurrent.Executor JavaDoc;
28 import java.util.concurrent.Executors JavaDoc;
29 import java.util.concurrent.LinkedBlockingQueue JavaDoc;
30 import java.util.concurrent.atomic.AtomicBoolean JavaDoc;
31
32 /**
33  * An activity which implements a more traditional workflow model where each
34  * method represents a transition.
35  *
36  * @version $Revision: $
37  */

38 public class Workflow<T> extends JoinSupport {
39     private static final Log log = LogFactory.getLog(Workflow.class);
40
41     private Executor JavaDoc executor;
42     private Interpreter interpreter;
43     private Timer JavaDoc timer = new Timer JavaDoc();
44     private AtomicBoolean JavaDoc suspended = new AtomicBoolean JavaDoc();
45     private BlockingQueue JavaDoc<T> queue = new LinkedBlockingQueue JavaDoc<T>();
46
47     /**
48      * TODO is there a way to reference the parameter type of this class?
49      *
50      * public Workflow() { this(T); }
51      */

52
53     @SuppressWarnings JavaDoc("unchecked")
54     public Workflow(Class JavaDoc<T> enumType) {
55         this((T) getFirstStep(enumType));
56     }
57
58     public Workflow(T firstStep) {
59         this(Executors.newSingleThreadExecutor(), firstStep);
60     }
61     
62     public Workflow(Executor JavaDoc executor, T firstStep) {
63         this(executor, new ReflectionInterpreter(), firstStep);
64     }
65     
66     public Workflow(Executor JavaDoc executor, Interpreter interpreter, T firstStep) {
67         this.executor = executor;
68         this.interpreter = interpreter;
69         
70         if (firstStep instanceof Enum JavaDoc) {
71             validateStepsExist(firstStep.getClass());
72         }
73         addStep(firstStep);
74     }
75
76     /**
77      * Returns the next step which will be executed asynchronously
78      */

79     public T getNextStep() {
80         return queue.peek();
81     }
82
83     /**
84      * Adds a step to be executed after the current step completes processing
85      */

86     public void addStep(T stepName) {
87         suspended.set(false);
88         queue.add(stepName);
89         executor.execute(this);
90     }
91
92     public void run() {
93         while (!isStopped()) {
94             try {
95                 T stepToExecute = queue.poll();
96                 if (stepToExecute != null) {
97                     if (log.isDebugEnabled()) {
98                         log.debug("About to execute step: " + stepToExecute);
99                     }
100                     interpreter.executeStep(stepToExecute, this);
101                 }
102                 else {
103                     break;
104                 }
105             }
106             catch (RuntimeException JavaDoc e) {
107                 log.warn("Caught: " + e, e);
108             }
109         }
110     }
111
112     /**
113      * Forks one or more child activities
114      */

115     public void fork(TimeoutActivity... activities) {
116         for (TimeoutActivity activity : activities) {
117             activity.start();
118         }
119     }
120
121     /**
122      * Forks one or more child activities
123      */

124     public void fork(long timeout, TimeoutActivity... activities) {
125         for (TimeoutActivity activity : activities) {
126             activity.scheduleTimeout(timer, timeout);
127             activity.start();
128         }
129     }
130
131     /**
132      * Creates a join such that when all of the activities are completed the
133      * given step will be executed
134      */

135     public void joinAll(T joinedStep, long timeout, Activity... activities) {
136         JoinAll joinFlow = new JoinAll(activities);
137         join(joinFlow, joinedStep, timeout);
138     }
139
140     /**
141      * Performs a join with the given join activity condition, advancing to the
142      * specified joinedStep when the join takes place using the given timeout to
143      * the join
144      */

145     public void join(JoinSupport joinFlow, T joinedStep, long timeout) {
146         // when the join completes move to the next step
147
joinFlow.onStop(createGoToStepTask(joinedStep));
148         
149         // start the join activity and register the timeout
150
fork(timeout, joinFlow);
151     }
152
153     /**
154      * Suspends the workflow processing. The workflow will then wait for an
155      * external event before restarting the activity
156      */

157     public void suspend() {
158         suspended.set(true);
159     }
160
161     /**
162      * Returns true if the workflow is in a suspended state where it is waiting
163      * for an external event to cause the workflow to resume
164      */

165     public boolean isSuspended() {
166         return suspended.get();
167     }
168
169     /**
170      * Returns true if this workflow has a next step to execute
171      */

172     public boolean isNextStepAvailable() {
173         return !queue.isEmpty();
174     }
175
176     /**
177      * Creates a task which will move to the given step
178      */

179     public Runnable JavaDoc createGoToStepTask(final T joinedStep) {
180         return new Runnable JavaDoc() {
181             public void run() {
182                 addStep(joinedStep);
183             }
184         };
185     }
186
187     /**
188      * Called when a step fails to execute
189      */

190     public void onStepException(String JavaDoc stepName, Exception JavaDoc e) {
191         log.warn("Step failed: " + stepName + ". Reason: " + e, e);
192         suspend();
193         fail("Failed to execute step: " + stepName + ". Reason: " + e, e);
194     }
195
196     @Override JavaDoc
197     protected void onChildStateChange(int childCount, int stoppedCount, int failedCount) {
198     }
199
200     /**
201      * Lets validate the steps exist on an enumerated type.
202      *
203      * Thanks to Sam Pullara for this idea :)
204      */

205     protected void validateStepsExist(Class JavaDoc enumType) {
206         Object JavaDoc[] values = null;
207         try {
208             values = EnumHelper.getEnumValues(enumType);
209         }
210         catch (Exception JavaDoc e) {
211             fail("Cannot get the values of the enumeration: " + enumType.getName(), e);
212         }
213         if (values != null) {
214             interpreter.validateStepsExist(values, this);
215         }
216     }
217
218     protected static Object JavaDoc getFirstStep(Class JavaDoc enumType) {
219         try {
220             Object JavaDoc[] values = EnumHelper.getEnumValues(enumType);
221             return values[0];
222         }
223         catch (Exception JavaDoc e) {
224             throw new IllegalArgumentException JavaDoc("Could not find the values for the enumeration: " + enumType.getName() + ". Reason: " + e, e);
225         }
226     }
227
228 }
229
Popular Tags