/*
* AlarmSystemInterfaceProxy.java
*
* Created on June 5, 2001, 10:21 AM
*/
package cern.laser.source.alarmsysteminterface.impl;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.jms.TextMessage;
import org.apache.log4j.Category;
import cern.cmw.mom.pubsub.ExceptionListener;
import cern.cmw.mom.pubsub.MOMException;
import cern.cmw.mom.pubsub.PubSubFactory;
import cern.cmw.mom.pubsub.Publisher;
import cern.laser.source.alarmsysteminterface.ASIException;
import cern.laser.source.alarmsysteminterface.AlarmSystemInterface;
import cern.laser.source.alarmsysteminterface.FaultState;
import cern.laser.source.alarmsysteminterface.impl.configuration.ASIConfiguration;
import cern.laser.source.alarmsysteminterface.impl.message.ASIMessage;
import cern.laser.util.buffer.PullEvent;
import cern.laser.util.buffer.PullException;
import cern.laser.util.buffer.SynchroBuffer;
import cern.laser.util.buffer.SynchroBufferListener;
import alma.acs.util.IsoDateFormat;
/**
* This class is the implementation of the interface between an alarm source
* and the alarm system.
* It provides the functionality defined in the interface AlarmSystemInterface.
*
* @author fracalde
* @version 1.0
*/
public class AlarmSystemInterfaceProxy implements AlarmSystemInterface, SynchroBufferListener, ExceptionListener {
/** logging category
*/
private static Category cat = Category.getInstance(AlarmSystemInterfaceProxy.class.getName());
/** configuration
*/
private ASIConfiguration configuration;
/** the publisher
*/
private Publisher publisher;
/** the hostname
*/
private String hostName;
/** the source name
*/
private String sourceName = "UNDEFINED";
/** the local buffer for packing alarm messages
*/
private SynchroBuffer buffer;
/** MOM connection flag
*/
private AtomicBoolean connected = new AtomicBoolean(false);
/** Create a new instance of AlarmSystemInterfaceProxy
* @param sourceName the name of the alarm source
*/
public AlarmSystemInterfaceProxy(String sourceName) throws ASIException {
cat.info("instantiating the alarm system interface");
/*
* We force all the sources to use the same channel
*
* The sourceName passes as a parameter is the name of the component
* and was used to create a channel where the service listen to
* (BTW this was wrong as the channel name is defined in the CDB
* and there is no relation between the name of a component and
* the channel)
*
* There could be a performance problem here that may force us to use
* more channels
*/
sourceName="ALARM_SYSTEM_SOURCES";
Configurator configurator = new Configurator();
configuration = configurator.getConfiguration();
setSourceName(sourceName);
try {
try {
hostName = java.net.InetAddress.getLocalHost().getHostName().toUpperCase();
if (hostName.endsWith(".CERN.CH")) {
hostName = hostName.substring(0, hostName.indexOf(".CERN.CH"));
}
} catch (UnknownHostException uhe) {
cat.warn("unable to get the host name", uhe);
hostName = "";
}
// create a MOM publisher instance
publisher = PubSubFactory.publisher();
connected.set(true);
publisher.setExceptionListener(this);
// create and start the buffer manager
buffer = new SynchroBuffer();
buffer.setSynchroBufferListener(this);
buffer.enable();
} catch (Exception e) {
ASIException asi_e = new ASIException("unable to instantiate the AlarmSystemInterfaceProxy : " + e.getMessage());
asi_e.setRootCause(e);
throw (asi_e);
}
}
/**
* Set the source name.
* @param newSourceName the source name.
*/
public void setSourceName(String newSourceName) {
synchronized (sourceName) {
sourceName = newSourceName;
}
}
/**
* Get the source name.
* @return the source name.
*/
public String getSourceName() {
String source_name;
synchronized (sourceName) {
source_name = sourceName;
}
return source_name;
}
/** Close the instance.
*/
public void close() {
cat.info("closing...");
// closing open threads and resources
if (buffer != null) {
buffer.close();
buffer = null;
}
if (publisher != null) {
publisher.close();
publisher = null;
}
connected.set(false);
cat.info("closed");
}
/** The exception handler called in case of communication exception
*
* @param e the MOMException caught
*
*/
public void onException(MOMException e) {
if (e.testException(MOMException.CONNECTION_LOST_EXCEPTION)) {
connected.set(false);
} else if (e.testException(MOMException.CONNECTION_RECOVERED_EXCEPTION)) {
connected.set(true);
}
}
/** Implement the SysnchroBufferListener interface.
* @param event the alarm message collection pulled from the buffer
* @throws PullException if the messages can not be published
*/
public void pull(PullEvent event) throws PullException {
try {
publish(event.getPulled(), false);
} catch (Exception e) {
cat.error("unable to publish message : " + e.getMessage(), e);
throw new PullException("unable to pull objects from the buffer");
}
}
/** Push a fault state.
* @param state the fault state to push
*/
public void push(FaultState state) throws ASIException {
if (!connected.get()) {
throw (new ASIException("not connected"));
}
if (state == null) {
throw new IllegalArgumentException("state is null");
}
if (state instanceof FaultStateImpl) {
((FaultStateImpl) state).validate();
}
buffer.push(state);
}
/** Push an fault states collection.
* @param states the fault states collection to push
*/
public void push(Collection states) throws ASIException {
if (!connected.get()) {
throw (new ASIException("not connected"));
}
if (states == null) {
throw new IllegalArgumentException("states collection is null");
}
Iterator iterator = states.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
if (next instanceof FaultState) {
push((FaultState) next);
} else {
throw new IllegalArgumentException("states collection does not contain FaultState instances");
}
}
}
/** Push the source active list forcing a backup
* @param active the source active list
*/
public void pushActiveList(Collection active) throws ASIException {
if (!connected.get()) {
throw (new ASIException("not connected"));
}
if (active == null) {
throw (new IllegalArgumentException("active list is null"));
}
Iterator iterator = active.iterator();
while (iterator.hasNext()) {
Object next = iterator.next();
if (next instanceof FaultStateImpl) {
((FaultStateImpl) next).validate();
}
}
try {
publish(active, true);
} catch (Exception e) {
cat.error("unable to publish backup : " + e.getMessage(), e);
}
}
/** Publish a collection of fault states.
* @param states the fault states collection to publish
* @param backup the type of fault states to publish (backup or not)
* @throw Exception if publishing fails
*/
private void publish(Collection states, boolean backup) throws Exception {
cat.debug("publishing " + states.size() + " fault state(s)");
cat.debug("content :\n" + states.toString());
ASIMessage asi_message = ASIMessageHelper.marshal(states);
asi_message.setSourceName(getSourceName());
asi_message.setSourceHostname(hostName);
asi_message.setSourceTimestamp(IsoDateFormat.formatCurrentDate());
asi_message.setBackup(backup);
asi_message.setVersion(configuration.getASIVersion());
TextMessage alarm_message = publisher.createTextMessage();
alarm_message.setText(XMLMessageHelper.marshal(asi_message));
alarm_message.setStringProperty(configuration.getSourceNameProperty(), getSourceName());
alarm_message.setStringProperty(configuration.getSourceHostnameProperty(), hostName);
alarm_message.setStringProperty(configuration.getBackupProperty(), String.valueOf(backup));
alarm_message.setStringProperty(configuration.getAlarmsNumberProperty(), String.valueOf(states.size()));
StringBuffer topic = new StringBuffer(configuration.getAlarmsTopic());
topic.append(".");
topic.append(getSourceName());
if (backup) {
publisher.publish(topic.toString(), alarm_message, configuration.getBackupDeliveryMode(), configuration.getBackupPriority(), configuration.getBackupTimeToLive());
} else {
publisher.publish(topic.toString(), alarm_message, configuration.getChangesDeliveryMode(), configuration.getChangesPriority(), configuration.getChangesTimeToLive());
}
cat.debug("published");
}
}