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.netty.handlers;
018
019 import org.apache.camel.CamelException;
020 import org.apache.camel.Exchange;
021 import org.apache.camel.ExchangePattern;
022 import org.apache.camel.component.netty.NettyConstants;
023 import org.apache.camel.component.netty.NettyConsumer;
024 import org.apache.camel.component.netty.NettyHelper;
025 import org.apache.camel.component.netty.NettyPayloadHelper;
026 import org.apache.camel.processor.Logger;
027 import org.apache.camel.util.ExchangeHelper;
028 import org.apache.commons.logging.Log;
029 import org.apache.commons.logging.LogFactory;
030 import org.jboss.netty.channel.ChannelHandlerContext;
031 import org.jboss.netty.channel.ChannelPipelineCoverage;
032 import org.jboss.netty.channel.ChannelStateEvent;
033 import org.jboss.netty.channel.ExceptionEvent;
034 import org.jboss.netty.channel.MessageEvent;
035 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
036
037 @ChannelPipelineCoverage("all")
038 public class ServerChannelHandler extends SimpleChannelUpstreamHandler {
039 private static final transient Log LOG = LogFactory.getLog(ServerChannelHandler.class);
040 private NettyConsumer consumer;
041 private Logger noReplyLogger;
042
043 public ServerChannelHandler(NettyConsumer consumer) {
044 super();
045 this.consumer = consumer;
046 this.noReplyLogger = new Logger(LOG, consumer.getConfiguration().getNoReplyLogLevel());
047 }
048
049 @Override
050 public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent channelStateEvent) throws Exception {
051 // to keep track of open sockets
052 consumer.getAllChannels().add(channelStateEvent.getChannel());
053 }
054
055 @Override
056 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
057 LOG.debug("Channel closed: " + e.getChannel());
058 }
059
060 @Override
061 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent exceptionEvent) throws Exception {
062 LOG.warn("Closing channel as an exception was thrown from Netty", exceptionEvent.getCause());
063
064 // close channel in case an exception was thrown
065 NettyHelper.close(exceptionEvent.getChannel());
066 }
067
068 @Override
069 public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception {
070 Object in = messageEvent.getMessage();
071 if (LOG.isDebugEnabled()) {
072 if (in instanceof byte[]) {
073 // byte arrays is not readable so convert to string
074 in = consumer.getEndpoint().getCamelContext().getTypeConverter().convertTo(String.class, in);
075 }
076 LOG.debug("Incoming message: " + in);
077 }
078
079 // create Exchange and let the consumer process it
080 Exchange exchange = consumer.getEndpoint().createExchange(ctx, messageEvent);
081 if (consumer.getConfiguration().isSync()) {
082 exchange.setPattern(ExchangePattern.InOut);
083 }
084
085 try {
086 consumer.getProcessor().process(exchange);
087 } catch (Throwable e) {
088 consumer.getExceptionHandler().handleException(e);
089 }
090
091 // send back response if the communication is synchronous
092 if (consumer.getConfiguration().isSync()) {
093 sendResponse(messageEvent, exchange);
094 }
095 }
096
097 private void sendResponse(MessageEvent messageEvent, Exchange exchange) throws Exception {
098 Object body;
099 if (ExchangeHelper.isOutCapable(exchange)) {
100 body = NettyPayloadHelper.getOut(consumer.getEndpoint(), exchange);
101 } else {
102 body = NettyPayloadHelper.getIn(consumer.getEndpoint(), exchange);
103 }
104
105 boolean failed = exchange.isFailed();
106 if (failed && !consumer.getEndpoint().getConfiguration().isTransferExchange()) {
107 if (exchange.getException() != null) {
108 body = exchange.getException();
109 } else {
110 // failed and no exception, must be a fault
111 body = exchange.getOut().getBody();
112 }
113 }
114
115 if (body == null) {
116 noReplyLogger.log("No payload to send as reply for exchange: " + exchange);
117 if (consumer.getConfiguration().isDisconnectOnNoReply()) {
118 // must close session if no data to write otherwise client will never receive a response
119 // and wait forever (if not timing out)
120 if (LOG.isDebugEnabled()) {
121 LOG.debug("Closing channel as no payload to send as reply at address: " + messageEvent.getRemoteAddress());
122 }
123 NettyHelper.close(messageEvent.getChannel());
124 }
125 } else {
126 // we got a body to write
127 if (LOG.isDebugEnabled()) {
128 LOG.debug("Writing body: " + body);
129 }
130 if (consumer.getConfiguration().getProtocol().equalsIgnoreCase("udp")) {
131 NettyHelper.writeBody(messageEvent.getChannel(), messageEvent.getRemoteAddress(), body, exchange);
132 } else {
133 NettyHelper.writeBody(messageEvent.getChannel(), null, body, exchange);
134 }
135 }
136
137 // should channel be closed after complete?
138 Boolean close;
139 if (ExchangeHelper.isOutCapable(exchange)) {
140 close = exchange.getOut().getHeader(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, Boolean.class);
141 } else {
142 close = exchange.getIn().getHeader(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, Boolean.class);
143 }
144
145 // should we disconnect, the header can override the configuration
146 boolean disconnect = consumer.getConfiguration().isDisconnect();
147 if (close != null) {
148 disconnect = close;
149 }
150 if (disconnect) {
151 if (LOG.isDebugEnabled()) {
152 LOG.debug("Closing channel when complete at address: " + messageEvent.getRemoteAddress());
153 }
154 NettyHelper.close(messageEvent.getChannel());
155 }
156 }
157
158 }