/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.camel.component.netty; import java.io.File; import java.util.Map; import org.apache.camel.spi.Metadata; import org.apache.camel.spi.UriParam; import org.apache.camel.spi.UriParams; import org.apache.camel.spi.UriPath; import org.apache.camel.util.jsse.SSLContextParameters; import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.nio.BossPool; import org.jboss.netty.channel.socket.nio.WorkerPool; import org.jboss.netty.handler.ssl.SslHandler; @UriParams public class NettyServerBootstrapConfiguration implements Cloneable { public static final String DEFAULT_ENABLED_PROTOCOLS = "TLSv1,TLSv1.1,TLSv1.2"; @UriPath(enums = "tcp,udp") @Metadata(required = "true") protected String protocol; @UriPath @Metadata(required = "true") protected String host; @UriPath @Metadata(required = "true") protected int port; @UriParam(label = "consumer") protected boolean broadcast; @UriParam(label = "advanced", defaultValue = "65536") protected long sendBufferSize = 65536; @UriParam(label = "advanced", defaultValue = "65536") protected long receiveBufferSize = 65536; @UriParam(label = "advanced") protected int receiveBufferSizePredictor; @UriParam(label = "consumer,advanced", defaultValue = "1") protected int bossCount = 1; @UriParam(label = "consumer,advanced") protected int workerCount; @UriParam(defaultValue = "true") protected boolean keepAlive = true; @UriParam(defaultValue = "true") protected boolean tcpNoDelay = true; @UriParam(defaultValue = "true") protected boolean reuseAddress = true; @UriParam(label = "producer", defaultValue = "10000") protected long connectTimeout = 10000; @UriParam(label = "consumer,advanced") protected int backlog; @UriParam(label = "consumer,advanced") protected ServerPipelineFactory serverPipelineFactory; @UriParam(label = "consumer,advanced") protected NettyServerBootstrapFactory nettyServerBootstrapFactory; @UriParam(label = "advanced", prefix = "option.", multiValue = true) protected Map<String, Object> options; // SSL options is also part of the server bootstrap as the server listener on port X is either plain or SSL @UriParam(label = "security") protected boolean ssl; @UriParam(label = "security") protected boolean sslClientCertHeaders; @UriParam(label = "security") protected SslHandler sslHandler; @UriParam(label = "security") protected SSLContextParameters sslContextParameters; @UriParam(label = "consumer,security") protected boolean needClientAuth; @UriParam(label = "security") protected File keyStoreFile; @UriParam(label = "security") protected File trustStoreFile; @UriParam(label = "security") protected String keyStoreResource; @UriParam(label = "security") protected String trustStoreResource; @UriParam(defaultValue = "JKS", label = "security") protected String keyStoreFormat = "JKS"; @UriParam(defaultValue = "SunX509", label = "security") protected String securityProvider = "SunX509"; @UriParam(defaultValue = DEFAULT_ENABLED_PROTOCOLS, label = "security") protected String enabledProtocols = DEFAULT_ENABLED_PROTOCOLS; @UriParam(label = "security", secret = true) protected String passphrase; @UriParam(label = "consumer,advanced") protected BossPool bossPool; @UriParam(label = "consumer,advanced") protected WorkerPool workerPool; @UriParam(label = "consumer,advanced") protected ChannelGroup channelGroup; @UriParam(label = "consumer,advanced") protected String networkInterface; public String getAddress() { return host + ":" + port; } public boolean isTcp() { return protocol.equalsIgnoreCase("tcp"); } public String getProtocol() { return protocol; } /** * The protocol to use which can be tcp or udp. */ public void setProtocol(String protocol) { this.protocol = protocol; } public String getHost() { return host; } /** * The hostname. * <p/> * For the consumer the hostname is localhost or 0.0.0.0 * For the producer the hostname is the remote host to connect to */ public void setHost(String host) { this.host = host; } public int getPort() { return port; } /** * The host port number */ public void setPort(int port) { this.port = port; } public boolean isBroadcast() { return broadcast; } /** * Setting to choose Multicast over UDP */ public void setBroadcast(boolean broadcast) { this.broadcast = broadcast; } public long getSendBufferSize() { return sendBufferSize; } /** * The TCP/UDP buffer sizes to be used during outbound communication. Size is bytes. */ public void setSendBufferSize(long sendBufferSize) { this.sendBufferSize = sendBufferSize; } public long getReceiveBufferSize() { return receiveBufferSize; } /** * The TCP/UDP buffer sizes to be used during inbound communication. Size is bytes. */ public void setReceiveBufferSize(long receiveBufferSize) { this.receiveBufferSize = receiveBufferSize; } public int getReceiveBufferSizePredictor() { return receiveBufferSizePredictor; } /** * Configures the buffer size predictor. See details at Jetty documentation and this mail thread. */ public void setReceiveBufferSizePredictor(int receiveBufferSizePredictor) { this.receiveBufferSizePredictor = receiveBufferSizePredictor; } public int getWorkerCount() { return workerCount; } /** * When netty works on nio mode, it uses default workerCount parameter from Netty, which is cpu_core_threads*2. * User can use this operation to override the default workerCount from Netty */ public void setWorkerCount(int workerCount) { this.workerCount = workerCount; } public int getBossCount() { return bossCount; } /** * When netty works on nio mode, it uses default bossCount parameter from Netty, which is 1. * User can use this operation to override the default bossCount from Netty */ public void setBossCount(int bossCount) { this.bossCount = bossCount; } public boolean isKeepAlive() { return keepAlive; } /** * Setting to ensure socket is not closed due to inactivity */ public void setKeepAlive(boolean keepAlive) { this.keepAlive = keepAlive; } public boolean isTcpNoDelay() { return tcpNoDelay; } /** * Setting to improve TCP protocol performance */ public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } public boolean isReuseAddress() { return reuseAddress; } /** * Setting to facilitate socket multiplexing */ public void setReuseAddress(boolean reuseAddress) { this.reuseAddress = reuseAddress; } public long getConnectTimeout() { return connectTimeout; } /** * Time to wait for a socket connection to be available. Value is in millis. */ public void setConnectTimeout(long connectTimeout) { this.connectTimeout = connectTimeout; } public int getBacklog() { return backlog; } /** * Allows to configure a backlog for netty consumer (server). * Note the backlog is just a best effort depending on the OS. * Setting this option to a value such as 200, 500 or 1000, tells the TCP stack how long the "accept" queue can be * If this option is not configured, then the backlog depends on OS setting. */ public void setBacklog(int backlog) { this.backlog = backlog; } public boolean isSsl() { return ssl; } /** * Setting to specify whether SSL encryption is applied to this endpoint */ public void setSsl(boolean ssl) { this.ssl = ssl; } public boolean isSslClientCertHeaders() { return sslClientCertHeaders; } /** * When enabled and in SSL mode, then the Netty consumer will enrich the Camel Message with headers having * information about the client certificate such as subject name, issuer name, serial number, and the valid date range. */ public void setSslClientCertHeaders(boolean sslClientCertHeaders) { this.sslClientCertHeaders = sslClientCertHeaders; } public SslHandler getSslHandler() { return sslHandler; } /** * Reference to a class that could be used to return an SSL Handler */ public void setSslHandler(SslHandler sslHandler) { this.sslHandler = sslHandler; } public SSLContextParameters getSslContextParameters() { return sslContextParameters; } /** * To configure security using SSLContextParameters */ public void setSslContextParameters(SSLContextParameters sslContextParameters) { this.sslContextParameters = sslContextParameters; } public boolean isNeedClientAuth() { return needClientAuth; } /** * Configures whether the server needs client authentication when using SSL. */ public void setNeedClientAuth(boolean needClientAuth) { this.needClientAuth = needClientAuth; } @Deprecated public File getKeyStoreFile() { return keyStoreFile; } /** * Client side certificate keystore to be used for encryption */ @Deprecated public void setKeyStoreFile(File keyStoreFile) { this.keyStoreFile = keyStoreFile; } @Deprecated public File getTrustStoreFile() { return trustStoreFile; } /** * Server side certificate keystore to be used for encryption */ @Deprecated public void setTrustStoreFile(File trustStoreFile) { this.trustStoreFile = trustStoreFile; } public String getKeyStoreResource() { return keyStoreResource; } /** * Client side certificate keystore to be used for encryption. Is loaded by default from classpath, * but you can prefix with "classpath:", "file:", or "http:" to load the resource from different systems. */ public void setKeyStoreResource(String keyStoreResource) { this.keyStoreResource = keyStoreResource; } public String getTrustStoreResource() { return trustStoreResource; } /** * Server side certificate keystore to be used for encryption. * Is loaded by default from classpath, but you can prefix with "classpath:", "file:", or "http:" to load the resource from different systems. */ public void setTrustStoreResource(String trustStoreResource) { this.trustStoreResource = trustStoreResource; } public String getKeyStoreFormat() { return keyStoreFormat; } /** * Keystore format to be used for payload encryption. Defaults to "JKS" if not set */ public void setKeyStoreFormat(String keyStoreFormat) { this.keyStoreFormat = keyStoreFormat; } public String getSecurityProvider() { return securityProvider; } /** * Security provider to be used for payload encryption. Defaults to "SunX509" if not set. */ public void setSecurityProvider(String securityProvider) { this.securityProvider = securityProvider; } public String getPassphrase() { return passphrase; } /** * Password setting to use in order to encrypt/decrypt payloads sent using SSH */ public void setPassphrase(String passphrase) { this.passphrase = passphrase; } public ServerPipelineFactory getServerPipelineFactory() { return serverPipelineFactory; } /** * To use a custom ServerPipelineFactory */ public void setServerPipelineFactory(ServerPipelineFactory serverPipelineFactory) { this.serverPipelineFactory = serverPipelineFactory; } public NettyServerBootstrapFactory getNettyServerBootstrapFactory() { return nettyServerBootstrapFactory; } /** * To use a custom NettyServerBootstrapFactory */ public void setNettyServerBootstrapFactory(NettyServerBootstrapFactory nettyServerBootstrapFactory) { this.nettyServerBootstrapFactory = nettyServerBootstrapFactory; } public Map<String, Object> getOptions() { return options; } /** * Allows to configure additional netty options using "option." as prefix. * For example "option.child.keepAlive=false" to set the netty option "child.keepAlive=false". See the Netty documentation for possible options that can be used. */ public void setOptions(Map<String, Object> options) { this.options = options; } public BossPool getBossPool() { return bossPool; } /** * To use a explicit org.jboss.netty.channel.socket.nio.BossPool as the boss thread pool. * For example to share a thread pool with multiple consumers. By default each consumer has their own boss pool with 1 core thread. */ public void setBossPool(BossPool bossPool) { this.bossPool = bossPool; } public WorkerPool getWorkerPool() { return workerPool; } /** * To use a explicit org.jboss.netty.channel.socket.nio.WorkerPool as the worker thread pool. * For example to share a thread pool with multiple consumers. By default each consumer has their own worker pool with 2 x cpu count core threads. */ public void setWorkerPool(WorkerPool workerPool) { this.workerPool = workerPool; } public ChannelGroup getChannelGroup() { return channelGroup; } /** * To use a explicit ChannelGroup. */ public void setChannelGroup(ChannelGroup channelGroup) { this.channelGroup = channelGroup; } public String getNetworkInterface() { return networkInterface; } /** * When using UDP then this option can be used to specify a network interface by its name, such as eth0 to join a multicast group. */ public void setNetworkInterface(String networkInterface) { this.networkInterface = networkInterface; } public String getEnabledProtocols() { return enabledProtocols; } /** * Which protocols to enable when using SSL */ public void setEnabledProtocols(String enabledProtocols) { this.enabledProtocols = enabledProtocols; } /** * Checks if the other {@link NettyServerBootstrapConfiguration} is compatible * with this, as a Netty listener bound on port X shares the same common * {@link NettyServerBootstrapConfiguration}, which must be identical. */ public boolean compatible(NettyServerBootstrapConfiguration other) { boolean isCompatible = true; if (!protocol.equals(other.protocol)) { isCompatible = false; } else if (!host.equals(other.host)) { isCompatible = false; } else if (port != other.port) { isCompatible = false; } else if (broadcast != other.broadcast) { isCompatible = false; } else if (sendBufferSize != other.sendBufferSize) { return false; } else if (receiveBufferSize != other.receiveBufferSize) { isCompatible = false; } else if (receiveBufferSizePredictor != other.receiveBufferSizePredictor) { isCompatible = false; } else if (workerCount != other.workerCount) { isCompatible = false; } else if (bossCount != other.bossCount) { isCompatible = false; } else if (keepAlive != other.keepAlive) { isCompatible = false; } else if (tcpNoDelay != other.tcpNoDelay) { isCompatible = false; } else if (reuseAddress != other.reuseAddress) { isCompatible = false; } else if (connectTimeout != other.connectTimeout) { isCompatible = false; } else if (backlog != other.backlog) { isCompatible = false; } else if (serverPipelineFactory != other.serverPipelineFactory) { isCompatible = false; } else if (nettyServerBootstrapFactory != other.nettyServerBootstrapFactory) { isCompatible = false; } else if (options == null && other.options != null) { // validate all the options is identical isCompatible = false; } else if (options != null && other.options == null) { isCompatible = false; } else if (options != null && other.options != null && options.size() != other.options.size()) { isCompatible = false; } else if (options != null && other.options != null && !options.keySet().containsAll(other.options.keySet())) { isCompatible = false; } else if (options != null && other.options != null && !options.values().containsAll(other.options.values())) { isCompatible = false; } else if (ssl != other.ssl) { isCompatible = false; } else if (sslHandler != other.sslHandler) { isCompatible = false; } else if (sslContextParameters != other.sslContextParameters) { isCompatible = false; } else if (needClientAuth != other.needClientAuth) { isCompatible = false; } else if (keyStoreFile != other.keyStoreFile) { isCompatible = false; } else if (trustStoreFile != other.trustStoreFile) { isCompatible = false; } else if (keyStoreResource != null && !keyStoreResource.equals(other.keyStoreResource)) { isCompatible = false; } else if (trustStoreResource != null && !trustStoreResource.equals(other.trustStoreResource)) { isCompatible = false; } else if (keyStoreFormat != null && !keyStoreFormat.equals(other.keyStoreFormat)) { isCompatible = false; } else if (securityProvider != null && !securityProvider.equals(other.securityProvider)) { isCompatible = false; } else if (passphrase != null && !passphrase.equals(other.passphrase)) { isCompatible = false; } else if (bossPool != other.bossPool) { isCompatible = false; } else if (workerPool != other.workerPool) { isCompatible = false; } else if (networkInterface != null && !networkInterface.equals(other.networkInterface)) { isCompatible = false; } return isCompatible; } public String toStringBootstrapConfiguration() { return "NettyServerBootstrapConfiguration{" + "protocol='" + protocol + '\'' + ", host='" + host + '\'' + ", port=" + port + ", broadcast=" + broadcast + ", sendBufferSize=" + sendBufferSize + ", receiveBufferSize=" + receiveBufferSize + ", receiveBufferSizePredictor=" + receiveBufferSizePredictor + ", workerCount=" + workerCount + ", bossCount=" + bossCount + ", keepAlive=" + keepAlive + ", tcpNoDelay=" + tcpNoDelay + ", reuseAddress=" + reuseAddress + ", connectTimeout=" + connectTimeout + ", backlog=" + backlog + ", serverPipelineFactory=" + serverPipelineFactory + ", nettyServerBootstrapFactory=" + nettyServerBootstrapFactory + ", options=" + options + ", ssl=" + ssl + ", sslHandler=" + sslHandler + ", sslContextParameters='" + sslContextParameters + '\'' + ", needClientAuth=" + needClientAuth + ", enabledProtocols='" + enabledProtocols + ", keyStoreFile=" + keyStoreFile + ", trustStoreFile=" + trustStoreFile + ", keyStoreResource='" + keyStoreResource + '\'' + ", trustStoreResource='" + trustStoreResource + '\'' + ", keyStoreFormat='" + keyStoreFormat + '\'' + ", securityProvider='" + securityProvider + '\'' + ", passphrase='" + passphrase + '\'' + ", bossPool=" + bossPool + ", workerPool=" + workerPool + ", networkInterface='" + networkInterface + '\'' + '}'; } }