1 25 package org.ofbiz.workflow.impl; 26 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Map ; 33 import java.util.Set ; 34 35 import org.ofbiz.base.util.Debug; 36 import org.ofbiz.base.util.StringUtil; 37 import org.ofbiz.base.util.UtilDateTime; 38 import org.ofbiz.base.util.UtilMisc; 39 import org.ofbiz.entity.GenericDelegator; 40 import org.ofbiz.entity.GenericEntityException; 41 import org.ofbiz.entity.GenericValue; 42 import org.ofbiz.service.GenericResultWaiter; 43 import org.ofbiz.service.LocalDispatcher; 44 import org.ofbiz.service.job.Job; 45 import org.ofbiz.service.job.JobManager; 46 import org.ofbiz.service.job.JobManagerException; 47 import org.ofbiz.workflow.AlreadyRunning; 48 import org.ofbiz.workflow.CannotChangeRequester; 49 import org.ofbiz.workflow.CannotStart; 50 import org.ofbiz.workflow.CannotStop; 51 import org.ofbiz.workflow.InvalidData; 52 import org.ofbiz.workflow.InvalidPerformer; 53 import org.ofbiz.workflow.InvalidState; 54 import org.ofbiz.workflow.NotRunning; 55 import org.ofbiz.workflow.ResultNotAvailable; 56 import org.ofbiz.workflow.WfActivity; 57 import org.ofbiz.workflow.WfEventAudit; 58 import org.ofbiz.workflow.WfException; 59 import org.ofbiz.workflow.WfFactory; 60 import org.ofbiz.workflow.WfProcess; 61 import org.ofbiz.workflow.WfProcessMgr; 62 import org.ofbiz.workflow.WfRequester; 63 import org.ofbiz.workflow.WfUtil; 64 import org.ofbiz.workflow.client.StartActivityJob; 65 66 74 public class WfProcessImpl extends WfExecutionObjectImpl implements WfProcess { 75 76 public static final String module = WfProcessImpl.class.getName(); 77 78 protected WfRequester requester = null; 79 protected WfProcessMgr manager = null; 80 81 public WfProcessImpl(GenericValue valueObject, WfProcessMgr manager) throws WfException { 82 super(valueObject, null); 83 this.manager = manager; 84 this.requester = null; 85 init(); 86 } 87 88 91 public WfProcessImpl(GenericDelegator delegator, String workEffortId) throws WfException { 92 super(delegator, workEffortId); 93 if (activityId != null && activityId.length() > 0) 94 throw new WfException("Execution object is not of type WfProcess."); 95 this.manager = WfFactory.getWfProcessMgr(delegator, packageId, packageVersion, processId, processVersion); 96 this.requester = null; 97 } 98 99 private void init() throws WfException { 100 Map context = manager.getInitialContext(); 103 this.parseDescriptions(context); 104 } 105 106 109 public void setRequester(WfRequester newValue) throws WfException, CannotChangeRequester { 110 if (requester != null) 111 throw new CannotChangeRequester(); 112 requester = newValue; 113 } 114 115 118 public List getSequenceStep(int maxNumber) throws WfException { 119 if (maxNumber > 0) 120 return new ArrayList (activeSteps().subList(0, maxNumber - 1)); 121 return activeSteps(); 122 } 123 124 127 public void abort() throws WfException, CannotStop, NotRunning { 128 super.abort(); 129 130 Iterator activities = this.activeSteps().iterator(); 132 while (activities.hasNext()) { 133 WfActivity activity = (WfActivity) activities.next(); 134 activity.abort(); 135 } 136 } 137 138 141 public void start() throws WfException, CannotStart, AlreadyRunning { 142 start(null); 143 } 144 145 148 public void start(String activityId) throws WfException, CannotStart, AlreadyRunning { 149 if (state().equals("open.running")) 150 throw new AlreadyRunning("Process is already running"); 151 152 if (activityId == null && getDefinitionObject().get("defaultStartActivityId") == null) 153 throw new CannotStart("Initial activity is not defined."); 154 155 changeState("open.running"); 156 157 GenericValue start = null; 159 160 try { 161 if (activityId != null) { 162 GenericValue processDef = getDefinitionObject(); 163 Map fields = UtilMisc.toMap("packageId", processDef.getString("packageId"), "packageVersion", 164 processDef.getString("packageVersion"), "processId", processDef.getString("processId"), 165 "processVersion", processDef.getString("processVersion"), "activityId", activityId); 166 start = getDelegator().findByPrimaryKey("WorkflowActivity", fields); 167 168 if (!start.getBoolean("canStart").booleanValue()) 170 throw new CannotStart("The specified activity cannot initiate the workflow process"); 171 } else { 172 start = getDefinitionObject().getRelatedOne("DefaultStartWorkflowActivity"); 175 } 176 } catch (GenericEntityException e) { 177 throw new WfException(e.getMessage(), e.getNested()); 178 } 179 if (start == null) 180 throw new CannotStart("No initial activity available"); 181 182 if (Debug.verboseOn()) 183 Debug.logVerbose("[WfProcess.start] : Started the workflow process.", module); 184 185 try { 187 GenericValue v = getRuntimeObject(); 188 v.set("actualStartDate", UtilDateTime.nowTimestamp()); 189 v.store(); 190 } catch (GenericEntityException e) { 191 Debug.logWarning("Could not set 'actualStartDate'.", module); 192 e.printStackTrace(); 193 } 194 startActivity(start); 195 } 196 197 200 public WfProcessMgr manager() throws WfException { 201 return manager; 202 } 203 204 207 public WfRequester requester() throws WfException { 208 return requester; 209 } 210 211 214 public Iterator getIteratorStep() throws WfException { 215 return activeSteps().iterator(); 216 } 217 218 221 public boolean isMemberOfStep(WfActivity member) throws WfException { 222 return activeSteps().contains(member); 223 } 224 225 228 public Iterator getActivitiesInState(String state) throws WfException, InvalidState { 229 ArrayList res = new ArrayList (); 230 Iterator i = getIteratorStep(); 231 232 while (i.hasNext()) { 233 WfActivity a = (WfActivity) i.next(); 234 235 if (a.state().equals(state)) 236 res.add(a); 237 } 238 return res.iterator(); 239 } 240 241 244 public Map result() throws WfException, ResultNotAvailable { 245 Map resultSig = manager().resultSignature(); 246 Map results = new HashMap (); 247 Map context = processContext(); 248 249 if (resultSig != null) { 250 Set resultKeys = resultSig.keySet(); 251 Iterator i = resultKeys.iterator(); 252 253 while (i.hasNext()) { 254 Object key = i.next(); 255 256 if (context.containsKey(key)) 257 results.put(key, context.get(key)); 258 } 259 } 260 return results; 261 } 262 263 266 public int howManyStep() throws WfException { 267 return activeSteps().size(); 268 } 269 270 273 public synchronized void receiveResults(WfActivity activity, Map results) throws WfException, InvalidData { 274 Map context = processContext(); 275 context.putAll(results); 276 setSerializedData(context); 277 } 278 279 282 public synchronized void activityComplete(WfActivity activity) throws WfException { 283 if (!activity.state().equals("closed.completed")) 284 throw new WfException("Activity state is not completed"); 285 if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.activityComplete] : Activity (" + activity.name() + ") is complete", module); 286 queueNext(activity); 287 } 288 289 292 public String executionObjectType() { 293 return "WfProcess"; 294 } 295 296 private void queueNext(WfActivity fromActivity) throws WfException { 298 List nextTrans = getTransFrom(fromActivity); 299 300 if (nextTrans.size() > 0) { 301 Iterator i = nextTrans.iterator(); 302 303 while (i.hasNext()) { 304 GenericValue trans = (GenericValue) i.next(); 305 306 GenericValue toActivity = null; 308 309 try { 310 toActivity = trans.getRelatedOne("ToWorkflowActivity"); 311 } catch (GenericEntityException e) { 312 throw new WfException(e.getMessage(), e); 313 } 314 315 String join = "WJT_AND"; 318 if (toActivity.get("joinTypeEnumId") != null) 319 join = toActivity.getString("joinTypeEnumId"); 320 321 if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.queueNext] : " + join + " join.", module); 322 323 if (join.equals("WJT_XOR")) 325 startActivity(toActivity); 326 else 327 joinTransition(toActivity, trans); 328 } 329 } else { 330 if (Debug.verboseOn()) 331 Debug.logVerbose("[WfProcess.queueNext] : No transitions left to follow.", module); 332 this.finishProcess(); 333 } 334 } 335 336 private void joinTransition(GenericValue toActivity, 338 GenericValue transition) throws WfException { 339 GenericValue dataObject = getRuntimeObject(); 341 Collection toTrans = null; 342 343 try { 344 toTrans = toActivity.getRelated("ToWorkflowTransition"); 345 } catch (GenericEntityException e) { 346 throw new WfException(e.getMessage(), e); 347 } 348 349 Collection followed = null; 351 352 try { 353 Map fields = new HashMap (); 354 fields.put("processWorkEffortId", dataObject.getString("workEffortId")); 355 fields.put("toActivityId", toActivity.getString("activityId")); 356 followed = getDelegator().findByAnd("WorkEffortTransBox", fields); 357 } catch (GenericEntityException e) { 358 throw new WfException(e.getMessage(), e); 359 } 360 361 if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.joinTransition] : toTrans (" + toTrans.size() + ") followed (" + 362 (followed.size() + 1) + ")", module); 363 364 if (toTrans.size() == (followed.size() + 1)) { 366 Debug.logVerbose("[WfProcess.joinTransition] : All transitions have followed.", module); 367 startActivity(toActivity); 368 try { 369 Map fields = new HashMap (); 370 fields.put("processWorkEffortId", dataObject.getString("workEffortId")); 371 fields.put("toActivityId", toActivity.getString("activityId")); 372 getDelegator().removeByAnd("WorkEffortTransBox", fields); 373 } catch (GenericEntityException e) { 374 throw new WfException(e.getMessage(), e); 375 } 376 } else { 377 Debug.logVerbose("[WfProcess.joinTransition] : Waiting for transitions to finish.", module); 378 try { 379 Map fields = new HashMap (); 380 fields.put("processWorkEffortId", dataObject.getString("workEffortId")); 381 fields.put("toActivityId", toActivity.getString("activityId")); 382 fields.put("transitionId", transition.getString("transitionId")); 383 GenericValue obj = getDelegator().makeValue("WorkEffortTransBox", fields); 384 385 getDelegator().create(obj); 386 } catch (GenericEntityException e) { 387 throw new WfException(e.getMessage(), e); 388 } 389 } 390 } 391 392 private void startActivity(GenericValue value) throws WfException { 394 WfActivity activity = WfFactory.getWfActivity(value, workEffortId); 395 GenericResultWaiter req = new GenericResultWaiter(); 396 397 if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.startActivity] : Attempting to start activity (" + activity.name() + ")", module); 398 399 LocalDispatcher dispatcher = this.getDispatcher(); 401 402 JobManager jm = dispatcher.getJobManager(); 404 if (jm == null) { 405 throw new WfException("No job manager found on the service dispatcher; cannot start activity"); 406 } 407 408 try { 410 Job activityJob = new StartActivityJob(activity, req); 411 jm.runJob(activityJob); 412 } catch (JobManagerException e) { 413 throw new WfException("JobManager error", e); 414 } 415 416 if (req.status() == GenericResultWaiter.SERVICE_FAILED) { 418 Throwable reqt = req.getThrowable(); 419 if (reqt instanceof CannotStart) 420 Debug.logVerbose("[WfProcess.startActivity] : Cannot start activity. Waiting for manual start.", module); 421 else if (reqt instanceof AlreadyRunning) 422 throw new WfException("Activity already running", reqt); 423 else 424 throw new WfException("Activity error", reqt); 425 } 426 } 427 428 private List getTransFrom(WfActivity fromActivity) throws WfException { 430 List transList = new ArrayList (); 431 Collection fromCol = null; 433 434 try { 435 fromCol = fromActivity.getDefinitionObject().getRelated("FromWorkflowTransition"); 436 } catch (GenericEntityException e) { 437 throw new WfException(e.getMessage(), e); 438 } 439 440 String split = "WST_AND"; 443 if (fromActivity.getDefinitionObject().get("splitTypeEnumId") != null) 444 split = fromActivity.getDefinitionObject().getString("splitTypeEnumId"); 445 446 boolean transitionOk = true; 448 449 GenericValue otherwise = null; 451 452 Iterator fromIt = fromCol.iterator(); 454 while (fromIt.hasNext()) { 455 GenericValue transition = (GenericValue) fromIt.next(); 456 457 if (transition.get("conditionTypeEnumId") != null && transition.getString("conditionTypeEnumId").equals("WTC_OTHERWISE")) { 459 otherwise = transition; 461 continue; 462 } 463 464 String conditionBody = transition.getString("conditionExpr"); 466 467 Map extendedAttr = StringUtil.strToMap(transition.getString("extendedAttributes")); 469 470 if (extendedAttr != null && extendedAttr.get("conditionClassName") != null) { 472 String conditionClassName = (String ) extendedAttr.get("conditionClassName"); 473 transitionOk = this.evalConditionClass(conditionClassName, conditionBody, this.processContext(), extendedAttr); 474 } else { 475 if (conditionBody != null) { 477 transitionOk = this.evalBshCondition(conditionBody, this.processContext()); 478 } 479 } 480 481 if (transitionOk) { 482 transList.add(transition); 483 if (split.equals("WST_XOR")) 484 break; 485 } 486 } 487 488 if (split.equals("WST_XOR") && transList.size() == 0 && otherwise != null) { 490 transList.add(otherwise); 491 Debug.logVerbose("Used OTHERWISE Transition.", module); 492 } 493 494 if (Debug.verboseOn()) Debug.logVerbose("[WfProcess.getTransFrom] : Transitions: " + transList.size(), module); 495 return transList; 496 } 497 498 private WfActivity getActivity(String key) throws WfException { 500 Iterator i = getIteratorStep(); 501 502 while (i.hasNext()) { 503 WfActivity a = (WfActivity) i.next(); 504 if (a.key().equals(key)) 505 return a; 506 } 507 throw new WfException("Activity not an active member of this process"); 508 } 509 510 private void finishProcess() throws WfException { 512 changeState("closed.completed"); 513 Debug.logVerbose("[WfProcess.finishProcess] : Workflow Complete. Calling back to requester.", module); 514 if (requester != null) { 515 WfEventAudit audit = WfFactory.getWfEventAudit(this, null); 517 try { 518 requester.receiveEvent(audit); 519 } catch (InvalidPerformer e) { 520 throw new WfException(e.getMessage(), e); 521 } 522 } 523 } 524 525 private List activeSteps() throws WfException { 527 List steps = new ArrayList (); 528 Collection c = null; 529 530 try { 531 c = getDelegator().findByAnd("WorkEffort", UtilMisc.toMap("workEffortParentId", runtimeKey())); 532 } catch (GenericEntityException e) { 533 throw new WfException(e.getMessage(), e); 534 } 535 if (c == null) 536 return steps; 537 Iterator i = c.iterator(); 538 539 while (i.hasNext()) { 540 GenericValue v = (GenericValue) i.next(); 541 542 if (v.get("currentStatusId") != null && 543 WfUtil.getOMGStatus(v.getString("currentStatusId")).startsWith("open.")) 544 steps.add(WfFactory.getWfActivity(getDelegator(), v.getString("workEffortId"))); 545 } 546 return steps; 547 } 548 } 549 550 | Popular Tags |