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.components.util;
018    
019    import java.util.concurrent.atomic.AtomicBoolean;
020    
021    import javax.jbi.JBIException;
022    import javax.jbi.messaging.DeliveryChannel;
023    import javax.jbi.messaging.ExchangeStatus;
024    import javax.jbi.messaging.MessageExchange;
025    import javax.jbi.messaging.MessagingException;
026    import javax.jbi.messaging.NormalizedMessage;
027    
028    import org.apache.commons.logging.Log;
029    import org.apache.commons.logging.LogFactory;
030    import org.apache.servicemix.MessageExchangeListener;
031    
032    /**
033     * A base class for bindings which process inbound JBI messages
034     *
035     * @version $Revision: 564374 $
036     */
037    public abstract class OutBinding extends ComponentSupport implements Runnable, MessageExchangeListener {
038    
039        private static final Log LOG = LogFactory.getLog(OutBinding.class);
040    
041        private AtomicBoolean stop = new AtomicBoolean(true);
042        private Thread runnable;
043    
044        public OutBinding() {
045        }
046    
047        public void onMessageExchange(MessageExchange exchange) throws MessagingException {
048            if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
049                try {
050                    NormalizedMessage message = getInMessage(exchange);
051                    process(exchange, message);
052                } catch (Exception e) {
053                    if (LOG.isDebugEnabled()) {
054                        LOG.debug("Exchange failed", e);
055                    }
056                    fail(exchange, e);
057                }
058            }
059        }
060    
061        /**
062         * Runnable implementation
063         */
064        public void run() {
065            try {
066                DeliveryChannel deliveryChannel = getDeliveryChannel();
067                while (!stop.get()) {
068                    MessageExchange exchange = deliveryChannel.accept();
069                    if (exchange != null) {
070                        try {
071                            onMessageExchange(exchange);
072                        } catch (MessagingException e) {
073                            LOG.error("MessageExchange processing failed", e);
074                        }
075                    }
076                }
077            } catch (MessagingException e) {
078                // Only log exception if the component really fails
079                // i.e. the exception has not been thrown to interrupt
080                // this thread
081                if (!stop.get()) {
082                    LOG.error("run failed", e);
083                }
084            }
085        }
086    
087        /**
088         * shutdown
089         *
090         * @throws JBIException
091         */
092        public void shutDown() throws JBIException {
093        }
094    
095        /**
096         * stop
097         *
098         * @throws JBIException
099         */
100        public void stop() throws JBIException {
101            stop.compareAndSet(false, true);
102            if (runnable != null) {
103                runnable.interrupt();
104                try {
105                    runnable.join();
106                } catch (InterruptedException e) {
107                    LOG.warn("Unable to stop component polling thread", e);
108                }
109                runnable = null;
110            }
111        }
112    
113        /**
114         * start
115         */
116        public void start() throws JBIException {
117            if (stop.compareAndSet(true, false)) {
118                runnable = new Thread(this);
119                runnable.setDaemon(true);
120                runnable.start();
121            }
122        }
123    
124        /**
125         * Process incoming exchange.
126         * The exchange is in the ACTIVE state.
127         * The method should end by a call to done() or answer().
128         * When an exception is thrown, the fail() method will be called.
129         *
130         * @param messageExchange the exchange to process
131         * @param message the input message of the exchange
132         * @throws Exception if an error occurs
133         */
134        protected abstract void process(MessageExchange messageExchange, NormalizedMessage message) throws Exception;
135    }