// // ERCNNotificationCoordinator.java // Project ERChangeNotificationJMS // // Created by tatsuya on Sat Mar 6 2004 // package er.changenotification; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Properties; import java.util.Timer; import java.util.TimerTask; import javax.jms.ConnectionMetaData; import javax.jms.ExceptionListener; import javax.jms.JMSException; import javax.jms.Topic; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; import javax.naming.CommunicationException; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import com.webobjects.foundation.NSLog; import com.webobjects.foundation.NSTimestamp; class ERCNConnectionKeeper implements ExceptionListener { public static final boolean VERBOSE_LOGGING = true; public static final boolean QUIET_LOGGING = false; private ERCNNotificationCoordinator _coordinator; private Timer _recoveryTimer; private Topic _topic; private TopicConnection _connection; private boolean _isConnected = false; ERCNConnectionKeeper(ERCNNotificationCoordinator coordinator) { _coordinator = coordinator; } // Open the connection to the JMS server. void openConnection(boolean verboseLogging) { if (_isConnected) { stopConnection(QUIET_LOGGING); closeConnection(QUIET_LOGGING); _isConnected = false; } Properties properties = _coordinator.configuration().jmsProperties(); //NSLog.debug.appendln(ERCNNotificationCoordinator.LOG_HEADER + "properties: " + properties); TopicConnectionFactory connectionFactory = null; try { Context context = new InitialContext(properties); connectionFactory = (TopicConnectionFactory) context.lookup("JmsTopicConnectionFactory"); _topic = (Topic) context.lookup(_coordinator.configuration().topicName()); } catch (CommunicationException ex) { // javax.naming.CommunicationException -- no JNDI server if (verboseLogging) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "Cannot connect to the JNDI server. Please check if the JNDI server is available: " + ex.getMessage()); } return; } catch (NameNotFoundException ex) { // javax.naming.NameNotFoundException -- no topic throw new RuntimeException("Cannot find the topic with name \"" + _coordinator.configuration().topicName() + "\"." + "Please check if the JMS server is properly configured: " + ex.getMessage()); } catch (NamingException ex) { if (verboseLogging) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "An exception occurred while locating the topic with JNDI server: " + ex.getMessage()); } return; } String providerName = null; String providerVersion = null; try { _connection = connectionFactory.createTopicConnection(); ConnectionMetaData metaData = _connection.getMetaData(); providerName = metaData.getJMSProviderName(); providerVersion = metaData.getProviderVersion(); // Set itself as the exception listener. _connection.setExceptionListener(this); } catch (JMSException ex) { if (verboseLogging) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "An exception occured while creating a JMS connection: " + ex.getMessage()); } return; } try { _connection.start(); _coordinator.didConnect(_connection); } catch (JMSException ex) { if (verboseLogging) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "An exception occured while starting the JMS connection : " + ex.getMessage()); ex.printStackTrace(); } return; } NSLog.out.appendln(ERCNNotificationCoordinator.LOG_HEADER + "Connected to the JMS server: " + providerName + " " + providerVersion); _isConnected = true; } void stopConnection(boolean verboseLogging) { if (_connection == null) return; try { _connection.stop(); } catch (JMSException ex) { if (verboseLogging) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "An exception occured while stopping the JMS connection: " + ex.getMessage()); } } } void closeConnection(boolean verboseLogging) { if (_connection == null) return; try { _connection.close(); } catch (JMSException ex) { if (verboseLogging) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "An exception occured while closing the JMS connection : " + ex.getMessage()); } } } void initiateRecoveryTask() { NSLog.out.appendln(ERCNNotificationCoordinator.LOG_HEADER + ": Trying to connect to the JMS Server... " + "(Recovery interval: " + _coordinator.configuration().connectionRecoveryInterval() + " seconds)"); if (_recoveryTimer != null) _recoveryTimer.cancel(); _recoveryTimer = new Timer(true); // This TimerTask trys to recover the JMS connection. TimerTask recoveryTask = new TimerTask() { @Override public void run() { openConnection(QUIET_LOGGING); if (isConnected()) _recoveryTimer.cancel(); } }; // This TimerTask displays warning messages. TimerTask warningMessageTask = new TimerTask() { private NSTimestamp _downTime = new NSTimestamp(); private String _downTimeString = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").format(_downTime); @Override public void run() { if (! _isConnected) { double elapsTime = (new NSTimestamp().getTime() - _downTime.getTime()) / (60.0d * 60.0d * 1000.0d); String elapsTimeString = new DecimalFormat("#,##0.0").format(elapsTime); NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "JMS connection has been down for " + elapsTimeString + " hours. " + "(Since " + _downTimeString + ")"); } } }; long recoveryIntervalMils = _coordinator.configuration().connectionRecoveryInterval() * 1000; _recoveryTimer.scheduleAtFixedRate(recoveryTask, recoveryIntervalMils, recoveryIntervalMils); long warningIntervalMils = _coordinator.configuration().disconnectionWarningInterval() * 1000; _recoveryTimer.scheduleAtFixedRate(warningMessageTask, warningIntervalMils, warningIntervalMils); } public void onException(JMSException exception) { NSLog.err.appendln(ERCNNotificationCoordinator.LOG_HEADER + "Connection Keeper has detected a problem with the current JMS connection: " + exception.getMessage()); _isConnected = false; stopConnection(QUIET_LOGGING); _coordinator.didDisconnect(_connection); closeConnection(QUIET_LOGGING); _topic = null; _connection = null; initiateRecoveryTask(); } Topic topic() { return _topic; } TopicConnection connection() { return _connection; } boolean isConnected() { return _isConnected; } synchronized void terminate() { // do nothing } }