001: /*
002: * $Id: WfActivityImpl.java,v 1.4 2003/09/02 02:17:15 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.impl;
026:
027: import java.util.ArrayList;
028: import java.util.Calendar;
029: import java.util.Collection;
030: import java.util.Date;
031: import java.util.HashMap;
032: import java.util.Iterator;
033: import java.util.List;
034: import java.util.Map;
035: import java.util.Set;
036:
037: import org.ofbiz.base.util.BshUtil;
038: import org.ofbiz.base.util.Debug;
039: import org.ofbiz.base.util.StringUtil;
040: import org.ofbiz.base.util.UtilDateTime;
041: import org.ofbiz.base.util.UtilMisc;
042: import org.ofbiz.entity.GenericDelegator;
043: import org.ofbiz.entity.GenericEntityException;
044: import org.ofbiz.entity.GenericValue;
045: import org.ofbiz.entity.util.EntityTypeUtil;
046: import org.ofbiz.entity.util.EntityUtil;
047: import org.ofbiz.service.DispatchContext;
048: import org.ofbiz.service.GenericServiceException;
049: import org.ofbiz.service.LocalDispatcher;
050: import org.ofbiz.service.ModelService;
051: import org.ofbiz.workflow.AlreadyRunning;
052: import org.ofbiz.workflow.CannotComplete;
053: import org.ofbiz.workflow.CannotResume;
054: import org.ofbiz.workflow.CannotStart;
055: import org.ofbiz.workflow.CannotStop;
056: import org.ofbiz.workflow.InvalidData;
057: import org.ofbiz.workflow.InvalidState;
058: import org.ofbiz.workflow.NotRunning;
059: import org.ofbiz.workflow.NotSuspended;
060: import org.ofbiz.workflow.ResultNotAvailable;
061: import org.ofbiz.workflow.TransitionNotAllowed;
062: import org.ofbiz.workflow.WfActivity;
063: import org.ofbiz.workflow.WfAssignment;
064: import org.ofbiz.workflow.WfException;
065: import org.ofbiz.workflow.WfFactory;
066: import org.ofbiz.workflow.WfProcess;
067: import org.ofbiz.workflow.WfResource;
068:
069: /**
070: * WfActivityImpl - Workflow Activity Object implementation
071: *
072: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
073: * @author David Ostrovsky (d.ostrovsky@gmx.de)
074: * @author Oswin Ondarza and Manuel Soto
075: * @version $Revision: 1.4 $
076: * @since 2.0
077: */
078: public class WfActivityImpl extends WfExecutionObjectImpl implements
079: WfActivity {
080:
081: public static final String module = WfActivityImpl.class.getName();
082:
083: private static final int CHECK_ASSIGN = 1;
084: private static final int CHECK_COMPLETE = 2;
085:
086: protected String processId = null;
087:
088: public WfActivityImpl(GenericValue value, String processId)
089: throws WfException {
090: super (value, processId);
091: this .processId = processId;
092: init();
093: }
094:
095: public WfActivityImpl(GenericDelegator delegator,
096: String workEffortId) throws WfException {
097: super (delegator, workEffortId);
098: if (activityId == null || activityId.length() == 0)
099: throw new WfException(
100: "Execution object is not of type WfActivity");
101: this .processId = getRuntimeObject().getString(
102: "workEffortParentId");
103: }
104:
105: private void init() throws WfException {
106: GenericValue valueObject = getDefinitionObject();
107:
108: // set the activity context
109: this .setProcessContext(container().contextKey());
110:
111: // parse the descriptions
112: this .parseDescriptions(this .processContext());
113:
114: // check for inheritPriority attribute
115: boolean inheritPriority = valueObject.getBoolean(
116: "inheritPriority").booleanValue() || false;
117:
118: if (inheritPriority) {
119: GenericValue runTime = getRuntimeObject();
120: Map context = processContext();
121:
122: if (context.containsKey("previousActivity")) {
123: String previousActivity = (String) context
124: .get("previousActivity");
125: WfActivity pAct = WfFactory.getWfActivity(
126: getDelegator(), previousActivity);
127:
128: if (pAct != null) {
129: try {
130: runTime.set("priority", new Long(pAct
131: .priority()));
132: runTime.store();
133: } catch (GenericEntityException e) {
134: throw new WfException(e.getMessage(), e);
135: }
136: }
137: }
138: }
139:
140: GenericValue performer = null;
141: if (valueObject.get("performerParticipantId") != null) {
142: try {
143: performer = valueObject
144: .getRelatedOne("PerformerWorkflowParticipant");
145: if (performer == null) {
146: Map performerFields = UtilMisc
147: .toMap(
148: "packageId",
149: valueObject.getString("packageId"),
150: "packageVersion",
151: valueObject
152: .getString("packageVersion"),
153: "processId",
154: "_NA_",
155: "processVersion",
156: "_NA_",
157: "participantId",
158: valueObject
159: .getString("performerParticipantId"));
160: performer = delegator.findByPrimaryKey(
161: "WorkflowParticipant", performerFields);
162: }
163: } catch (GenericEntityException e) {
164: throw new WfException(e.getMessage(), e);
165: }
166: }
167: if (performer != null)
168: createAssignments(performer);
169:
170: boolean limitAfterStart = valueObject.getBoolean(
171: "limitAfterStart").booleanValue();
172:
173: if (Debug.verboseOn()) {
174: Debug.logVerbose("[WfActivity.init]: limitAfterStart - "
175: + limitAfterStart, module);
176: }
177: if (!limitAfterStart && valueObject.get("limitService") != null
178: && !valueObject.getString("limitService").equals("")) {
179: Debug
180: .logVerbose(
181: "[WfActivity.init]: limit service is not after start, setting up now.",
182: module);
183: setLimitService();
184: }
185: }
186:
187: private void createAssignments(GenericValue currentPerformer)
188: throws WfException {
189: GenericValue valueObject = getDefinitionObject();
190: GenericValue performer = checkPerformer(currentPerformer);
191: boolean assignAll = false;
192:
193: if (valueObject.get("acceptAllAssignments") != null) {
194: assignAll = valueObject.getBoolean("acceptAllAssignments")
195: .booleanValue();
196: }
197:
198: // first check for single assignment
199: if (!assignAll) {
200: if (performer != null) {
201: Debug
202: .logVerbose(
203: "[WfActivity.createAssignments] : (S) Single assignment",
204: module);
205: assign(WfFactory.getWfResource(performer), false);
206: }
207: }
208:
209: // check for a party group
210: else if (performer.get("partyId") != null
211: && !performer.getString("partyId").equals("_NA_")) {
212: GenericValue partyType = null;
213: GenericValue groupType = null;
214:
215: try {
216: Map fields1 = UtilMisc.toMap("partyId", performer
217: .getString("partyId"));
218: GenericValue v1 = getDelegator().findByPrimaryKey(
219: "Party", fields1);
220:
221: partyType = v1.getRelatedOne("PartyType");
222: Map fields2 = UtilMisc.toMap("partyTypeId",
223: "PARTY_GROUP");
224: groupType = getDelegator().findByPrimaryKeyCache(
225: "PartyType", fields2);
226: } catch (GenericEntityException e) {
227: throw new WfException(e.getMessage(), e);
228: }
229: if (EntityTypeUtil.isType(partyType, groupType)) {
230: // party is a group
231: Collection partyRelations = null;
232: try {
233: Map fields = UtilMisc.toMap("partyIdFrom",
234: performer.getString("partyId"),
235: "partyRelationshipTypeId", "GROUP_ROLLUP");
236: partyRelations = getDelegator().findByAnd(
237: "PartyRelationship", fields);
238: } catch (GenericEntityException e) {
239: throw new WfException(e.getMessage(), e);
240: }
241:
242: // make assignments for these parties
243: Debug
244: .logVerbose(
245: "[WfActivity.createAssignments] : Group assignment",
246: module);
247: Iterator i = partyRelations.iterator();
248:
249: while (i.hasNext()) {
250: GenericValue value = (GenericValue) i.next();
251: assign(WfFactory.getWfResource(getDelegator(),
252: null, null, value.getString("partyIdTo"),
253: null), true);
254: }
255: } else {
256: // not a group
257: Debug
258: .logVerbose(
259: "[WfActivity.createAssignments] : (G) Single assignment",
260: module);
261: assign(WfFactory.getWfResource(performer), false);
262: }
263: }
264:
265: // check for role types
266: else if (performer.get("roleTypeId") != null
267: && !performer.getString("roleTypeId").equals("_NA_")) {
268: Collection partyRoles = null;
269:
270: try {
271: Map fields = UtilMisc.toMap("roleTypeId", performer
272: .getString("roleTypeId"));
273: partyRoles = getDelegator().findByAnd("PartyRole",
274: fields);
275: } catch (GenericEntityException e) {
276: throw new WfException(e.getMessage(), e);
277: }
278:
279: // loop through the roles and create assignments
280: Debug.logVerbose(
281: "[WfActivity.createAssignments] : Role assignment",
282: module);
283: Iterator i = partyRoles.iterator();
284:
285: while (i.hasNext()) {
286: GenericValue value = (GenericValue) i.next();
287: assign(WfFactory.getWfResource(value.getDelegator(),
288: null, null, value.getString("partyId"), null),
289: true);
290: }
291: }
292: }
293:
294: private List getAssignments() throws WfException {
295: List assignments = new ArrayList();
296: List assignList = this .getAllAssignments();
297:
298: if (assignList == null)
299: return assignments;
300:
301: Iterator i = assignList.iterator();
302: while (i.hasNext()) {
303: GenericValue value = (GenericValue) i.next();
304: String party = value.getString("partyId");
305: String role = value.getString("roleTypeId");
306: String status = value.getString("statusId");
307: java.sql.Timestamp from = value.getTimestamp("fromDate");
308:
309: if (status.equals("CAL_SENT")
310: || status.equals("CAL_ACCEPTED")
311: || status.equals("CAL_TENTATIVE"))
312: assignments.add(WfFactory
313: .getWfAssignment(getDelegator(), runtimeKey(),
314: party, role, from));
315: }
316: if (Debug.verboseOn())
317: Debug.logVerbose("Found [" + assignments.size()
318: + "] assignment(s)", module);
319: return assignments;
320: }
321:
322: private List getAllAssignments() throws WfException {
323: List assignList = null;
324: try {
325: assignList = getDelegator().findByAnd(
326: "WorkEffortPartyAssignment",
327: UtilMisc.toMap("workEffortId", runtimeKey()));
328: } catch (GenericEntityException e) {
329: throw new WfException(e.getMessage(), e);
330: }
331:
332: if (assignList != null) {
333: assignList = EntityUtil.filterByDate(assignList);
334: } else {
335: return new ArrayList();
336: }
337: return assignList;
338: }
339:
340: // create a new assignment
341: private WfAssignment assign(WfResource resource, boolean append)
342: throws WfException {
343: if (!append) {
344: Iterator ai = getIteratorAssignment();
345: while (ai.hasNext()) {
346: WfAssignment a = (WfAssignment) ai.next();
347: a.remove();
348: }
349: }
350:
351: WfAssignment assign = WfFactory.getWfAssignment(this , resource,
352: null, true);
353: return assign;
354: }
355:
356: // check the performer: dynamic; defined partyId/roleTypeId
357: private GenericValue checkPerformer(GenericValue performer)
358: throws WfException {
359: GenericValue newPerformer = new GenericValue(performer);
360: Map context = processContext();
361:
362: String performerType = performer.getString("participantTypeId");
363: String partyId = performer.getString("partyId");
364: String roleTypeId = performer.getString("roleTypeId");
365:
366: // check for dynamic party
367: if (partyId != null
368: && partyId.trim().toLowerCase().startsWith("expr:")) {
369: if (Debug.verboseOn())
370: Debug.logVerbose(
371: "Dynamic performer: Found a party expression",
372: module);
373: Object value = null;
374: try {
375: value = BshUtil.eval(
376: partyId.trim().substring(5).trim(), context);
377: } catch (bsh.EvalError e) {
378: throw new WfException("Bsh evaluation error occurred.",
379: e);
380: }
381: if (value != null) {
382: if (value instanceof String) {
383: newPerformer.set("partyId", value);
384: } else {
385: throw new WfException(
386: "Expression did not return a String");
387: }
388: }
389: }
390:
391: // check for dynamic role
392: if (roleTypeId != null
393: && roleTypeId.trim().toLowerCase().startsWith("expr:")) {
394: if (Debug.verboseOn())
395: Debug.logVerbose(
396: "Dynamic performer: Found a role expression",
397: module);
398: Object value = null;
399: try {
400: value = BshUtil.eval(roleTypeId.trim().substring(5)
401: .trim(), context);
402: } catch (bsh.EvalError e) {
403: throw new WfException("Bsh evaluation error occurred.",
404: e);
405: }
406: if (value != null) {
407: if (value instanceof String) {
408: newPerformer.set("roleTypeId", value);
409: } else {
410: throw new WfException(
411: "Expression did not return a String");
412: }
413: }
414: }
415:
416: // check for un-defined party
417: if (performerType.equals("HUMAN")
418: || performerType.equals("ORGANIZATIONAL_UNIT")) {
419: if (partyId == null) {
420: newPerformer.set("partyId", performer
421: .getString("participantId"));
422: }
423: }
424:
425: // check for un-defined role
426: if (performerType.equals("ROLE")) {
427: if (roleTypeId == null) {
428: newPerformer.set("roleTypeId", performer
429: .getString("participantId"));
430: }
431: }
432:
433: return newPerformer;
434: }
435:
436: /**
437: * @see org.ofbiz.workflow.WfActivity#activate()
438: */
439: public void activate() throws WfException, CannotStart,
440: AlreadyRunning {
441: // make sure we aren't already running
442: if (this .state().equals("open.running"))
443: throw new AlreadyRunning();
444:
445: // check the start mode
446: String mode = getDefinitionObject()
447: .getString("startModeEnumId");
448:
449: if (mode == null) {
450: throw new WfException("Start mode cannot be null");
451: }
452:
453: if (mode.equals("WAM_AUTOMATIC")) {
454: Debug.logVerbose("Activity start mode is AUTO", module);
455: Iterator i = getIteratorAssignment();
456: while (i.hasNext())
457: ((WfAssignment) i.next()).changeStatus("CAL_ACCEPTED"); // accept all assignments (AUTO)
458: Debug.logVerbose(
459: "All assignments accepted, starting activity: "
460: + this .runtimeKey(), module);
461: startActivity();
462: } else if (howManyAssignment() > 0
463: && checkAssignStatus(CHECK_ASSIGN)) {
464: Debug.logVerbose("Starting activity: " + this .runtimeKey(),
465: module);
466: startActivity();
467: }
468: }
469:
470: /**
471: * @see org.ofbiz.workflow.WfActivity#complete()
472: */
473: public void complete() throws WfException, CannotComplete {
474: // check to make sure all assignements are complete
475: if (howManyAssignment() > 0
476: && !checkAssignStatus(CHECK_COMPLETE))
477: throw new CannotComplete(
478: "All assignments have not been completed");
479: try {
480: container().receiveResults(this , result());
481: } catch (InvalidData e) {
482: throw new WfException("Invalid result data was passed", e);
483: }
484: try {
485: changeState("closed.completed");
486: GenericValue activityWe = getRuntimeObject();
487: activityWe.set("actualCompletionDate", UtilDateTime
488: .nowTimestamp());
489: activityWe.store();
490: } catch (InvalidState is) {
491: throw new WfException("Invalid WF State", is);
492: } catch (TransitionNotAllowed tna) {
493: throw new WfException(tna.getMessage(), tna);
494: } catch (GenericEntityException gee) {
495: throw new WfException(gee.getMessage(), gee);
496: }
497:
498: container().activityComplete(this );
499: }
500:
501: /**
502: * @see org.ofbiz.workflow.WfExecutionObject#resume()
503: */
504: public void resume() throws WfException, CannotResume, NotRunning,
505: NotSuspended {
506: super .resume();
507: try {
508: Debug.logVerbose(
509: "Checking to see if we can complete the activity",
510: module);
511: this .checkComplete();
512: } catch (CannotComplete e) {
513: throw new CannotResume(
514: "Attempt to complete activity failed", e);
515: }
516: }
517:
518: /**
519: * @see org.ofbiz.workflow.WfExecutionObject#abort()
520: */
521: public void abort() throws WfException, CannotStop, NotRunning {
522: super .abort();
523:
524: // cancel the active assignments
525: Iterator assignments = this .getAssignments().iterator();
526: while (assignments.hasNext()) {
527: WfAssignment assignment = (WfAssignment) assignments.next();
528: assignment.changeStatus("CAL_CANCELLED");
529: }
530: }
531:
532: /**
533: * @see org.ofbiz.workflow.WfActivity#isMemberOfAssignment(org.ofbiz.workflow.WfAssignment)
534: */
535: public boolean isMemberOfAssignment(WfAssignment member)
536: throws WfException {
537: return getAssignments().contains(member);
538: }
539:
540: /**
541: * @see org.ofbiz.workflow.WfActivity#container()
542: */
543: public WfProcess container() throws WfException {
544: return WfFactory.getWfProcess(delegator, processId);
545: }
546:
547: /**
548: * @see org.ofbiz.workflow.WfActivity#setResult(java.util.Map)
549: */
550: public void setResult(Map newResult) throws WfException,
551: InvalidData {
552: if (newResult != null && newResult.size() > 0) {
553: if (Debug.verboseOn())
554: Debug.logVerbose("[WfActivity.setResult]: putting ("
555: + newResult.size() + ") keys into context.",
556: module);
557: Map context = processContext();
558: context.putAll(newResult);
559: setSerializedData(context);
560: }
561: }
562:
563: /**
564: * @see org.ofbiz.workflow.WfActivity#howManyAssignment()
565: */
566: public int howManyAssignment() throws WfException {
567: return getAssignments().size();
568: }
569:
570: /**
571: * @see org.ofbiz.workflow.WfActivity#result()
572: */
573: public Map result() throws WfException, ResultNotAvailable {
574: // Get the results from the signature.
575: Map resultSig = container().manager().resultSignature();
576: Map results = new HashMap();
577: Map context = processContext();
578:
579: if (resultSig != null) {
580: Set resultKeys = resultSig.keySet();
581: Iterator i = resultKeys.iterator();
582:
583: while (i.hasNext()) {
584: Object key = i.next();
585: if (context.containsKey(key))
586: results.put(key, context.get(key));
587: }
588: }
589: return results;
590: }
591:
592: /**
593: * @see org.ofbiz.workflow.WfActivity#getSequenceAssignment(int)
594: */
595: public List getSequenceAssignment(int maxNumber) throws WfException {
596: if (maxNumber > 0)
597: return getAssignments().subList(0, (maxNumber - 1));
598: return getAssignments();
599: }
600:
601: /**
602: * @see org.ofbiz.workflow.WfActivity#getIteratorAssignment()
603: */
604: public Iterator getIteratorAssignment() throws WfException {
605: return getAssignments().iterator();
606: }
607:
608: /**
609: * @see org.ofbiz.workflow.impl.WfExecutionObjectImpl#executionObjectType()
610: */
611: public String executionObjectType() {
612: return "WfActivity";
613: }
614:
615: // Checks to see if we can complete
616: private void checkComplete() throws WfException, CannotComplete {
617: String mode = getDefinitionObject().getString(
618: "finishModeEnumId");
619:
620: if (mode == null)
621: throw new CannotComplete("Finish mode cannot be null");
622:
623: // Default mode is MANUAL -- only finish if we are automatic
624: if (mode.equals("WAM_AUTOMATIC")) {
625: // check and make sure we are not suspended
626: if (state().equals("open.running")) {
627: // set the status of the assignments
628: Iterator i = getIteratorAssignment();
629: while (i.hasNext())
630: ((WfAssignment) i.next())
631: .changeStatus("CAL_COMPLETED");
632: this .complete();
633: }
634: }
635: }
636:
637: // Checks the staus of all assignments
638: // type 1 -> accept status
639: // type 2 -> complete status
640: private boolean checkAssignStatus(int type) throws WfException {
641: boolean acceptAll = false;
642: boolean completeAll = false;
643: GenericValue valueObject = getDefinitionObject();
644:
645: if (valueObject.get("acceptAllAssignments") != null)
646: acceptAll = valueObject.getBoolean("acceptAllAssignments")
647: .booleanValue();
648: if (valueObject.get("completeAllAssignments") != null)
649: completeAll = valueObject.getBoolean(
650: "completeAllAssignments").booleanValue();
651:
652: List validStatus = null;
653:
654: if (type == CHECK_ASSIGN)
655: validStatus = UtilMisc.toList("CAL_ACCEPTED",
656: "CAL_COMPLETED", "CAL_DELEGATED");
657: else if (type == CHECK_COMPLETE)
658: validStatus = UtilMisc.toList("CAL_COMPLETED",
659: "CAL_DELEGATED");
660: else
661: throw new WfException("Invalid status type");
662:
663: boolean foundOne = false;
664:
665: List assignList = this .getAllAssignments();
666: Iterator i = assignList.iterator();
667:
668: while (i.hasNext()) {
669: GenericValue value = (GenericValue) i.next();
670: String party = value.getString("partyId");
671: String role = value.getString("roleTypeId");
672: String status = value.getString("statusId");
673: java.sql.Timestamp from = value.getTimestamp("fromDate");
674: WfAssignment a = WfFactory.getWfAssignment(getDelegator(),
675: runtimeKey(), party, role, from);
676:
677: if (validStatus.contains(a.status())) {
678: // if we find one set this to true
679: foundOne = true;
680: } else {
681: // if we must completeAll / assignAll and this one fails return false
682: if ((type == CHECK_COMPLETE && completeAll)
683: || (type == CHECK_ASSIGN && acceptAll))
684: return false;
685: }
686: }
687:
688: // we are here only if all are done, or complete/assign is false; so if not false we are done
689: if ((type == CHECK_COMPLETE && completeAll)
690: || (type == CHECK_ASSIGN && acceptAll)) {
691: return true;
692: } else {
693: // if not all done, we don't require all, so use that foundOne stored above
694: Debug
695: .logVerbose(
696: "[checkAssignStatus] : need only one assignment to pass",
697: module);
698: if (foundOne)
699: return true;
700: Debug.logVerbose(
701: "[checkAssignStatus] : found no assignment(s)",
702: module);
703: return false;
704: }
705: }
706:
707: // Starts or activates this automatic activity
708: private void startActivity() throws WfException, CannotStart {
709: try {
710: changeState("open.running");
711: } catch (InvalidState is) {
712: throw new CannotStart(is.getMessage(), is);
713: } catch (TransitionNotAllowed tna) {
714: throw new CannotStart(tna.getMessage(), tna);
715: }
716: // check the limit service
717: boolean limitAfterStart = getDefinitionObject().getBoolean(
718: "limitAfterStart").booleanValue();
719:
720: if (limitAfterStart
721: && getDefinitionObject().get("limitService") != null
722: && !getDefinitionObject().getString("limitService")
723: .equals("")) {
724: Debug
725: .logVerbose(
726: "[WfActivity.init]: limit service is after start, setting up now.",
727: module);
728: setLimitService();
729: }
730:
731: // set the new previousActivity
732: Map context = processContext();
733:
734: context.put("previousActivity", workEffortId);
735: this .setProcessContext(context);
736:
737: // set the actualStartDate
738: try {
739: GenericValue v = getRuntimeObject();
740: v.set("actualStartDate", UtilDateTime.nowTimestamp());
741: v.store();
742: } catch (GenericEntityException e) {
743: Debug
744: .logWarning("Could not set 'actualStartDate'.",
745: module);
746: e.printStackTrace();
747: }
748:
749: // get the type of this activity
750: String type = getDefinitionObject().getString(
751: "activityTypeEnumId");
752:
753: if (type == null)
754: throw new WfException("Illegal activity type");
755:
756: WfActivityAbstractImplementation executor = WfActivityImplementationFact
757: .getConcretImplementation(type, this );
758: executor.run();
759: this .setResult(executor.getResult());
760: if (executor.isComplete())
761: this .checkComplete();
762: }
763:
764: // schedule the limit service to run
765: private void setLimitService() throws WfException {
766: LocalDispatcher dispatcher = getDispatcher();
767:
768: DispatchContext dctx = dispatcher.getDispatchContext();
769: String limitService = getDefinitionObject().getString(
770: "limitService");
771: ModelService service = null;
772:
773: try {
774: service = dctx.getModelService(limitService);
775: Debug
776: .logVerbose(
777: "[WfActivity.setLimitService] : Found service model.",
778: module);
779: } catch (GenericServiceException e) {
780: Debug
781: .logError(
782: e,
783: "[WfActivity.setLimitService] : Cannot get service model.",
784: module);
785: }
786: if (service == null) {
787: Debug
788: .logWarning(
789: "[WfActivity.setLimitService] : Cannot determine limit service, ignoring.",
790: module);
791: return;
792: }
793:
794: // make the limit service context
795: List inList = new ArrayList(service.getInParamNames());
796: String inParams = StringUtil.join(inList, ",");
797:
798: Map serviceContext = actualContext(inParams, null, null, true);
799: Debug.logVerbose("Setting limit service with context: "
800: + serviceContext, module);
801:
802: Double timeLimit = null;
803:
804: if (getDefinitionObject().get("timeLimit") != null)
805: timeLimit = getDefinitionObject().getDouble("timeLimit");
806: if (timeLimit == null)
807: return;
808:
809: String durationUOM = null;
810:
811: if (container().getDefinitionObject()
812: .getString("durationUomId") != null)
813: durationUOM = container().getDefinitionObject().getString(
814: "durationUomId");
815: if (durationUOM == null)
816: return;
817:
818: char durChar = durationUOM.charAt(0);
819: Calendar cal = Calendar.getInstance();
820:
821: cal.setTime(new Date());
822: switch (durChar) {
823: case 'Y':
824: cal.add(Calendar.YEAR, timeLimit.intValue());
825: break;
826:
827: case 'M':
828: cal.add(Calendar.MONTH, timeLimit.intValue());
829: break;
830:
831: case 'D':
832: cal.add(Calendar.DATE, timeLimit.intValue());
833: break;
834:
835: case 'h':
836: cal.add(Calendar.HOUR, timeLimit.intValue());
837: break;
838:
839: case 'm':
840: cal.add(Calendar.MINUTE, timeLimit.intValue());
841: break;
842:
843: case 's':
844: cal.add(Calendar.SECOND, timeLimit.intValue());
845: break;
846:
847: default:
848: throw new WfException("Invalid duration unit");
849: }
850:
851: long startTime = cal.getTime().getTime();
852: Map context = new HashMap();
853:
854: context.put("serviceName", limitService);
855: context.put("serviceContext", serviceContext);
856: context.put("workEffortId", runtimeKey());
857:
858: try {
859: dispatcher.schedule("wfLimitInvoker", context, startTime); // yes we are hard coded!
860: } catch (GenericServiceException e) {
861: throw new WfException(e.getMessage(), e);
862: }
863: if (Debug.verboseOn()) {
864: Debug.logVerbose(
865: "[WfActivity.setLimitService]: Set limit service ("
866: + limitService + " ) to run at "
867: + startTime, module);
868: }
869: }
870:
871: Map actualContext(String actualParameters, String extendedAttr,
872: List serviceSignature, boolean ignoreUnknown)
873: throws WfException {
874: Map actualContext = new HashMap();
875: Map context = processContext();
876:
877: // extended attributes take priority over context attributes
878: Map extendedAttributes = StringUtil.strToMap(extendedAttr);
879:
880: if (extendedAttributes != null && extendedAttributes.size() > 0) {
881: context.putAll(extendedAttributes);
882: }
883:
884: // setup some internal buffer parameters
885: GenericValue userLogin = null;
886:
887: if (context.containsKey("runAsUser")) {
888: userLogin = getUserLogin((String) context.get("runAsUser"));
889: actualContext.put("userLogin", userLogin);
890: } else if (context.containsKey("workflowOwnerId")) {
891: userLogin = getUserLogin((String) context
892: .get("workflowOwnerId"));
893: }
894:
895: // some static context values
896: context.put("userLogin", userLogin);
897: context.put("workEffortId", runtimeKey());
898: if (howManyAssignment() == 1) {
899: Debug.logVerbose(
900: "Single assignment; getting assignment info.",
901: module);
902: List assignments = getAssignments();
903: WfAssignment assign = (WfAssignment) assignments.iterator()
904: .next();
905: WfResource res = assign.assignee();
906: context.put("assignedPartyId", res.resourcePartyId());
907: context.put("assignedRoleTypeId", res.resourceRoleId());
908: }
909:
910: // first we will pull out the values from the context for the actual parameters
911: if (actualParameters != null) {
912: List params = StringUtil.split(actualParameters, ",");
913: Iterator i = params.iterator();
914:
915: while (i.hasNext()) {
916: Object key = i.next();
917: String keyStr = (String) key;
918:
919: if (keyStr != null
920: && keyStr.trim().toLowerCase().startsWith(
921: "expr:")) {
922: // check for bsh expressions; this does not place values into the context
923: try {
924: BshUtil.eval(keyStr.trim().substring(5).trim(),
925: context);
926: } catch (bsh.EvalError e) {
927: throw new WfException("Bsh evaluation error.",
928: e);
929: }
930: } else if (keyStr != null
931: && keyStr.trim().toLowerCase().startsWith(
932: "name:")) {
933: // name mapping of context values
934: List couple = StringUtil.split(keyStr.trim()
935: .substring(5).trim(), "=");
936: String mName = (String) couple.get(0); // mapped name
937: String cName = (String) couple.get(1); // context name
938:
939: // trim out blank space
940: if (mName != null)
941: mName = mName.trim();
942: if (cName != null)
943: cName = cName.trim();
944:
945: if (mName != null && cName != null
946: && context.containsKey(cName)) {
947: actualContext.put(mName, context.get(cName));
948: }
949: } else if (context.containsKey(key)) {
950: // direct assignment from context
951: actualContext.put(key, context.get(key));
952: } else if (!actualContext.containsKey(key)
953: && !ignoreUnknown) {
954: throw new WfException(
955: "Context does not contain the key: '"
956: + (String) key + "'");
957: }
958: }
959: }
960:
961: // the serviceSignature should not limit which parameters are in the actualContext
962: // so instead we will use this signature to pull out values so they do not all have to be defined
963: if (serviceSignature != null) {
964: Iterator si = serviceSignature.iterator();
965: while (si.hasNext()) {
966: Object key = si.next();
967: String keyStr = (String) key;
968: if (!actualContext.containsKey(key)
969: && context.containsKey(key)) {
970: actualContext.put(keyStr, context.get(keyStr));
971: }
972: }
973: }
974: return actualContext;
975: }
976:
977: // Gets a UserLogin object for service invocation
978: // This allows a workflow to invoke a service as a specific user
979: private GenericValue getUserLogin(String userId) throws WfException {
980: GenericValue userLogin = null;
981: try {
982: userLogin = getDelegator().findByPrimaryKey("UserLogin",
983: UtilMisc.toMap("userLoginId", userId));
984: } catch (GenericEntityException e) {
985: throw new WfException(e.getMessage(), e);
986: }
987: return userLogin;
988: }
989: }
|