package com.trendmicro.mist; import java.util.ArrayList; import java.util.concurrent.TimeoutException; import javax.jms.ConnectionFactory; import javax.jms.ExceptionListener; import javax.jms.JMSException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.trendmicro.mist.proto.GateTalk; import com.trendmicro.mist.session.Session; import com.trendmicro.mist.session.SessionPool; import com.trendmicro.mist.util.ConnectionList; import com.trendmicro.mist.util.Exchange; import com.trendmicro.spn.common.FixedReconnect; import com.trendmicro.spn.common.InfiniteReconnect; import com.trendmicro.spn.common.ReconnectCounter; public class Connection implements ExceptionListener { private GateTalk.Connection connectionConfig; private javax.jms.Connection connection = null; private ConnectionList connList = new ConnectionList(); private int myId = -1; private static int connectionIdCnt = 0; private final static Logger logger = LoggerFactory.getLogger(Connection.class); private boolean connected = false; private int referenceCount = 0; private boolean isOpenMQCluster = false; private void createJMSConnection() throws MistException { try { tryConnect(new FixedReconnect(3, 150)); } catch(MistException e) { throw e; } } private void closeJMSConnection() { if(connected) { try { connection.close(); logger.info(String.format("%d: `%s' closed", getId(), getConnectionString())); } catch(JMSException e) { logger.error("can not close connection"); } connected = false; connection = null; } } private void tryConnect(ReconnectCounter counter) throws MistException { if(connected) closeJMSConnection(); counter.init(); do { connected = false; try { String username = connectionConfig.getUsername(); String password = connectionConfig.getPassword(); if(username == null) username = ""; if(password == null) password = ""; try { if(connectionConfig.getBrokerType().equals("openmq")) { ConnectionFactory conn_fact = new com.sun.messaging.ConnectionFactory(); if(connList.size() == 1) { ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqBrokerHostName, connList.get(0).getHost()); ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqBrokerHostPort, connList.get(0).getPort()); } else if(connList.size() > 1) { ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressList, connList.toString()); ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqAddressListIterations, "-1"); ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqReconnectEnabled, "true"); ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqReconnectAttempts, "1"); } ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqDefaultUsername, username); ((com.sun.messaging.ConnectionFactory) conn_fact).setProperty(com.sun.messaging.ConnectionConfiguration.imqDefaultPassword, password); connection = conn_fact.createConnection(); } } catch(JMSException e) { throw e; } connection.setExceptionListener(this); connection.start(); connected = true; logger.info(String.format("%d: `%s' connected. Current connected broker: %s", getId(), getConnectionString(), connection.toString())); } catch(JMSException e) { logger.error(String.format("%d: %s", getId(), e.getMessage())); if(Daemon.isShutdownRequested()) { logger.warn("shutdown, abort re-connection"); break; } try { counter.waitAndCheckCounter(); if(referenceCount <= 0) { Daemon.connectionPool.remove(this); break; } } catch(TimeoutException e2) { throw new MistException(String.format("reach re-connect limit %d, abort", counter.getCounter())); } } } while(connected == false); } private synchronized void reconnect() { logger.warn(String.format("Re-connecting (%d)", myId)); try { tryConnect(new InfiniteReconnect()); } catch(Exception e) { logger.error(e.getMessage(), e); logger.error("connection %d: fail to reconnect", myId); return; } class MigrateEntry { public Session sess; public Exchange ex; public MigrateEntry(Session sess, Exchange ex) { this.sess = sess; this.ex = ex; } } ArrayList<MigrateEntry> migrateList = new ArrayList<MigrateEntry>(); for(Session sess : SessionPool.pool.values()) if(sess.isAttached()) for(Client client : sess.getClientList()) if(client.getConnection() == this) migrateList.add(new MigrateEntry(sess, client.getExchange())); for(MigrateEntry ent : migrateList) ent.sess.migrateClient(ent.ex); } // ////////////////////////////////////////////////////////////////////////////// public Connection(GateTalk.Connection conn_config) { connectionConfig = conn_config; connList.set(connectionConfig.getHostName(), connectionConfig.getHostPort()); if(connectionConfig.getBrokerType().equals("openmq") && connList.size() > 1) isOpenMQCluster = true; myId = connectionIdCnt++; } public GateTalk.Connection getConfig() { return connectionConfig; } public String getType() { return connectionConfig.getBrokerType(); } public javax.jms.Connection getJMSConnection() { return connection; } public void open() throws MistException { try { createJMSConnection(); } catch(MistException e) { throw e; } } public void close() { closeJMSConnection(); } public int getId() { return myId; } public boolean isConnected() { return connected; } public String getHostName() { return connectionConfig.getHostName(); } public String getActiveBroker() { if(connectionConfig.getBrokerType().equals("openmq")) return ((com.sun.messaging.jms.Connection) connection).getBrokerAddress(); else return ""; } public String getConnectionString() { if(connList.size() > 1) return String.format("%s (active: %s)", connList.toString(), getActiveBroker()); return connList.toString(); } public boolean isOpenMQCluster() { return isOpenMQCluster; } public void onException(JMSException e) { logger.error(String.format("connection %d: received JMSException", getId()), e); reconnect(); } public void increaseReference() { synchronized(Daemon.connectionPool) { referenceCount++; } } public void decreaseReference() { synchronized(Daemon.connectionPool) { referenceCount--; if(referenceCount == 0) { close(); Daemon.connectionPool.remove(this); } } } public int getReferenceCount() { return referenceCount; } }