001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.lenya.workflow.impl;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.apache.lenya.workflow.Action;
024: import org.apache.lenya.workflow.Condition;
025: import org.apache.lenya.workflow.Transition;
026: import org.apache.lenya.workflow.Version;
027: import org.apache.lenya.workflow.Workflow;
028: import org.apache.lenya.workflow.WorkflowEngine;
029: import org.apache.lenya.workflow.WorkflowException;
030: import org.apache.lenya.workflow.Workflowable;
031:
032: /**
033: * Workflow engine implementation.
034: *
035: * @version $Id: WorkflowEngineImpl.java 473861 2006-11-12 03:51:14Z gregor $
036: */
037: public class WorkflowEngineImpl implements WorkflowEngine {
038:
039: /**
040: * @see org.apache.lenya.workflow.WorkflowEngine#canInvoke(org.apache.lenya.workflow.Workflowable,
041: * org.apache.lenya.workflow.Workflow, java.lang.String)
042: */
043: public boolean canInvoke(Workflowable workflowable,
044: Workflow workflow, String event) throws WorkflowException {
045: List firingTransitions = getFiringTransitions(workflowable,
046: workflow, event);
047: return firingTransitions.size() == 1;
048: }
049:
050: /**
051: * @see org.apache.lenya.workflow.WorkflowEngine#invoke(org.apache.lenya.workflow.Workflowable,
052: * org.apache.lenya.workflow.Workflow, java.lang.String)
053: */
054: public void invoke(Workflowable workflowable, Workflow workflow,
055: String event) throws WorkflowException {
056:
057: Transition firingTransition = null;
058: List firingTransitions = getFiringTransitions(workflowable,
059: workflow, event);
060:
061: if (firingTransitions.size() == 0) {
062: throw new WorkflowException("No transition can fire!");
063: } else if (firingTransitions.size() > 1) {
064: throw new WorkflowException(
065: "More than one transitions can fire!");
066: } else {
067: firingTransition = (Transition) firingTransitions.get(0);
068: }
069:
070: String destination = firingTransition.getDestination();
071:
072: Version newVersion = createNewVersion(workflowable, workflow,
073: event, destination);
074:
075: Action[] actions = firingTransition.getActions();
076: for (int i = 0; i < actions.length; i++) {
077: actions[i].execute(newVersion);
078: }
079:
080: workflowable.newVersion(workflow, newVersion);
081: }
082:
083: /**
084: * Creates a new version.
085: * @param workflowable The workflowable.
086: * @param workflow The workflow.
087: * @param event The event.
088: * @param destination The destination.
089: * @return A version.
090: * @throws WorkflowException if an error occurs.
091: */
092: protected Version createNewVersion(Workflowable workflowable,
093: Workflow workflow, String event, String destination)
094: throws WorkflowException {
095: Version latestVersion = workflowable.getLatestVersion();
096: Version newVersion = new VersionImpl(event, destination);
097: String[] variableNames = workflow.getVariableNames();
098: for (int i = 0; i < variableNames.length; i++) {
099: String name = variableNames[i];
100: boolean value;
101: if (latestVersion == null) {
102: value = workflow.getInitialValue(name);
103: } else {
104: value = latestVersion.getValue(name);
105: }
106: newVersion.setValue(name, value);
107: }
108: return newVersion;
109: }
110:
111: /**
112: * Returns the transitions that would fire in a certain situation.
113: * @param workflowable The workflowable.
114: * @param workflow The workflow.
115: * @param event The event.
116: * @return A list of transitions.
117: * @throws WorkflowException if an error occurs.
118: */
119: protected List getFiringTransitions(Workflowable workflowable,
120: Workflow workflow, String event) throws WorkflowException {
121: Version lastVersion = workflowable.getLatestVersion();
122:
123: String currentState;
124: if (lastVersion == null) {
125: currentState = workflow.getInitialState();
126: } else {
127: currentState = lastVersion.getState();
128: }
129:
130: Transition[] transitions = workflow
131: .getLeavingTransitions(currentState);
132: List firingTransitions = new ArrayList();
133:
134: for (int i = 0; i < transitions.length; i++) {
135: if (transitions[i].getEvent().equals(event)
136: && canFire(transitions[i], workflow, workflowable)) {
137: firingTransitions.add(transitions[i]);
138: }
139: }
140: return firingTransitions;
141: }
142:
143: /**
144: * Checks if a transition can fire.
145: * @param transition The transition.
146: * @param workflow The workflow.
147: * @param workflowable The workflowable.
148: * @return A boolean value.
149: * @throws WorkflowException if an error occurs.
150: */
151: public boolean canFire(Transition transition, Workflow workflow,
152: Workflowable workflowable) throws WorkflowException {
153: Condition[] _conditions = transition.getConditions();
154: boolean canFire = true;
155:
156: int i = 0;
157: while (canFire && i < _conditions.length) {
158: canFire = canFire
159: && _conditions[i]
160: .isComplied(workflow, workflowable);
161: i++;
162: }
163:
164: return canFire;
165: }
166:
167: }
|