001: /*
002: * $Id: WorkflowClient.java,v 1.1 2003/08/17 09:29:34 ajzeneski Exp $
003: *
004: * Copyright (c) 2001, 2002 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.workflow.client;
026:
027: import java.sql.Timestamp;
028: import java.util.Iterator;
029: import java.util.Map;
030:
031: import org.ofbiz.base.util.Debug;
032: import org.ofbiz.entity.GenericDelegator;
033: import org.ofbiz.service.DispatchContext;
034: import org.ofbiz.service.LocalDispatcher;
035: import org.ofbiz.service.job.Job;
036: import org.ofbiz.service.job.JobManagerException;
037: import org.ofbiz.workflow.CannotStop;
038: import org.ofbiz.workflow.NotRunning;
039: import org.ofbiz.workflow.WfActivity;
040: import org.ofbiz.workflow.WfAssignment;
041: import org.ofbiz.workflow.WfException;
042: import org.ofbiz.workflow.WfExecutionObject;
043: import org.ofbiz.workflow.WfFactory;
044: import org.ofbiz.workflow.WfProcess;
045: import org.ofbiz.workflow.WfResource;
046:
047: /**
048: * Workflow Client - Client API to the Workflow Engine.
049: *
050: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
051: * @version $Revision: 1.1 $
052: * @since 2.0
053: */
054: public class WorkflowClient {
055:
056: public static final String module = WorkflowClient.class.getName();
057:
058: protected GenericDelegator delegator = null;
059: protected LocalDispatcher dispatcher = null;
060:
061: protected WorkflowClient() {
062: }
063:
064: /**
065: * Get a new instance of the Workflow Client
066: * @param delegator the GenericDelegator object which matchs the delegator used by the workflow engine.
067: * @param dispatcher a LocalDispatcher object to invoke the workflow services.
068: */
069: public WorkflowClient(GenericDelegator delegator,
070: LocalDispatcher dispatcher) {
071: if (delegator == null)
072: throw new IllegalArgumentException(
073: "GenericDelegator cannot be null");
074: if (dispatcher == null)
075: throw new IllegalArgumentException(
076: "LocalDispatcher cannot be null");
077: this .delegator = delegator;
078: this .dispatcher = dispatcher;
079: }
080:
081: /**
082: * Get a new instance of the Workflow Client
083: * @param dctx A DispatchContext object.
084: * *** Note the delegator from this object must match the delegator used by the workflow engine.
085: */
086: public WorkflowClient(DispatchContext context) {
087: this (context.getDelegator(), context.getDispatcher());
088: }
089:
090: /**
091: * Create an activity assignment.
092: * @param workEffortId The WorkEffort entity ID for the activitiy.
093: * @param partyId The assigned / to be assigned users party ID.
094: * @param roleTypeId The assigned / to be assigned role type ID.
095: * @param append Append this assignment to the list, if others exist.
096: * @return The new assignment object.
097: * @throws WfException
098: */
099: public WfAssignment assign(String workEffortId, String partyId,
100: String roleTypeId, Timestamp fromDate, boolean append)
101: throws WfException {
102: WfActivity activity = WfFactory.getWfActivity(delegator,
103: workEffortId);
104: WfResource resource = WfFactory.getWfResource(delegator, null,
105: null, partyId, roleTypeId);
106:
107: if (!append) {
108: Iterator i = activity.getIteratorAssignment();
109:
110: while (i.hasNext()) {
111: WfAssignment a = (WfAssignment) i.next();
112: a.remove();
113: }
114: }
115: return WfFactory.getWfAssignment(activity, resource, fromDate,
116: true);
117: }
118:
119: /**
120: * Accept an activity assignment.
121: * @param workEffortId The WorkEffort entity ID for the activitiy.
122: * @param partyId The assigned / to be assigned users party ID.
123: * @param roleTypeId The assigned / to be assigned role type ID.
124: * @param fromDate The assignment's from date.
125: * @throws WfException
126: */
127: public void accept(String workEffortId, String partyId,
128: String roleTypeId, Timestamp fromDate) throws WfException {
129: WfAssignment assign = WfFactory.getWfAssignment(delegator,
130: workEffortId, partyId, roleTypeId, fromDate);
131: assign.accept();
132: }
133:
134: /**
135: * Accept an activity assignment and begin processing.
136: * @param workEffortId The WorkEffort entity ID for the activitiy.
137: * @param partyId The assigned / to be assigned users party ID.
138: * @param roleTypeId The assigned / to be assigned role type ID.
139: * @param fromDate The assignment's from date.
140: * @return GenericResultWaiter of the start job.
141: * @throws WfException
142: */
143: public void acceptAndStart(String workEffortId, String partyId,
144: String roleTypeId, Timestamp fromDate) throws WfException {
145: accept(workEffortId, partyId, roleTypeId, fromDate);
146: start(workEffortId);
147: }
148:
149: /**
150: * Delegate an activity assignment.
151: * @param workEffortId The WorkEffort entity ID for the activitiy.
152: * @param fromPartyId The current assignment partyId.
153: * @param fromRoleTypeId The current assignment roleTypeId.
154: * @param fromFromDate The current assignment fromDate.
155: * @param toPartyId The new delegated assignment partyId.
156: * @param toRoleTypeId The new delegated assignment roleTypeId.
157: * @param toFromDate The new delegated assignment fromDate.
158: * @return The new assignment object.
159: * @throws WfException
160: */
161: public WfAssignment delegate(String workEffortId,
162: String fromPartyId, String fromRoleTypeId,
163: Timestamp fromFromDate, String toPartyId,
164: String toRoleTypeId, Timestamp toFromDate)
165: throws WfException {
166: WfActivity activity = WfFactory.getWfActivity(delegator,
167: workEffortId);
168: WfAssignment fromAssign = null;
169:
170: // check status and delegateAfterStart attribute
171: if (activity.state().equals("open.running")
172: && !activity.getDefinitionObject().getBoolean(
173: "delegateAfterStart").booleanValue())
174: throw new WfException(
175: "This activity cannot be delegated once it has been started");
176:
177: if (fromPartyId == null && fromRoleTypeId == null
178: && fromFromDate == null) {
179: Iterator i = activity.getIteratorAssignment();
180: fromAssign = (WfAssignment) i.next();
181: if (i.hasNext()) {
182: throw new WfException(
183: "Cannot locate the assignment to delegate from, there is more then one "
184: + "assignment for this activity.");
185: }
186: }
187:
188: if (fromAssign == null) {
189: fromAssign = WfFactory.getWfAssignment(delegator,
190: workEffortId, fromPartyId, fromRoleTypeId,
191: fromFromDate);
192: }
193: fromAssign.delegate();
194:
195: // check for a restartOnDelegate
196: WfActivity newActivity = null;
197: if (activity.getDefinitionObject().getBoolean(
198: "restartOnDelegate").booleanValue()) {
199: // this only applies to running single assignment activities
200: if (activity.state().equals("open.running")
201: && activity.howManyAssignment() == 0) {
202: try {
203: activity.abort();
204: } catch (CannotStop cs) {
205: throw new WfException(
206: "Cannot stop the current activity");
207: } catch (NotRunning nr) {
208: throw new WfException(
209: "Current activity is not running; cannot abort");
210: }
211: String parentProcessId = activity.container()
212: .runtimeKey();
213: newActivity = WfFactory.getWfActivity(activity
214: .getDefinitionObject(), parentProcessId);
215: }
216: }
217:
218: WfAssignment assign = null;
219: if (newActivity != null) {
220: assign = assign(newActivity.runtimeKey(), toPartyId,
221: toRoleTypeId, toFromDate, true);
222: } else {
223: assign = assign(workEffortId, toPartyId, toRoleTypeId,
224: toFromDate, true);
225: }
226:
227: return assign;
228: }
229:
230: /**
231: * Delegate and accept an activity assignment.
232: * @param workEffortId The WorkEffort entity ID for the activitiy.
233: * @param partyId The assigned / to be assigned users party ID.
234: * @param roleTypeId The assigned / to be assigned role type ID.
235: * @param fromDate The assignment's from date.
236: * @param start True to attempt to start the activity.
237: * @return GenericResultWaiter of the start job.
238: * @throws WfException
239: */
240: public void delegateAndAccept(String workEffortId,
241: String fromPartyId, String fromRoleTypeId,
242: Timestamp fromFromDate, String toPartyId,
243: String toRoleTypeId, Timestamp toFromDate, boolean start)
244: throws WfException {
245: WfAssignment assign = delegate(workEffortId, fromPartyId,
246: fromRoleTypeId, fromFromDate, toPartyId, toRoleTypeId,
247: toFromDate);
248: assign.accept();
249: Debug.logVerbose("Delegated assignment.", module);
250:
251: if (start) {
252: Debug.logVerbose("Starting activity.", module);
253: if (!activityRunning(assign.activity())) {
254: start(assign.activity().runtimeKey());
255: } else {
256: Debug.logWarning(
257: "Activity already running; not starting.",
258: module);
259: }
260: } else {
261: Debug.logVerbose("Not starting assignment.", module);
262: }
263: }
264:
265: /**
266: * Start the activity.
267: * @param workEffortId The WorkEffort entity ID for the activitiy.
268: * @return GenericResultWaiter of the start job.
269: * @throws WfException
270: */
271: public void start(String workEffortId) throws WfException {
272: if (dispatcher == null) {
273: throw new WfException(
274: "LocalDispatcher is null; cannot create job for activity startup");
275: }
276:
277: WfActivity activity = WfFactory.getWfActivity(delegator,
278: workEffortId);
279:
280: if (Debug.verboseOn())
281: Debug.logVerbose("Starting activity: " + activity.name(),
282: module);
283: if (activityRunning(activity))
284: throw new WfException("Activity is already running");
285:
286: Job job = new StartActivityJob(activity);
287:
288: if (Debug.verboseOn())
289: Debug.logVerbose("Job: " + job, module);
290: try {
291: dispatcher.getJobManager().runJob(job);
292: } catch (JobManagerException e) {
293: throw new WfException(e.getMessage(), e);
294: }
295:
296: }
297:
298: /**
299: * Complete an activity assignment and follow the next transition(s).
300: * @param workEffortId The WorkEffort entity ID for the activity.
301: * @param partyId The assigned / to be assigned users party ID.
302: * @param roleTypeId The assigned / to be assigned role type ID.
303: * @param fromDate The assignment's from date.
304: * @return GenericResultWaiter for the complete job.
305: * @throws WfException
306: */
307: public void complete(String workEffortId, String partyId,
308: String roleTypeId, Timestamp fromDate, Map result)
309: throws WfException {
310: WfAssignment assign = WfFactory.getWfAssignment(delegator,
311: workEffortId, partyId, roleTypeId, fromDate);
312: if (result != null && result.size() > 0)
313: assign.setResult(result);
314: assign.complete();
315: }
316:
317: /**
318: * Suspend an activity
319: * @param workEffortId The WorkEffort entity key for the activity object
320: * @throws WfException
321: */
322: public void suspend(String workEffortId) throws WfException {
323: WfActivity activity = WfFactory.getWfActivity(delegator,
324: workEffortId);
325:
326: if (Debug.verboseOn())
327: Debug.logVerbose("Suspending activity: " + activity.name(),
328: module);
329: if (!activityRunning(activity))
330: throw new WfException("Activity is not running");
331:
332: activity.suspend();
333: }
334:
335: /**
336: * Resume an activity
337: * @param workEffortId The WorkEffort entity key for the activity object
338: * @throws WfException
339: */
340: public void resume(String workEffortId) throws WfException {
341: WfActivity activity = WfFactory.getWfActivity(delegator,
342: workEffortId);
343:
344: if (Debug.verboseOn())
345: Debug.logVerbose("Resuming activity: " + activity.name(),
346: module);
347: if (activityRunning(activity))
348: throw new WfException("Activity is already running");
349:
350: activity.resume();
351: }
352:
353: /**
354: * Abort a process
355: * @param workEffortId The workeffort entity key for the process to abort
356: * @throws WfException
357: */
358: public void abortProcess(String workEffortId) throws WfException {
359: WfProcess process = WfFactory.getWfProcess(delegator,
360: workEffortId);
361: process.abort();
362: }
363:
364: /**
365: * Append data to the execution object's process context.
366: * @param workEffortId The WorkEffort entity key for the execution object.
367: * @param append The data to append.
368: * @throws WfException
369: */
370: public void appendContext(String workEffortId, Map append)
371: throws WfException {
372: WfExecutionObject obj = getExecutionObject(workEffortId);
373:
374: if (obj != null) {
375: Map oCtx = obj.processContext();
376:
377: oCtx.putAll(append);
378: obj.setProcessContext(oCtx);
379: if (Debug.verboseOn())
380: Debug.logVerbose("ProcessContext (" + workEffortId
381: + ") => " + obj.processContext(), module);
382: }
383: }
384:
385: /**
386: * Returns the process context of the execution object.
387: * @param workEffortId The WorkEffort entity key for the execution object.
388: * @throws WfException
389: */
390: public Map getContext(String workEffortId) throws WfException {
391: WfExecutionObject obj = getExecutionObject(workEffortId);
392:
393: if (obj == null)
394: throw new WfException(
395: "Invalid Execution Object (null value)");
396: if (Debug.verboseOn())
397: Debug.logVerbose("ProcessContext (" + workEffortId
398: + ") => " + obj.processContext(), module);
399: return obj.processContext();
400: }
401:
402: /**
403: * Gets the state of the execution object defined by the work effort key.
404: * @param workEffortId The WorkEffort entity key for the execution object.
405: * @throws WfException
406: */
407: public String getState(String workEffortId) throws WfException {
408: WfExecutionObject obj = getExecutionObject(workEffortId);
409:
410: if (obj == null)
411: throw new WfException(
412: "Invalid Execution Object (null value)");
413: if (Debug.verboseOn())
414: Debug.logVerbose("Current State (" + workEffortId + ") => "
415: + obj.state(), module);
416: return obj.state();
417: }
418:
419: /**
420: * Set the state of the execution object defined by the work effort key.
421: * @param workEffortId The WorkEffort entity key for the execution object.
422: * @param state The new state of the execution object.
423: * @return Current state of the execution object as a string.
424: * @throws WfException If state change is not allowed.
425: */
426: public void setState(String workEffortId, String state)
427: throws WfException {
428: WfExecutionObject obj = getExecutionObject(workEffortId);
429:
430: if (obj == null)
431: throw new WfException(
432: "Invalid Execution Object (null value)");
433: obj.changeState(state);
434: if (Debug.verboseOn())
435: Debug.logVerbose("Current State (" + workEffortId + ") => "
436: + obj.state(), module);
437: }
438:
439: /**
440: * Gets the priority of the execution object defined by the work effort key.
441: * @param workEffortId The WorkEffort entity key for the execution object.
442: * @return Priority of the execution object as a long.
443: * @throws WfException
444: */
445: public long getPriority(String workEffortId) throws WfException {
446: WfExecutionObject obj = getExecutionObject(workEffortId);
447:
448: if (obj == null)
449: throw new WfException(
450: "Invalid Execution Object (null value)");
451: if (Debug.verboseOn())
452: Debug.logVerbose("Current Priority (" + workEffortId
453: + ") => " + obj.priority(), module);
454: return obj.priority();
455: }
456:
457: /**
458: * Set the priority of the execution object defined by the work effort key.
459: * @param workEffortId The WorkEffort entity key for the execution object.
460: * @param priority The new priority of the execution object.
461: * @throws WfException If state change is not allowed.
462: */
463: public void setPriority(String workEffortId, long priority)
464: throws WfException {
465: WfExecutionObject obj = getExecutionObject(workEffortId);
466:
467: if (obj == null)
468: throw new WfException(
469: "Invalid Execution Object (null value)");
470: obj.setPriority(priority);
471: if (Debug.verboseOn())
472: Debug.logVerbose("Current Priority (" + workEffortId
473: + ") => " + obj.priority(), module);
474: }
475:
476: // Get the execution object for the workeffort
477: private WfExecutionObject getExecutionObject(String workEffortId) {
478: WfExecutionObject obj = null;
479:
480: try {
481: obj = (WfExecutionObject) WfFactory.getWfActivity(
482: delegator, workEffortId);
483: } catch (WfException e) {// ingore
484: }
485: if (obj == null) {
486: try {
487: obj = (WfExecutionObject) WfFactory.getWfProcess(
488: delegator, workEffortId);
489: } catch (WfException e) {// ignore
490: }
491: }
492: return obj;
493: }
494:
495: // Test an activity for running state.
496: private boolean activityRunning(String workEffortId)
497: throws WfException {
498: return activityRunning(WfFactory.getWfActivity(delegator,
499: workEffortId));
500: }
501:
502: // Test an activity for running state.
503: private boolean activityRunning(WfActivity activity)
504: throws WfException {
505: if (activity.state().equals("open.running"))
506: return true;
507: return false;
508: }
509:
510: }
|