/** * Blitz Trading */ package executionserver.controller; import executionserver.domain.Connection; import executionserver.domain.Settings; import executionserver.fix.FixConnection; import executionserver.mina.BsonHandler; import executionserver.mina.codecs.BsonCodecFactory; import executionserver.mina.codecs.ProtobufCodecFactory; import executionserver.mina.codecs.StringCodecFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.InetSocketAddress; import java.util.HashMap; import javax.xml.bind.JAXBException; import org.apache.log4j.PropertyConfigurator; import org.apache.mina.common.IoAcceptor; import org.apache.mina.common.IoSession; import org.apache.mina.filter.LoggingFilter; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.transport.socket.nio.SocketAcceptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Server control class. * * @author Sylvio Azevedo <sylvio.azevedo@blitz-trading.com> */ public class ExecutionServerController implements Runnable { // constants public static final String SERVER_VERSION = "1.0"; public static final String LOGGER_CONFIG_FILE = "log4j.properties"; public static final int BSON_DEFAULT_PORT = 60100; public static final int PROTOBUFF_DEFAULT_PORT = 60000; public static final int ADMIN_DEFAULT_PORT = 60777; // logger private final Logger logger = LoggerFactory.getLogger(ExecutionServerController.class); // properties private boolean running; private Thread server; private IoAcceptor bsonAcceptor; private IoAcceptor protobuffAcceptor; private IoAcceptor adminAcceptor; public static int bsonPort = BSON_DEFAULT_PORT; public static int protobuffPort = PROTOBUFF_DEFAULT_PORT; public static int adminPort = ADMIN_DEFAULT_PORT; public static Settings settings; public static String configPath; public static HashMap<String, FixConnection> connections; public static HashMap<String, IoSession> clients; public ExecutionServerController() { // initialize list and maps. connections = new HashMap<String, FixConnection>(); clients = new HashMap<String, IoSession>(); } public void start(String configFilePath) throws JAXBException, FileNotFoundException, IOException, InterruptedException { // Keep config file path reference. configPath = configFilePath; // Load settings from file settings = SettingsController.load(configFilePath); // Start execution server thread. server = new Thread(this); server.start(); // Start administration console acceptor. if (settings.adminAcceptor != null && settings.adminAcceptor.port != null) { adminPort = Integer.parseInt(settings.adminAcceptor.port); } startAdmin(); running = true; } public void startProtobuff() throws IOException, InterruptedException { protobuffAcceptor = new SocketAcceptor(); protobuffAcceptor.getFilterChain().addLast("logging", new LoggingFilter()); protobuffAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ProtobufCodecFactory())); protobuffAcceptor.bind(new InetSocketAddress(protobuffPort), new ProtobufHandler()); System.out.println("Protobuff accpetor listening on port " + protobuffPort); } private void stopProtobuff() { protobuffAcceptor.unbindAll(); } public void startBsonAcceptor() throws IOException, InterruptedException { bsonAcceptor = new SocketAcceptor(); bsonAcceptor.getFilterChain().addLast("logging", new LoggingFilter()); bsonAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new BsonCodecFactory())); bsonAcceptor.bind(new InetSocketAddress(bsonPort), new BsonHandler()); System.out.println("BSON accpetor listening on port " + bsonPort); } private void stopBsonAcceptor() { bsonAcceptor.unbindAll(); } private void addAndStart(Connection conn) throws ClassNotFoundException, InstantiationException, IllegalAccessException { // check if exists a connection with the same name. if(connections.containsKey(conn.name)) { // ingore connection. logger.warn("Connection with name [" + conn.name + "] already exists and started. please review the server settings."); return; } // start fix connection and put it in control. FixConnection fixConn = (FixConnection) Class.forName(conn.impl).newInstance(); fixConn.start(conn); connections.put(conn.name, fixConn); } public static void orderNotify() { for (FixConnection conn : connections.values()) { conn.orderNotify(); } } private void startAdmin() throws IOException { adminAcceptor = new SocketAcceptor(); adminAcceptor.getFilterChain().addLast("logging", new LoggingFilter()); adminAcceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new StringCodecFactory())); adminAcceptor.bind(new InetSocketAddress(adminPort), new TextLineHandler(this)); System.out.println("Administration service accpetor listening on port " + adminPort); } private void stopAdmin() { adminAcceptor.unbindAll(); } @Override public void run() { // set log4j configuration file. PropertyConfigurator.configure("etc" + File.separator + LOGGER_CONFIG_FILE); // Start fix connections for (Connection conn : settings.connections) { try { addAndStart(conn); } catch (ClassNotFoundException cnfe) { logger.error("Could not find class implementation [" + conn.impl + "] :" + cnfe.getMessage()); } catch (Exception ex) { logger.error(ex.getMessage()); } } // Start Protobuff commands acceptor. if (settings.protobuffAcceptor != null && settings.protobuffAcceptor.port != null) { protobuffPort = Integer.parseInt(settings.protobuffAcceptor.port); } try { //startProtobuff(); // Start Bson commands acceptor. startBsonAcceptor(); } catch (Exception ex) { logger.error(ex.getMessage()); } } private void stopFixConnections() { for (FixConnection conn : connections.values()) { conn.stop(); } } public void minStop() { stopFixConnections(); stopProtobuff(); } public void minStart(String configFilePath) { // Start execution server thread. server = new Thread(this); server.start(); } public void stop() { stopFixConnections(); //stopProtobuff(); stopBsonAcceptor(); stopAdmin(); running = false; synchronized(this) { this.notify(); } System.exit(0); } public static String getServerPath() { return System.getProperty("user.dir"); } }