[Yanel-commits] rev 24457 - in public/yanel/trunk/src: core/java/org/wyona/yanel/core core/java/org/wyona/yanel/core/workflow core/java/org/wyona/yanel/core/workflow/impl impl/java/org/wyona/yanel/impl impl/java/org/wyona/yanel/impl/workflow

michi at wyona.com michi at wyona.com
Mon May 14 22:57:08 CEST 2007


Author: michi
Date: 2007-05-14 22:57:06 +0200 (Mon, 14 May 2007)
New Revision: 24457

Added:
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Action.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Condition.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Transition.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Workflow.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowBuilder.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowException.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowHelper.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/TransitionImpl.java
   public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/WorkflowImpl.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/DeactivateAction.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/PublishAction.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RemoveVariableAction.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionEqualsCondition.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionNotEqualsCondition.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RoleCondition.java
   public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/SetRevisionAction.java
Log:
workflow api and impl added

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Action.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Action.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Action.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+
+public interface Action {
+
+    void execute(WorkflowableV1 workflowable, Workflow workflow,
+            String revision) throws WorkflowException;
+
+    void setExpression(String expression) throws WorkflowException;
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Condition.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Condition.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Condition.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+
+public interface Condition {
+
+    boolean isComplied(WorkflowableV1 workflowable, Workflow workflow,
+            String revision) throws WorkflowException;
+
+    void setExpression(String expression) throws WorkflowException;
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Transition.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Transition.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Transition.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow;
+
+public interface Transition {
+    
+    String getID();
+
+    String getSourceState();
+    
+    String getDestinationState();
+    
+    Condition[] getConditions();
+    
+    Action[] getActions();
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Workflow.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Workflow.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/Workflow.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow;
+
+public interface Workflow {
+    
+    String NAMESPACE = "http://www.wyona.org/yanel/workflow/1.0";
+    
+    String getInitialState();
+    
+//    String[] getStates();
+    
+//    Transition[] getTransitions();
+    
+    Transition[] getLeavingTransitions(String state);
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowBuilder.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowBuilder.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowBuilder.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xml.resolver.tools.CatalogResolver;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.wyona.yanel.core.workflow.impl.TransitionImpl;
+import org.wyona.yanel.core.workflow.impl.WorkflowImpl;
+
+public class WorkflowBuilder {
+
+    public Workflow buildWorkflow(InputStream stream) throws WorkflowException {
+        try {
+            Document document = readDocument(stream);
+            Workflow workflow = buildWorkflow(document);
+            return workflow;
+        } catch (Exception e) {
+            throw new WorkflowException(e);
+        }
+    }
+
+    private Document readDocument(InputStream stream) throws Exception {
+        DocumentBuilder builder = createBuilder();
+        return builder.parse(stream);
+    }
+
+    /**
+     * Creates a non-validating and namespace-aware DocumentBuilder.
+     * @return A new DocumentBuilder object.
+     * @throws ParserConfigurationException if an error occurs
+     */
+    protected DocumentBuilder createBuilder() throws ParserConfigurationException {
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+
+        CatalogResolver cr = new CatalogResolver();
+        builder.setEntityResolver(cr);
+        return builder;
+    }
+
+    /**
+     * 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 Workflow buildWorkflow(Document document) throws WorkflowException {
+
+        WorkflowImpl workflow = new WorkflowImpl();
+
+        Element root = document.getDocumentElement();
+        String initialState = null;
+
+        // load states
+        Element statesElement = (Element) root.getElementsByTagNameNS(Workflow.NAMESPACE, "states")
+                .item(0);
+        NodeList stateElements = statesElement.getElementsByTagNameNS(Workflow.NAMESPACE, "state");
+
+        ArrayList states = new ArrayList();
+        for (int i = 0; i < stateElements.getLength(); i++) {
+            Element element = (Element) stateElements.item(i);
+            String state = buildState(element);
+
+            if (isInitialStateElement(element)) {
+                initialState = state;
+            }
+            states.add(state);
+        }
+
+        workflow.setStates((String[]) states.toArray(new String[states.size()]));
+        workflow.setInitialState(initialState);
+
+        // load transitions
+        Element transitionsElement = (Element) root.getElementsByTagNameNS(Workflow.NAMESPACE,
+                "transitions").item(0);
+        NodeList transitionElements = transitionsElement.getElementsByTagNameNS(Workflow.NAMESPACE,
+                "transition");
+
+        ArrayList transitions = new ArrayList();
+        for (int i = 0; i < transitionElements.getLength(); i++) {
+            Transition transition = buildTransition((Element) transitionElements.item(i));
+            transitions.add(transition);
+        }
+
+        workflow.setTransitions((Transition[]) transitions.toArray(new Transition[transitions
+                .size()]));
+
+        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");
+
+        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");
+    }
+
+    /**
+     * Builds a transition from an XML element.
+     * @param element An XML element.
+     * @return A transition.
+     * @throws WorkflowException when something went wrong.
+     */
+    protected Transition buildTransition(Element element) throws WorkflowException {
+
+        String id = element.getAttribute("id");
+        String source = element.getAttribute("from");
+        String destination = element.getAttribute("to");
+
+        TransitionImpl transition = new TransitionImpl(id, source, destination);
+
+        NodeList conditionElements = element.getElementsByTagNameNS(Workflow.NAMESPACE,
+        "condition");
+        
+        Condition[] conditions = new Condition[conditionElements.getLength()];
+        for (int i = 0; i < conditionElements.getLength(); i++) {
+            conditions[i] = buildCondition((Element) conditionElements.item(i));
+        }
+
+        transition.setConditions(conditions);
+        
+        NodeList actionElements = element.getElementsByTagNameNS(Workflow.NAMESPACE,
+        "action");
+        
+        Action[] actions = new Action[actionElements.getLength()];
+        for (int i = 0; i < actionElements.getLength(); i++) {
+            actions[i] = buildAction((Element) actionElements.item(i));
+        }
+
+        transition.setActions(actions);
+
+        return transition;
+    }
+    
+    protected Condition buildCondition(Element element) throws WorkflowException {
+        String className = element.getAttribute("class");
+        Class conditionClass;
+        Condition condition = null;
+        try {
+            conditionClass = Class.forName(className);
+            condition = (Condition)conditionClass.newInstance();
+        } catch (Exception e) {
+            throw new WorkflowException(e.getMessage(), e);
+        }
+        Node node = element.getFirstChild();
+        String expression = null;
+        if (node != null) {
+            expression = node.getNodeValue();
+        }
+        condition.setExpression(expression);
+        return condition;
+    }
+
+    protected Action buildAction(Element element) throws WorkflowException {
+        String className = element.getAttribute("class");
+        Class actionClass;
+        Action action = null;
+        try {
+            actionClass = Class.forName(className);
+            action = (Action)actionClass.newInstance();
+        } catch (Exception e) {
+            throw new WorkflowException(e.getMessage(), e);
+        }
+        Node node = element.getFirstChild();
+        String expression = null;
+        if (node != null) {
+            expression = node.getNodeValue();
+        }
+        action.setExpression(expression);
+        return action;
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowException.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowException.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowException.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,36 @@
+package org.wyona.yanel.core.workflow;
+
+/**
+ * 
+ */
+public class WorkflowException extends Exception {
+
+    /**
+     *
+     */
+    public WorkflowException() {
+        super();
+    }
+
+    /**
+     *
+     */
+    public WorkflowException(Throwable t) {
+        super(t);
+    }
+
+    /**
+     *
+     */
+    public WorkflowException(String s) {
+        super(s);
+    }
+
+    /**
+     *
+     */
+    public WorkflowException(String s, Throwable t) {
+        super(s, t);
+    }
+
+}

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowHelper.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowHelper.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/WorkflowHelper.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow;
+
+import java.io.InputStream;
+import java.util.Date;
+
+import org.apache.log4j.Category;
+import org.wyona.yanel.core.Resource;
+import org.wyona.yanel.core.api.attributes.VersionableV2;
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.attributes.versionable.RevisionInformation;
+import org.wyona.yanel.core.util.DateUtil;
+import org.wyona.yarep.core.Node;
+import org.wyona.yarep.core.Property;
+import org.wyona.yarep.core.Revision;
+
+/**
+ * This class provides some helper methods related to workflow for resources 
+ * which are WorkflowableV1 and VersionableV2 and which implement workflow
+ * according to the following conditions:
+ * - there is a resource config property 'workflow-schema' which points to the schema
+ * - the workflow information is stored as properties of a repository node in the repository
+ *   of the resource with the path of the resource.
+ *
+ */
+public class WorkflowHelper {
+    
+    private static Category log = Category.getInstance(WorkflowHelper.class);
+
+    protected static final String LIVE_REVISION_PROPERTY = "live-revision";
+    protected static final String WORKFLOW_DATE_PROPERTY = "workflow-date";
+    protected static final String WORKFLOW_STATE_PROPERTY = "workflow-state";
+
+    public static void doTransition(Resource resource, String transitionID, String revision) 
+            throws WorkflowException {
+        boolean foundTransition = false;
+        String currentState = null;
+        WorkflowableV1 workflowable = (WorkflowableV1)resource;
+        Workflow workflow = getWorkflow(resource);
+        currentState = workflowable.getWorkflowState(revision);
+        if (currentState == null) {
+            currentState = workflow.getInitialState(); 
+        }
+        Transition[] transitions = workflow.getLeavingTransitions(currentState);
+        
+        for (int i = 0; i < transitions.length; i++) {
+            if (transitions[i].getID().equals(transitionID)) {
+                Condition[] conditions = transitions[i].getConditions();
+                for (int j = 0; j < conditions.length; j++) {
+                    if (!conditions[j].isComplied(workflowable, workflow, revision)) {
+                        throw new WorkflowException("Workflow condition not complied for state " + 
+                                currentState + " and transition " + transitionID);
+                    }
+                }
+                String newState = transitions[i].getDestinationState();
+                
+                workflowable.setWorkflowState(newState, revision);
+                
+                Action[] actions = transitions[i].getActions();
+                for (int j = 0; j < actions.length; j++) {
+                    actions[j].execute(workflowable, workflow, revision);
+                }
+                
+                foundTransition = true;
+            }
+        }
+        if (!foundTransition) {
+            throw new WorkflowException("Invalid workflow transition: " + transitionID + 
+                    " for state: " + currentState);
+        }
+    }
+    
+    /*public static boolean canDoTransition(Resource resource, String transitionID, String revision) 
+            throws WorkflowException {
+        WorkflowableV1 workflowable = (WorkflowableV1)resource;
+        Workflow workflow = getWorkflow(resource);
+        String currentState = workflowable.getWorkflowState(revision);
+        if (currentState == null) {
+            currentState = workflow.getInitialState(); 
+        }
+        Transition[] transitions = workflow.getLeavingTransitions(currentState);
+        
+        for (int j = 0; j < transitions.length; j++) {
+            Condition[] conditions = transitions[j].getConditions();
+            for (int k = 0; k < conditions.length; k++) {
+                if (!conditions[k].isComplied(workflowable, workflow, revision)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }*/
+    
+    public static String getLiveRevision(Resource resource) throws WorkflowException {
+        try {
+            WorkflowableV1 workflowable = (WorkflowableV1)resource;
+            return workflowable.getWorkflowVariable(LIVE_REVISION_PROPERTY);
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+    public static boolean isLive(Resource resource) throws WorkflowException {
+        try {
+            WorkflowableV1 workflowable = (WorkflowableV1)resource;
+            if (workflowable.getWorkflowVariable(LIVE_REVISION_PROPERTY) != null) {
+                return true;
+            } else {
+                return false;
+            }
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+    
+    public static Workflow getWorkflow(Resource resource) throws WorkflowException {
+        try {
+            String workflowSchema = resource.getResourceConfigProperty("workflow-schema");
+            if (workflowSchema == null) {
+                return null;
+            } else {
+                WorkflowBuilder builder = new WorkflowBuilder();
+                InputStream stream;
+                    stream = resource.getRealm().getRepository().getNode(workflowSchema).getInputStream();
+                // TODO: cache of workflow
+                return builder.buildWorkflow(stream);
+            }
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+    
+    public static String getWorkflowIntrospection(Resource resource) throws WorkflowException {
+        try {
+            StringBuffer sb = new StringBuffer();
+            RevisionInformation[] revisions = ((VersionableV2)resource).getRevisions();
+            WorkflowableV1 workflowable = (WorkflowableV1)resource;
+            String liveRevision = getLiveRevision(resource);
+            if (revisions != null && revisions.length > 0) {
+                sb.append("<versions>");
+                for (int i = revisions.length - 1; i >= 0; i--) {
+                    
+                    Workflow workflow = getWorkflow(resource);
+                    String state = workflowable.getWorkflowState(revisions[i].getName());
+                    if (state == null) {
+                        state = workflow.getInitialState();
+                    }
+                    Date workflowDate = workflowable.getWorkflowDate(revisions[i].getName());
+                    String date = "";
+                    if (workflowDate != null) {
+                        date = DateUtil.format(workflowDate);
+                    }
+                    
+                    Transition[] transitions = workflow.getLeavingTransitions(state);
+
+                    sb.append("<version url=\"?yanel.resource.revision=" + revisions[i].getName() + "\">");
+                    sb.append("<comment>" + revisions[i].getComment() + "</comment>");
+                    sb.append("<date>" + revisions[i].getDate() + "</date>");
+                    sb.append("<user>" + revisions[i].getUser() + "</user>");
+                    sb.append("<revision>" + revisions[i].getName() + "</revision>");
+    
+                    sb.append("<workflow>");
+
+                    if (revisions[i].getName().equals(liveRevision)) {
+                        state += "-LIVE"; // TODO: this is a hack
+                    }
+                    sb.append("<state date=\"" + date + "\">" + state + "</state>");
+                    
+                    sb.append("<transitions>");
+transitions:        for (int j = 0; j < transitions.length; j++) {
+                        Condition[] conditions = transitions[j].getConditions();
+                        for (int k = 0; k < conditions.length; k++) {
+                            if (!conditions[k].isComplied(workflowable, workflow, revisions[i].getName())) {
+                                continue transitions; // jump to next transition
+                            }
+                        }
+                        sb.append("<transition id=\""+transitions[j].getID()+"\" to=\""+transitions[j].getDestinationState()+"\" url=\"?yanel.resource.workflow.transition="+transitions[j].getID()+"&amp;yanel.resource.revision=" + revisions[i].getName() + "\" method=\"POST\">");
+                        sb.append("<description>"+transitions[j].getID()+"</description>");
+                        sb.append("</transition>");
+                    }
+                    sb.append("</transitions>");
+                    sb.append("<history/>");
+                    sb.append("</workflow>");
+                    
+                    sb.append("</version>");
+                }
+                sb.append("</versions>");
+                return sb.toString();
+            } else {
+                return "";
+            }
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+    public static String getWorkflowIntrospectionAnswer(Resource resource, String revision) throws WorkflowException {
+        try {
+            StringBuffer sb = new StringBuffer();
+            WorkflowableV1 workflowable = (WorkflowableV1)resource;
+
+            Workflow workflow = getWorkflow(resource);
+            String state = workflowable.getWorkflowState(revision);
+            if (state == null) {
+                state = workflow.getInitialState();
+            }
+            String date = "";
+            
+            sb.append("<workflow xmlns=\"http://www.wyona.org/neutron/2.0\">");
+            sb.append("  <state date=\"" + date + "\">" + state + "</state>");
+            
+            Transition[] transitions = workflow.getLeavingTransitions(state);
+                
+            sb.append("<transitions>");
+transitions: for (int j = 0; j < transitions.length; j++) {
+                Condition[] conditions = transitions[j].getConditions();
+                for (int k = 0; k < conditions.length; k++) {
+                    if (!conditions[k].isComplied(workflowable, workflow, revision)) {
+                        continue transitions; // jump to next transition
+                    }
+                }
+                sb.append("<transition id=\""+transitions[j].getID()+"\" to=\""+transitions[j].getDestinationState()+"\" url=\"?yanel.resource.workflow.transition="+transitions[j].getID()+"\" method=\"POST\">");
+                sb.append("<description>"+transitions[j].getID()+"</description>");
+                sb.append("</transition>");
+            }
+            sb.append("</transitions>");
+            sb.append("<history/>");
+            sb.append("</workflow>");
+                    
+            return sb.toString();
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+    
+    public static String getWorkflowVariable(Resource resource, String name) throws WorkflowException {
+        try {
+            Node node = resource.getRealm().getRepository().getNode(resource.getPath());
+            Property property = node.getProperty(name);
+            if (property != null) {
+                return property.getString();
+            } else {
+                return null;
+            }
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+    public static void setWorkflowVariable(Resource resource, String name, String value) throws WorkflowException {
+        try {
+            Node node = resource.getRealm().getRepository().getNode(resource.getPath());
+            node.setProperty(name, value);
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+    
+    public static void removeWorkflowVariable(Resource resource, String name) throws WorkflowException {
+        try {
+            Node node = resource.getRealm().getRepository().getNode(resource.getPath());
+            node.removeProperty(name);
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+    public static String getWorkflowState(Resource resource, String revision) throws WorkflowException {
+        try {
+            Node node = resource.getRealm().getRepository().getNode(resource.getPath());
+            Property stateProp = node.getRevision(revision).getProperty(WORKFLOW_STATE_PROPERTY);
+            if (stateProp != null) {
+                return stateProp.getString();
+            } else {
+                return null;
+            }
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+    public static void setWorkflowState(Resource resource, String state, String revision) throws WorkflowException {
+        try {
+            Node node = resource.getRealm().getRepository().getNode(resource.getPath());
+            Revision rev = node.getRevision(revision); 
+            rev.setProperty(WORKFLOW_STATE_PROPERTY, state);
+            rev.setProperty(WORKFLOW_DATE_PROPERTY, new Date());
+            // TODO: write workflow history
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+    public static Date getWorkflowDate(Resource resource, String revision) throws WorkflowException {
+        try {
+            Node node = resource.getRealm().getRepository().getNode(resource.getPath());
+            Property dateProp = node.getRevision(revision).getProperty(WORKFLOW_DATE_PROPERTY);
+            if (dateProp != null) {
+                return dateProp.getDate();
+            } else {
+                return null;
+            }
+        } catch (Exception e) {
+            log.error(e, e);
+            throw new WorkflowException(e.getMessage(), e);
+        }
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/TransitionImpl.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/TransitionImpl.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/TransitionImpl.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow.impl;
+
+import org.wyona.yanel.core.workflow.Action;
+import org.wyona.yanel.core.workflow.Condition;
+import org.wyona.yanel.core.workflow.Transition;
+
+public class TransitionImpl implements Transition {
+    private String id;
+    private String sourceState;
+    private String destinationState;
+    private Condition[] conditions;
+    private Action[] actions;
+    
+    public TransitionImpl(String id, String from, String to) {
+        this.id = id;
+        this.sourceState = from;
+        this.destinationState = to;
+    }
+    
+    public String getID() {
+        return id;
+    }
+    
+    public void setID(String id) {
+        this.id = id;
+    }
+    
+    public String getDestinationState() {
+        return destinationState;
+    }
+    
+    public void setDestinationState(String destinationState) {
+        this.destinationState = destinationState;
+    }
+    
+    public String getSourceState() {
+        return sourceState;
+    }
+    
+    public void setSourceState(String sourceState) {
+        this.sourceState = sourceState;
+    }
+
+    public Action[] getActions() {
+        return actions;
+    }
+
+    public void setActions(Action[] actions) {
+        this.actions = actions;
+    }
+
+    public Condition[] getConditions() {
+        return conditions;
+    }
+
+    public void setConditions(Condition[] conditions) {
+        this.conditions = conditions;
+    }
+}
\ No newline at end of file

Added: public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/WorkflowImpl.java
===================================================================
--- public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/WorkflowImpl.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/core/java/org/wyona/yanel/core/workflow/impl/WorkflowImpl.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.core.workflow.impl;
+
+import java.util.ArrayList;
+
+import org.wyona.yanel.core.workflow.Transition;
+import org.wyona.yanel.core.workflow.Workflow;
+
+public class WorkflowImpl implements Workflow {
+    
+    private String[] states;
+    private String initialState;
+    private Transition[] transitions;
+
+    public WorkflowImpl() {
+    }
+    
+    public String getInitialState() {
+        return this.initialState;
+    }
+    
+    public void setInitialState(String state) {
+        this.initialState = state;
+    }
+    
+    public String[] getStates() {
+        return this.states;
+    }
+    
+    public void setStates(String[] states) {
+        this.states = states;
+    }
+    
+    public Transition[] getTransitions() {
+        return this.transitions;
+    }
+    
+    public void setTransitions(Transition[] transitions) {
+        this.transitions = transitions;
+    }
+
+    public Transition[] getLeavingTransitions(String state) {
+        ArrayList leavingTransitions = new ArrayList();
+        for (int i = 0; i < transitions.length; i++) {
+            if (transitions[i].getSourceState().equals(state)) {
+                leavingTransitions.add(transitions[i]);
+            }
+        }
+        return (Transition[])leavingTransitions.toArray(new Transition[leavingTransitions.size()]);
+    }
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/DeactivateAction.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/DeactivateAction.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/DeactivateAction.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Action;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class DeactivateAction implements Action {
+
+    protected String variable;
+
+    public void setExpression(String expression) {
+        this.variable = expression;
+    }
+
+    public void execute(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        // TODO
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/PublishAction.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/PublishAction.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/PublishAction.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Action;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class PublishAction implements Action {
+
+    protected String variable;
+
+    public void setExpression(String expression) {
+        this.variable = expression;
+    }
+
+    public void execute(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        // TODO
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RemoveVariableAction.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RemoveVariableAction.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RemoveVariableAction.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Action;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class RemoveVariableAction implements Action {
+
+    protected String variable;
+
+    public void setExpression(String expression) {
+        this.variable = expression;
+    }
+
+    public void execute(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        workflowable.removeWorkflowVariable(variable);
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionEqualsCondition.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionEqualsCondition.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionEqualsCondition.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Condition;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class RevisionEqualsCondition implements Condition {
+
+    protected String variable;
+
+    public void setExpression(String expression) {
+        this.variable = expression;
+    }
+
+    public boolean isComplied(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        String liveRevision = workflowable.getWorkflowVariable(variable);
+        boolean result = revision.equals(liveRevision);
+        return result;
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionNotEqualsCondition.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionNotEqualsCondition.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RevisionNotEqualsCondition.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Condition;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class RevisionNotEqualsCondition implements Condition {
+
+    protected String variable;
+
+    public void setExpression(String expression) {
+        this.variable = expression;
+    }
+
+    public boolean isComplied(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        String liveRevision = workflowable.getWorkflowVariable(variable);
+        boolean result = !revision.equals(liveRevision);
+        return result;
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RoleCondition.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RoleCondition.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/RoleCondition.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Condition;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class RoleCondition implements Condition {
+
+    protected String role;
+
+    public void setExpression(String expression) {
+        this.role = expression;
+    }
+
+    public boolean isComplied(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        // TODO
+        return true;
+    }
+
+}
\ No newline at end of file

Added: public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/SetRevisionAction.java
===================================================================
--- public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/SetRevisionAction.java	2007-05-14 20:54:57 UTC (rev 24456)
+++ public/yanel/trunk/src/impl/java/org/wyona/yanel/impl/workflow/SetRevisionAction.java	2007-05-14 20:57:06 UTC (rev 24457)
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2006 Wyona
+ *
+ *  Licensed 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.wyona.org/licenses/APACHE-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.wyona.yanel.impl.workflow;
+
+import org.wyona.yanel.core.api.attributes.WorkflowableV1;
+import org.wyona.yanel.core.workflow.Action;
+import org.wyona.yanel.core.workflow.Workflow;
+import org.wyona.yanel.core.workflow.WorkflowException;
+
+public class SetRevisionAction implements Action {
+
+    protected String variable;
+
+    public void setExpression(String expression) {
+        this.variable = expression;
+    }
+
+    public void execute(WorkflowableV1 workflowable, Workflow workflow, String revision)
+            throws WorkflowException {
+        workflowable.setWorkflowVariable(variable, revision);
+    }
+
+}
\ No newline at end of file




More information about the Yanel-commits mailing list