org.xsocket.connection.Server Maven / Gradle / Ivy
/*
* Copyright (c) xsocket.org, 2006 - 2008. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Please refer to the LGPL license at: http://www.gnu.org/copyleft/lesser.txt
* The latest copy of this software may be found on http://www.xsocket.org/
*/
package org.xsocket.connection;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLContext;
import org.xsocket.connection.IConnection.FlushMode;
import org.xsocket.connection.spi.DefaultIoProvider;
import org.xsocket.connection.spi.IAcceptor;
import org.xsocket.connection.spi.IAcceptorCallback;
import org.xsocket.connection.spi.IIoHandler;
import org.xsocket.connection.spi.IServerIoProvider;
/**
* Implementation of a server. For more information see
* {@link IServer}
*
* @author [email protected]
*/
public class Server implements IServer {
private static final Logger LOG = Logger.getLogger(Server.class.getName());
public static final int SIZE_DEFAULT_WORKER_POOL = 40;
private static String implementationVersion = null;
private FlushMode flushMode = IConnection.DEFAULT_FLUSH_MODE;
private boolean autoflush = IConnection.DEFAULT_AUTOFLUSH;
private Integer writeRate = null;
private Integer readRate = null;
// is open flag
private boolean isOpen = false;
// name
private String name = "server";
// acceptor
private boolean isSsslOn = false;
private static IServerIoProvider serverIoProvider = null;
private IAcceptor acceptor = null;
// workerpool
private ExecutorService defaultWorkerPool = Executors.newFixedThreadPool(SIZE_DEFAULT_WORKER_POOL, new DefaultThreadFactory());
private Executor workerpool = defaultWorkerPool;
// app handler
private HandlerProxy handlerProxyPrototype = HandlerProxy.newPrototype(null, null);
// timeouts
private long idleTimeoutMillis = IConnection.MAX_TIMEOUT_MILLIS;
private long connectionTimeoutMillis = IConnection.MAX_TIMEOUT_MILLIS;
// server listeners
private final ArrayList listeners = new ArrayList();
// modules
private String startUpLogMessage = null;
/**
* constructor
*
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws IOException If some other I/O error occurs
* @throws UnknownHostException if the local host cannot determined
*/
public Server(IHandler handler) throws UnknownHostException, IOException {
this(new InetSocketAddress(InetAddress.getByName(DEFAULT_HOST_ADDRESS), 0), new HashMap(), handler, null, false);
}
/**
* constructor
*
* @param options the socket options
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws IOException If some other I/O error occurs
* @throws UnknownHostException if the local host cannot determined
*/
public Server(Map options, IHandler handler) throws UnknownHostException, IOException {
this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), 0, options, handler, null, false);
}
/**
* constructor
*
*
* @param port the local port
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(int port, IHandler handler) throws UnknownHostException, IOException {
this(new InetSocketAddress(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port), new HashMap(), handler, null, false);
}
/**
* constructor
*
* @param port the local port
* @param options the acceptor socket options
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(int port, Map options, IHandler handler) throws UnknownHostException, IOException {
this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, options, handler, null, false);
}
/**
* constructor
*
* @param address the local address
* @param port the local port
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(InetAddress address, int port, IHandler handler) throws UnknownHostException, IOException {
this(address, port, new HashMap(), handler, null, false);
}
/**
* constructor
*
* @param ipAddress the local ip address
* @param port the local port
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(String ipAddress, int port, IHandler handler) throws UnknownHostException, IOException {
this(InetAddress.getByName(ipAddress), port, new HashMap(), handler, null, false);
}
/**
* constructor
*
*
* @param ipAddress the local ip address
* @param port the local port
* @param options the socket options
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(String ipAddress, int port, Map options, IHandler handler) throws UnknownHostException, IOException {
this(InetAddress.getByName(ipAddress), port, options, handler, null, false);
}
/**
* constructor
*
* @param port local port
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @param sslOn true, is SSL should be activated
* @param sslContext the ssl context to use
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(int port, IHandler handler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, new HashMap(), handler, sslContext, sslOn);
}
/**
* constructor
*
* @param port local port
* @param options the acceptor socket options
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @param sslOn true, is SSL should be activated
* @param sslContext the ssl context to use
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(int port,Map options, IHandler handler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
this(InetAddress.getByName(DEFAULT_HOST_ADDRESS), port, options, handler, sslContext, sslOn);
}
/**
* constructor
*
* @param ipAddress local ip address
* @param port local port
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @param sslOn true, is SSL should be activated
* @param sslContext the ssl context to use
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(String ipAddress, int port, IHandler handler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
this(InetAddress.getByName(ipAddress), port, new HashMap(), handler, sslContext, sslOn);
}
/**
* constructor
*
* @param ipAddress local ip address
* @param port local port
* @param options the acceptor socket options
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @param sslOn true, is SSL should be activated
* @param sslContext the ssl context to use
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(String ipAddress, int port, Map options, IHandler handler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
this(InetAddress.getByName(ipAddress), port, options, handler, sslContext, sslOn);
}
/**
* constructor
*
* @param address local address
* @param port local port
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @param sslOn true, is SSL should be activated
* @param sslContext the ssl context to use
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(InetAddress address, int port, IHandler handler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
this(address, port, new HashMap(), handler, sslContext, sslOn);
}
/**
* constructor
*
* @param address local address
* @param port local port
* @param options the socket options
* @param handler the handler to use (supported: IConnectHandler, IDisconnectHandler, IDataHandler, IIdleTimeoutHandler, IConnectionTimeoutHandler, IConnectionScoped, ILifeCycle)
* @param sslOn true, is SSL should be activated
* @param sslContext the ssl context to use
* @throws UnknownHostException if the local host cannot determined
* @throws IOException If some other I/O error occurs
*/
public Server(InetAddress address, int port, Map options, IHandler handler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
this(new InetSocketAddress(address, port), options, handler, sslContext, sslOn);
}
protected Server(InetSocketAddress address, Map options, IHandler appHandler, SSLContext sslContext, boolean sslOn) throws UnknownHostException, IOException {
if (sslContext != null) {
isSsslOn = true;
acceptor = new DefaultIoProvider().create(new AcceptorCallback(), address, 0, options, sslContext, sslOn);
} else {
isSsslOn = false;
acceptor = getServerIoProvider().createAcceptor(new AcceptorCallback(), address, 0, options);
}
setHandler(appHandler);
}
private void setHandler(IHandler handler) {
if (isOpen) {
destroyCurrentHandler();
}
handlerProxyPrototype = HandlerProxy.newPrototype(handler, this);
if (isOpen) {
initCurrentHandler();
}
}
private void initCurrentHandler() {
handlerProxyPrototype.onInit();
}
private void destroyCurrentHandler() {
handlerProxyPrototype.onDestroy();
}
IServerIoProvider getIoProvider() {
return serverIoProvider;
}
/**
* the the server name. The server name will be used to print out the start log message.
*
* E.g.
*
* IServer cacheServer = new Server(port, new CacheHandler());
* ConnectionUtils.start(server);
* server.setServerName("CacheServer");
*
*
* // prints out
* // 01::52::42,756 10 INFO [Server$AcceptorCallback#onConnected] CacheServer listening on 172.25.34.33/172.25.34.33:9921 (xSocket 2.0)
*
*
* @param name the server name
*/
public final void setServerName(String name) {
this.name = name;
}
/**
* return the server name
*
* @return the server name
*/
public final String getServerName() {
return name;
}
/**
* {@inheritDoc}
*/
public String getStartUpLogMessage() {
return startUpLogMessage;
}
/**
* {@inheritDoc}
*/
public void setStartUpLogMessage(String message) {
this.startUpLogMessage = message;
}
@SuppressWarnings("unchecked")
private static IServerIoProvider getServerIoProvider() {
if (serverIoProvider == null) {
String serverIoProviderClassname = System.getProperty(IServerIoProvider.PROVIDER_CLASSNAME_KEY);
if (serverIoProviderClassname != null) {
try {
Class serverIoProviderClass = Class.forName(serverIoProviderClassname, true, Thread.currentThread().getContextClassLoader());
serverIoProvider = (IServerIoProvider) serverIoProviderClass.newInstance();
} catch (Exception e) {
LOG.warning("error occured by creating ServerIoProivder " + serverIoProviderClassname + ": " + e.toString());
LOG.info("using default ServerIoProvider");
}
}
if (serverIoProvider == null) {
serverIoProvider = new DefaultIoProvider();
}
}
return serverIoProvider;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public final void run() {
try {
if (getHandler() == null) {
LOG.warning("no handler has been set. Call setHandler-method to set an assigned handler");
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
close();
}
});
// start listening
acceptor.listen();
} catch (Exception e) {
throw new RuntimeException(e.toString());
}
}
/**
* {@inheritDoc}
*/
public final Object getOption(String name) throws IOException {
return acceptor.getOption(name);
}
public IHandler getHandler() {
return handlerProxyPrototype.getHandler();
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public final Map getOptions() {
return acceptor.getOptions();
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
public final void close() {
if (isOpen) {
isOpen = false;
try {
acceptor.close(); // closing of dispatcher will be initiated by acceptor
} catch (IOException ignore) { }
if (defaultWorkerPool != null) {
defaultWorkerPool.shutdownNow();
}
}
}
IAcceptor getAcceptor() {
return acceptor;
}
/**
* {@inheritDoc}
*/
public final void addListener(IServerListener listener) {
listeners.add(listener);
}
/**
* {@inheritDoc}
*/
public final boolean removeListener(IServerListener listener) {
boolean result = listeners.remove(listener);
return result;
}
/**
* {@inheritDoc}
*/
public final Executor getWorkerpool() {
return workerpool;
}
/**
* {@inheritDoc}
*/
public final void setWorkerpool(Executor executor) {
if (executor == null) {
throw new NullPointerException("executor has to be set");
}
if (isOpen) {
LOG.warning("server is already running");
}
workerpool = executor;
if (defaultWorkerPool != null) {
defaultWorkerPool.shutdown();
defaultWorkerPool = null;
}
}
/**
* {@inheritDoc}
*/
public final boolean isOpen() {
return isOpen;
}
/**
* {@inheritDoc}
*/
public final int getLocalPort() {
return acceptor.getLocalPort();
}
/**
* {@inheritDoc}
*/
public final InetAddress getLocalAddress() {
return acceptor.getLocalAddress();
}
/**
* {@inheritDoc}
*/
public final int getNumberOfOpenConnections() {
return acceptor.getNumberOfOpenConnections();
}
/**
* {@inheritDoc}
*/
public final FlushMode getFlushMode() {
return flushMode;
}
/**
* {@inheritDoc}
*/
public final void setFlushMode(FlushMode flusmode) {
this.flushMode = flusmode;
}
/**
* {@inheritDoc}
*/
public final void setAutoflush(boolean autoflush) {
this.autoflush = autoflush;
}
/**
* {@inheritDoc}
*/
public final boolean getAutoflush() {
return autoflush;
}
/**
* {@inheritDoc}
*/
public final void setConnectionTimeoutMillis(long timeoutMillis) {
this.connectionTimeoutMillis = timeoutMillis;
}
/**
* {@inheritDoc}
*/
public void setWriteTransferRate(int bytesPerSecond) throws IOException {
this.writeRate = bytesPerSecond;
}
/**
* {@inheritDoc}
*/
public void setReadTransferRate(int bytesPerSecond) throws IOException {
this.readRate = bytesPerSecond;
}
/**
* {@inheritDoc}
*/
public void setIdleTimeoutMillis(long timeoutMillis) {
this.idleTimeoutMillis = timeoutMillis;
}
/**
* {@inheritDoc}
*/
public final long getConnectionTimeoutMillis() {
return connectionTimeoutMillis;
}
/**
* {@inheritDoc}
*/
public final long getIdleTimeoutMillis() {
return idleTimeoutMillis;
}
public final String getVersion() {
if (implementationVersion == null) {
implementationVersion = ConnectionUtils.getVersionInfo();
}
return implementationVersion;
}
private final class AcceptorCallback implements IAcceptorCallback {
@SuppressWarnings("unchecked")
public void onConnected() {
isOpen = true;
startUpLogMessage = getVersion();
if (startUpLogMessage.length() > 0) {
startUpLogMessage = "xSocket " + startUpLogMessage;
}
if (!(serverIoProvider instanceof DefaultIoProvider)) {
String verInfo = getServerIoProvider().getImplementationVersion();
if (verInfo.length() > 0) {
startUpLogMessage = startUpLogMessage + "/" + getServerIoProvider().getClass().getSimpleName() + " " + verInfo;
}
}
// init app handler
initCurrentHandler();
// notify listeners
for (IServerListener listener : (ArrayList)listeners.clone()) {
listener.onInit();
}
// print out the startUp log message
if (isSsslOn) {
LOG.info(name + " listening on " + acceptor.getLocalAddress().getHostName() + ":" + acceptor.getLocalPort() + " - SSL mode (" + startUpLogMessage + ")");
} else {
LOG.info(name + " listening on " + acceptor.getLocalAddress().getHostName() + ":" + acceptor.getLocalPort() + " (" + startUpLogMessage + ")");
}
}
@SuppressWarnings("unchecked")
public void onDisconnected() {
destroyCurrentHandler();
for (IServerListener listener : (ArrayList)listeners.clone()) {
try {
listener.onDestroy();
} catch (IOException ioe) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("exception occured by destroying " + listener + " " + ioe.toString());
}
}
}
LOG.info("server has been shutdown");
}
public void onConnectionAccepted(IIoHandler ioHandler) throws IOException {
// create a new connection
NonBlockingConnection connection = new NonBlockingConnection();
// set default flush properties
connection.setAutoflush(autoflush);
connection.setFlushmode(flushMode);
// initialize the connection
connection.init(ioHandler, getServerIoProvider(), handlerProxyPrototype.newProxy(connection), workerpool);
// set timeouts (requires that connection is already initialized)
connection.setIdleTimeoutMillis(idleTimeoutMillis);
connection.setConnectionTimeoutMillis(connectionTimeoutMillis);
// set transfer rates
if (writeRate != null) {
connection.setWriteTransferRate(writeRate);
}
/* if (readRate != null) {
connection.setReadTransferRate(readRate);
}*/
}
}
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null)? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = "xServerPool-" + poolNumber.getAndIncrement() + "-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon()) {
t.setDaemon(false);
}
if (t.getPriority() != Thread.NORM_PRIORITY) {
t.setPriority(Thread.NORM_PRIORITY);
}
return t;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy