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