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