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.HashMap;
020    
021    import javax.jbi.messaging.ExchangeStatus;
022    import javax.jbi.messaging.InOnly;
023    import javax.jbi.messaging.InOut;
024    import javax.jbi.messaging.MessageExchange;
025    import javax.jbi.messaging.MessageExchange.Role;
026    import javax.jbi.messaging.MessagingException;
027    import javax.jbi.messaging.NormalizedMessage;
028    import javax.jbi.messaging.RobustInOnly;
029    import javax.xml.namespace.QName;
030    import javax.xml.transform.Source;
031    
032    import org.apache.servicemix.common.endpoints.ProviderEndpoint;
033    import org.apache.servicemix.common.EndpointSupport;
034    import org.apache.servicemix.jbi.jaxp.SourceTransformer;
035    import org.apache.servicemix.executors.Executor;
036    
037    /**
038     * @org.apache.xbean.XBean element="endpoint"
039     * 
040     * @author lhe
041     */
042    public class OSWorkflowEndpoint extends ProviderEndpoint {
043    
044        private static final long TIME_OUT = 30000;
045    
046        private String workflowName;
047    
048        private String caller;
049    
050        private int action;
051    
052        private Executor executor;
053    
054        private SourceTransformer sourceTransformer = new SourceTransformer();
055    
056        public void start() throws Exception {
057            super.start();
058            OSWorkflowComponent component = (OSWorkflowComponent) getServiceUnit().getComponent();
059            executor = component.getExecutorFactory().createExecutor("component." + component.getComponentName() + "." + EndpointSupport.getKey(this));
060        }
061    
062        public void stop() throws Exception {
063            executor.shutdown();
064            super.stop();
065        }
066    
067        /*
068         * (non-Javadoc)
069         * 
070         * @see org.apache.servicemix.common.ExchangeProcessor#process(javax.jbi.messaging.MessageExchange)
071         */
072        public void process(MessageExchange exchange) throws Exception {
073            if (exchange == null) {
074                return;
075            }
076    
077            // The component acts as a consumer, this means this exchange is
078            // received because
079            // we sent it to another component. As it is active, this is either an
080            // out or a fault
081            // If this component does not create / send exchanges, you may just
082            // throw an
083            // UnsupportedOperationException
084            if (exchange.getRole() == Role.CONSUMER) {
085                onConsumerExchange(exchange);
086            } else if (exchange.getRole() == MessageExchange.Role.PROVIDER) {
087    //          The component acts as a provider, this means that another component
088                // has requested our
089                // service
090                // As this exchange is active, this is either an in or a fault (out are
091                // send by this
092                // component)
093                onProviderExchange(exchange);
094            } else {
095                // Unknown role
096                throw new MessagingException("OSWorkflowEndpoint.onMessageExchange(): Unknown role: "
097                                + exchange.getRole());
098            }
099        }
100    
101        /**
102         * handles the incoming consumer messages
103         * 
104         * @param exchange
105         * @throws MessagingException
106         */
107        protected void onConsumerExchange(MessageExchange exchange)
108            throws MessagingException {
109            // Out message
110            if (exchange.getMessage("out") != null) {
111                done(exchange);
112            } else if (exchange.getFault() != null) {
113                //Fault message
114                done(exchange);
115            } else {
116                //This is not compliant with the default MEPs
117                throw new MessagingException(
118                        "OSWorkflowEndpoint.onConsumerExchange(): Consumer exchange is ACTIVE, but no out or fault is provided");
119            }
120        }
121    
122        /**
123         * handles the incoming provider messages
124         * 
125         * @param exchange
126         * @throws MessagingException
127         */
128        protected void onProviderExchange(MessageExchange exchange)
129            throws MessagingException {
130            
131            if (exchange.getStatus() == ExchangeStatus.DONE) {
132                //Exchange is finished
133                return;
134            } else if (exchange.getStatus() == ExchangeStatus.ERROR) {
135                //Exchange has been aborted with an exception
136                return;
137            } else if (exchange.getFault() != null) {
138                //Fault message
139                done(exchange);
140            } else {
141                NormalizedMessage in = exchange.getMessage("in");
142    
143                if (in == null) {
144                    // no in message - strange
145                    throw new MessagingException(
146                            "OSWorkflowEndpoint.onProviderExchange(): Exchange has no IN message");
147                } else {
148                    // create a new workflow object
149                    OSWorkflow osWorkflow = new OSWorkflow(this, this.workflowName,
150                            this.action, new HashMap(), this.caller, exchange);
151    
152                    executor.execute(osWorkflow);
153                }
154            }
155        }
156    
157        /**
158         * sends the given DOMSource as message to the given service (inOnly)
159         * 
160         * @param service
161         *            the service name to send the message to
162         * @param source
163         *            the source to put in the in message content
164         * @return true on sucessful delivering or false on failure
165         * @throws MessagingException
166         *             on any messaging exception
167         */
168        public boolean sendMessage(QName service, Source source)
169            throws MessagingException {
170            InOnly inOnly = getChannel().createExchangeFactoryForService(service).createInOnlyExchange();
171            NormalizedMessage msg = inOnly.createMessage();
172            msg.setContent(source);
173            inOnly.setInMessage(msg);
174            if (getChannel().sendSync(inOnly)) {
175                return inOnly.getStatus() == ExchangeStatus.DONE;
176            } else {
177                return false;
178            }
179        }
180    
181        /**
182         * sends the given DOMSource as message to the given service (inOut)
183         * 
184         * @param service
185         *            the service name to send the message to
186         * @param source
187         *            the source to put in the in message content
188         * @return the DOMSource of the out message or null
189         * @throws MessagingException
190         *             on any messaging exception
191         */
192        public Source sendRequest(QName service, Source source)
193            throws MessagingException {
194            InOut inOut = getChannel().createExchangeFactoryForService(service).createInOutExchange();
195            NormalizedMessage msg = inOut.createMessage();
196            msg.setContent(source);
197            inOut.setInMessage(msg);
198    
199            if (getChannel().sendSync(inOut)) {
200                try {
201                    Source result = sourceTransformer.toDOMSource(inOut.getOutMessage().getContent());
202                    done(inOut);
203                    return result;
204                } catch (Exception ex) {
205                    ex.printStackTrace();
206                    return null;
207                }
208            } else {
209                return null;
210            }
211        }
212    
213        /**
214         * sends the given DOMSource as message to the given service (inOut)
215         * 
216         * @param service
217         *            the service name to send the message to
218         * @param source
219         *            the source to put in the in message content
220         * @return the DOMSource of the out message or null
221         * @throws MessagingException
222         *             on any messaging exception
223         */
224        public MessageExchange sendRawInOutRequest(QName service, Source source)
225            throws MessagingException {
226            InOut inOut = getChannel().createExchangeFactoryForService(service).createInOutExchange();
227            NormalizedMessage msg = inOut.createMessage();
228            msg.setContent(source);
229            inOut.setInMessage(msg);
230            if (getChannel().sendSync(inOut)) {
231                return inOut;
232            } else {
233                return null;
234            }
235        }
236    
237        /**
238         * creates a msg object
239         * 
240         * @param qname
241         *            the service which will be the receiver
242         * @param inOut
243         *            should it be inOut or InOnly
244         * @return the created exchange
245         * @throws MessagingException
246         */
247        public MessageExchange getNewExchange(QName qname, boolean inOut)
248            throws MessagingException {
249            MessageExchange exchange = null;
250    
251            if (inOut) {
252                exchange = getChannel().createExchangeFactoryForService(qname).createInOutExchange();
253            } else {
254                exchange = getChannel().createExchangeFactoryForService(qname).createInOnlyExchange();
255            }
256    
257            return exchange;
258        }
259    
260        /**
261         * sends a done to the channel
262         *
263         * @param ex
264         * @throws MessagingException
265         */
266        public void done(MessageExchange ex) throws MessagingException {
267            super.done(ex);
268        }
269    
270        /**
271         * sends a msg to the channel
272         *
273         * @param ex
274         * @param sync
275         * @throws MessagingException
276         */
277        public void send(MessageExchange ex, boolean sync)
278            throws MessagingException {
279            if (sync) {
280                getChannel().sendSync(ex, TIME_OUT);
281            } else {
282                getChannel().send(ex);
283            }
284        }
285    
286        /**
287         * sends a error to the channel
288         *
289         * @param ex
290         * @throws MessagingException
291         */
292        public void fail(MessageExchange ex) throws MessagingException {
293            super.fail(ex, new Exception("Failure"));
294        }
295    
296        /**
297         * @return the workflowName
298         */
299        public String getWorkflowName() {
300            return this.workflowName;
301        }
302    
303        /**
304         * @param workflowName
305         *            the workflowName to set
306         */
307        public void setWorkflowName(String workflowName) {
308            this.workflowName = workflowName;
309        }
310    
311        /**
312         * @return the caller
313         */
314        public String getCaller() {
315            return this.caller;
316        }
317    
318        /**
319         * @param caller
320         *            the caller to set
321         */
322        public void setCaller(String caller) {
323            this.caller = caller;
324        }
325    
326        /**
327         * @return the action
328         */
329        public int getAction() {
330            return this.action;
331        }
332    
333        /**
334         * @param action
335         *            the action to set
336         */
337        public void setAction(int action) {
338            this.action = action;
339        }
340    
341        /**
342         * init actions
343         */
344        public void preWorkflow() {
345            // nothing for now
346        }
347    
348        /**
349         * cleanup action
350         */
351        public void postWorkflow() {
352            // nothing for now
353        }
354    
355    }