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