KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > workflow > WorkflowEngine


1 /*
2  * $Id: WorkflowEngine.java 5462 2005-08-05 18:35:48Z jonesde $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  */

25 package org.ofbiz.workflow;
26
27 import java.util.Date JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.Locale JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.transaction.InvalidTransactionException JavaDoc;
33 import javax.transaction.SystemException JavaDoc;
34 import javax.transaction.Transaction JavaDoc;
35 import javax.transaction.TransactionManager JavaDoc;
36
37 import org.ofbiz.base.util.Debug;
38 import org.ofbiz.base.util.StringUtil;
39 import org.ofbiz.base.util.UtilDateTime;
40 import org.ofbiz.base.util.UtilMisc;
41 import org.ofbiz.entity.GenericEntityException;
42 import org.ofbiz.entity.GenericValue;
43 import org.ofbiz.entity.transaction.GenericTransactionException;
44 import org.ofbiz.entity.transaction.TransactionFactory;
45 import org.ofbiz.entity.transaction.TransactionUtil;
46 import org.ofbiz.service.GenericRequester;
47 import org.ofbiz.service.GenericResultWaiter;
48 import org.ofbiz.service.GenericServiceException;
49 import org.ofbiz.service.ModelService;
50 import org.ofbiz.service.ServiceDispatcher;
51 import org.ofbiz.service.engine.AbstractEngine;
52 import org.ofbiz.service.job.AbstractJob;
53 import org.ofbiz.service.job.Job;
54 import org.ofbiz.service.job.JobManagerException;
55
56 /**
57  * WorkflowEngine - Workflow Service Engine
58  *
59  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
60  * @version $Rev: 5462 $
61  * @since 2.0
62  */

63 public class WorkflowEngine extends AbstractEngine {
64
65     public static final String JavaDoc module = WorkflowEngine.class.getName();
66
67     public WorkflowEngine(ServiceDispatcher dispatcher) {
68         super(dispatcher);
69     }
70        
71     /**
72      * @see org.ofbiz.service.engine.GenericEngine#runSync(java.lang.String, org.ofbiz.service.ModelService, java.util.Map)
73      */

74     public Map JavaDoc runSync(String JavaDoc localName, ModelService modelService, Map JavaDoc context) throws GenericServiceException {
75         GenericResultWaiter waiter = new GenericResultWaiter();
76         runAsync(localName, modelService, context, waiter, false);
77         return waiter.waitForResult();
78     }
79    
80     /**
81      * @see org.ofbiz.service.engine.GenericEngine#runSyncIgnore(java.lang.String, org.ofbiz.service.ModelService, java.util.Map)
82      */

83     public void runSyncIgnore(String JavaDoc localName, ModelService modelService, Map JavaDoc context) throws GenericServiceException {
84         runAsync(localName, modelService, context, null, false);
85     }
86    
87     /**
88      * @see org.ofbiz.service.engine.GenericEngine#runAsync(java.lang.String, org.ofbiz.service.ModelService, java.util.Map, boolean)
89      */

90     public void runAsync(String JavaDoc localName, ModelService modelService, Map JavaDoc context, boolean persist) throws GenericServiceException {
91         runAsync(localName, modelService, context, null, persist);
92     }
93    
94     /**
95      * @see org.ofbiz.service.engine.GenericEngine#runAsync(java.lang.String, org.ofbiz.service.ModelService, java.util.Map, org.ofbiz.service.GenericRequester, boolean)
96      */

97     public void runAsync(String JavaDoc localName, ModelService modelService, Map JavaDoc context, GenericRequester requester, boolean persist) throws GenericServiceException {
98         // Suspend the current transaction
99
TransactionManager JavaDoc tm = TransactionFactory.getTransactionManager();
100         if (tm == null) {
101             throw new GenericServiceException("Cannot get the transaction manager; cannot run persisted services.");
102         }
103
104         Transaction JavaDoc parentTrans = null;
105         boolean beganTransaction = false;
106         try {
107             try {
108                 parentTrans = tm.suspend();
109                 beganTransaction = TransactionUtil.begin();
110                 //Debug.logInfo("Suspended transaction; began new: " + beganTransaction, module);
111
} catch (SystemException JavaDoc se) {
112                 Debug.logError(se, "Cannot suspend transaction: " + se.getMessage(), module);
113             } catch (GenericTransactionException e) {
114                 Debug.logError(e, "Cannot begin nested transaction: " + e.getMessage(), module);
115             }
116             
117             // Build the requester
118
WfRequester req = null;
119             try {
120                 req = WfFactory.getWfRequester();
121             } catch (WfException e) {
122                 try {
123                     TransactionUtil.rollback(beganTransaction, "Error getting Workflow Requester", e);
124                 } catch (GenericTransactionException gte) {
125                     Debug.logError(gte, "Unable to rollback nested exception.", module);
126                 }
127                 throw new GenericServiceException(e.getMessage(), e);
128             }
129
130             // Get the package and process ID::VERSION
131
String JavaDoc location = this.getLocation(modelService);
132             String JavaDoc invoke = modelService.invoke;
133             String JavaDoc packageId = this.getSplitPosition(location, 0);
134             String JavaDoc packageVersion = this.getSplitPosition(location, 1);
135             String JavaDoc processId = this.getSplitPosition(invoke, 0);
136             String JavaDoc processVersion = this.getSplitPosition(invoke, 1);
137
138             // Build the process manager
139
WfProcessMgr mgr = null;
140             try {
141                 mgr = WfFactory.getWfProcessMgr(dispatcher.getDelegator(), packageId, packageVersion, processId, processVersion);
142             } catch (WfException e) {
143                 String JavaDoc errMsg = "Process manager error";
144                 Debug.logError(e, errMsg, module);
145                 try {
146                     TransactionUtil.rollback(beganTransaction, errMsg, e);
147                 } catch (GenericTransactionException gte) {
148                     Debug.logError(gte, "Unable to rollback nested exception.", module);
149                 }
150                 throw new GenericServiceException(e.getMessage(), e);
151             } catch (Exception JavaDoc e) {
152                 Debug.logError(e, "Un-handled process manager error", module);
153                 throw new GenericServiceException(e.getMessage(), e);
154             }
155
156             // Create the process
157
WfProcess process = null;
158             try {
159                 process = mgr.createProcess(req);
160             } catch (NotEnabled ne) {
161                 try {
162                     TransactionUtil.rollback(beganTransaction, "Error in create workflow process: Not Enabled", ne);
163                 } catch (GenericTransactionException gte) {
164                     Debug.logError(gte, "Unable to rollback nested exception.", module);
165                 }
166                 throw new GenericServiceException(ne.getMessage(), ne);
167             } catch (InvalidRequester ir) {
168                 try {
169                     TransactionUtil.rollback(beganTransaction, "Error in create workflow process: Invalid Requester", ir);
170                 } catch (GenericTransactionException gte) {
171                     Debug.logError(gte, "Unable to rollback nested exception.", module);
172                 }
173                 throw new GenericServiceException(ir.getMessage(), ir);
174             } catch (RequesterRequired rr) {
175                 try {
176                     TransactionUtil.rollback(beganTransaction, "Error in create workflow process: Requester Required", rr);
177                 } catch (GenericTransactionException gte) {
178                     Debug.logError(gte, "Unable to rollback nested exception.", module);
179                 }
180                 throw new GenericServiceException(rr.getMessage(), rr);
181             } catch (WfException wfe) {
182                 try {
183                     TransactionUtil.rollback(beganTransaction, "Error in create workflow process: general workflow error error", wfe);
184                 } catch (GenericTransactionException gte) {
185                     Debug.logError(gte, "Unable to rollback nested exception.", module);
186                 }
187                 throw new GenericServiceException(wfe.getMessage(), wfe);
188             } catch (Exception JavaDoc e) {
189                 Debug.logError(e, "Un-handled process exception", module);
190                 throw new GenericServiceException(e.getMessage(), e);
191             }
192             
193             // Assign the owner of the process
194
GenericValue userLogin = null;
195             if (context.containsKey("userLogin")) {
196                 userLogin = (GenericValue) context.remove("userLogin");
197                 try {
198                     Map JavaDoc fields = UtilMisc.toMap("partyId", userLogin.getString("partyId"),
199                             "roleTypeId", "WF_OWNER", "workEffortId", process.runtimeKey(),
200                             "fromDate", UtilDateTime.nowTimestamp());
201
202                     try {
203                         GenericValue wepa = dispatcher.getDelegator().makeValue("WorkEffortPartyAssignment", fields);
204                         dispatcher.getDelegator().create(wepa);
205                     } catch (GenericEntityException e) {
206                         String JavaDoc errMsg = "Cannot set ownership of workflow";
207                         try {
208                             TransactionUtil.rollback(beganTransaction, errMsg, e);
209                         } catch (GenericTransactionException gte) {
210                             Debug.logError(gte, "Unable to rollback nested exception.", module);
211                         }
212                         throw new GenericServiceException(errMsg, e);
213                     }
214                 } catch (WfException we) {
215                     String JavaDoc errMsg = "Cannot get the workflow process runtime key";
216                     try {
217                         TransactionUtil.rollback(beganTransaction, errMsg, we);
218                     } catch (GenericTransactionException gte) {
219                         Debug.logError(gte, "Unable to rollback nested exception.", module);
220                     }
221                     throw new GenericServiceException(errMsg);
222                 }
223             }
224         
225             // Grab the locale from the context
226
Locale JavaDoc locale = (Locale JavaDoc) context.remove("locale");
227         
228             // Grab the starting activityId from the context
229
String JavaDoc startActivityId = (String JavaDoc) context.remove("startWithActivityId");
230
231             // Register the process and set the workflow owner
232
try {
233                 req.registerProcess(process, context, requester);
234                 if (userLogin != null) {
235                     Map JavaDoc pContext = process.processContext();
236                     pContext.put("workflowOwnerId", userLogin.getString("userLoginId"));
237                     process.setProcessContext(pContext);
238                 }
239             } catch (WfException wfe) {
240                 try {
241                     TransactionUtil.rollback(beganTransaction, wfe.getMessage(), wfe);
242                 } catch (GenericTransactionException gte) {
243                     Debug.logError(gte, "Unable to rollback nested exception.", module);
244                 }
245                 throw new GenericServiceException(wfe.getMessage(), wfe);
246             }
247         
248             // Set the initial locale - (in context)
249
if (locale != null) {
250                 try {
251                     Map JavaDoc pContext = process.processContext();
252                     pContext.put("initialLocale", locale);
253                     process.setProcessContext(pContext);
254                 } catch (WfException wfe) {
255                     try {
256                         TransactionUtil.rollback(beganTransaction, wfe.getMessage(), wfe);
257                     } catch (GenericTransactionException gte) {
258                         Debug.logError(gte, "Unable to rollback nested exception.", module);
259                     }
260                     throw new GenericServiceException(wfe.getMessage(), wfe);
261                 }
262             }
263         
264             // Use the WorkflowRunner to start the workflow in a new thread
265
try {
266                 Job job = new WorkflowRunner(process, requester, startActivityId);
267                 if (Debug.verboseOn()) Debug.logVerbose("Created WorkflowRunner: " + job, module);
268                 dispatcher.getJobManager().runJob(job);
269             } catch (JobManagerException je) {
270                 try {
271                     TransactionUtil.rollback(beganTransaction, je.getMessage(), je);
272                 } catch (GenericTransactionException gte) {
273                     Debug.logError(gte, "Unable to rollback nested exception.", module);
274                 }
275                 throw new GenericServiceException(je.getMessage(), je);
276             }
277             
278             try {
279                 TransactionUtil.commit(beganTransaction);
280             } catch (GenericTransactionException e) {
281                 Debug.logError(e, "Cannot commit nested transaction: " + e.getMessage(), module);
282             }
283         } finally {
284             // Resume the parent transaction
285
if (parentTrans != null) {
286                 try {
287                     tm.resume(parentTrans);
288                     //Debug.logInfo("Resumed the parent transaction.", module);
289
} catch (InvalidTransactionException JavaDoc ite) {
290                     throw new GenericServiceException("Cannot resume transaction", ite);
291                 } catch (SystemException JavaDoc se) {
292                     throw new GenericServiceException("Unexpected transaction error", se);
293                 }
294             }
295         }
296     }
297
298     private String JavaDoc getSplitPosition(String JavaDoc splitString, int position) {
299         if (splitString.indexOf("::") == -1) {
300             if (position == 0)
301                 return splitString;
302             if (position == 1)
303                 return null;
304         }
305         List JavaDoc splitList = StringUtil.split(splitString, "::");
306         return (String JavaDoc) splitList.get(position);
307     }
308 }
309
310 /** Workflow Runner class runs inside its own thread using the Scheduler API */
311 class WorkflowRunner extends AbstractJob {
312
313     GenericRequester requester;
314     WfProcess process;
315     String JavaDoc startActivityId;
316
317     WorkflowRunner(WfProcess process, GenericRequester requester, String JavaDoc startActivityId) {
318         super(process.toString() + "." + System.currentTimeMillis(), process.toString());
319         this.process = process;
320         this.requester = requester;
321         this.startActivityId = startActivityId;
322         runtime = new Date JavaDoc().getTime();
323     }
324
325     protected void finish() {
326         runtime = -1;
327     }
328
329     public void exec() {
330         try {
331             if (startActivityId != null)
332                 process.start(startActivityId);
333             else
334                 process.start();
335         } catch (Exception JavaDoc e) {
336             Debug.logError(e, module);
337             if (requester != null)
338                 requester.receiveResult(null);
339         }
340         finish();
341     }
342 }
343
344
Popular Tags