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 java.util.concurrent.CountDownLatch;
020    
021    import org.apache.camel.CamelException;
022    import org.apache.camel.component.netty.NettyHelper;
023    import org.apache.camel.component.netty.NettyProducer;
024    import org.apache.commons.logging.Log;
025    import org.apache.commons.logging.LogFactory;
026    import org.jboss.netty.channel.ChannelHandlerContext;
027    import org.jboss.netty.channel.ChannelPipelineCoverage;
028    import org.jboss.netty.channel.ChannelStateEvent;
029    import org.jboss.netty.channel.ExceptionEvent;
030    import org.jboss.netty.channel.MessageEvent;
031    import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
032    
033    @ChannelPipelineCoverage("all")
034    public class ClientChannelHandler extends SimpleChannelUpstreamHandler {
035        private static final transient Log LOG = LogFactory.getLog(ClientChannelHandler.class);
036        private NettyProducer producer;
037        private Object message;
038        private Throwable cause;
039        private boolean messageReceived;
040    
041        public ClientChannelHandler(NettyProducer producer) {
042            super();
043            this.producer = producer;
044        }
045    
046        public void reset() {
047            this.message = null;
048            this.cause = null;
049            this.messageReceived = false;
050        }
051    
052        @Override
053        public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent channelStateEvent) throws Exception {
054            // to keep track of open sockets
055            producer.getAllChannels().add(channelStateEvent.getChannel());
056        }
057    
058        @Override
059        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent exceptionEvent) throws Exception {
060            this.message = null;
061            this.messageReceived = false;
062            this.cause = exceptionEvent.getCause();
063    
064            if (LOG.isDebugEnabled()) {
065                LOG.debug("Closing channel as an exception was thrown from Netty", cause);
066            }
067            // close channel in case an exception was thrown
068            NettyHelper.close(exceptionEvent.getChannel());
069        }
070    
071        @Override
072        public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
073            if (producer.getConfiguration().isSync() && !messageReceived) {
074                // sync=true (InOut mode) so we expected a message as reply but did not get one before the session is closed
075                if (LOG.isDebugEnabled()) {
076                    LOG.debug("Channel closed but no message received from address: " + producer.getConfiguration().getAddress());
077                }
078                // session was closed but no message received. This could be because the remote server had an internal error
079                // and could not return a response. We should count down to stop waiting for a response
080                countDown();
081            }
082        }
083    
084        @Override
085        public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent) throws Exception {
086            message = messageEvent.getMessage();
087            messageReceived = true;
088            cause = null;
089    
090            if (LOG.isDebugEnabled()) {
091                LOG.debug("Message received: " + message);
092            }
093    
094            // signal we have received message
095            countDown();
096        }
097    
098        protected void countDown() {
099            if (producer.getConfiguration().isSync()) {
100                producer.getCountdownLatch().countDown();
101            }
102        }
103    
104        public Object getMessage() {
105            return message;
106        }
107    
108        public boolean isMessageReceived() {
109            return messageReceived;
110        }
111    
112        public Throwable getCause() {
113            return cause;
114        }
115    }