- add moved class to core-workflow
git-svn-id: https://svn.apache.org/repos/asf/lenya/trunk@1034330 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/DocumentWorkflowable.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/DocumentWorkflowable.java
new file mode 100644
index 0000000..baafb02
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/DocumentWorkflowable.java
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.cms.workflow;
+
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.cocoon.util.AbstractLogEnabled;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lenya.ac.Identity;
+import org.apache.lenya.ac.User;
+import org.apache.lenya.cms.metadata.MetaData;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.ResourceType;
+import org.apache.lenya.workflow.Version;
+import org.apache.lenya.workflow.Workflow;
+import org.apache.lenya.workflow.Workflowable;
+
+/**
+ * Workflowable around a CMS document.
+ *
+ * @version $Id: DocumentWorkflowable.java 416648 2006-06-23 09:15:28Z andreas $
+ */
+class DocumentWorkflowable extends AbstractLogEnabled implements Workflowable {
+
+ private static final Log logger = LogFactory.getLog(DocumentWorkflowable.class);
+
+ /**
+ * Ctor.
+ * @param manager The service manager.
+ * @param document The document.
+ * @param logger The logger.
+ */
+ public DocumentWorkflowable(Document document) {
+ if (document.getSession().getIdentity() == null) {
+ throw new IllegalArgumentException("The session must have an identity.");
+ }
+ this.document = document;
+ }
+
+ private Document document;
+
+ protected Document getDocument() {
+ return this.document;
+ }
+
+ /**
+ * @return The name of the workflow schema.
+ */
+ protected String getWorkflowSchema() {
+ String workflowName = null;
+ try {
+ ResourceType doctype = document.getResourceType();
+ if (doctype != null) {
+ workflowName = document.getPublication().getWorkflowSchema(doctype);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return workflowName;
+ }
+
+ private Version[] versions = null;
+
+ private int revision = 0;
+
+ protected static final String METADATA_NAMESPACE = "http://apache.org/lenya/metadata/workflow/1.0";
+ protected static final String METADATA_VERSION = "workflowVersion";
+
+ protected int getLatestRevision(int[] revisions) {
+ return revisions[revisions.length - 1];
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Workflowable#getVersions()
+ */
+ public Version[] getVersions() {
+ try {
+ MetaData meta = this.document.getMetaData(METADATA_NAMESPACE);
+
+ int[] revisions = getDocument().getHistory().getRevisionNumbers();
+ boolean checkedIn = revisions.length > 0;
+ if (this.versions == null
+ || (checkedIn && getLatestRevision(revisions) > this.revision)) {
+ String[] versionStrings = meta.getValues(METADATA_VERSION);
+ this.versions = new Version[versionStrings.length];
+
+ SortedMap number2version = new TreeMap();
+
+ for (int i = 0; i < versionStrings.length; i++) {
+ String string = versionStrings[i];
+ int spaceIndex = string.indexOf(" ");
+ String numberString = string.substring(0, spaceIndex);
+ int number = Integer.parseInt(numberString);
+ String versionString = string.substring(spaceIndex + 1);
+ Version version = decodeVersion(versionString);
+ number2version.put(new Integer(number), version);
+ }
+
+ int number = 0;
+ for (Iterator i = number2version.keySet().iterator(); i.hasNext();) {
+ Version version = (Version) number2version.get(i.next());
+ this.versions[number] = version;
+ number++;
+ }
+
+ if (checkedIn) {
+ this.revision = getLatestRevision(revisions);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return this.versions;
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Workflowable#getLatestVersion()
+ */
+ public Version getLatestVersion() {
+ Version version = null;
+ Version[] versions = getVersions();
+ if (versions.length > 0) {
+ version = versions[versions.length - 1];
+ }
+ return version;
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Workflowable#newVersion(org.apache.lenya.workflow.Workflow,
+ * org.apache.lenya.workflow.Version)
+ */
+ public void newVersion(Workflow workflow, Version version) {
+ Version[] newVersions = new Version[getVersions().length + 1];
+ for (int i = 0; i < getVersions().length; i++) {
+ newVersions[i] = getVersions()[i];
+ }
+
+ int number = newVersions.length - 1;
+ newVersions[number] = version;
+
+ String string = number + " " + encodeVersion(workflow, version);
+ addToMetaData(string);
+
+ WorkflowEventDescriptor descriptor = new WorkflowEventDescriptor(version);
+ getDocument().getSession().enqueueEvent(getDocument(), descriptor);
+ }
+
+ protected void addToMetaData(String versionString) {
+ try {
+ String[] areas = getDocument().getPublication().getAreaNames();
+ for (int i = 0; i < areas.length; i++) {
+ if (getDocument().existsAreaVersion(areas[i])) {
+ Document doc = getDocument().getAreaVersion(areas[i]);
+ MetaData meta = doc.getMetaData(METADATA_NAMESPACE);
+ meta.addValue(METADATA_VERSION, versionString);
+ }
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected String encodeVersion(Workflow workflow, Version version) {
+
+ StringBuffer stringBuf = new StringBuffer("event:").append(version.getEvent());
+ stringBuf.append(" state:").append(version.getState());
+
+ Identity identity = getDocument().getSession().getIdentity();
+ User user = identity.getUser();
+ if (user != null) {
+ stringBuf.append(" user:").append(identity.getUser().getId());
+ }
+ stringBuf.append(" machine:").append(identity.getMachine().getIp());
+
+ SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss");
+ stringBuf.append(" date:").append(format.format(new Date()));
+
+ String names[] = workflow.getVariableNames();
+ for (int i = 0; i < names.length; i++) {
+ String value = Boolean.toString(version.getValue(names[i]));
+ stringBuf.append(" var:").append(names[i]);
+ stringBuf.append("=").append(value);
+ }
+ return stringBuf.toString();
+ }
+
+ protected Version decodeVersion(String string) {
+
+ String event = null;
+ String state = null;
+ String user = null;
+ String machine = null;
+ Date date = null;
+ Map variables = new HashMap();
+
+ String[] parts = string.split(" ");
+ for (int i = 0; i < parts.length; i++) {
+ String[] steps = parts[i].split(":", 2);
+ if (steps[0].equals("event")) {
+ event = steps[1];
+ } else if (steps[0].equals("state")) {
+ state = steps[1];
+ } else if (steps[0].equals("user")) {
+ user = steps[1];
+ } else if (steps[0].equals("date")) {
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss", Locale.US);
+ date = sdf.parse(steps[1], new ParsePosition(0));
+ } else if (steps[0].equals("machine")) {
+ machine = steps[1];
+ } else if (steps[0].equals("var")) {
+ String[] nameValue = steps[1].split("=");
+ variables.put(nameValue[0], nameValue[1]);
+ }
+ }
+
+ Version version = new LenyaVersion(event, state);
+ for (Iterator i = variables.keySet().iterator(); i.hasNext();) {
+ String name = (String) i.next();
+ String value = (String) variables.get(name);
+ version.setUserId(user);
+ version.setDate(date);
+ version.setIPAddress(machine);
+ version.setValue(name, Boolean.valueOf(value).booleanValue());
+ }
+ return version;
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Workflowable#getWorkflowSchemaURI()
+ */
+ public String getWorkflowSchemaURI() {
+ String uri = null;
+ String schema = getWorkflowSchema();
+ if (schema != null) {
+
+ if (schema.indexOf("://") != -1) {
+ return schema;
+ } else {
+ uri = this.document.getPublication().getSourceUri() + "/config/workflow/" + schema;
+ uri = uri.substring("lenya://".length());
+ uri = "context://" + uri;
+ }
+ }
+ return uri;
+ }
+
+ public String toString() {
+ return this.document.toString();
+ }
+
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/LenyaVersion.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/LenyaVersion.java
new file mode 100644
index 0000000..b59b9bb
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/LenyaVersion.java
@@ -0,0 +1,131 @@
+/*
+ * 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: VersionImpl.java 372568 2006-01-26 16:51:38Z andreas $ */
+
+package org.apache.lenya.cms.workflow;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lenya.workflow.Version;
+
+/**
+ * A version of the workflow history.
+ */
+public class LenyaVersion implements Version {
+
+ private Date date;
+ private String event;
+ private String ipAddress;
+ private String state;
+ private String userId;
+ private Map variableValues = new HashMap();
+
+ /**
+ * @see org.apache.lenya.workflow.Version#getEvent()
+ */
+ public String getEvent() {
+ return this.event;
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Version#getState()
+ */
+ public String getState() {
+ return this.state;
+ }
+
+ /**
+ * Returns the date.
+ * @return A string.
+ */
+ public Date getDate() {
+ return (Date)this.date.clone();
+ }
+
+ /**
+ * Sets the date.
+ * @param _date A date.
+ */
+ public void setDate(Date _date) {
+ this.date = (Date)_date.clone();
+ }
+
+ /**
+ * Returns the user ID.
+ * @return A string.
+ */
+ public String getUserId() {
+ return this.userId;
+ }
+
+ /**
+ * Sets the user ID.
+ * @param _userId A user ID.
+ */
+ public void setUserId(String _userId) {
+ this.userId = _userId;
+ }
+
+ /**
+ * Returns the ip address.
+ * @return A string.
+ */
+ public String getIPAddress() {
+ return this.ipAddress;
+ }
+
+ /**
+ * Sets the ip address.
+ * @param _ipaddress A ip address.
+ */
+ public void setIPAddress(String _ipaddress){
+ this.ipAddress = _ipaddress;
+ }
+
+ /**
+ * Ctor.
+ * @param _event The event that caused the version change.
+ * @param _state The destination state.
+ */
+ public LenyaVersion(String _event, String _state) {
+ this.event = _event;
+ this.state = _state;
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Version#getValue(java.lang.String)
+ */
+ public boolean getValue(String variableName) {
+ Boolean value = (Boolean) this.variableValues.get(variableName);
+ if (value == null) {
+ throw new RuntimeException("No value set for variable [" + variableName + "]");
+ }
+ return value.booleanValue();
+ }
+
+ /**
+ * @see org.apache.lenya.workflow.Version#setValue(java.lang.String, boolean)
+ */
+ public void setValue(String variableName, boolean value) {
+ this.variableValues.put(variableName, Boolean.valueOf(value));
+ }
+
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/RoleCondition.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/RoleCondition.java
new file mode 100644
index 0000000..f0460e6
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/RoleCondition.java
@@ -0,0 +1,127 @@
+/*
+ * 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.cms.workflow;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.cocoon.spring.configurator.WebAppContextUtils;
+import org.apache.lenya.ac.AccessController;
+import org.apache.lenya.ac.AccessControllerResolver;
+import org.apache.lenya.ac.AccreditableManager;
+import org.apache.lenya.ac.Identity;
+import org.apache.lenya.ac.Policy;
+import org.apache.lenya.ac.PolicyManager;
+import org.apache.lenya.ac.Role;
+import org.apache.lenya.ac.RoleManager;
+import org.apache.lenya.workflow.Condition;
+import org.apache.lenya.workflow.Workflow;
+import org.apache.lenya.workflow.WorkflowException;
+import org.apache.lenya.workflow.Workflowable;
+
+/**
+ * Role condition
+ */
+public class RoleCondition implements Condition {
+
+ private Set roleIds = new HashSet();
+
+ protected static final String SEPARATOR = ",";
+
+ /**
+ * @see org.apache.lenya.workflow.Condition#setExpression(java.lang.String)
+ */
+ public void setExpression(String expression) throws WorkflowException {
+ this.expression = expression;
+
+ String[] roles = expression.split(SEPARATOR);
+ for (int i = 0; i < roles.length; i++) {
+ this.roleIds.add(roles[i].trim());
+ }
+ }
+
+ protected AccessControllerResolver getAccessControllerResolver() {
+ return (AccessControllerResolver) WebAppContextUtils.getCurrentWebApplicationContext()
+ .getBean(AccessControllerResolver.ROLE);
+ }
+
+ /**
+ * Returns if the condition is complied in a certain situation. The condition is complied when
+ * the current user has the role that is required by the RoleCondition.
+ */
+ public boolean isComplied(Workflow workflow, Workflowable instance) {
+
+ DocumentWorkflowable workflowable = (DocumentWorkflowable) instance;
+ String url = workflowable.getDocument().getCanonicalWebappURL();
+
+ AccessControllerResolver acResolver = getAccessControllerResolver();
+ AccessController accessController = null;
+ try {
+ accessController = acResolver.resolveAccessController(url);
+
+ PolicyManager policyManager = accessController.getPolicyManager();
+ Identity identity = workflowable.getDocument().getSession().getIdentity();
+ if (identity == null) {
+ throw new IllegalArgumentException("The session of the workflowable "
+ + workflowable + " has no identity.");
+ }
+ AccreditableManager accreditableMgr = accessController.getAccreditableManager();
+ Policy policy = policyManager.getPolicy(accreditableMgr, url);
+ RoleManager roleManager = accreditableMgr.getRoleManager();
+
+ boolean complied = false;
+
+ for (Iterator i = this.roleIds.iterator(); i.hasNext();) {
+ String roleId = (String) i.next();
+ Role role = roleManager.getRole(roleId);
+ if (policy.check(identity, role) == Policy.RESULT_GRANTED) {
+ complied = true;
+ }
+ }
+
+ return complied;
+
+ } catch (final Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private String expression;
+
+ /**
+ * Returns the expression of this condition.
+ *
+ * @return A string.
+ */
+ public String getExpression() {
+ return this.expression;
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ public String toString() {
+ return getExpression();
+ }
+
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/WorkflowEventDescriptor.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/WorkflowEventDescriptor.java
new file mode 100644
index 0000000..6f978e6
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/WorkflowEventDescriptor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.cms.workflow;
+
+import org.apache.commons.lang.Validate;
+import org.apache.lenya.workflow.Version;
+
+/**
+ * Descriptor for workflow events.
+ */
+public class WorkflowEventDescriptor {
+
+ private Version version;
+
+ /**
+ * @param version The version.
+ */
+ public WorkflowEventDescriptor(Version version) {
+ Validate.notNull(version);
+ this.version = version;
+ }
+
+ /**
+ * @return The version.
+ */
+ public Version getVersion() {
+ return this.version;
+ }
+
+ public String toString() {
+ return "workflow:" + this.version.getEvent() + "->" + this.version.getState();
+ }
+
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/WorkflowUtil.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/WorkflowUtil.java
new file mode 100644
index 0000000..84767aa
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/cms/workflow/WorkflowUtil.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.cms.workflow;
+
+import org.apache.cocoon.spring.configurator.WebAppContextUtils;
+import org.apache.lenya.cms.publication.Document;
+import org.apache.lenya.cms.publication.Session;
+import org.apache.lenya.cms.publication.util.DocumentSet;
+import org.apache.lenya.workflow.Workflow;
+import org.apache.lenya.workflow.WorkflowException;
+import org.apache.lenya.workflow.WorkflowManager;
+import org.apache.lenya.workflow.Workflowable;
+
+/**
+ * Utility class for workflow tasks.
+ *
+ * @version $Id:$
+ */
+public class WorkflowUtil {
+
+ /**
+ * Invokes a workflow event on a document. This is the same as
+ * <code>invoke(Document, String, true)</code>.
+ * @param document The document.
+ * @param event The name of the event.
+ * @throws WorkflowException if the event could not be invoked in the current situation.
+ */
+ public static void invoke(Document document, String event) throws WorkflowException {
+ WorkflowManager wfManager = getWorkflowManager();
+ Workflowable workflowable = getWorkflowable(document);
+ wfManager.invoke(workflowable, event);
+ }
+
+ /**
+ * Invokes a workflow event on a document.
+ * @param document The document.
+ * @param event The name of the event.
+ * @param force If this is set to <code>true</code>, the execution is forced, which means an
+ * exception is thrown if the workflowable in the set does not support the event. If
+ * set to <code>false</code>, non-supporting documents are ignored.
+ * @throws WorkflowException if the event could not be invoked in the current situation.
+ */
+ public static void invoke(Document document, String event, boolean force)
+ throws WorkflowException {
+ WorkflowManager wfManager = getWorkflowManager();
+ Workflowable workflowable = getWorkflowable(document);
+ wfManager.invoke(workflowable, event, force);
+ }
+
+ /**
+ * Invokes a workflow event on a document set.
+ * @param documentSet The document.
+ * @param event The event.
+ * @param force If this is set to <code>true</code>, the execution is forced, which means an
+ * exception is thrown if a document in the set does not support the event. If set to
+ * <code>false</code>, non-supporting documents are ignored.
+ * @throws WorkflowException if <code>force</code> is set to <code>true</code> and a document
+ * does not support the workflow event.
+ */
+ public static void invoke(DocumentSet documentSet, String event, boolean force)
+ throws WorkflowException {
+ WorkflowManager wfManager = getWorkflowManager();
+ Document[] documents = documentSet.getDocuments();
+ for (int i = 0; i < documents.length; i++) {
+ Workflowable workflowable = new DocumentWorkflowable(documents[i]);
+ wfManager.invoke(workflowable, event, force);
+ }
+ }
+
+ protected static WorkflowManager getWorkflowManager() {
+ return (WorkflowManager) WebAppContextUtils.getCurrentWebApplicationContext().getBean(
+ WorkflowManager.ROLE);
+ }
+
+ /**
+ * Checks if an event can be invoked on a document.
+ * @param document The document.
+ * @param event The event.
+ * @return A boolean value.
+ * @throws WorkflowException
+ */
+ public static boolean canInvoke(Document document, String event)
+ throws WorkflowException {
+ Workflowable workflowable = new DocumentWorkflowable(document);
+ return getWorkflowManager().canInvoke(workflowable, event);
+ }
+
+ /**
+ * Checks if an event can be invoked on all documents in a set.
+ * @param session The repository session.
+ * @param documents The documents.
+ * @param event The event.
+ * @return if an error occurs.
+ * @throws WorkflowException
+ */
+ public static boolean canInvoke(Session session, DocumentSet documents, String event)
+ throws WorkflowException {
+ WorkflowManager wfManager = getWorkflowManager();
+
+ boolean canInvoke = true;
+ Document[] documentArray = documents.getDocuments();
+ for (int i = 0; i < documentArray.length; i++) {
+ Workflowable workflowable = new DocumentWorkflowable(documentArray[i]);
+ canInvoke = canInvoke && wfManager.canInvoke(workflowable, event);
+ }
+ return canInvoke;
+ }
+
+ /**
+ * Returns if a document has a workflow.
+ * @param logger The logger.
+ * @param document The document.
+ * @return A boolean value.
+ * @throws WorkflowException if an error occurs.
+ */
+ public static boolean hasWorkflow(Document document) throws WorkflowException {
+ Workflowable workflowable = new DocumentWorkflowable(document);
+ return getWorkflowManager().hasWorkflow(workflowable);
+ }
+
+ /**
+ * Returns the workflow schema of a document.
+ * @param logger The logger.
+ * @param document The document.
+ * @return A workflow schema.
+ * @throws WorkflowException if an error occurs.
+ */
+ public static Workflow getWorkflowSchema(Document document)
+ throws WorkflowException {
+ WorkflowManager wfManager = getWorkflowManager();
+ Workflowable workflowable = getWorkflowable(document);
+ if (wfManager.hasWorkflow(workflowable)) {
+ return wfManager.getWorkflowSchema(workflowable);
+ } else {
+ throw new WorkflowException("The document [" + document + "] has no workflow!");
+ }
+ }
+
+ /**
+ * Returns a workflowable for a document.
+ * @param logger The logger.
+ * @param document The document.
+ * @return A workflowable.
+ */
+ public static Workflowable getWorkflowable(Document document) {
+ return new DocumentWorkflowable(document);
+ }
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Action.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Action.java
new file mode 100644
index 0000000..febbacb
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Action.java
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+
+/**
+ * Workflow action.
+ */
+public interface Action {
+
+ /**
+ * Executes this action for a given workflow instance.
+ * @param resultingVersion The resulting version.
+ * @throws WorkflowException if the execution failed
+ */
+ void execute(Version resultingVersion) throws WorkflowException;
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/BooleanVariable.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/BooleanVariable.java
new file mode 100644
index 0000000..d1d4651
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/BooleanVariable.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+
+/**
+ * <p>Boolean state variable.</p>
+ * <p>
+ * A workflow schema can contain a set of state variables.
+ * For each instance, the state variables hold certain values.
+ * Values can be assigned during transitions, so a variable can
+ * change its value when a transition fires. Currently,
+ * the workflow supports only boolean state variables.
+ * </p>
+ */
+public interface BooleanVariable {
+
+ /**
+ * Returns the name of this variable.
+ * @return the name
+ */
+ String getName();
+
+ /**
+ * Returns the initial value of this variable.
+ * @return A boolean value.
+ */
+ boolean getInitialValue();
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/BooleanVariableAssignment.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/BooleanVariableAssignment.java
new file mode 100644
index 0000000..8b2021f
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/BooleanVariableAssignment.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+
+/**
+ * Boolean variable assignment.
+ */
+public interface BooleanVariableAssignment extends Action {
+ // do nothing
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Condition.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Condition.java
new file mode 100644
index 0000000..ee758a3
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Condition.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+/**
+ * <p>A condition can prevent a transition from firing,
+ * based on the current situation. Examples:</p>
+ * <ul>
+ * <li>Does the current user have a certain role on the current URL?</li>
+ * <li>Does a certain state variable have a certain value (e.g., is the document published)? (BooleanVariableCondition)<li>
+ * <li>Is the sun shining? (e.g., if the weather report may only be published on sunny days)</li>
+ * </ul>
+ */
+public interface Condition {
+
+ /**
+ * Returns if the condition is complied in a certain situation.
+ * @param workflow The workflow to use.
+ * @param workflowable The workflowable to check the condition on.
+ * @return if the condition is complied.
+ * @throws WorkflowException when the expression could not be evaluated.
+ */
+ boolean isComplied(Workflow workflow, Workflowable workflowable) throws WorkflowException;
+
+ /** Sets the expression for this condition.
+ * @param expression The expression.
+ * @throws WorkflowException when the expression is not valid.
+ */
+ void setExpression(String expression) throws WorkflowException;
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Transition.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Transition.java
new file mode 100644
index 0000000..c026ee1
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Transition.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+
+/**
+ * <p>
+ * A transition describes the switching of a workflow instance
+ * from one state to another. A transition has
+ * </p>
+ *
+ * <ul>
+ * <li>a source state,</li>
+ * <li>a destination state,</li>
+ * <li>an event,</li>
+ * <li>a set of conditions,</li>
+ * <li>a set of assignments.</li>
+ * </ul>
+ *
+ * <p>
+ * Additionally, a transition can be marked as synchronized.
+ * </p>
+ */
+public interface Transition {
+
+ /**
+ * Returns the event of this transition.
+ * @return the event
+ */
+ String getEvent();
+
+ /**
+ * @return The source state.
+ */
+ String getSource();
+
+ /**
+ * @return The destination state.
+ */
+ String getDestination();
+
+ /**
+ * Returns the actions of this transition.
+ * @return the actions
+ */
+ Action[] getActions();
+
+ /**
+ * @return The conditions.
+ */
+ Condition[] getConditions();
+
+ /**
+ * Returns if this transition is synchronized.
+ * @return A boolean value.
+ */
+ boolean isSynchronized();
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Version.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Version.java
new file mode 100644
index 0000000..86bfcf8
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Version.java
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.workflow;
+
+import java.util.Date;
+
+/**
+ * A version of the workflow history.
+ *
+ * @version $Id$
+ */
+public interface Version {
+
+ /**
+ * Returns the event.
+ * @return An event.
+ */
+ String getEvent();
+
+ /**
+ * Returns the state.
+ * @return A state.
+ */
+ String getState();
+
+
+ /**
+ * Returns the date.
+ * @return A string.
+ */
+ Date getDate();
+
+ /**
+ * Sets the date.
+ * @param _date A date.
+ */
+ void setDate(Date _date);
+
+ /**
+ * Returns the user ID.
+ * @return A string.
+ */
+ public String getUserId();
+
+ /**
+ * Sets the user ID.
+ * @param _userId A user ID.
+ */
+ public void setUserId(String _userId);
+
+ /**
+ * Returns the ip address.
+ * @return A string.
+ */
+ public String getIPAddress();
+
+ /**
+ * Sets the ip address.
+ * @param _ipaddress A ip address.
+ */
+ public void setIPAddress(String _ipaddress);
+
+ /**
+ * Returns the value of a variable.
+ * @param variableName The variable name.
+ * @return A boolean value.
+ */
+ boolean getValue(String variableName);
+
+ /**
+ * Sets a variable value.
+ * @param variableName The variable name.
+ * @param value The value.
+ */
+ void setValue(String variableName, boolean value);
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Workflow.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Workflow.java
new file mode 100644
index 0000000..2ea9c01
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Workflow.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+/**
+ * <p>A workflow schema.</p>
+ * <p>
+ * A workflow schema defines a state machine (deterministic finite
+ * automaton - DFA), consisting of
+ * </p>
+ * <ul>
+ * <li>states, including a marked initial state,</li>
+ * <li>transitions, and</li>
+ * <li>state variables.</li>
+ */
+public interface Workflow {
+ /**
+ * <code>NAMESPACE</code> Workflow namespace URI
+ */
+ String NAMESPACE = "http://apache.org/cocoon/lenya/workflow/1.0";
+ /**
+ * <code>DEFAULT_PREFIX</code> Default workflow namespace prefix
+ */
+ String DEFAULT_PREFIX = "wf";
+
+ /**
+ * Returns the initial state of this workflow.
+ * @return The initial state
+ */
+ String getInitialState();
+
+ /**
+ * Returns the transitions that leave a state.
+ * This method is used, e.g., to disable menu items.
+ * @param state A state.
+ * @return The transitions that leave the state.
+ * @throws WorkflowException if the state is not contained.
+ */
+ Transition[] getLeavingTransitions(String state) throws WorkflowException;
+
+ /**
+ * Returns the variable names.
+ * @return A string array.
+ */
+ String[] getVariableNames();
+
+ /**
+ * @return The name of this workflow.
+ */
+ String getName();
+
+ /**
+ * @param variableName The variable name.
+ * @return The initial value of the variable.
+ * @throws WorkflowException if the variable does not exist.
+ */
+ boolean getInitialValue(String variableName) throws WorkflowException;
+
+ /**
+ * @return The events.
+ */
+ String[] getEvents();
+
+ /**
+ * @return The states.
+ */
+ String[] getStates();
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowEngine.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowEngine.java
new file mode 100644
index 0000000..7d14807
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowEngine.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.workflow;
+
+/**
+ * Workflow engine.
+ *
+ * @version $Id$
+ */
+public interface WorkflowEngine {
+
+ /**
+ * Checks if an event can be invoked.
+ * @param workflowable The workflowable.
+ * @param workflow The workflow schema.
+ * @param event The event.
+ * @return A boolean value.
+ * @throws WorkflowException if an error occurs.
+ */
+ boolean canInvoke(Workflowable workflowable, Workflow workflow, String event)
+ throws WorkflowException;
+
+ /**
+ * Invokes an event.
+ * @param workflowable The workflowable.
+ * @param workflow The workflow.
+ * @param event The event.
+ * @throws WorkflowException if an error occurs.
+ */
+ void invoke(Workflowable workflowable, Workflow workflow, String event)
+ throws WorkflowException;
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowException.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowException.java
new file mode 100644
index 0000000..a3c8aea
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowException.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+
+/**
+ * Workflow exception.
+ */
+public class WorkflowException extends Exception {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructor
+ */
+ public WorkflowException() {
+ super();
+ }
+
+ /**
+ * Create a WorkflowException.
+ * @param message The message.
+ */
+ public WorkflowException(String message) {
+ super(message);
+ }
+
+ /**
+ * Create a WorkflowException.
+ * @param message The message.
+ * @param cause The cause.
+ */
+ public WorkflowException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ /**
+ * Create a WorkflowException.
+ * @param cause The cause.
+ */
+ public WorkflowException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowManager.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowManager.java
new file mode 100644
index 0000000..13c32b6
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/WorkflowManager.java
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.workflow;
+
+/**
+ * Manager for workflow issues. This is the main entry point for
+ * workflow-related tasks. You can safely invoke all methods for non-workflow
+ * documents.
+ *
+ * @version $Id: WorkflowManager.java 179751 2005-06-03 09:13:35Z andreas $
+ */
+public interface WorkflowManager {
+
+ /**
+ * The Avalon role.
+ */
+ String ROLE = WorkflowManager.class.getName();
+
+ /**
+ * Invokes a workflow event on a document. This is the same as
+ * <code>invoke(Document, String, true)</code>.
+ * @param workflowable The workflowable.
+ * @param event The name of the event.
+ * @throws WorkflowException if the event could not be invoked in the
+ * current situation.
+ */
+ void invoke(Workflowable workflowable, String event) throws WorkflowException;
+
+ /**
+ * Invokes a workflow event on a document.
+ * @param workflowable The document.
+ * @param event The name of the event.
+ * @param force If this is set to <code>true</code>, the execution is
+ * forced, which means an exception is thrown if the workflowable in
+ * the set does not support the event. If set to
+ * <code>false</code>, non-supporting documents are ignored.
+ * @throws WorkflowException if the event could not be invoked in the
+ * current situation.
+ */
+ void invoke(Workflowable workflowable, String event, boolean force) throws WorkflowException;
+
+ /**
+ * Checks if an event can be invoked on a document.
+ * @param workflowable The workflowable.
+ * @param event The event.
+ * @return A boolean value.
+ */
+ boolean canInvoke(Workflowable workflowable, String event);
+
+ /**
+ * Checks if a workflowable has a workflow.
+ * @param workflowable The workflowable.
+ * @return A boolean value.
+ */
+ boolean hasWorkflow(Workflowable workflowable);
+
+ /**
+ * Resolves the workflow schema of a workflowable.
+ * @param workflowable The workflowable.
+ * @return A workflow schema.
+ * @throws WorkflowException if the document has no workflow.
+ */
+ Workflow getWorkflowSchema(Workflowable workflowable) throws WorkflowException;
+
+}
\ No newline at end of file
diff --git a/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Workflowable.java b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Workflowable.java
new file mode 100644
index 0000000..f735fad
--- /dev/null
+++ b/org.apache.lenya.core.workflow/src/main/java/org/apache/lenya/workflow/Workflowable.java
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ */
+package org.apache.lenya.workflow;
+
+/**
+ * Interface for objects which can be workflowed.
+ *
+ * @version $Id$
+ */
+public interface Workflowable {
+
+ /**
+ * @return The versions in chronological order.
+ */
+ Version[] getVersions();
+
+ /**
+ * @return The latest version.
+ */
+ Version getLatestVersion();
+
+ /**
+ * Adds a new version.
+ * @param workflow The workflow.
+ * @param version The version.
+ */
+ void newVersion(Workflow workflow, Version version);
+
+ /**
+ * @return The URI to resolve the schema configuration from.
+ */
+ String getWorkflowSchemaURI();
+
+}