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.jboss.netty.bootstrap.ConnectionlessBootstrap;
026    import org.jboss.netty.bootstrap.ServerBootstrap;
027    import org.jboss.netty.channel.Channel;
028    import org.jboss.netty.channel.ChannelFactory;
029    import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
030    import org.jboss.netty.channel.group.ChannelGroup;
031    import org.jboss.netty.channel.group.ChannelGroupFuture;
032    import org.jboss.netty.channel.group.DefaultChannelGroup;
033    import org.jboss.netty.channel.socket.DatagramChannelFactory;
034    import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
035    import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
036    import org.slf4j.Logger;
037    import org.slf4j.LoggerFactory;
038    
039    public class NettyConsumer extends DefaultConsumer {
040        private static final transient Logger LOG = LoggerFactory.getLogger(NettyConsumer.class);
041        private final ChannelGroup allChannels;
042        private CamelContext context;
043        private NettyConfiguration configuration;
044        private ChannelFactory channelFactory;
045        private DatagramChannelFactory datagramChannelFactory;
046        private ServerBootstrap serverBootstrap;
047        private ConnectionlessBootstrap connectionlessServerBootstrap;
048        private Channel channel;
049    
050        public NettyConsumer(NettyEndpoint nettyEndpoint, Processor processor, NettyConfiguration configuration) {
051            super(nettyEndpoint, processor);
052            this.context = this.getEndpoint().getCamelContext();
053            this.configuration = configuration;
054            this.allChannels = new DefaultChannelGroup("NettyProducer-" + nettyEndpoint.getEndpointUri());
055        }
056    
057        @Override
058        public NettyEndpoint getEndpoint() {
059            return (NettyEndpoint) super.getEndpoint();
060        }
061    
062        @Override
063        protected void doStart() throws Exception {
064            LOG.debug("Netty consumer binding to: {}", configuration.getAddress());
065    
066            super.doStart();
067            if (isTcp()) {
068                initializeTCPServerSocketCommunicationLayer();
069            } else {
070                initializeUDPServerSocketCommunicationLayer();
071            }
072    
073            LOG.info("Netty consumer bound to: " + configuration.getAddress());
074        }
075    
076        @Override
077        protected void doStop() throws Exception {
078            LOG.debug("Netty consumer unbinding from: {}", configuration.getAddress());
079    
080            // close all channels
081            ChannelGroupFuture future = allChannels.close();
082            future.awaitUninterruptibly();
083    
084            // and then release other resources
085            if (channelFactory != null) {
086                channelFactory.releaseExternalResources();
087            }
088    
089            super.doStop();
090    
091            LOG.info("Netty consumer unbound from: " + configuration.getAddress());
092        }
093    
094        public CamelContext getContext() {
095            return context;
096        }
097    
098        public ChannelGroup getAllChannels() {
099            return allChannels;
100        }
101    
102        public NettyConfiguration getConfiguration() {
103            return configuration;
104        }
105    
106        public void setConfiguration(NettyConfiguration configuration) {
107            this.configuration = configuration;
108        }
109    
110        public ChannelFactory getChannelFactory() {
111            return channelFactory;
112        }
113    
114        public void setChannelFactory(ChannelFactory channelFactory) {
115            this.channelFactory = channelFactory;
116        }
117    
118        public DatagramChannelFactory getDatagramChannelFactory() {
119            return datagramChannelFactory;
120        }
121    
122        public void setDatagramChannelFactory(DatagramChannelFactory datagramChannelFactory) {
123            this.datagramChannelFactory = datagramChannelFactory;
124        }
125    
126        public ServerBootstrap getServerBootstrap() {
127            return serverBootstrap;
128        }
129    
130        public void setServerBootstrap(ServerBootstrap serverBootstrap) {
131            this.serverBootstrap = serverBootstrap;
132        }
133    
134        public ConnectionlessBootstrap getConnectionlessServerBootstrap() {
135            return connectionlessServerBootstrap;
136        }
137    
138        public void setConnectionlessServerBootstrap(ConnectionlessBootstrap connectionlessServerBootstrap) {
139            this.connectionlessServerBootstrap = connectionlessServerBootstrap;
140        }
141    
142        protected boolean isTcp() {
143            return configuration.getProtocol().equalsIgnoreCase("tcp");
144        }
145    
146        private void initializeTCPServerSocketCommunicationLayer() throws Exception {
147            ExecutorService bossExecutor = context.getExecutorServiceStrategy().newThreadPool(this, "NettyTCPBoss",
148                    configuration.getCorePoolSize(), configuration.getMaxPoolSize());
149            ExecutorService workerExecutor = context.getExecutorServiceStrategy().newThreadPool(this, "NettyTCPWorker",
150                    configuration.getCorePoolSize(), configuration.getMaxPoolSize());
151    
152            if (configuration.getWorkerCount() == 0) {
153                channelFactory = new NioServerSocketChannelFactory(bossExecutor, workerExecutor);
154            } else {
155                channelFactory = new NioServerSocketChannelFactory(bossExecutor, workerExecutor,
156                                                                   configuration.getWorkerCount());
157            }
158            serverBootstrap = new ServerBootstrap(channelFactory);
159            if (configuration.getServerPipelineFactory() != null) {
160                configuration.getServerPipelineFactory().setConsumer(this);
161                serverBootstrap.setPipelineFactory(configuration.getServerPipelineFactory());
162            } else {
163                serverBootstrap.setPipelineFactory(new DefaultServerPipelineFactory(this));
164            }
165            serverBootstrap.setOption("child.keepAlive", configuration.isKeepAlive());
166            serverBootstrap.setOption("child.tcpNoDelay", configuration.isTcpNoDelay());
167            serverBootstrap.setOption("child.reuseAddress", configuration.isReuseAddress());
168            serverBootstrap.setOption("child.connectTimeoutMillis", configuration.getConnectTimeout());
169    
170            channel = serverBootstrap.bind(new InetSocketAddress(configuration.getHost(), configuration.getPort()));
171            // to keep track of all channels in use
172            allChannels.add(channel);
173        }
174    
175        private void initializeUDPServerSocketCommunicationLayer() throws Exception {
176            ExecutorService workerExecutor = context.getExecutorServiceStrategy().newThreadPool(this, "NettyUDPWorker",
177                    configuration.getCorePoolSize(), configuration.getMaxPoolSize());
178    
179            datagramChannelFactory = new NioDatagramChannelFactory(workerExecutor);
180            connectionlessServerBootstrap = new ConnectionlessBootstrap(datagramChannelFactory);
181            if (configuration.getServerPipelineFactory() != null) {
182                configuration.getServerPipelineFactory().setConsumer(this);
183                connectionlessServerBootstrap.setPipelineFactory(configuration.getServerPipelineFactory());
184            } else {
185                connectionlessServerBootstrap.setPipelineFactory(new DefaultServerPipelineFactory(this));
186            }
187            connectionlessServerBootstrap.setOption("child.keepAlive", configuration.isKeepAlive());
188            connectionlessServerBootstrap.setOption("child.tcpNoDelay", configuration.isTcpNoDelay());
189            connectionlessServerBootstrap.setOption("child.reuseAddress", configuration.isReuseAddress());
190            connectionlessServerBootstrap.setOption("child.connectTimeoutMillis", configuration.getConnectTimeout());
191            connectionlessServerBootstrap.setOption("child.broadcast", configuration.isBroadcast());
192            connectionlessServerBootstrap.setOption("sendBufferSize", configuration.getSendBufferSize());
193            connectionlessServerBootstrap.setOption("receiveBufferSize", configuration.getReceiveBufferSize());
194            // only set this if user has specified
195            if (configuration.getReceiveBufferSizePredictor() > 0) {
196                connectionlessServerBootstrap.setOption("receiveBufferSizePredictorFactory",
197                    new FixedReceiveBufferSizePredictorFactory(configuration.getReceiveBufferSizePredictor()));
198            }
199    
200            channel = connectionlessServerBootstrap.bind(new InetSocketAddress(configuration.getHost(), configuration.getPort()));
201            // to keep track of all channels in use
202            allChannels.add(channel);
203        }
204    
205    }