package com.rayo.server.cdr;
import java.io.IOException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.pubsub.AccessModel;
import org.jivesoftware.smackx.pubsub.ConfigureForm;
import org.jivesoftware.smackx.pubsub.FormType;
import org.jivesoftware.smackx.pubsub.LeafNode;
import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smackx.pubsub.PubSubManager;
import org.jivesoftware.smackx.pubsub.PublishModel;
import org.jivesoftware.smackx.pubsub.SimplePayload;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import com.rayo.server.jmx.XmppCdrMXBean;
import com.rayo.core.cdr.Cdr;
import com.rayo.core.cdr.CdrException;
import com.voxeo.logging.Loggerf;
@ManagedResource(objectName = "com.rayo:Type=Admin,name=Xmpp CDR", description = "Xmpp PubSub based CDR storage")
public class XmppCdrStorageStrategy implements CdrStorageStrategy, XmppCdrMXBean {
private Loggerf logger = Loggerf.getLogger(XmppCdrStorageStrategy.class);
private String server;
private int port = 5222;
private String username;
private String password;
private String node;
// Lock to enable JMS settings hot replacement
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private LeafNode pubsubNode;
private PubSubManager mgr;
private XMPPConnection connection;
public void init() throws IOException {
logger.info("Initializing Xmpp CDR Storage Strategy");
try {
ConnectionConfiguration config = new ConnectionConfiguration(server, port);
connection = new XMPPConnection(config);
connection.connect();
connection.login(username, password);
logger.debug("Connected to Xmpp PubSub node");
} catch (Exception e) {
logger.error("Could not initialize Xmpp CDR Storage strategy");
throw new IOException(e);
}
mgr = new PubSubManager(connection);
try {
pubsubNode = (LeafNode)mgr.getNode(node);
} catch (XMPPException e) {
if (e.getXMPPError().getCondition().equals(XMPPError.Condition.item_not_found.toString())) {
if (pubsubNode == null) {
try {
ConfigureForm form = new ConfigureForm(FormType.submit);
form.setAccessModel(AccessModel.open);
form.setDeliverPayloads(true);
form.setNotifyRetract(true);
form.setPersistentItems(false);
form.setPublishModel(PublishModel.open);
pubsubNode = (LeafNode) mgr.createNode(node, form);
} catch (Exception e2) {
logger.error("Could not initialize Xmpp CDR Storage strategy");
throw new IOException(e2);
}
logger.debug("Created PubSub Node");
}
} else {
logger.error("Could not initialize Xmpp CDR Storage strategy");
throw new IOException(e);
}
}
}
@Override
@ManagedOperation(description = "Change CDRs Xmpp destination")
public void changeDestination(String server, Integer port, String username, String password, String node) {
logger.info("Changing CDRs audit file to %s:%s,%s/%s,%s", server,port,username,password,node);
String oldServer = this.server;
Integer oldPort = this.port;
String oldUsername = this.username;
String oldPassword = this.password;
String oldNode = this.node;
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.node = node;
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.node = oldNode;
} finally {
lock.writeLock().unlock();
}
}
public void shutdown() {
logger.info("Shutting down Xmpp CDR Storage Strategy");
if (connection != null) {
try {
connection.disconnect();
} catch (Exception e) {
logger.warn("Error while shutting down Xmpp CDR Storage Strategy");
logger.error(e.getMessage(),e);
}
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public void store(Cdr cdr) throws CdrException {
try {
lock.readLock().lock();
pubsubNode.send(new PayloadItem(cdr.getCallId(),
new SimplePayload("cdr", "cdr", cdr.toString())));
} 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 getNode() {
return node;
}
@Required
public void setNode(String node) {
this.node = node;
}
}