Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* 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.activemq.transport.tcp;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLServerSocket;
import org.apache.activemq.Service;
import org.apache.activemq.ThreadPriorities;
import org.apache.activemq.TransportLoggerSupport;
import org.apache.activemq.command.BrokerInfo;
import org.apache.activemq.openwire.OpenWireFormatFactory;
import org.apache.activemq.transport.Transport;
import org.apache.activemq.transport.TransportFactory;
import org.apache.activemq.transport.TransportServer;
import org.apache.activemq.transport.TransportServerThreadSupport;
import org.apache.activemq.util.IOExceptionSupport;
import org.apache.activemq.util.InetAddressUtil;
import org.apache.activemq.util.IntrospectionSupport;
import org.apache.activemq.util.ServiceListener;
import org.apache.activemq.util.ServiceStopper;
import org.apache.activemq.util.ServiceSupport;
import org.apache.activemq.wireformat.WireFormat;
import org.apache.activemq.wireformat.WireFormatFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A TCP based implementation of {@link TransportServer}
*/
public class TcpTransportServer extends TransportServerThreadSupport implements ServiceListener {
private static final Logger LOG = LoggerFactory.getLogger(TcpTransportServer.class);
protected volatile ServerSocket serverSocket;
protected volatile Selector selector;
protected int backlog = 5000;
protected WireFormatFactory wireFormatFactory = new OpenWireFormatFactory();
protected final TcpTransportFactory transportFactory;
protected long maxInactivityDuration = 30000;
protected long maxInactivityDurationInitalDelay = 10000;
protected int minmumWireFormatVersion;
protected boolean useQueueForAccept = true;
protected boolean allowLinkStealing;
/**
* trace=true -> the Transport stack where this TcpTransport object will be, will have a TransportLogger layer
* trace=false -> the Transport stack where this TcpTransport object will be, will NOT have a TransportLogger layer,
* and therefore will never be able to print logging messages. This parameter is most probably set in Connection or
* TransportConnector URIs.
*/
protected boolean trace = false;
protected int soTimeout = 0;
protected int socketBufferSize = 64 * 1024;
protected int connectionTimeout = 30000;
/**
* Name of the LogWriter implementation to use. Names are mapped to classes in the
* resources/META-INF/services/org/apache/activemq/transport/logwriters directory. This parameter is most probably
* set in Connection or TransportConnector URIs.
*/
protected String logWriterName = TransportLoggerSupport.defaultLogWriterName;
/**
* Specifies if the TransportLogger will be manageable by JMX or not. Also, as long as there is at least 1
* TransportLogger which is manageable, a TransportLoggerControl MBean will me created.
*/
protected boolean dynamicManagement = false;
/**
* startLogging=true -> the TransportLogger object of the Transport stack will initially write messages to the log.
* startLogging=false -> the TransportLogger object of the Transport stack will initially NOT write messages to the
* log. This parameter only has an effect if trace == true. This parameter is most probably set in Connection or
* TransportConnector URIs.
*/
protected boolean startLogging = true;
protected final ServerSocketFactory serverSocketFactory;
protected final BlockingQueue socketQueue = new LinkedBlockingQueue();
protected Thread socketHandlerThread;
/**
* The maximum number of sockets allowed for this server
*/
protected int maximumConnections = Integer.MAX_VALUE;
protected final AtomicInteger currentTransportCount = new AtomicInteger();
public TcpTransportServer(TcpTransportFactory transportFactory, URI location, ServerSocketFactory serverSocketFactory) throws IOException,
URISyntaxException {
super(location);
this.transportFactory = transportFactory;
this.serverSocketFactory = serverSocketFactory;
}
public void bind() throws IOException {
URI bind = getBindLocation();
String host = bind.getHost();
host = (host == null || host.length() == 0) ? "localhost" : host;
InetAddress addr = InetAddress.getByName(host);
try {
serverSocket = serverSocketFactory.createServerSocket(bind.getPort(), backlog, addr);
configureServerSocket(serverSocket);
} catch (IOException e) {
throw IOExceptionSupport.create("Failed to bind to server socket: " + bind + " due to: " + e, e);
}
try {
setConnectURI(new URI(bind.getScheme(), bind.getUserInfo(), resolveHostName(serverSocket, addr), serverSocket.getLocalPort(), bind.getPath(),
bind.getQuery(), bind.getFragment()));
} catch (URISyntaxException e) {
// it could be that the host name contains invalid characters such
// as _ on unix platforms so lets try use the IP address instead
try {
setConnectURI(new URI(bind.getScheme(), bind.getUserInfo(), addr.getHostAddress(), serverSocket.getLocalPort(), bind.getPath(),
bind.getQuery(), bind.getFragment()));
} catch (URISyntaxException e2) {
throw IOExceptionSupport.create(e2);
}
}
}
private void configureServerSocket(ServerSocket socket) throws SocketException {
socket.setSoTimeout(2000);
if (transportOptions != null) {
// If the enabledCipherSuites option is invalid we don't want to ignore it as the call
// to SSLServerSocket to configure it has a side effect on the socket rendering it
// useless as all suites are enabled many of which are considered as insecure. We
// instead trap that option here and throw an exception. We should really consider
// all invalid options as breaking and not start the transport but the current design
// doesn't really allow for this.
//
// see: https://issues.apache.org/jira/browse/AMQ-4582
//
if (socket instanceof SSLServerSocket) {
if (transportOptions.containsKey("enabledCipherSuites")) {
Object cipherSuites = transportOptions.remove("enabledCipherSuites");
if (!IntrospectionSupport.setProperty(socket, "enabledCipherSuites", cipherSuites)) {
throw new SocketException(String.format(
"Invalid transport options {enabledCipherSuites=%s}", cipherSuites));
}
}
}
//AMQ-6599 - don't strip out set properties on the socket as we need to set them
//on the Transport as well later
IntrospectionSupport.setProperties(socket, transportOptions, false);
}
}
/**
* @return Returns the wireFormatFactory.
*/
public WireFormatFactory getWireFormatFactory() {
return wireFormatFactory;
}
/**
* @param wireFormatFactory
* The wireFormatFactory to set.
*/
public void setWireFormatFactory(WireFormatFactory wireFormatFactory) {
this.wireFormatFactory = wireFormatFactory;
}
/**
* Associates a broker info with the transport server so that the transport can do discovery advertisements of the
* broker.
*
* @param brokerInfo
*/
@Override
public void setBrokerInfo(BrokerInfo brokerInfo) {
}
public long getMaxInactivityDuration() {
return maxInactivityDuration;
}
public void setMaxInactivityDuration(long maxInactivityDuration) {
this.maxInactivityDuration = maxInactivityDuration;
}
public long getMaxInactivityDurationInitalDelay() {
return this.maxInactivityDurationInitalDelay;
}
public void setMaxInactivityDurationInitalDelay(long maxInactivityDurationInitalDelay) {
this.maxInactivityDurationInitalDelay = maxInactivityDurationInitalDelay;
}
public int getMinmumWireFormatVersion() {
return minmumWireFormatVersion;
}
public void setMinmumWireFormatVersion(int minmumWireFormatVersion) {
this.minmumWireFormatVersion = minmumWireFormatVersion;
}
public boolean isTrace() {
return trace;
}
public void setTrace(boolean trace) {
this.trace = trace;
}
public String getLogWriterName() {
return logWriterName;
}
public void setLogWriterName(String logFormat) {
this.logWriterName = logFormat;
}
public boolean isDynamicManagement() {
return dynamicManagement;
}
public void setDynamicManagement(boolean useJmx) {
this.dynamicManagement = useJmx;
}
public boolean isStartLogging() {
return startLogging;
}
public void setStartLogging(boolean startLogging) {
this.startLogging = startLogging;
}
/**
* @return the backlog
*/
public int getBacklog() {
return backlog;
}
/**
* @param backlog
* the backlog to set
*/
public void setBacklog(int backlog) {
this.backlog = backlog;
}
/**
* @return the useQueueForAccept
*/
public boolean isUseQueueForAccept() {
return useQueueForAccept;
}
/**
* @param useQueueForAccept
* the useQueueForAccept to set
*/
public void setUseQueueForAccept(boolean useQueueForAccept) {
this.useQueueForAccept = useQueueForAccept;
}
/**
* pull Sockets from the ServerSocket
*/
@Override
public void run() {
if (!isStopped() && !isStopping()) {
final ServerSocket serverSocket = this.serverSocket;
if (serverSocket == null) {
onAcceptError(new IOException("Server started without a valid ServerSocket"));
}
final ServerSocketChannel channel = serverSocket.getChannel();
if (channel != null) {
doRunWithServerSocketChannel(channel);
} else {
doRunWithServerSocket(serverSocket);
}
}
}
private void doRunWithServerSocketChannel(final ServerSocketChannel channel) {
try {
channel.configureBlocking(false);
final Selector selector = Selector.open();
try {
channel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException ex) {
try {
selector.close();
} catch (IOException ignore) {}
throw ex;
}
// Update object instance for later cleanup.
this.selector = selector;
while (!isStopped()) {
int count = selector.select(10);
if (count == 0) {
continue;
}
Set keys = selector.selectedKeys();
for (Iterator i = keys.iterator(); i.hasNext(); ) {
final SelectionKey key = i.next();
if (key.isAcceptable()) {
try {
SocketChannel sc = channel.accept();
if (sc != null) {
if (isStopped() || getAcceptListener() == null) {
sc.close();
} else {
if (useQueueForAccept) {
socketQueue.put(sc.socket());
} else {
handleSocket(sc.socket());
}
}
}
} catch (SocketTimeoutException ste) {
// expect this to happen
} catch (Exception e) {
e.printStackTrace();
if (!isStopping()) {
onAcceptError(e);
} else if (!isStopped()) {
LOG.warn("run()", e);
onAcceptError(e);
}
}
}
i.remove();
}
}
} catch (IOException ex) {
if (!isStopping()) {
onAcceptError(ex);
} else if (!isStopped()) {
LOG.warn("run()", ex);
onAcceptError(ex);
}
}
}
private void doRunWithServerSocket(final ServerSocket serverSocket) {
while (!isStopped()) {
Socket socket = null;
try {
socket = serverSocket.accept();
if (socket != null) {
if (isStopped() || getAcceptListener() == null) {
socket.close();
} else {
if (useQueueForAccept) {
socketQueue.put(socket);
} else {
handleSocket(socket);
}
}
}
} catch (SocketTimeoutException ste) {
// expect this to happen
} catch (Exception e) {
if (!isStopping()) {
onAcceptError(e);
} else if (!isStopped()) {
LOG.warn("run()", e);
onAcceptError(e);
}
}
}
}
/**
* Allow derived classes to override the Transport implementation that this transport server creates.
*
* @param socket
* @param format
*
* @return a new Transport instance.
*
* @throws IOException
*/
protected Transport createTransport(Socket socket, WireFormat format) throws IOException {
return new TcpTransport(format, socket);
}
/**
* @return pretty print of this
*/
@Override
public String toString() {
return "" + getBindLocation();
}
/**
* @param socket
* @param bindAddress
* @return real hostName
* @throws UnknownHostException
*/
protected String resolveHostName(ServerSocket socket, InetAddress bindAddress) throws UnknownHostException {
String result = null;
if (socket.isBound()) {
if (socket.getInetAddress().isAnyLocalAddress()) {
// make it more human readable and useful, an alternative to 0.0.0.0
result = InetAddressUtil.getLocalHostName();
} else {
result = socket.getInetAddress().getCanonicalHostName();
}
} else {
result = bindAddress.getCanonicalHostName();
}
return result;
}
@Override
protected void doStart() throws Exception {
if (useQueueForAccept) {
Runnable run = new Runnable() {
@Override
public void run() {
try {
while (!isStopped() && !isStopping()) {
Socket sock = socketQueue.poll(1, TimeUnit.SECONDS);
if (sock != null) {
try {
handleSocket(sock);
} catch (Throwable thrown) {
if (!isStopping()) {
onAcceptError(new Exception(thrown));
} else if (!isStopped()) {
LOG.warn("Unexpected error thrown during accept handling: ", thrown);
onAcceptError(new Exception(thrown));
}
}
}
}
} catch (InterruptedException e) {
if (!isStopped() || !isStopping()) {
LOG.info("socketQueue interrupted - stopping");
onAcceptError(e);
}
}
}
};
socketHandlerThread = new Thread(null, run, "ActiveMQ Transport Server Thread Handler: " + toString(), getStackSize());
socketHandlerThread.setDaemon(true);
socketHandlerThread.setPriority(ThreadPriorities.BROKER_MANAGEMENT - 1);
socketHandlerThread.start();
}
super.doStart();
}
@Override
protected void doStop(ServiceStopper stopper) throws Exception {
Exception firstFailure = null;
try {
if (selector != null) {
selector.close();
selector = null;
}
} catch (Exception error) {
}
try {
final ServerSocket serverSocket = this.serverSocket;
if (serverSocket != null) {
this.serverSocket = null;
serverSocket.close();
}
} catch (Exception error) {
firstFailure = error;
}
if (socketHandlerThread != null) {
socketHandlerThread.interrupt();
socketHandlerThread = null;
}
try {
super.doStop(stopper);
} catch (Exception error) {
if (firstFailure != null) {
firstFailure = error;
}
}
if (firstFailure != null) {
throw firstFailure;
}
}
@Override
public InetSocketAddress getSocketAddress() {
return (InetSocketAddress) serverSocket.getLocalSocketAddress();
}
protected void handleSocket(Socket socket) {
doHandleSocket(socket);
}
final protected void doHandleSocket(Socket socket) {
boolean closeSocket = true;
boolean countIncremented = false;
try {
int currentCount;
do {
currentCount = currentTransportCount.get();
if (currentCount >= this.maximumConnections) {
throw new ExceededMaximumConnectionsException(
"Exceeded the maximum number of allowed client connections. See the '" +
"maximumConnections' property on the TCP transport configuration URI " +
"in the ActiveMQ configuration file (e.g., activemq.xml)");
}
//Increment this value before configuring the transport
//This is necessary because some of the transport servers must read from the
//socket during configureTransport() so we want to make sure this value is
//accurate as the transport server could pause here waiting for data to be sent from a client
} while(!currentTransportCount.compareAndSet(currentCount, currentCount + 1));
countIncremented = true;
HashMap options = new HashMap();
options.put("maxInactivityDuration", Long.valueOf(maxInactivityDuration));
options.put("maxInactivityDurationInitalDelay", Long.valueOf(maxInactivityDurationInitalDelay));
options.put("minmumWireFormatVersion", Integer.valueOf(minmumWireFormatVersion));
options.put("trace", Boolean.valueOf(trace));
options.put("soTimeout", Integer.valueOf(soTimeout));
options.put("socketBufferSize", Integer.valueOf(socketBufferSize));
options.put("connectionTimeout", Integer.valueOf(connectionTimeout));
options.put("logWriterName", logWriterName);
options.put("dynamicManagement", Boolean.valueOf(dynamicManagement));
options.put("startLogging", Boolean.valueOf(startLogging));
options.putAll(transportOptions);
TransportInfo transportInfo = configureTransport(this, socket);
closeSocket = false;
if (transportInfo.transport instanceof ServiceSupport) {
((ServiceSupport) transportInfo.transport).addServiceListener(this);
}
Transport configuredTransport = transportInfo.transportFactory.serverConfigure(
transportInfo.transport, transportInfo.format, options);
getAcceptListener().onAccept(configuredTransport);
} catch (SocketTimeoutException ste) {
// expect this to happen
} catch (Exception e) {
if (closeSocket) {
try {
//if closing the socket, only decrement the count it was actually incremented
//where it was incremented
if (countIncremented) {
currentTransportCount.decrementAndGet();
}
socket.close();
} catch (Exception ignore) {
}
}
if (!isStopping()) {
onAcceptError(e);
} else if (!isStopped()) {
LOG.warn("run()", e);
onAcceptError(e);
}
}
}
protected TransportInfo configureTransport(final TcpTransportServer server, final Socket socket) throws Exception {
WireFormat format = wireFormatFactory.createWireFormat();
Transport transport = createTransport(socket, format);
return new TransportInfo(format, transport, transportFactory);
}
protected class TransportInfo {
final WireFormat format;
final Transport transport;
final TransportFactory transportFactory;
public TransportInfo(WireFormat format, Transport transport, TransportFactory transportFactory) {
this.format = format;
this.transport = transport;
this.transportFactory = transportFactory;
}
}
public int getSoTimeout() {
return soTimeout;
}
public void setSoTimeout(int soTimeout) {
this.soTimeout = soTimeout;
}
public int getSocketBufferSize() {
return socketBufferSize;
}
public void setSocketBufferSize(int socketBufferSize) {
this.socketBufferSize = socketBufferSize;
}
public int getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
/**
* @return the maximumConnections
*/
public int getMaximumConnections() {
return maximumConnections;
}
/**
* @param maximumConnections
* the maximumConnections to set
*/
public void setMaximumConnections(int maximumConnections) {
this.maximumConnections = maximumConnections;
}
public AtomicInteger getCurrentTransportCount() {
return currentTransportCount;
}
@Override
public void started(Service service) {
}
@Override
public void stopped(Service service) {
this.currentTransportCount.decrementAndGet();
}
@Override
public boolean isSslServer() {
return false;
}
@Override
public boolean isAllowLinkStealing() {
return allowLinkStealing;
}
@Override
public void setAllowLinkStealing(boolean allowLinkStealing) {
this.allowLinkStealing = allowLinkStealing;
}
}