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