/* * Copyright 2014, The Sporting Exchange Limited * * Licensed 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 com.betfair.cougar.transport.nio; import com.betfair.cougar.core.api.BindingDescriptor; import com.betfair.cougar.core.api.transports.AbstractRegisterableTransport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.betfair.cougar.netutil.nio.CougarProtocol; import com.betfair.cougar.netutil.nio.NioConfig; import com.betfair.cougar.netutil.nio.TlsNioConfig; import com.betfair.cougar.transport.api.protocol.socket.SocketBindingDescriptor; import org.apache.mina.transport.socket.nio.SocketAcceptor; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedResource; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.logging.Level; @ManagedResource public class ExecutionVenueNioServer extends AbstractRegisterableTransport { final static Logger LOGGER = LoggerFactory.getLogger(ExecutionVenueNioServer.class); private TlsNioConfig nioConfig; private SocketAcceptor socketAcceptor; private IoSessionManager sessionManager; private InetSocketAddress socketAddress; private int socketAcceptorProcessors; private ExecutionVenueServerHandler serverHandler; private ExecutorService serverExecutor; private volatile boolean running; private volatile boolean shutdownInProgress; @Override public void notify(BindingDescriptor bindingDescriptor) { if (bindingDescriptor instanceof SocketBindingDescriptor) { serverHandler.notify((SocketBindingDescriptor) bindingDescriptor); } } public void setServerHandler(ExecutionVenueServerHandler serverHandler) { this.serverHandler = serverHandler;//NOSONAR } public void setNioConfig(TlsNioConfig nioConfig) { this.nioConfig = nioConfig; } public TlsNioConfig getNioConfig() { return nioConfig; } public InetAddress getBoundAddress() { return socketAddress != null ? socketAddress.getAddress() : null; } @ManagedAttribute public int getBoundPort() { return socketAddress != null ? socketAddress.getPort() : 0; } @ManagedAttribute public String getHostAddress() { return socketAddress != null ? socketAddress.getHostName() : "Not Bound"; } public synchronized void start() throws IOException { register(); if (serverHandler != null) { if (socketAcceptor == null) { socketAcceptor = new SocketAcceptor(socketAcceptorProcessors, serverExecutor); } SocketAcceptorConfig config = socketAcceptor.getDefaultConfig(); nioConfig.configureSocketAcceptorConfig(config); socketAcceptor.bind(nioConfig.getServerSocketAddress(), serverHandler, config); socketAddress = (InetSocketAddress) socketAcceptor.getManagedServiceAddresses().iterator().next(); LOGGER.info("ExecutionVenueNioServer started on " + socketAcceptor.getManagedServiceAddresses()); // Create a shutdown hook to close the Socket Server cleanly Runtime.getRuntime().addShutdownHook(new Thread("EV Socket Server Shutdown Thread") { @Override public void run() { LOGGER.info("Gracefully shutting down ExecutionVenueNioServer"); try { ExecutionVenueNioServer.this.stop(); } catch (Exception e) { LOGGER.warn("Failed to shutdown ExecutionVenueNioServer", e); } } }); running = true; } } @ManagedAttribute public synchronized void setHealthState(boolean isHealthy) { if (LOGGER.isInfoEnabled()) { LOGGER.info("setting protocol to " + (isHealthy ? "enabled" : "disabled")); } if (socketAcceptor != null) { CougarProtocol cougarProtocol = (CougarProtocol) socketAcceptor.getDefaultConfig().getFilterChain().get("protocol"); cougarProtocol.setEnabled(isHealthy); if (!isHealthy) { shutdownSessions(false); } } } @ManagedAttribute public synchronized Boolean isHealthState() { if (socketAcceptor != null) { CougarProtocol cougarProtocol = (CougarProtocol) socketAcceptor.getDefaultConfig().getFilterChain().get("protocol"); return cougarProtocol.isEnabled(); } return null; } @ManagedAttribute public boolean isEnabled() { final CougarProtocol protocol = (CougarProtocol) socketAcceptor.getDefaultConfig().getFilterChain().get("protocol"); if (protocol != null) { return protocol.isEnabled(); } return false; } public synchronized void stop() { if (running) { shutdownInProgress = true; running = false; if (socketAcceptor != null) { shutdownSessions(true); socketAcceptor.unbindAll(); socketAcceptor = null; } serverExecutor.shutdown(); shutdownInProgress = false; } } public void setServerExecutor(ExecutorService serverExecutor) { this.serverExecutor = serverExecutor;//NOSONAR } @ManagedAttribute public int getSocketAcceptorProcessors() { return socketAcceptorProcessors; } public void setSocketAcceptorProcessors(int socketAcceptorProcessors) { this.socketAcceptorProcessors = socketAcceptorProcessors; } public void setSessionManager(IoSessionManager sessionManager) { this.sessionManager = sessionManager; } private void shutdownSessions(boolean blockUntilComplete) { CougarProtocol cougarProtocol = (CougarProtocol) socketAcceptor.getDefaultConfig().getFilterChain().get("protocol"); sessionManager.shutdownSessions(socketAcceptor.getManagedSessions(socketAddress), cougarProtocol, this.serverHandler, blockUntilComplete); } @ManagedAttribute public boolean isRunning() { return running; } @ManagedAttribute public boolean isShutdownInProgress() { return shutdownInProgress; } }