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.io.File;
020    import java.net.URI;
021    import java.nio.charset.Charset;
022    import java.util.ArrayList;
023    import java.util.List;
024    import java.util.Map;
025    
026    import org.apache.camel.LoggingLevel;
027    import org.apache.camel.RuntimeCamelException;
028    import org.apache.camel.util.EndpointHelper;
029    import org.jboss.netty.channel.ChannelDownstreamHandler;
030    import org.jboss.netty.channel.ChannelUpstreamHandler;
031    import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
032    import org.jboss.netty.handler.codec.frame.Delimiters;
033    import org.jboss.netty.handler.codec.serialization.ObjectDecoder;
034    import org.jboss.netty.handler.codec.serialization.ObjectEncoder;
035    import org.jboss.netty.handler.codec.string.StringDecoder;
036    import org.jboss.netty.handler.codec.string.StringEncoder;
037    import org.jboss.netty.handler.ssl.SslHandler;
038    import org.jboss.netty.util.CharsetUtil;
039    import org.slf4j.Logger;
040    import org.slf4j.LoggerFactory;
041    
042    @SuppressWarnings("unchecked")
043    public class NettyConfiguration implements Cloneable {
044        private static final transient Logger LOG = LoggerFactory.getLogger(NettyConfiguration.class);
045    
046        private String protocol;
047        private String host;
048        private int port;
049        private boolean keepAlive = true;
050        private boolean tcpNoDelay = true;
051        private boolean broadcast;
052        private long connectTimeout = 10000;
053        private boolean reuseAddress = true;
054        private boolean sync = true;
055        private boolean textline;
056        private TextLineDelimiter delimiter = TextLineDelimiter.LINE;
057        private boolean autoAppendDelimiter = true;
058        private int decoderMaxLineLength = 1024;
059        private String encoding;
060        private String passphrase;
061        private File keyStoreFile;
062        private File trustStoreFile;
063        private SslHandler sslHandler;
064        private List<ChannelDownstreamHandler> encoders = new ArrayList<ChannelDownstreamHandler>();
065        private List<ChannelUpstreamHandler> decoders = new ArrayList<ChannelUpstreamHandler>();
066        private boolean ssl;
067        private long sendBufferSize = 65536;
068        private long receiveBufferSize = 65536;
069        private int receiveBufferSizePredictor;
070        private int corePoolSize = 10;
071        private int maxPoolSize = 100;
072        private int workerCount;
073        private String keyStoreFormat;
074        private String securityProvider;
075        private boolean disconnect;
076        private boolean lazyChannelCreation = true;
077        private boolean transferExchange;
078        private boolean disconnectOnNoReply = true;
079        private LoggingLevel noReplyLogLevel = LoggingLevel.WARN;
080        private boolean allowDefaultCodec = true;
081        private ClientPipelineFactory clientPipelineFactory;
082        private ServerPipelineFactory serverPipelineFactory;
083        
084        /**
085         * Returns a copy of this configuration
086         */
087        public NettyConfiguration copy() {
088            try {
089                NettyConfiguration answer = (NettyConfiguration) clone();
090                // make sure the lists is copied in its own instance
091                List<ChannelDownstreamHandler> encodersCopy = new ArrayList<ChannelDownstreamHandler>(encoders);
092                answer.setEncoders(encodersCopy);
093                List<ChannelUpstreamHandler> decodersCopy = new ArrayList<ChannelUpstreamHandler>(decoders);
094                answer.setDecoders(decodersCopy);
095                return answer;
096            } catch (CloneNotSupportedException e) {
097                throw new RuntimeCamelException(e);
098            }
099        }
100    
101        public void parseURI(URI uri, Map<String, Object> parameters, NettyComponent component) throws Exception {
102            protocol = uri.getScheme();
103    
104            if ((!protocol.equalsIgnoreCase("tcp")) && (!protocol.equalsIgnoreCase("udp"))) {
105                throw new IllegalArgumentException("Unrecognized Netty protocol: " + protocol + " for uri: " + uri);
106            }
107    
108            setHost(uri.getHost());
109            setPort(uri.getPort());
110    
111            sslHandler = component.resolveAndRemoveReferenceParameter(parameters, "sslHandler", SslHandler.class, null);
112            passphrase = component.resolveAndRemoveReferenceParameter(parameters, "passphrase", String.class, null);
113            keyStoreFormat = component.getAndRemoveParameter(parameters, "keyStoreFormat", String.class, "JKS");
114            securityProvider = component.getAndRemoveParameter(parameters, "securityProvider", String.class, "SunX509");
115            keyStoreFile = component.resolveAndRemoveReferenceParameter(parameters, "keyStoreFile", File.class, null);
116            trustStoreFile = component.resolveAndRemoveReferenceParameter(parameters, "trustStoreFile", File.class, null);
117            clientPipelineFactory = component.resolveAndRemoveReferenceParameter(parameters, "clientPipelineFactory", ClientPipelineFactory.class, null);
118            serverPipelineFactory = component.resolveAndRemoveReferenceParameter(parameters, "serverPipelineFactory", ServerPipelineFactory.class, null);
119    
120            // set custom encoders and decoders first
121            List<ChannelDownstreamHandler> referencedEncoders = component.resolveAndRemoveReferenceListParameter(parameters, "encoders", ChannelDownstreamHandler.class, null);
122            addToHandlersList(encoders, referencedEncoders, ChannelDownstreamHandler.class);
123            List<ChannelUpstreamHandler> referencedDecoders = component.resolveAndRemoveReferenceListParameter(parameters, "decoders", ChannelUpstreamHandler.class, null);
124            addToHandlersList(decoders, referencedDecoders, ChannelUpstreamHandler.class);
125    
126            // then set parameters with the help of the camel context type converters
127            EndpointHelper.setReferenceProperties(component.getCamelContext(), this, parameters);
128            EndpointHelper.setProperties(component.getCamelContext(), this, parameters);
129    
130            // add default encoders and decoders
131            if (encoders.isEmpty() && decoders.isEmpty()) {
132                if (allowDefaultCodec) {
133                    // are we textline or object?
134                    if (isTextline()) {
135                        Charset charset = getEncoding() != null ? Charset.forName(getEncoding()) : CharsetUtil.UTF_8;
136                        encoders.add(new StringEncoder(charset));
137                        decoders.add(new DelimiterBasedFrameDecoder(decoderMaxLineLength, true, delimiter == TextLineDelimiter.LINE ? Delimiters.lineDelimiter() : Delimiters.nulDelimiter()));
138                        decoders.add(new StringDecoder(charset));
139    
140                        if (LOG.isDebugEnabled()) {
141                            LOG.debug("Using textline encoders and decoders with charset: {}, delimiter: {} and decoderMaxLineLength: {}", 
142                                    new Object[]{charset, delimiter, decoderMaxLineLength});
143                        }
144                    } else {
145                        // object serializable is then used
146                        encoders.add(new ObjectEncoder());
147                        decoders.add(new ObjectDecoder());
148    
149                        LOG.debug("Using object encoders and decoders");
150                    }
151                } else {
152                    LOG.debug("No encoders and decoders will be used");
153                }
154            } else {
155                LOG.debug("Using configured encoders and/or decoders");
156            }
157        }
158    
159        public String getCharsetName() {
160            if (encoding == null) {
161                return null;
162            }
163            if (!Charset.isSupported(encoding)) {
164                throw new IllegalArgumentException("The encoding: " + encoding + " is not supported");
165            }
166    
167            return Charset.forName(encoding).name();
168        }
169    
170        public boolean isTcp() {
171            return protocol.equalsIgnoreCase("tcp");
172        }
173    
174        public String getProtocol() {
175            return protocol;
176        }
177    
178        public void setProtocol(String protocol) {
179            this.protocol = protocol;
180        }
181    
182        public String getHost() {
183            return host;
184        }
185    
186        public void setHost(String host) {
187            this.host = host;
188        }
189    
190        public int getPort() {
191            return port;
192        }
193    
194        public void setPort(int port) {
195            this.port = port;
196        }
197    
198        public boolean isKeepAlive() {
199            return keepAlive;
200        }
201    
202        public void setKeepAlive(boolean keepAlive) {
203            this.keepAlive = keepAlive;
204        }
205    
206        public boolean isTcpNoDelay() {
207            return tcpNoDelay;
208        }
209    
210        public void setTcpNoDelay(boolean tcpNoDelay) {
211            this.tcpNoDelay = tcpNoDelay;
212        }
213    
214        public boolean isBroadcast() {
215            return broadcast;
216        }
217    
218        public void setBroadcast(boolean broadcast) {
219            this.broadcast = broadcast;
220        }
221    
222        public long getConnectTimeout() {
223            return connectTimeout;
224        }
225    
226        public void setConnectTimeout(long connectTimeout) {
227            this.connectTimeout = connectTimeout;
228        }
229    
230        public boolean isReuseAddress() {
231            return reuseAddress;
232        }
233    
234        public void setReuseAddress(boolean reuseAddress) {
235            this.reuseAddress = reuseAddress;
236        }
237    
238        public boolean isSync() {
239            return sync;
240        }
241    
242        public void setSync(boolean sync) {
243            this.sync = sync;
244        }
245    
246        public boolean isTextline() {
247            return textline;
248        }
249    
250        public void setTextline(boolean textline) {
251            this.textline = textline;
252        }
253    
254        public int getDecoderMaxLineLength() {
255            return decoderMaxLineLength;
256        }
257    
258        public void setDecoderMaxLineLength(int decoderMaxLineLength) {
259            this.decoderMaxLineLength = decoderMaxLineLength;
260        }
261    
262        public TextLineDelimiter getDelimiter() {
263            return delimiter;
264        }
265    
266        public void setDelimiter(TextLineDelimiter delimiter) {
267            this.delimiter = delimiter;
268        }
269    
270        public boolean isAutoAppendDelimiter() {
271            return autoAppendDelimiter;
272        }
273    
274        public void setAutoAppendDelimiter(boolean autoAppendDelimiter) {
275            this.autoAppendDelimiter = autoAppendDelimiter;
276        }
277    
278        public String getEncoding() {
279            return encoding;
280        }
281    
282        public void setEncoding(String encoding) {
283            this.encoding = encoding;
284        }
285    
286        public SslHandler getSslHandler() {
287            return sslHandler;
288        }
289    
290        public void setSslHandler(SslHandler sslHandler) {
291            this.sslHandler = sslHandler;
292        }
293    
294        public List<ChannelDownstreamHandler> getEncoders() {
295            return encoders;
296        }
297    
298        public List<ChannelUpstreamHandler> getDecoders() {
299            return decoders;
300        }
301    
302        public ChannelDownstreamHandler getEncoder() {
303            return encoders.isEmpty() ? null : encoders.get(0);
304        }
305    
306        public void setEncoder(ChannelDownstreamHandler encoder) {
307            if (!encoders.contains(encoder)) {
308                encoders.add(encoder);
309            }
310        }
311    
312        public void setEncoders(List<ChannelDownstreamHandler> encoders) {
313            this.encoders = encoders;
314        }
315    
316        public ChannelUpstreamHandler getDecoder() {
317            return decoders.isEmpty() ? null : decoders.get(0);
318        }
319    
320        public void setDecoder(ChannelUpstreamHandler decoder) {
321            if (!decoders.contains(decoder)) {
322                decoders.add(decoder);
323            }
324        }
325    
326        public void setDecoders(List<ChannelUpstreamHandler> decoders) {
327            this.decoders = decoders;
328        }
329    
330        public long getSendBufferSize() {
331            return sendBufferSize;
332        }
333    
334        public void setSendBufferSize(long sendBufferSize) {
335            this.sendBufferSize = sendBufferSize;
336        }
337    
338        public boolean isSsl() {
339            return ssl;
340        }
341    
342        public void setSsl(boolean ssl) {
343            this.ssl = ssl;
344        }
345    
346        public long getReceiveBufferSize() {
347            return receiveBufferSize;
348        }
349    
350        public void setReceiveBufferSize(long receiveBufferSize) {
351            this.receiveBufferSize = receiveBufferSize;
352        }
353        
354        public int getReceiveBufferSizePredictor() {
355            return receiveBufferSizePredictor;
356        }
357    
358        public void setReceiveBufferSizePredictor(int receiveBufferSizePredictor) {
359            this.receiveBufferSizePredictor = receiveBufferSizePredictor;
360        }
361    
362        public String getPassphrase() {
363            return passphrase;
364        }
365    
366        public void setPassphrase(String passphrase) {
367            this.passphrase = passphrase;
368        }
369    
370        public File getKeyStoreFile() {
371            return keyStoreFile;
372        }
373    
374        public void setKeyStoreFile(File keyStoreFile) {
375            this.keyStoreFile = keyStoreFile;
376        }
377    
378        public File getTrustStoreFile() {
379            return trustStoreFile;
380        }
381    
382        public void setTrustStoreFile(File trustStoreFile) {
383            this.trustStoreFile = trustStoreFile;
384        }
385    
386        public int getCorePoolSize() {
387            return corePoolSize;
388        }
389    
390        public void setCorePoolSize(int corePoolSize) {
391            this.corePoolSize = corePoolSize;
392        }
393    
394        public int getMaxPoolSize() {
395            return maxPoolSize;
396        }
397    
398        public void setMaxPoolSize(int maxPoolSize) {
399            this.maxPoolSize = maxPoolSize;
400        }
401    
402        public String getKeyStoreFormat() {
403            return keyStoreFormat;
404        }
405    
406        public void setKeyStoreFormat(String keyStoreFormat) {
407            this.keyStoreFormat = keyStoreFormat;
408        }
409    
410        public String getSecurityProvider() {
411            return securityProvider;
412        }
413    
414        public void setSecurityProvider(String securityProvider) {
415            this.securityProvider = securityProvider;
416        }
417    
418        public boolean isDisconnect() {
419            return disconnect;
420        }
421    
422        public void setDisconnect(boolean disconnect) {
423            this.disconnect = disconnect;
424        }
425    
426        public boolean isLazyChannelCreation() {
427            return lazyChannelCreation;
428        }
429    
430        public void setLazyChannelCreation(boolean lazyChannelCreation) {
431            this.lazyChannelCreation = lazyChannelCreation;
432        }
433    
434        public boolean isTransferExchange() {
435            return transferExchange;
436        }
437    
438        public void setTransferExchange(boolean transferExchange) {
439            this.transferExchange = transferExchange;
440        }
441    
442        public boolean isDisconnectOnNoReply() {
443            return disconnectOnNoReply;
444        }
445    
446        public void setDisconnectOnNoReply(boolean disconnectOnNoReply) {
447            this.disconnectOnNoReply = disconnectOnNoReply;
448        }
449    
450        public LoggingLevel getNoReplyLogLevel() {
451            return noReplyLogLevel;
452        }
453    
454        public void setNoReplyLogLevel(LoggingLevel noReplyLogLevel) {
455            this.noReplyLogLevel = noReplyLogLevel;
456        }
457    
458        public boolean isAllowDefaultCodec() {
459            return allowDefaultCodec;
460        }
461    
462        public void setAllowDefaultCodec(boolean allowDefaultCodec) {
463            this.allowDefaultCodec = allowDefaultCodec;
464        }
465    
466        public String getAddress() {
467            return host + ":" + port;
468        }
469    
470        private <T> void addToHandlersList(List configured, List handlers, Class<? extends T> handlerType) {
471            if (handlers != null) {
472                for (int x = 0; x < handlers.size(); x++) {
473                    Object handler = handlers.get(x);
474                    if (handlerType.isInstance(handler)) {
475                        configured.add(handler);
476                    }
477                }
478            }
479        }
480    
481        public void setClientPipelineFactory(ClientPipelineFactory clientPipelineFactory) {
482            this.clientPipelineFactory = clientPipelineFactory;
483        }
484    
485        public ClientPipelineFactory getClientPipelineFactory() {
486            return clientPipelineFactory;
487        }
488    
489        public void setServerPipelineFactory(ServerPipelineFactory serverPipelineFactory) {
490            this.serverPipelineFactory = serverPipelineFactory;
491        }
492    
493        public ServerPipelineFactory getServerPipelineFactory() {
494            return serverPipelineFactory;
495        }
496        
497        public int getWorkerCount() {
498            return workerCount;
499        }
500    
501        public void setWorkerCount(int workerCount) {
502            this.workerCount = workerCount;
503        }
504    
505    }