package com.rayo.server.cdr; import java.io.IOException; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.springframework.beans.factory.annotation.Required; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import com.rayo.server.jmx.AmqpCdrMXBean; import com.rayo.core.cdr.Cdr; import com.rayo.core.cdr.CdrException; import com.voxeo.logging.Loggerf; @ManagedResource(objectName = "com.rayo:Type=Admin,name=Amqp CDR", description = "AMQP based CDR storage") public class AmqpCdrStorageStrategy implements CdrStorageStrategy, AmqpCdrMXBean { private Loggerf logger = Loggerf.getLogger(AmqpCdrStorageStrategy.class); private String server; private int port = 5222; private String username; private String password; private String exchange; private String route; // Lock to enable JMS settings hot replacement private final ReadWriteLock lock = new ReentrantReadWriteLock(); private Channel channel; private Connection connection; public void init() throws IOException { logger.info("Initializing AMQP CDR Storage Strategy"); ConnectionFactory factory = new ConnectionFactory(); factory.setUsername("guest"); factory.setPassword("guest"); factory.setVirtualHost("/"); factory.setHost("localhost"); factory.setPort(5672); try { connection = factory.newConnection(); channel = connection.createChannel(); } catch (Exception e) { logger.error("Could not initialize AMQP CDR Storage strategy"); throw new IOException(e); } } @Override @ManagedOperation(description = "Change CDRs AMQP destination") public void changeDestination(String server, Integer port, String username, String password, String exchange, String route) { logger.info("Changing CDRs audit file to %s:%s,%s/%s,%s-%s", server,port,username,password,exchange, route); String oldServer = this.server; Integer oldPort = this.port; String oldUsername = this.username; String oldPassword = this.password; String oldExchange = this.exchange; String oldRoute = this.route; try { // We do not let the system to do any logging while we are changing the config lock.writeLock().lock(); this.server = server; this.port = port; this.username = username; this.password = password; this.exchange = exchange; this.route = route; init(); } catch (IOException ioe) { logger.error("Could not replace File storage configuration settings. Rolling back to previous setup"); this.server = oldServer; this.port = oldPort; this.username = oldUsername; this.password = oldPassword; this.exchange = oldExchange; this.route = oldRoute; } finally { lock.writeLock().unlock(); } } public void shutdown() { logger.info("Shutting down AMQP CDR Storage Strategy"); if (channel != null) { try { channel.close(); } catch (Exception e) { logger.warn("Error while shutting down AMQP CDR Storage Strategy"); logger.error(e.getMessage(),e); } } if (connection != null) { try { connection.close(); } catch (Exception e) { logger.warn("Error while shutting down AMQP CDR Storage Strategy"); logger.error(e.getMessage(),e); } } } @Override public void store(Cdr cdr) throws CdrException { try { lock.readLock().lock(); synchronized(channel) { // As per RabbitMQ docs, Channels are not thread-safe byte[] messageBodyBytes = cdr.toString().getBytes(); channel.basicPublish(exchange, route, null, messageBodyBytes); } } catch (Exception e) { logger.error("Error while sending CDR message", e.getMessage()); throw new CdrException(e); } finally { lock.readLock().unlock(); } } public String getServer() { return server; } @Required public void setServer(String server) { this.server = server; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getUsername() { return username; } @Required public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } @Required public void setPassword(String password) { this.password = password; } public String getExchange() { return exchange; } @Required public void setExchange(String exchange) { this.exchange = exchange; } public String getRoute() { return route; } @Required public void setRoute(String route) { this.route = route; } }