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;
018    
019    import java.net.InetSocketAddress;
020    import java.util.concurrent.ExecutorService;
021    
022    import org.apache.camel.CamelContext;
023    import org.apache.camel.Processor;
024    import org.apache.camel.impl.DefaultConsumer;
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
028    import org.jboss.netty.bootstrap.ServerBootstrap;
029    import org.jboss.netty.channel.Channel;
030    import org.jboss.netty.channel.ChannelFactory;
031    import org.jboss.netty.channel.group.ChannelGroup;
032    import org.jboss.netty.channel.group.ChannelGroupFuture;
033    import org.jboss.netty.channel.group.DefaultChannelGroup;
034    import org.jboss.netty.channel.socket.DatagramChannelFactory;
035    import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
036    import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
037    
038    public class NettyConsumer extends DefaultConsumer {
039        private static final transient Log LOG = LogFactory.getLog(NettyConsumer.class);
040        private final ChannelGroup allChannels;
041        private CamelContext context;
042        private NettyConfiguration configuration;
043        private ChannelFactory channelFactory;
044        private DatagramChannelFactory datagramChannelFactory;
045        private ServerBootstrap serverBootstrap;
046        private ConnectionlessBootstrap connectionlessServerBootstrap;
047        private Channel channel;
048    
049        public NettyConsumer(NettyEndpoint nettyEndpoint, Processor processor, NettyConfiguration configuration) {
050            super(nettyEndpoint, processor);
051            this.context = this.getEndpoint().getCamelContext();
052            this.configuration = configuration;
053            this.allChannels = new DefaultChannelGroup("NettyProducer-" + nettyEndpoint.getEndpointUri());
054        }
055    
056        @Override
057        public NettyEndpoint getEndpoint() {
058            return (NettyEndpoint) super.getEndpoint();
059        }
060    
061        @Override
062        protected void doStart() throws Exception {
063            super.doStart();
064            if (configuration.getProtocol().equalsIgnoreCase("udp")) {
065                initializeUDPServerSocketCommunicationLayer();
066            } else {
067                initializeTCPServerSocketCommunicationLayer();
068            }
069    
070            LOG.info("Netty consumer bound to: " + configuration.getAddress());
071        }
072    
073        @Override
074        protected void doStop() throws Exception {
075            if (LOG.isInfoEnabled()) {
076                LOG.info("Netty consumer unbinding from: " + configuration.getAddress());
077            }
078    
079            // close all channels
080            ChannelGroupFuture future = allChannels.close();
081            future.awaitUninterruptibly();
082    
083            // and then release other resources
084            if (channelFactory != null) {
085                channelFactory.releaseExternalResources();
086            }
087    
088            super.doStop();
089        }
090    
091        public ChannelGroup getAllChannels() {
092            return allChannels;
093        }
094    
095        public NettyConfiguration getConfiguration() {
096            return configuration;
097        }
098    
099        public void setConfiguration(NettyConfiguration configuration) {
100            this.configuration = configuration;
101        }
102    
103        public ChannelFactory getChannelFactory() {
104            return channelFactory;
105        }
106    
107        public void setChannelFactory(ChannelFactory channelFactory) {
108            this.channelFactory = channelFactory;
109        }
110    
111        public DatagramChannelFactory getDatagramChannelFactory() {
112            return datagramChannelFactory;
113        }
114    
115        public void setDatagramChannelFactory(DatagramChannelFactory datagramChannelFactory) {
116            this.datagramChannelFactory = datagramChannelFactory;
117        }
118    
119        public ServerBootstrap getServerBootstrap() {
120            return serverBootstrap;
121        }
122    
123        public void setServerBootstrap(ServerBootstrap serverBootstrap) {
124            this.serverBootstrap = serverBootstrap;
125        }
126    
127        public ConnectionlessBootstrap getConnectionlessServerBootstrap() {
128            return connectionlessServerBootstrap;
129        }
130    
131        public void setConnectionlessServerBootstrap(ConnectionlessBootstrap connectionlessServerBootstrap) {
132            this.connectionlessServerBootstrap = connectionlessServerBootstrap;
133        }
134    
135        private void initializeTCPServerSocketCommunicationLayer() throws Exception {
136            ExecutorService bossExecutor = context.getExecutorServiceStrategy().newThreadPool(this, "NettyTCPBoss",
137                    configuration.getCorePoolSize(), configuration.getMaxPoolSize());
138            ExecutorService workerExecutor = context.getExecutorServiceStrategy().newThreadPool(this, "NettyTCPWorker",
139                    configuration.getCorePoolSize(), configuration.getMaxPoolSize());
140    
141            channelFactory = new NioServerSocketChannelFactory(bossExecutor, workerExecutor);
142            serverBootstrap = new ServerBootstrap(channelFactory);
143            serverBootstrap.setPipelineFactory(new ServerPipelineFactory(this));
144            serverBootstrap.setOption("child.keepAlive", configuration.isKeepAlive());
145            serverBootstrap.setOption("child.tcpNoDelay", configuration.isTcpNoDelay());
146            serverBootstrap.setOption("child.reuseAddress", configuration.isReuseAddress());
147            serverBootstrap.setOption("child.connectTimeoutMillis", configuration.getConnectTimeout());
148    
149            channel = serverBootstrap.bind(new InetSocketAddress(configuration.getHost(), configuration.getPort()));
150            // to keep track of all channels in use
151            allChannels.add(channel);
152        }
153    
154        private void initializeUDPServerSocketCommunicationLayer() throws Exception {
155            ExecutorService workerExecutor = context.getExecutorServiceStrategy().newThreadPool(this, "NettyUDPWorker",
156                    configuration.getCorePoolSize(), configuration.getMaxPoolSize());
157    
158            datagramChannelFactory = new NioDatagramChannelFactory(workerExecutor);
159            connectionlessServerBootstrap = new ConnectionlessBootstrap(datagramChannelFactory);
160            connectionlessServerBootstrap.setPipelineFactory(new ServerPipelineFactory(this));
161            connectionlessServerBootstrap.setOption("child.keepAlive", configuration.isKeepAlive());
162            connectionlessServerBootstrap.setOption("child.tcpNoDelay", configuration.isTcpNoDelay());
163            connectionlessServerBootstrap.setOption("child.reuseAddress", configuration.isReuseAddress());
164            connectionlessServerBootstrap.setOption("child.connectTimeoutMillis", configuration.getConnectTimeout());
165            connectionlessServerBootstrap.setOption("child.broadcast", configuration.isBroadcast());
166            connectionlessServerBootstrap.setOption("sendBufferSize", configuration.getSendBufferSize());
167            connectionlessServerBootstrap.setOption("receiveBufferSize", configuration.getReceiveBufferSize());
168    
169            channel = connectionlessServerBootstrap.bind(new InetSocketAddress(configuration.getHost(), configuration.getPort()));
170            // to keep track of all channels in use
171            allChannels.add(channel);
172        }
173    
174    }