001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.osworkflow;
018    
019    import java.util.Map;
020    
021    import javax.jbi.messaging.InOnly;
022    import javax.jbi.messaging.MessageExchange;
023    import javax.jbi.messaging.RobustInOnly;
024    
025    
026    import com.opensymphony.workflow.InvalidInputException;
027    import com.opensymphony.workflow.InvalidRoleException;
028    import com.opensymphony.workflow.Workflow;
029    import com.opensymphony.workflow.WorkflowException;
030    import com.opensymphony.workflow.basic.BasicWorkflow;
031    import com.opensymphony.workflow.config.DefaultConfiguration;
032    
033    
034    import org.apache.commons.logging.Log;
035    import org.apache.commons.logging.LogFactory;
036    /**
037     * @author lhe
038     */
039    public class OSWorkflow implements Runnable {
040        
041    
042        public static final String KEY_EXCHANGE = "exchange";
043    
044        public static final String KEY_IN_MESSAGE = "in-message";
045    
046        public static final String KEY_ENDPOINT = "endpoint";
047    
048        public static final String KEY_CALLER = "caller";
049    
050        public static final String KEY_ASYNC_PROCESSING = "asynchronous";
051    
052        private static Log log = LogFactory.getLog(OSWorkflow.class);
053        
054        private Workflow osWorkflowInstance;
055    
056        private String caller;
057    
058        private String osWorkflowName;
059    
060        private Map map;
061    
062        private int action = -1;
063    
064        private long workflowId = -1L;
065    
066        private boolean finished;
067    
068        private boolean aborted;
069    
070        private OSWorkflowEndpoint endpoint;
071    
072        private MessageExchange exchange;
073    
074        /**
075         * creates and initializes a new workflow object
076         * 
077         * @param ep
078         *            the endpoint reference
079         * @param workflowName
080         *            the unique workflow name as defined in workflows.xml
081         * @param action
082         *            the initial action
083         * @param map
084         *            the value map
085         * @param caller
086         *            the caller
087         * @param exchange
088         *            the received message exchange
089         */
090        public OSWorkflow(OSWorkflowEndpoint ep, String workflowName, int action,
091                Map map, String caller, MessageExchange exchange) {
092    
093            this.endpoint = ep; // remember the endpoint which called the osworkflow
094            this.osWorkflowName = workflowName;
095            this.osWorkflowInstance = null;
096            this.action = action;
097            this.map = map;
098            this.caller = caller;
099            this.exchange = exchange;
100    
101            // now fill the transient vars with some useful objects
102            this.map.put(KEY_ENDPOINT, this.endpoint);
103            this.map.put(KEY_CALLER, this.caller);
104            this.map.put(KEY_IN_MESSAGE, this.exchange.getMessage("in"));
105            this.map.put(KEY_EXCHANGE, this.exchange);
106            this.map.put(KEY_ASYNC_PROCESSING, this.exchange instanceof InOnly || this.exchange instanceof RobustInOnly);
107        }
108    
109        /**
110         * initializes the workflow and a default config
111         * 
112         * @return the unique workflow id
113         */
114        private long createWorkflow() throws InvalidRoleException,
115                InvalidInputException, WorkflowException {
116            this.osWorkflowInstance = new BasicWorkflow(this.caller);
117            DefaultConfiguration config = new DefaultConfiguration();
118            this.osWorkflowInstance.setConfiguration(config);
119            long wfId = this.osWorkflowInstance.initialize(this.osWorkflowName, this.action, this.map);
120            return wfId;
121        }
122    
123        /*
124         * (non-Javadoc)
125         * 
126         * @see java.lang.Runnable#run()
127         */
128        public void run() {
129            // call the endpoint method for init actions
130            this.endpoint.preWorkflow();
131    
132            if (log.isDebugEnabled()) {
133                log.debug("Starting workflow...");
134                log.debug("Name:       " + this.osWorkflowName);
135                log.debug("Action:     " + this.action);
136                log.debug("Caller:     " + this.caller);
137                log.debug("Map:        " + this.map);
138            }
139    
140            // loop as long as there are more actions to do and the workflow is not
141            // finished or aborted
142            while (!finished && !aborted) {
143                // initial creation
144                if (this.osWorkflowInstance == null) {
145                    try {
146                        this.workflowId = createWorkflow();
147                    } catch (Exception ex) {
148                        log.error("Error creating the workflow", ex);
149                        aborted = true;
150                        break;
151                    }
152                }
153    
154                // determine the available actions
155                int[] availableActions = this.osWorkflowInstance.getAvailableActions(this.workflowId, this.map);
156    
157                // check if there are more actions available
158                if (availableActions.length == 0) {
159                    // no, no more actions available - workflow finished
160                    log.debug("No more actions. Workflow is finished...");
161                    this.finished = true;
162                } else {
163                    // get first available action to execute
164                    int nextAction = availableActions[0];
165    
166                    log.debug("call action " + nextAction);
167                    try {
168                        // call the action
169                        this.osWorkflowInstance.doAction(this.workflowId,nextAction, this.map);
170                    } catch (InvalidInputException iiex) {
171                        log.error(iiex);
172                        aborted = true;
173                    } catch (WorkflowException wfex) {
174                        log.error(wfex);
175                        aborted = true;
176                    }
177                }
178            }
179    
180            if (log.isDebugEnabled()) {
181                log.debug("Stopping workflow...");
182                log.debug("Name:       " + this.osWorkflowName);
183                log.debug("Action:     " + this.action);
184                log.debug("Caller:     " + this.caller);
185                log.debug("Map:        " + this.map);
186                log.debug("WorkflowId: " + this.workflowId);
187                log.debug("End state:  " + (finished ? "Finished" : "Aborted"));
188            }
189    
190            // call the endpoint method for cleanup actions or message exchange
191            this.endpoint.postWorkflow();
192        }
193    }