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.camel.component.mina;
018
019 import java.net.SocketAddress;
020
021 import org.apache.camel.CamelException;
022 import org.apache.camel.Exchange;
023 import org.apache.camel.Processor;
024 import org.apache.camel.impl.DefaultConsumer;
025 import org.apache.camel.processor.Logger;
026 import org.apache.camel.util.ExchangeHelper;
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029 import org.apache.mina.common.IoAcceptor;
030 import org.apache.mina.common.IoHandlerAdapter;
031 import org.apache.mina.common.IoSession;
032
033 /**
034 * A {@link org.apache.camel.Consumer Consumer} implementation for Apache MINA.
035 *
036 * @version $Revision: 19337 $
037 */
038 public class MinaConsumer extends DefaultConsumer {
039 private static final transient Log LOG = LogFactory.getLog(MinaConsumer.class);
040
041 private final MinaEndpoint endpoint;
042 private final SocketAddress address;
043 private final IoAcceptor acceptor;
044 private boolean sync;
045 private Logger noReplyLogger;
046
047 public MinaConsumer(final MinaEndpoint endpoint, Processor processor) {
048 super(endpoint, processor);
049 this.endpoint = endpoint;
050 this.address = endpoint.getAddress();
051 this.acceptor = endpoint.getAcceptor();
052 this.sync = endpoint.getConfiguration().isSync();
053 this.noReplyLogger = new Logger(LOG, endpoint.getConfiguration().getNoReplyLogLevel());
054 }
055
056 @Override
057 protected void doStart() throws Exception {
058 super.doStart();
059 if (LOG.isInfoEnabled()) {
060 LOG.info("Binding to server address: " + address + " using acceptor: " + acceptor);
061 }
062
063 acceptor.bind(address, new ReceiveHandler(), endpoint.getAcceptorConfig());
064 }
065
066 @Override
067 protected void doStop() throws Exception {
068 if (LOG.isInfoEnabled()) {
069 LOG.info("Unbinding from server address: " + address + " using acceptor: " + acceptor);
070 }
071 acceptor.unbind(address);
072 super.doStop();
073 }
074
075 /**
076 * Handles consuming messages and replying if the exchange is out capable.
077 */
078 private final class ReceiveHandler extends IoHandlerAdapter {
079
080 @Override
081 public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
082 // close invalid session
083 if (session != null) {
084 LOG.debug("Closing session as an exception was thrown from MINA");
085 session.close();
086 }
087
088 // must wrap and rethrow since cause can be of Throwable and we must only throw Exception
089 throw new CamelException(cause);
090 }
091
092 @Override
093 public void messageReceived(IoSession session, Object object) throws Exception {
094 // log what we received
095 if (LOG.isDebugEnabled()) {
096 Object in = object;
097 if (in instanceof byte[]) {
098 // byte arrays is not readable so convert to string
099 in = endpoint.getCamelContext().getTypeConverter().convertTo(String.class, in);
100 }
101 LOG.debug("Received body: " + in);
102 }
103 Exchange exchange = endpoint.createExchange(session, object);
104 //Set the exchange charset property for converting
105 if (endpoint.getConfiguration().getCharsetName() != null) {
106 exchange.setProperty(Exchange.CHARSET_NAME, endpoint.getConfiguration().getCharsetName());
107 }
108
109 try {
110 getProcessor().process(exchange);
111 } catch (Throwable e) {
112 getExceptionHandler().handleException(e);
113 }
114
115 // if sync then we should return a response
116 if (sync) {
117 Object body;
118 if (ExchangeHelper.isOutCapable(exchange)) {
119 body = MinaPayloadHelper.getOut(endpoint, exchange);
120 } else {
121 body = MinaPayloadHelper.getIn(endpoint, exchange);
122 }
123
124 boolean failed = exchange.isFailed();
125 if (failed && !endpoint.getConfiguration().isTransferExchange()) {
126 if (exchange.getException() != null) {
127 body = exchange.getException();
128 } else {
129 // failed and no exception, must be a fault
130 body = exchange.getOut().getBody();
131 }
132 }
133
134 if (body == null) {
135 noReplyLogger.log("No payload to send as reply for exchange: " + exchange);
136 if (endpoint.getConfiguration().isDisconnectOnNoReply()) {
137 // must close session if no data to write otherwise client will never receive a response
138 // and wait forever (if not timing out)
139 if (LOG.isDebugEnabled()) {
140 LOG.debug("Closing session as no payload to send as reply at address: " + address);
141 }
142 session.close();
143 }
144 } else {
145 // we got a response to write
146 if (LOG.isDebugEnabled()) {
147 LOG.debug("Writing body: " + body);
148 }
149 MinaHelper.writeBody(session, body, exchange);
150 }
151 }
152
153 // should session be closed after complete?
154 Boolean close;
155 if (ExchangeHelper.isOutCapable(exchange)) {
156 close = exchange.getOut().getHeader(MinaConstants.MINA_CLOSE_SESSION_WHEN_COMPLETE, Boolean.class);
157 } else {
158 close = exchange.getIn().getHeader(MinaConstants.MINA_CLOSE_SESSION_WHEN_COMPLETE, Boolean.class);
159 }
160
161 // should we disconnect, the header can override the configuration
162 boolean disconnect = endpoint.getConfiguration().isDisconnect();
163 if (close != null) {
164 disconnect = close;
165 }
166 if (disconnect) {
167 if (LOG.isDebugEnabled()) {
168 LOG.debug("Closing session when complete at address: " + address);
169 }
170 session.close();
171 }
172 }
173 }
174
175 }
176