blob: 1ed1e9f38c445a30c0e3c8519fe11e4452e6ca47 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/* $Id$ */
package org.apache.lenya.workflow.impl;
import java.io.File;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.lenya.workflow.Condition;
import org.apache.lenya.workflow.Workflow;
import org.apache.lenya.workflow.WorkflowException;
import org.apache.lenya.xml.DocumentHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
* Utility class to build a workflow schema from a file.
*/
public class WorkflowBuilder extends AbstractLogEnabled {
protected static final String STATE_ELEMENT = "state";
protected static final String TRANSITION_ELEMENT = "transition";
protected static final String EVENT_ELEMENT = "event";
protected static final String CONDITION_ELEMENT = "condition";
//protected static final String ACTION_ELEMENT = "action";
protected static final String ID_ATTRIBUTE = "id";
protected static final String INITIAL_ATTRIBUTE = "initial";
protected static final String SOURCE_ATTRIBUTE = "source";
protected static final String DESTINATION_ATTRIBUTE = "destination";
protected static final String CLASS_ATTRIBUTE = "class";
protected static final String VARIABLE_ELEMENT = "variable";
protected static final String ASSIGNMENT_ELEMENT = "assign";
protected static final String VARIABLE_ATTRIBUTE = "variable";
protected static final String VALUE_ATTRIBUTE = "value";
protected static final String NAME_ATTRIBUTE = "name";
protected static final String SYNCHRONIZED_ATTRIBUTE = "synchronized";
private ConditionFactory conditionFactory = null;
/**
* Ctor.
* @param logger The logger to use.
*/
public WorkflowBuilder(Logger logger) {
ContainerUtil.enableLogging(this, logger);
}
/**
* Builds a workflow schema from a file.
* @param name The workflow name.
* @param file The file.
* @return A workflow schema implementation.
* @throws WorkflowException if the file does not represent a valid workflow
* schema.
*/
public WorkflowImpl buildWorkflow(String name, File file) throws WorkflowException {
WorkflowImpl workflow;
try {
Document document = DocumentHelper.readDocument(file);
workflow = buildWorkflow(name, document);
} catch (Exception e) {
throw new WorkflowException(e);
}
return workflow;
}
/**
* Builds a workflow object from an XML document.
* @param name The workflow name.
* @param document The XML document.
* @return A workflow implementation.
* @throws WorkflowException when something went wrong.
*/
protected WorkflowImpl buildWorkflow(String name, Document document) throws WorkflowException {
Element root = document.getDocumentElement();
String initialState = null;
// load states
NodeList stateElements = root.getElementsByTagNameNS(Workflow.NAMESPACE, STATE_ELEMENT);
for (int i = 0; i < stateElements.getLength(); i++) {
Element element = (Element) stateElements.item(i);
String state = buildState(element);
if (isInitialStateElement(element)) {
initialState = state;
}
}
WorkflowImpl workflow = new WorkflowImpl(name, initialState);
// load variables
NodeList variableElements = root.getElementsByTagNameNS(Workflow.NAMESPACE,
VARIABLE_ELEMENT);
for (int i = 0; i < variableElements.getLength(); i++) {
Element element = (Element) variableElements.item(i);
BooleanVariableImpl variable = buildVariable(element);
workflow.addVariable(variable);
}
// load events
NodeList eventElements = root.getElementsByTagNameNS(Workflow.NAMESPACE, EVENT_ELEMENT);
for (int i = 0; i < eventElements.getLength(); i++) {
String event = buildEvent((Element) eventElements.item(i));
workflow.addEvent(event);
}
// load transitions
NodeList transitionElements = root.getElementsByTagNameNS(Workflow.NAMESPACE,
TRANSITION_ELEMENT);
for (int i = 0; i < transitionElements.getLength(); i++) {
TransitionImpl transition = buildTransition((Element) transitionElements.item(i));
workflow.addTransition(transition);
}
return workflow;
}
/**
* Checks if a state element contains the initial state.
* @param element An XML element.
* @return A boolean value.
*/
protected boolean isInitialStateElement(Element element) {
String initialAttribute = element.getAttribute(INITIAL_ATTRIBUTE);
return (initialAttribute != null)
&& (initialAttribute.equals("yes") || initialAttribute.equals("true"));
}
/**
* Builds a state from an XML element.
* @param element An XML element.
* @return A state.
*/
protected String buildState(Element element) {
return element.getAttribute(ID_ATTRIBUTE);
}
/**
* Builds a transition from an XML element.
* @param element An XML element.
* @return A transition.
* @throws WorkflowException when something went wrong.
*/
protected TransitionImpl buildTransition(Element element) throws WorkflowException {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Building transition");
}
String source = element.getAttribute(SOURCE_ATTRIBUTE);
String destination = element.getAttribute(DESTINATION_ATTRIBUTE);
TransitionImpl transition = new TransitionImpl(source, destination);
ContainerUtil.enableLogging(transition, getLogger());
// set event
Element eventElement = (Element) element.getElementsByTagNameNS(Workflow.NAMESPACE,
EVENT_ELEMENT).item(0);
String event = eventElement.getAttribute(ID_ATTRIBUTE);
transition.setEvent(event);
if (getLogger().isDebugEnabled()) {
getLogger().debug(" Event: [" + event + "]");
}
// load conditions
NodeList conditionElements = element.getElementsByTagNameNS(Workflow.NAMESPACE,
CONDITION_ELEMENT);
for (int i = 0; i < conditionElements.getLength(); i++) {
Condition condition = buildCondition((Element) conditionElements.item(i));
transition.addCondition(condition);
}
// load assignments
NodeList assignmentElements = element.getElementsByTagNameNS(Workflow.NAMESPACE,
ASSIGNMENT_ELEMENT);
for (int i = 0; i < assignmentElements.getLength(); i++) {
BooleanVariableAssignmentImpl action = buildAssignment((Element) assignmentElements
.item(i));
transition.addAction(action);
}
// load actions
/*
* NodeList actionElements = element
* .getElementsByTagNameNS(Workflow.NAMESPACE, ACTION_ELEMENT);
*
* for (int i = 0; i < actionElements.getLength(); i++) { Action action =
* buildAction((Element) actionElements.item(i));
* transition.addAction(action); }
*/
// set synchronization
/* FIXME: this is not used in the default publication, and is not currently accepted by the workflow xml validation. what does it do? */
if (element.hasAttribute(SYNCHRONIZED_ATTRIBUTE)) {
Boolean isSynchronized = Boolean.valueOf(element.getAttribute(SYNCHRONIZED_ATTRIBUTE));
transition.setSynchronized(isSynchronized.booleanValue());
}
return transition;
}
/**
* Builds an event from an XML element.
* @param element An XML element.
* @return An event.
*/
protected String buildEvent(Element element) {
return element.getAttribute(ID_ATTRIBUTE);
}
/**
* Builds a condition from an XML element.
* @param element An XML element.
* @return A condition.
* @throws WorkflowException when something went wrong.
*/
protected Condition buildCondition(Element element) throws WorkflowException {
String className = element.getAttribute(CLASS_ATTRIBUTE);
String expression = DocumentHelper.getSimpleElementText(element);
if (this.conditionFactory == null) {
this.conditionFactory = new ConditionFactory(getLogger());
}
Condition condition = this.conditionFactory.createCondition(className, expression);
return condition;
}
/**
* Builds a boolean variable from an XML element.
* @param element An XML element.
* @return A boolean variable.
*/
protected BooleanVariableImpl buildVariable(Element element) {
String name = element.getAttribute(NAME_ATTRIBUTE);
String value = element.getAttribute(VALUE_ATTRIBUTE);
return new BooleanVariableImpl(name, Boolean.getBoolean(value));
}
/**
* Builds an assignment object from an XML element.
* @param element An XML element.
* @return An assignment object.
* @throws WorkflowException when something went wrong.
*/
protected BooleanVariableAssignmentImpl buildAssignment(Element element)
throws WorkflowException {
String variableName = element.getAttribute(VARIABLE_ATTRIBUTE);
String valueString = element.getAttribute(VALUE_ATTRIBUTE);
boolean value = Boolean.valueOf(valueString).booleanValue();
return new BooleanVariableAssignmentImpl(variableName, value);
}
}