package com.rayo.provisioning; import java.util.Hashtable; import java.util.Properties; import java.util.concurrent.locks.ReentrantLock; import javax.jms.Connection; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.QueueConnectionFactory; import javax.jms.Session; import javax.naming.Context; import javax.naming.InitialContext; import org.apache.activemq.command.ActiveMQQueue; import org.springframework.context.ApplicationContext; import com.rayo.provisioning.storage.StorageServiceClient; import com.voxeo.logging.Loggerf; /** * <p>Base class for provisioning agents. It receives a set of properties file and with * those properties it will connect to JMS to receive notifications from the Provisioning * API.</p> * * <p>Concrete implementations of this class will use different storage services. Once messages * are received from JMS, they will be parsed and the information will be updated in the * corresponding datastore using the storage client for the concrete implementation.</p> * * @author martin * */ public abstract class DefaultProvisioningAgent implements ProvisioningAgent { private Loggerf logger = Loggerf.getLogger(DefaultProvisioningAgent.class); public static final String TOPIC_NAME_CONSTANT = "notificationsTopic"; private static final String CONTEXT_FACTORY="com.rayo.provisioning.jms.context.factory"; private static final String PROVIDER_URL="com.rayo.provisioning.jms.provider.url"; private static final String USERNAME="com.rayo.provisioning.jms.username"; private static final String PASSWORD="com.rayo.provisioning.jms.password"; private static final String RETRIES="com.rayo.provisioning.jms.retries"; private static final String RETRY_INTERVAL="com.rayo.provisioning.jms.retryInterval"; private static final String PROVISIONING_QUEUE="com.rayo.provisioning.jms.notifications.queue"; private static final String PROVISIONING_ENDPOINT="com.rayo.provisioning.api"; private static final String PROVISIONING_ENDPOINT_USERNAME="com.rayo.provisioning.api.username"; private static final String PROVISIONING_ENDPOINT_PASSWORD="com.rayo.provisioning.api.password"; public static final String PROVISIONING_DEFAULT_PERMISSIONS="com.rayo.provisioning.default.permissions"; private static final String RAYO_DOMAIN_NAME="com.rayo.domain.name"; private ReentrantLock initLock = new ReentrantLock(); private InitialContext context; private Connection connection; private Destination destination; private Session session; private MessageConsumer consumer; // Number of retries in cse private int retries = 10; private int retryInterval = 1000; private boolean connected; private String provisioningEndpoint; private String provisioningUsername; private String provisioningPassword; private String domainName; private MessageProcessor messageProcessor = new MessageProcessor(); private StorageServiceClient storageServiceClient; private ProvisioningClient provisioningServiceClient; public void init(ApplicationContext applicationContext, Properties properties) { logger.info("Initializing default provisioning service"); initLock.lock(); try { int i=0; do { try { loadProperties(properties); String queueName = checkProperty(properties, PROVISIONING_QUEUE); Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, checkProperty(properties, CONTEXT_FACTORY)); env.put(Context.PROVIDER_URL, checkProperty(properties, PROVIDER_URL)); context = new InitialContext(env); logger.debug("Getting connection factory"); QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup("QueueConnectionFactory"); if (properties.get(USERNAME) != null && !properties.get(USERNAME).equals("")) { logger.debug("Connecting to JMS Provider with username %s", properties.get(USERNAME)); connection = connectionFactory.createConnection((String)properties.get(USERNAME), (String)properties.get(PASSWORD)); } else { logger.debug("Connecting to JMS Provider with empty username and password"); connection = connectionFactory.createConnection(); } logger.debug("Starting connection"); connection.start(); String virtualQueue = queueName; if (!virtualQueue.startsWith("Consumer.")) { // make it a virtual topic logger.warn("Queue name %s does not start with Consumer. Converting it to ActiveMQ's virtual topic syntax"); virtualQueue = "Consumer." + queueName + ".VirtualTopic.Provisioning"; } logger.debug("Connecting to virtual queue " + virtualQueue); destination = new ActiveMQQueue(virtualQueue); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); String selector = "voicePlatform='rayo' or messagingPlatform='rayo' or (voicePlatform='' and messagingPlatform='')"; logger.debug("Creating consumer in %s with selector %s", destination, selector); consumer = session.createConsumer(destination, selector); logger.debug("JMS system is connected now"); consumer.setMessageListener(messageProcessor); logger.debug("Starting JMS connection"); connection.start(); connected = true; } catch (IllegalStateException ise) { logger.error(ise.getMessage(), ise); return; } catch (Exception e) { logger.error("Could not initialize JMS notifications service", e); logger.debug(String.format("Waiting %s milliseconds for retrying", retryInterval)); try { Thread.sleep(retryInterval); } catch (InterruptedException ie) {} connected = false; } } while (!connected && i <= retries); if (!connected) { throw new IllegalStateException("Could not initialize JMS Service. Is the JMS service running?"); } provisioningServiceClient = new ProvisioningClient(provisioningEndpoint, provisioningUsername, provisioningPassword); storageServiceClient.init(applicationContext, properties); messageProcessor.setStorageServiceClient(storageServiceClient); messageProcessor.setProvisioningServiceClient(provisioningServiceClient); messageProcessor.setDomainName(domainName); } finally { initLock.unlock(); } } private void loadProperties(Properties properties) { try { if (properties.get(RETRIES) != null && !properties.get(RETRIES).equals("")) { retries = Integer.parseInt((String)properties.get(RETRIES)); } if (properties.get(RETRY_INTERVAL) != null && !properties.get(RETRY_INTERVAL).equals("")) { System.out.println(properties.get(RETRY_INTERVAL)); retryInterval = Integer.parseInt((String)properties.get(RETRY_INTERVAL)); } } catch (NumberFormatException nfe) { logger.error(nfe.getMessage(), nfe); } provisioningEndpoint = checkProperty(properties, PROVISIONING_ENDPOINT); provisioningUsername = checkProperty(properties, PROVISIONING_ENDPOINT_USERNAME); provisioningPassword = checkProperty(properties, PROVISIONING_ENDPOINT_PASSWORD); domainName = checkProperty(properties, RAYO_DOMAIN_NAME ); } public void shutdown() { logger.debug("About to shutdon JMS provisioning service"); initLock.lock(); try { logger.info("Shutting down JMS provisioning service"); if (session != null) { try { session.close(); } catch (JMSException e) { logger.warn("Error while shutting down JMS provisioning service"); logger.error(e.getMessage(),e); } } if (connection != null) { try { connection.close(); } catch (JMSException e) { logger.warn("Error while shutting down JMS provisioning service"); logger.error(e.getMessage(),e); } } } finally { initLock.unlock(); } } private String checkProperty(Properties properties, String property) { String prop = properties.getProperty(property); if (prop == null) { logger.error("Could not find value for property %s", property); throw new IllegalStateException("Could not find value for property " + property); } return prop; } public boolean isConnected() { return connected; } protected long getMessagesProcessed() { return messageProcessor.getMessagesProcessed(); } protected long getMessagesFailed() { return messageProcessor.getMessagesFailed(); } public void setProvisioningServiceClient( ProvisioningClient provisioningServiceClient) { this.provisioningServiceClient = provisioningServiceClient; } public void setStorageServiceClient(StorageServiceClient storageServiceClient) { this.storageServiceClient = storageServiceClient; } StorageServiceClient getStorageServiceClient() { return storageServiceClient; } }