1 25 package org.ofbiz.workflow.impl; 26 27 import java.io.FileNotFoundException ; 28 import java.io.IOException ; 29 import java.sql.Timestamp ; 30 import java.util.ArrayList ; 31 import java.util.Arrays ; 32 import java.util.Date ; 33 import java.util.HashMap ; 34 import java.util.Iterator ; 35 import java.util.List ; 36 import java.util.Map ; 37 38 import org.ofbiz.base.util.BshUtil; 39 import org.ofbiz.base.util.Debug; 40 import org.ofbiz.base.util.ObjectType; 41 import org.ofbiz.base.util.UtilMisc; 42 import org.ofbiz.base.util.string.FlexibleStringExpander; 43 import org.ofbiz.entity.GenericDelegator; 44 import org.ofbiz.entity.GenericEntityException; 45 import org.ofbiz.entity.GenericValue; 46 import org.ofbiz.entity.serialize.SerializeException; 47 import org.ofbiz.entity.serialize.XmlSerializer; 48 import org.ofbiz.service.DispatchContext; 49 import org.ofbiz.service.GenericDispatcher; 50 import org.ofbiz.service.GenericServiceException; 51 import org.ofbiz.service.LocalDispatcher; 52 import org.ofbiz.workflow.AlreadySuspended; 53 import org.ofbiz.workflow.CannotResume; 54 import org.ofbiz.workflow.CannotStop; 55 import org.ofbiz.workflow.CannotSuspend; 56 import org.ofbiz.workflow.EvaluationException; 57 import org.ofbiz.workflow.HistoryNotAvailable; 58 import org.ofbiz.workflow.InvalidData; 59 import org.ofbiz.workflow.InvalidState; 60 import org.ofbiz.workflow.NotRunning; 61 import org.ofbiz.workflow.NotSuspended; 62 import org.ofbiz.workflow.TransitionCondition; 63 import org.ofbiz.workflow.TransitionNotAllowed; 64 import org.ofbiz.workflow.UpdateNotAllowed; 65 import org.ofbiz.workflow.WfException; 66 import org.ofbiz.workflow.WfExecutionObject; 67 import org.ofbiz.workflow.WfUtil; 68 69 77 public abstract class WfExecutionObjectImpl implements WfExecutionObject { 78 79 public static final String module = WfExecutionObjectImpl.class.getName(); 80 public static final String dispatcherName = "WFDispatcher"; 81 82 protected String packageId = null; 83 protected String packageVersion = null; 84 protected String processId = null; 85 protected String processVersion = null; 86 protected String activityId = null; 87 protected String workEffortId = null; 88 protected GenericDelegator delegator = null; 89 protected List history = null; 90 91 public WfExecutionObjectImpl(GenericValue valueObject, String parentId) throws WfException { 92 this.packageId = valueObject.getString("packageId"); 93 this.packageVersion = valueObject.getString("packageVersion"); 94 this.processId = valueObject.getString("processId"); 95 this.processVersion = valueObject.getString("processVersion"); 96 if (valueObject.getEntityName().equals("WorkflowActivity")) { 97 this.activityId = valueObject.getString("activityId"); 98 } else { 99 this.activityId = null; 100 } 101 this.delegator = valueObject.getDelegator(); 102 createRuntime(parentId); 103 } 104 105 public WfExecutionObjectImpl(GenericDelegator delegator, String workEffortId) throws WfException { 106 this.delegator = delegator; 107 this.workEffortId = workEffortId; 108 this.packageId = getRuntimeObject().getString("workflowPackageId"); 109 this.packageVersion = getRuntimeObject().getString("workflowPackageVersion"); 110 this.processId = getRuntimeObject().getString("workflowProcessId"); 111 this.processVersion = getRuntimeObject().getString("workflowProcessVersion"); 112 this.activityId = getRuntimeObject().getString("workflowActivityId"); 113 this.history = null; 114 if (Debug.verboseOn()) Debug.logVerbose(" Package ID: " + packageId + " V: " + packageVersion, module); 115 if (Debug.verboseOn()) Debug.logVerbose(" Process ID: " + processId + " V: " + processVersion, module); 116 if (Debug.verboseOn()) Debug.logVerbose("Activity ID: " + activityId, module); 117 } 118 119 private void createRuntime(String parentId) throws WfException { 121 GenericValue valueObject = getDefinitionObject(); 122 GenericValue dataObject = null; 123 124 workEffortId = getDelegator().getNextSeqId("WorkEffort").toString(); 125 Map dataMap = new HashMap (); 126 String weType = activityId != null ? "ACTIVITY" : "WORK_FLOW"; 127 128 dataMap.put("workEffortId", workEffortId); 129 dataMap.put("workEffortTypeId", weType); 130 dataMap.put("workEffortParentId", parentId); 131 dataMap.put("workflowPackageId", packageId); 132 dataMap.put("workflowPackageVersion", packageVersion); 133 dataMap.put("workflowProcessId", processId); 134 dataMap.put("workflowProcessVersion", processVersion); 135 dataMap.put("workEffortName", valueObject.getString("objectName")); 136 dataMap.put("description", valueObject.getString("description")); 137 dataMap.put("createdDate", new Timestamp ((new Date ()).getTime())); 138 dataMap.put("estimatedStartDate", dataMap.get("createdDate")); 139 dataMap.put("lastModifiedDate", dataMap.get("createdDate")); 140 dataMap.put("priority", valueObject.getLong("objectPriority")); 141 dataMap.put("currentStatusId", WfUtil.getOFBStatus("open.not_running.not_started")); 142 if (activityId != null) 143 dataMap.put("workflowActivityId", activityId); 144 if (activityId != null && parentId != null) { 145 GenericValue parentWorkEffort = getWorkEffort(parentId); 146 if (parentWorkEffort != null && parentWorkEffort.get("sourceReferenceId") != null) 147 dataMap.put("sourceReferenceId", parentWorkEffort.getString("sourceReferenceId")); 148 } 149 150 try { 151 dataObject = getDelegator().makeValue("WorkEffort", dataMap); 152 getDelegator().create(dataObject); 153 154 String objectId = activityId != null ? activityId : processId; 155 if (Debug.verboseOn()) Debug.logVerbose("Created new runtime object [" + objectId + "] (Workeffort: " + runtimeKey() + ")", module); 156 } catch (GenericEntityException e) { 157 throw new WfException(e.getMessage(), e); 158 } 159 } 160 161 protected void parseDescriptions(Map parseContext) throws WfException { 162 GenericValue runtime = getRuntimeObject(); 163 String name = runtime.getString("workEffortName"); 164 String desc = runtime.getString("description"); 165 String nameExp = FlexibleStringExpander.expandString(name, parseContext); 166 String descExp = FlexibleStringExpander.expandString(desc, parseContext); 167 168 boolean changed = false; 169 if (nameExp != null && !nameExp.equals(name)) { 170 changed = true; 171 runtime.set("workEffortName", nameExp); 172 } 173 if (descExp != null && !descExp.equals(desc)) { 174 changed = true; 175 runtime.set("description", descExp); 176 } 177 178 if (changed) { 179 try { 180 runtime.store(); 181 } catch (GenericEntityException e) { 182 throw new WfException(e.getMessage(), e); 183 } 184 } 185 } 186 187 190 public String name() throws WfException { 191 return getRuntimeObject().getString("workEffortName"); 192 } 193 194 197 public void setName(String newValue) throws WfException { 198 GenericValue dataObject = getRuntimeObject(); 199 200 try { 201 dataObject.set("workEffortName", newValue); 202 dataObject.store(); 203 } catch (GenericEntityException e) { 204 throw new WfException(e.getMessage(), e); 205 } 206 } 207 208 211 public void setPriority(long newValue) throws WfException { 212 GenericValue dataObject = getRuntimeObject(); 213 214 try { 215 dataObject.set("priority", new Long (newValue)); 216 dataObject.store(); 217 } catch (GenericEntityException e) { 218 throw new WfException(e.getMessage(), e); 219 } 220 } 221 222 225 public long priority() throws WfException { 226 if (getRuntimeObject().get("priority") != null) 227 return getRuntimeObject().getLong("priority").longValue(); 228 return 0; } 230 231 234 public String state() throws WfException { 235 GenericValue statusObj = null; 236 String stateStr = null; 237 238 try { 239 statusObj = getRuntimeObject().getRelatedOne("CurrentStatusItem"); 240 } catch (GenericEntityException e) { 241 throw new WfException(e.getMessage(), e); 242 } 243 if (statusObj != null) 244 stateStr = statusObj.getString("statusCode"); 245 246 if (stateStr == null) 247 throw new WfException("Stored state is not a valid type."); 248 249 if (Debug.verboseOn()) Debug.logVerbose("Current state: " + stateStr, module); 250 return stateStr; 251 } 252 253 256 public List validStates() throws WfException { 257 String statesArr[] = {"open.running", "open.not_running.not_started", "open.not_running.suspended", 258 "closed.completed", "closed.terminated", "closed.aborted"}; 259 ArrayList possibleStates = new ArrayList (Arrays.asList(statesArr)); 260 String currentState = state(); 261 262 if (currentState.startsWith("closed")) 263 return new ArrayList (); 264 if (!currentState.startsWith("open")) 265 throw new WfException("Currently in an unknown state."); 266 if (currentState.equals("open.running")) { 267 possibleStates.remove("open.running"); 268 possibleStates.remove("open.not_running.not_started"); 269 return possibleStates; 270 } 271 if (currentState.equals("open.not_running.not_started")) { 272 possibleStates.remove("open.not_running.not_started"); 273 possibleStates.remove("open.not_running.suspended"); 274 possibleStates.remove("closed.completed"); 275 possibleStates.remove("closed.terminated"); 276 return possibleStates; 277 } 278 if (currentState.equals("open.not_running.suspended")) { 279 possibleStates.remove("open.not_running.suspended"); 280 possibleStates.remove("open.not_running.not_started"); 281 possibleStates.remove("closed.complete"); 282 possibleStates.remove("closed.terminated"); 283 return possibleStates; 284 } 285 return new ArrayList (); 286 } 287 288 291 public int howManyHistory() throws WfException, HistoryNotAvailable { 292 if (history.size() < 1) 293 throw new HistoryNotAvailable(); 294 return history.size(); 295 } 296 297 300 public void abort() throws WfException, CannotStop, NotRunning { 301 Debug.logInfo("Aborting current state : " + state(), module); 302 String stateStr = "closed.aborted"; 303 304 if (!state().startsWith("open")) { 305 throw new NotRunning(); 306 } 307 308 if (!validStates().contains(stateStr)) { 309 throw new CannotStop(); 310 } 311 312 changeState(stateStr); 313 } 314 315 318 public List whileOpenType() throws WfException { 319 String [] list = {"running", "not_running"}; 320 321 return Arrays.asList(list); 322 } 323 324 327 public List whyNotRunningType() throws WfException { 328 String [] list = {"not_started", "suspended"}; 329 330 return Arrays.asList(list); 331 } 332 333 336 public String runtimeKey() throws WfException { 337 return getRuntimeObject().getString("workEffortId"); 338 } 339 340 343 public String key() throws WfException { 344 if (activityId != null) 345 return activityId; 346 else 347 return processId; 348 } 349 350 353 public boolean isMemberOfHistory(WfExecutionObject member) throws WfException { 354 return false; 355 } 356 357 360 public void setProcessContext(Map newValue) throws WfException, InvalidData, UpdateNotAllowed { 361 setSerializedData(newValue); 362 } 363 364 367 public void setProcessContext(String contextKey) throws WfException, InvalidData, UpdateNotAllowed { 368 GenericValue dataObject = getRuntimeObject(); 369 370 try { 371 dataObject.set("runtimeDataId", contextKey); 372 dataObject.store(); 373 } catch (GenericEntityException e) { 374 throw new WfException(e.getMessage(), e); 375 } 376 } 377 378 381 public String contextKey() throws WfException { 382 if (getRuntimeObject().get("runtimeDataId") == null) 383 return null; 384 else 385 return getRuntimeObject().getString("runtimeDataId"); 386 } 387 388 391 public Map processContext() throws WfException { 392 return getContext(); 393 } 394 395 398 public List workflowStateType() throws WfException { 399 String [] list = {"open", "closed"}; 400 return Arrays.asList(list); 401 } 402 403 406 public void terminate() throws WfException, CannotStop, NotRunning { 407 String stateStr = "closed.terminated"; 408 409 if (!state().equals("open.running")) 410 throw new NotRunning(); 411 if (!validStates().contains(stateStr)) 412 throw new CannotStop(); 413 changeState(stateStr); 414 } 415 416 419 public void setDescription(String newValue) throws WfException { 420 GenericValue valueObject = getDefinitionObject(); 421 422 try { 423 valueObject.set("description", newValue); 424 valueObject.store(); 425 } catch (GenericEntityException e) { 426 throw new WfException(e.getMessage(), e); 427 } 428 } 429 430 433 public String description() throws WfException { 434 return getDefinitionObject().getString("description"); 435 } 436 437 440 public Timestamp lastStateTime() throws WfException { 441 GenericValue dataObject = getRuntimeObject(); 442 443 if (dataObject == null || dataObject.get("lastStatusUpdate") == null) 444 throw new WfException("No runtime object or status has never been set."); 445 return dataObject.getTimestamp("lastStatusUpdate"); 446 } 447 448 451 public List getSequenceHistory(int maxNumber) throws WfException, 452 HistoryNotAvailable { 453 return history; 454 } 455 456 459 public Iterator getIteratorHistory(String query, 460 Map namesInQuery) throws WfException, HistoryNotAvailable { 461 return history.iterator(); 462 } 463 464 467 public void resume() throws WfException, CannotResume, NotRunning, NotSuspended { 468 if (!state().equals("open.not_running.suspended")) { 469 if (state().equals("open.not_running.not_started")) { 470 throw new NotRunning(); 471 } else if (state().startsWith("closed")) { 472 throw new CannotResume(); 473 } else { 474 throw new NotSuspended(); 475 } 476 } else { 477 changeState("open.running"); 478 } 479 } 480 481 484 public List howClosedType() throws WfException { 485 String [] list = {"completed", "terminated", "aborted"}; 486 487 return Arrays.asList(list); 488 } 489 490 493 public void changeState(String newState) throws WfException, InvalidState, TransitionNotAllowed { 494 GenericValue dataObject = getRuntimeObject(); 496 497 if (validStates().contains(newState)) { 498 try { 499 long now = (new Date ()).getTime(); 500 501 dataObject.set("currentStatusId", WfUtil.getOFBStatus(newState)); 502 dataObject.set("lastStatusUpdate", new Timestamp (now)); 503 dataObject.store(); 504 } catch (GenericEntityException e) { 505 throw new WfException(e.getMessage(), e); 506 } 507 } else { 508 throw new InvalidState(); 509 } 510 } 511 512 515 public void suspend() throws WfException, CannotSuspend, NotRunning, AlreadySuspended { 516 changeState("open.not_running.suspended"); 517 } 518 519 522 public GenericDelegator getDelegator() throws WfException { 523 return delegator; 524 } 525 526 529 public GenericValue getDefinitionObject() throws WfException { 530 String entityName = activityId != null ? "WorkflowActivity" : "WorkflowProcess"; 531 GenericValue value = null; 532 Map fields = UtilMisc.toMap("packageId", packageId, "packageVersion", packageVersion, "processId", processId, 533 "processVersion", processVersion); 534 535 if (activityId != null) 536 fields.put("activityId", activityId); 537 try { 538 value = getDelegator().findByPrimaryKey(entityName, fields); 539 } catch (GenericEntityException e) { 540 throw new WfException(e.getMessage(), e); 541 } 542 return value; 543 } 544 545 public GenericValue getRuntimeObject() throws WfException { 546 GenericValue value = null; 547 548 try { 549 value = getDelegator().findByPrimaryKey("WorkEffort", 550 UtilMisc.toMap("workEffortId", workEffortId)); 551 } catch (GenericEntityException e) { 552 throw new WfException(e.getMessage(), e); 553 } 554 return value; 555 } 556 557 561 public abstract String executionObjectType(); 562 563 569 protected void setSerializedData(Map value) throws WfException, InvalidData { 570 GenericValue runtimeData = null; 571 GenericValue dataObject = getRuntimeObject(); 572 573 try { 574 if (dataObject.get("runtimeDataId") == null) { 575 String seqId = getDelegator().getNextSeqId("RuntimeData").toString(); 576 577 runtimeData = getDelegator().makeValue("RuntimeData", 578 UtilMisc.toMap("runtimeDataId", seqId)); 579 getDelegator().create(runtimeData); 580 dataObject.set("runtimeDataId", seqId); 581 dataObject.store(); 582 } else { 583 runtimeData = dataObject.getRelatedOne("RuntimeData"); 584 } 585 588 runtimeData.set("runtimeInfo", XmlSerializer.serialize(value)); 589 runtimeData.store(); 590 } catch (GenericEntityException e) { 591 throw new WfException(e.getMessage(), e); 592 } catch (SerializeException e) { 593 throw new InvalidData(e.getMessage(), e); 594 } catch (FileNotFoundException e) { 595 throw new InvalidData(e.getMessage(), e); 596 } catch (IOException e) { 597 throw new InvalidData(e.getMessage(), e); 598 } 599 } 600 601 606 protected LocalDispatcher getDispatcher() throws WfException { 607 try { 608 return GenericDispatcher.getLocalDispatcher(dispatcherName, getDelegator()); 609 } catch (GenericServiceException e) { 610 throw new WfException("No workflow service dispatcher", e); 611 } 612 } 613 614 private Map getContext() throws WfException { 615 GenericValue dataObject = getRuntimeObject(); 616 String contextXML = null; 617 Map context = null; 618 619 if (dataObject.get("runtimeDataId") == null) 620 return context; 621 try { 622 GenericValue runtimeData = dataObject.getRelatedOne("RuntimeData"); 623 624 contextXML = runtimeData.getString("runtimeInfo"); 625 } catch (GenericEntityException e) { 626 throw new WfException(e.getMessage(), e); 627 } 628 if (contextXML != null) { 630 try { 631 context = (Map ) XmlSerializer.deserialize(contextXML, getDelegator()); 632 } catch (SerializeException e) { 633 throw new WfException(e.getMessage(), e); 634 } catch (IOException e) { 635 throw new WfException(e.getMessage(), e); 636 } catch (Exception e) { 637 throw new WfException(e.getMessage(), e); 638 } 639 } 640 return context; 641 } 642 643 private GenericValue getWorkEffort(String workEffortId) throws WfException { 644 GenericValue we = null; 645 try { 646 we = getDelegator().findByPrimaryKey("WorkEffort", UtilMisc.toMap("workEffortId", workEffortId)); 647 } catch (GenericEntityException e) { 648 throw new WfException("Problem getting WorkEffort entity (" + workEffortId + ")", e); 649 } 650 return we; 651 } 652 653 660 protected boolean evalConditionClass(String className, String expression, Map context, Map attrs) throws WfException { 661 Object conditionObject = null; 663 try { 664 conditionObject = ObjectType.getInstance(className); 665 } catch (ClassNotFoundException e) { 666 Debug.logError(e, "Cannot load class " + className, module); 667 return false; 668 } catch (InstantiationException e) { 669 Debug.logError(e, "Cannot get instance of class " + className, module); 670 return false; 671 } catch (IllegalAccessException e) { 672 Debug.logError(e, "Cannot access class " + className, module); 673 return false; 674 } 675 676 if (!ObjectType.instanceOf(conditionObject, "org.ofbiz.workflow.TransitionCondition")) { 678 Debug.logError("Class " + className + " is not an instance of TransitionCondition", module); 679 return false; 680 } 681 682 TransitionCondition cond = (TransitionCondition) conditionObject; 684 685 if (expression != null) 687 expression = expression.trim(); 688 689 DispatchContext dctx = this.getDispatcher().getDispatchContext(); 691 692 Boolean evaluation = null; 694 try { 695 evaluation = cond.evaluateCondition(context, attrs, expression, dctx); 696 } catch (EvaluationException e) { 697 throw new WfException("Problems evaluating condition", e); 698 } 699 700 return evaluation.booleanValue(); 701 } 702 703 710 protected boolean evalBshCondition(String expression, Map context) throws WfException { 711 if (expression == null || expression.length() == 0) { 712 Debug.logVerbose("Null or empty expression, returning true.", module); 713 return true; 714 } 715 716 Object o = null; 717 try { 718 o = BshUtil.eval(expression.trim(), context); 719 } catch (bsh.EvalError e) { 720 throw new WfException("Bsh evaluation error.", e); 721 } 722 723 if (o == null) 724 return false; 725 else if (o instanceof Number ) 726 return (((Number ) o).doubleValue() == 0) ? false : true; 727 else 728 return (!o.toString().equalsIgnoreCase("true")) ? false : true; 729 } 730 } 731 732 | Popular Tags |