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 }