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 }