/*
* ALMA - Atacama Large Millimiter Array (c) European Southern Observatory, 2007
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package alma.alarmsystem.clients;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.omg.CORBA.ORB;
import cern.laser.business.data.AlarmImpl;
import cern.laser.business.data.Building;
import cern.laser.business.data.CategoryImpl;
import cern.laser.business.data.Location;
import cern.laser.business.data.ResponsiblePerson;
import cern.laser.business.data.Source;
import cern.laser.business.data.Status;
import cern.laser.business.data.StatusImpl;
import cern.laser.business.data.Triplet;
import cern.laser.client.data.Alarm;
import cern.laser.client.services.selection.AlarmSelectionHandler;
import cern.laser.client.services.selection.AlarmSelectionListener;
import cern.laser.client.services.selection.CategorySelection;
import cern.laser.client.services.selection.Selection;
import cern.laser.console.Configuration;
import cern.laser.console.User;
import cern.laser.console.impl.UserHandlerImpl;
import alma.acs.container.ContainerServices;
import alma.acs.logging.AcsLogLevel;
import alma.acs.logging.AcsLogger;
import alma.acs.logging.adapters.Log4jFactory;
import alma.alarmsystem.CERNAlarmService;
import alma.alarmsystem.Category;
import alma.alarmsystem.clients.alarm.AlarmClientException;
import alma.alarmsystem.corbaservice.CernAlarmServiceUtils;
import alma.maciErrType.wrappers.AcsJCannotGetComponentEx;
/**
* A client that listen to alarms from all the categories.
* It is meant to be used only by {@link AlarmCategoryClient}
* and <EM>should not be instantiated directly</EM>.
* <P>
* It is a wrapper to CERN classes in order to simplify
* the usage from ACS without dealing with low level
* details of the alarm system.
* <P>
* The class connects to the alarm system as a CERN client,
* logging in a generic user.
* The listener receives alarms and errors from the alarm system by means
* of a callback.
* The alarm system sends all the already active alarms when the user logs is.
* <P>
* The close() method has to be called in order to free all the resources.
* <P>
* TODO: reduce the visibility of this class to ensure it is not used outside of
* {@link AlarmCategoryClient}
*
* @author acaproni
*
*/
public class CategoryClient {
/**
* The user handler
*/
private UserHandlerImpl userHandler;
/**
* The user to log in (test for instance)
*/
private User testUser;
/**
* The user to log in (test for instance)
*/
private Configuration defaultConf;
/**
* / The alarm selection handler
*/
private AlarmSelectionHandler jms_selectionHandler;
/**
* ACS ContainerServices
*/
//private ContainerServices contSvc;
/**
* The logger
*/
private final AcsLogger logger;
/**
* The orb
*/
private final ORB orb;
/**
* The alarm service component
*/
private CERNAlarmService alarm;
/**
* To avoid to release the resources twice
*/
private volatile boolean closed=false;
/**
* Constructor
*
* @param contServices The containerServices
* @throws AlarmClientException
*/
public CategoryClient(ContainerServices contServices) throws AlarmClientException {
this(contServices.getAdvancedContainerServices().getORB(),contServices.getLogger());
}
/**
* Contructor
*
* @param orb The orb
* @param logger The logger
*/
public CategoryClient(ORB orb, AcsLogger logger) {
this.logger=logger;
if (logger==null) {
throw new IllegalStateException("Got a null logger from the container services!");
}
this.orb=orb;
if (orb==null) {
throw new IllegalStateException("Got a null ORB from the container services!");
}
Log4jFactory.enableAcsLogging();
}
/**
* Add the categories to the configuration i.e. add the categories
* the client wants to listen to
*
* @param config The Configuration
* @param categories The categories to listen to
* If it is null, it adds all the categories returned
* by the alarm system component
* @throws Exception
*/
private void addCategories(Configuration config,Category[] categories) throws Exception {
if (categories==null) {
categories = alarm.getCategories();
}
if (categories.length==0) {
logger.log(AcsLogLevel.WARNING,"No categories to connect to");
return;
}
Selection selection = config.getSelection();
CategorySelection catSel = selection.createCategorySelection();
for (Category cat: categories) {
cern.laser.business.data.CategoryImpl businessCategory = new cern.laser.business.data.CategoryImpl(
cat.categoryId,
cat.name,
cat.description,
cat.path,
cat.leaf);
cern.laser.client.impl.data.CategoryImpl cImpl=new cern.laser.client.impl.data.CategoryImpl(businessCategory);
catSel.add(cImpl);
}
selection.setCategorySelection(catSel);
}
/**
* Connects to all the categories of the alarm system.
*
* It is equivalent to <code>connect(listener,null)</code>.
*
* @param listener The lister to notify of the alarms received from the categories
* @throws AlarmClientException In case of failure connecting the client
* @throws AcsJCannotGetComponentEx If the alarm service component is not available
*
* @see CategoryClient#connect(AlarmSelectionListener, Category[])
*/
public void connect(AlarmSelectionListener listener) throws AlarmClientException, AcsJCannotGetComponentEx {
connect(listener,null);
}
/**
* Connects to the passed categories of the alarm system
*
* @param listener The lister to notify of the alarms received from the categories
* @param categories The categories to connect to
* @throws AcsJCannotGetComponentEx In case the AlarmService is not available
* @throws AlarmClientException In case of failure connecting the client
*/
public void connect(AlarmSelectionListener listener, Category[] categories) throws AlarmClientException, AcsJCannotGetComponentEx {
if (listener==null) {
throw new IllegalArgumentException("The listener can't be null");
}
if (closed) {
throw new IllegalStateException("SourceClient is closed!");
}
try {
CernAlarmServiceUtils alarmUtils = new CernAlarmServiceUtils(orb,logger);
alarm=alarmUtils.getCernAlarmService();
} catch (Throwable t) {
AcsJCannotGetComponentEx ex = new AcsJCannotGetComponentEx(t);
ex.setReason("Alarm service unavailable");
throw ex;
}
try {
userHandler=new UserHandlerImpl(orb,logger);
logger.log(AcsLogLevel.DEBUG,"UserHandler succesfully built");
testUser = userHandler.getUser("test",orb,logger);
logger.log(AcsLogLevel.DEBUG,"User generated");
defaultConf=testUser.getDefaultConfiguration();
logger.log(AcsLogLevel.DEBUG,"Getting the selection handler");
jms_selectionHandler = AlarmSelectionHandler.get(orb,logger);
addCategories(defaultConf,categories);
// Get the active alarms (they are received by the listener)
java.util.Map<String, Alarm> alreadyActive=jms_selectionHandler.select(defaultConf.getSelection(),listener);
if (alreadyActive!=null && alreadyActive.size()>0) {
Set<String> keys = alreadyActive.keySet();
for (String key: keys) {
listener.onAlarm(alreadyActive.get(key));
}
}
} catch (Throwable t) {
throw new AlarmClientException("Exception connecting the category client",t);
}
}
/**
* Release all the resource,
*
* @throws AlarmClientException
*/
public void close() throws AlarmClientException {
if (closed) {
return;
}
closed=true;
try {
if (jms_selectionHandler!=null) {
jms_selectionHandler.close();
jms_selectionHandler=null;
}
} catch (Exception e) {
throw new AlarmClientException("Exception closing: ",e);
}
}
/**
* Ensure that the resources have been released before destroying the object
*/
protected void finalize() throws Throwable {
if (!closed) {
close();
}
super.finalize();
}
/**
* Get the parents of a reduced alarm.
* <P>
* The method asks the alarm service component for the parents of a reduced
* alarm.
*
* @param id The id of the alarm
* @param node <code>true</code> if the alarm is a Node alarm;
* <code>false</code> if the alarm of the passed ID is a multiplicity.
* @return The array of the alarm parent of the alarm with the passed ID
* @throws AlarmClientException In case of error getting the alarms from the component
*/
public Alarm[] getParents(String id, boolean node) throws AlarmClientException {
if (id==null || id.isEmpty()) {
throw new IllegalArgumentException("Invalid alarm ID");
}
alma.alarmsystem.Alarm[] alarms = null;
try {
if (node) {
alarms=alarm.getNodeParents(id);
} else {
alarms=alarm.getMultiplicityParents(id);
}
} catch (Throwable t) {
throw new AlarmClientException("Error getting parents from component",t);
}
Alarm[] ret = new Alarm[alarms.length];
for (int t=0; t< ret.length; t++) {
ret[t]=convertAlarmType(alarms[t]);
}
return ret;
}
/**
* Get the parents of a reduced alarm.
* <P>
* The method asks the alarm service component for the children of a reduced
* alarm.
*
* @param id The id of the alarm
* @param node <code>true</code> if the alarm is a Node alarm;
* <code>false</code> if the alarm of the passed ID is a multiplicity.
* @return The array of the alarm parent of the alarm with the passed ID
* @throws AlarmClientException In case of error getting the alarms from the component
*/
public Alarm[] getChildren(String id, boolean node) throws AlarmClientException {
if (id==null || id.isEmpty()) {
throw new IllegalArgumentException("Invalid alarm ID");
}
alma.alarmsystem.Alarm[] alarms = null;
try {
if (node) {
alarms=alarm.getNodeChildren(id);
} else {
alarms=alarm.getMultiplicityChildren(id);
}
} catch (Throwable t) {
throw new AlarmClientException("Error getting children from component",t);
}
Alarm[] ret = new Alarm[alarms.length];
for (int t=0; t< ret.length; t++) {
ret[t]=convertAlarmType(alarms[t]);
}
return ret;
}
/**
* Return the threshold for the multiplicity node whose
* ID is passed as parameter.
*
* @param id The id of the multiplicity node
* @return The multiplicity threshold of the node with the given id
* @throws AlarmClientException If an error happens getting the threshold from the component
*/
public int getMultiplicityThreshold(String id) throws AlarmClientException {
if (id==null || id.isEmpty()) {
throw new IllegalArgumentException("Invalid alarm ID");
}
try {
return alarm.getMultiplicityThreshold(id);
} catch (Throwable t) {
throw new AlarmClientException("Error getting threshold from component",t);
}
}
/**
* Get the active children of a reduced alarm.
* <P>
* The method asks the alarm service component for the active children of a reduced
* alarm.
*
* @param id The id of the alarm
* @param node <code>true</code> if the alarm is a Node alarm;
* <code>false</code> if the alarm of the passed ID is a multiplicity.
* @return The array of the alarm parent of the alarm with the passed ID
* @throws AlarmClientException In case of error getting the alarms from the component
*/
public Alarm[] getActiveChildren(String id, boolean node) throws AlarmClientException {
if (id==null || id.isEmpty()) {
throw new IllegalArgumentException("Invalid alarm ID");
}
alma.alarmsystem.Alarm[] alarms = null;
try {
if (node) {
alarms=alarm.getActiveNodeChildren(id);
} else {
alarms=alarm.getActiveMultiplicityChildren(id);
}
} catch (Throwable t) {
throw new AlarmClientException("Error getting children from component",t);
}
Alarm[] ret = new Alarm[alarms.length];
for (int t=0; t< ret.length; t++) {
ret[t]=convertAlarmType(alarms[t]);
}
return ret;
}
/**
* Convert a CORBA alarm into a client alarm.
*
* @param alarm The CORBA alarm
* @return the client alarm
*/
private Alarm convertAlarmType(alma.alarmsystem.Alarm alarm) {
Source source = new Source();
Building building = new Building(
alarm.alarmLocation.buildingNb,
alarm.alarmLocation.site,
alarm.alarmLocation.zone,
alarm.alarmLocation.map);
Location location =new Location(
alarm.alarmLocation.locationId,
alarm.alarmLocation.floor,
alarm.alarmLocation.mnemonic,
alarm.alarmLocation.position,
alarm.alarmLocation.room);
location.setBuilding(building);
ResponsiblePerson responsiblePerson = new ResponsiblePerson(
alarm.alarmResponsiblePerson.responsibleId,
alarm.alarmResponsiblePerson.familyName,
alarm.alarmResponsiblePerson.firstName,
alarm.alarmResponsiblePerson.eMail,
alarm.alarmResponsiblePerson.gsmNumber,
alarm.alarmResponsiblePerson.phoneNumber);
Properties userProperties = new Properties();
for (org.omg.CosPropertyService.Property prop: alarm.alarmStatus.userProperties) {
userProperties.put(prop.property_name, prop.property_value);
}
Status status = new StatusImpl(
Boolean.valueOf(alarm.alarmStatus.active),
Boolean.valueOf(alarm.alarmStatus.masked),
Boolean.valueOf(alarm.alarmStatus.reduced),
Boolean.FALSE,
Boolean.FALSE,
alarm.alarmStatus.sourceHostname,
new Timestamp(alarm.alarmStatus.sourceTimestamp.miliseconds),
new Timestamp(alarm.alarmStatus.userTimestamp.miliseconds),
new Timestamp(alarm.alarmStatus.systemTimestamp.miliseconds),
userProperties);
Triplet triplet = new Triplet(
alarm.alarmTriplet.faultFamily,
alarm.alarmTriplet.faultMember,
alarm.alarmTriplet.faultCode);
Set<cern.laser.business.data.Category> categories = new HashSet<cern.laser.business.data.Category>();
for (Category cat: alarm.categories) {
CategoryImpl catImpl=new CategoryImpl(cat.categoryId,cat.name,cat.description,cat.path,cat.leaf);
categories.add(catImpl);
}
cern.laser.business.data.Alarm businessAlarm = new AlarmImpl(
alarm.alarmId,
alarm.systemName,
alarm.identifier,
alarm.problemDescription,
Integer.valueOf(alarm.priority),
alarm.cause,
alarm.action,
alarm.consequence,
alarm.piquetGSM,
alarm.piquetEmail,
alarm.helpURL,
Boolean.valueOf(alarm.instant),
source,
location,
responsiblePerson,
categories,
status,
triplet,
alarm.nodeParent,
alarm.multiplicityParent,
alarm.nodeChild,
alarm.multiplicityChild
);
Alarm ret = new cern.laser.client.impl.data.AlarmImpl(businessAlarm);
return ret;
}
}