/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration),
* and Cosylab
* All rights reserved
*
* 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 com.cosylab.acs.laser.dao;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.exolab.castor.xml.Unmarshaller;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import alma.acs.alarmsystem.generated.Contact;
import alma.acs.alarmsystem.generated.FaultCode;
import alma.acs.alarmsystem.generated.FaultFamily;
import alma.acs.alarmsystem.generated.FaultMember;
import alma.acs.alarmsystem.generated.FaultMemberDefault;
import alma.acs.logging.AcsLogLevel;
import alma.alarmsystem.alarmmessage.generated.Child;
import alma.alarmsystem.alarmmessage.generated.Parent;
import alma.alarmsystem.alarmmessage.generated.ReductionDefinitions;
import alma.alarmsystem.alarmmessage.generated.ReductionLinkDefinitionListType;
import alma.alarmsystem.alarmmessage.generated.ReductionLinkType;
import alma.alarmsystem.alarmmessage.generated.Threshold;
import alma.alarmsystem.alarmmessage.generated.Thresholds;
import alma.alarmsystem.core.alarms.LaserCoreFaultState.LaserCoreFaultCodes;
import alma.cdbErrType.CDBRecordDoesNotExistEx;
import cern.laser.business.LaserObjectNotFoundException;
import cern.laser.business.dao.AlarmDAO;
import cern.laser.business.dao.ResponsiblePersonDAO;
import cern.laser.business.data.Alarm;
import cern.laser.business.data.AlarmImpl;
import cern.laser.business.data.Building;
import cern.laser.business.data.Category;
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.Triplet;
import cern.laser.business.definition.data.SourceDefinition;
import cern.laser.business.pojo.AlarmMessageProcessorImpl;
import com.cosylab.acs.laser.dao.utils.AlarmRefMatcher;
import com.cosylab.acs.laser.dao.utils.LinkSpec;
class HardcodedBuilding extends Building
{
private static final long serialVersionUID = -2341173312854231369L;
private HardcodedBuilding()
{
super("B/1", "Site", new Integer(1), "Map");
}
static final HardcodedBuilding instance = new HardcodedBuilding();
}
class HardcodedLocation extends Location
{
private static final long serialVersionUID = -4988092784308952674L;
private HardcodedLocation()
{
super("L/1", "1", "L/1/1", "1", "1");
this.setBuilding(HardcodedBuilding.instance);
}
static final HardcodedLocation instance = new HardcodedLocation();
}
/**
* Read alarms from the CDB.
*
* CDB contains one file per each possible FF and one entry per each FC and FM.
* It is possible to specify a default member to be used when the administrator
* did not specify the member.
* <P>
* The alarms are stored in an HashMap having the triplet as key.
* The default member has a triplet with a "*" replacing its name.
* <P>
* The sources are defined together with an alarm definition so they are read here
* and requested by the ACSSourceDAOImpl at startup (instead of being read again from CDB).
* <P>
* The initialization of the alarms is not completely done by loadAlarms because not all the info
* are available at this time. In fact the categories are assigned to alarms by ACSCategoryDAOImpl
* <P>
* For the assigning alarms to reduction rules, the class take advantage of the fact that
* a parent in a reduction rule never contains regular expressions nor wildcards.
*
*
* @see ACSSourceDAOImpl
* @see ACSCategoryDAOImpl
*
* @author acaproni
*
*/
public class ACSAlarmDAOImpl implements AlarmDAO
{
static final HardcodedBuilding theBuilding=HardcodedBuilding.instance;
static final HardcodedLocation theLocation=HardcodedLocation.instance;
// The path where alarm definitions are
private static final String ALARM_DEFINITION_PATH = "/Alarms/AlarmDefinitions";
// The path in the CDB where reduction rules are defined
private static final String REDUCTION_DEFINITION_PATH = "/Alarms/Administrative/ReductionDefinitions";
// The type of the alarm definition in the XML
private static final String XML_DOCUMENT_TYPE="AlarmDefinitions";
// The FM for the default member
private static final String DEFAULT_FM = "*";
// The ACS logger
private Logger logger;
private ConfigurationAccessor conf;
private String surveillanceAlarmId;
private ResponsiblePersonDAO responsiblePersonDAO;
/** The alarms read out the CDB
* The CDB contains fault families.
* The alarms are generated from the fault families.
*/
private final ConcurrentHashMap<String,Alarm> alarmDefs=new ConcurrentHashMap<String,Alarm>();
/**
* Source are defined together with alarms
* This HashMap contains all the sources read from CDB
*/
private final ConcurrentHashMap<String, Source> srcDefs = new ConcurrentHashMap<String, Source>();
/**
* The thresholds from the CDB
*/
//private Thresholds thresholds;
/**
* The threshold read from the CDB.
*
* The key is the alarm ID (FF:FM:FC) of the alarm.
* The value is the value of the threshold
*/
private final ConcurrentHashMap<String, Integer>theThreshods = new ConcurrentHashMap<String, Integer>();
/**
* The alarm cache used to notify on alarm changes
*/
private ACSAlarmCacheImpl alarmCache=null;
/**
* The alarm message processor
*/
private AlarmMessageProcessorImpl messageProcessor;
/**
* The reduction rules (<parent, child>)
*/
private final ArrayList<LinkSpec> reductionRules=new ArrayList<LinkSpec>();
/**
* Constructor
*
* @param log The log (not null)
* @param
*/
public ACSAlarmDAOImpl(Logger log) {
if (log==null) {
throw new IllegalArgumentException("Invalid null logger");
}
logger =log;
generateLaserCoreAlarms();
}
/**
* Load alarms from CDB.
*
* Read the alarms by the alarm definitions file of the CDB.
* The initialization of the alarms is not complete at this stage.
* In fact the categories are assigned to alarms when reading the
* categories from the CDB by ACSCategoryDAOImpl
*
*
* @throws Exception In case of error while parsing XML definition files
*
* @see ACSCategoryDAOImpl
*/
public List<FaultFamily> loadAlarms() throws Exception{
if (conf==null) {
throw new IllegalStateException("Missing dal");
}
String xml;
try {
xml=conf.getConfiguration(ALARM_DEFINITION_PATH);
} catch (Throwable t) {
throw new RuntimeException("Couldn't read alarm XML: "+ALARM_DEFINITION_PATH, t);
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try {
builder= factory.newDocumentBuilder();
} catch (Exception e) {
throw new Exception("Error building the DocumentBuilder from the DocumentBuilderFactory",e);
}
StringReader stringReader = new StringReader(xml);
InputSource inputSource = new InputSource(stringReader);
Document doc;
try {
doc= builder.parse(inputSource);
if (doc==null) {
throw new Exception("The builder returned a null Document after parsing");
}
} catch (Exception e) {
throw new Exception("Error parsing XML: "+xml,e);
}
NodeList docChilds = doc.getChildNodes();
if (docChilds==null || docChilds.getLength()!=1) {
throw new Exception("Malformed xml: only one node (AlarmDefinitions) expected");
}
Node alarmDefNode = docChilds.item(0);
if (alarmDefNode==null || alarmDefNode.getNodeName()!=XML_DOCUMENT_TYPE) {
throw new Exception("Malformed xml: "+XML_DOCUMENT_TYPE+" not found");
}
NodeList alarmDefsNodes = alarmDefNode.getChildNodes();
Unmarshaller FF_unmarshaller = new Unmarshaller(FaultFamily.class);
FF_unmarshaller.setValidation(false);
FF_unmarshaller.setWhitespacePreserve(true);
Vector<FaultFamily> cdbFamilies= new Vector<FaultFamily>();
for (int t=0; t<alarmDefsNodes.getLength(); t++) {
Node alarmDef = alarmDefsNodes.item(t);
try {
FaultFamily family = (FaultFamily) FF_unmarshaller.unmarshal(alarmDef);
if (family==null) {
throw new Exception("Error unmarshalling a family node");
}
cdbFamilies.add(family);
} catch (Exception e) {
throw new Exception("Error parsing "+alarmDef.getNodeName(),e);
}
}
generateAlarmsMap(cdbFamilies);
loadReductionRules();
return cdbFamilies;
}
/**
* Add the alarms generated by the alarm component
*/
private void generateLaserCoreAlarms() {
Collection<AlarmImpl> coreAlarms=LaserCoreFaultCodes.generateAlarms();
for (AlarmImpl alarm: coreAlarms) {
addAlarmToCache(alarm);
logger.log(AcsLogLevel.DEBUG,"Alarm added "+alarm.getAlarmId());
}
}
/**
* Generate the alarms from the definition of the fault families.
* The alarms will be added into the HashMap with their triplet as key.
* The default item has FM="*".
*
* The sources read from the families are also added to the HashMap of the sources
*
* @param families The FF read from the CDB
*/
private void generateAlarmsMap(Vector<FaultFamily> families) {
if (families==null) {
throw new IllegalArgumentException("Invalid null vector of FFs");
}
for (FaultFamily family: families) {
String FF= family.getName();
String helpUrl = family.getHelpUrl();
String source = family.getAlarmSource();
Contact contactPerson = family.getContact();
FaultMember[] FMs = family.getFaultMember();
FaultMemberDefault defaultFM = family.getFaultMemberDefault();
FaultCode[] FCs = family.getFaultCode();
// Check the FCs
//
// There should be at least one FC in the CDB
if (FCs==null || FCs.length==0) {
logger.log(AcsLogLevel.WARNING,"No FC defined for family "+family.getName());
continue;
}
// Check the FM
//
// There should be at least one FM or a default FM defined in the CDB
if (defaultFM==null && (FMs==null || FMs.length==0)) {
logger.log(AcsLogLevel.WARNING,"No FM defined for family "+family.getName());
continue;
}
// Iterate over the FCs
for (FaultCode code: FCs) {
int FC=code.getValue();
int priority = code.getPriority();
String action = code.getAction();
String cause = code.getCause();
String consequence = code.getConsequence();
String problemDesc = code.getProblemDescription();
boolean instant = code.getInstant();
// Iterate over all the FMs
for (FaultMember member: FMs) {
alma.acs.alarmsystem.generated.Location loc = member.getLocation();
if (loc==null) {
loc = new alma.acs.alarmsystem.generated.Location();
}
if (loc.getBuilding()==null) {
loc.setBuilding("");
}
if (loc.getFloor()==null) {
loc.setFloor("");
}
if (loc.getMnemonic()==null) {
loc.setMnemonic("");
}
if (loc.getPosition()==null) {
loc.setPosition("");
}
if (loc.getRoom()==null) {
loc.setRoom("");
}
String FM = member.getName();
if (FM.equals(DEFAULT_FM)) {
logger.log(AcsLogLevel.ERROR,"In the CDB, FM="+DEFAULT_FM+" in family "+FF+" is not allowed");
}
AlarmImpl alarm = new AlarmImpl();
alarm.setMultiplicityChildrenIds(new HashSet());
alarm.setMultiplicityParentIds(new HashSet());
alarm.setNodeChildrenIds(new HashSet());
alarm.setNodeParentIds(new HashSet());
alarm.setAction(action);
alarm.setTriplet(new Triplet(FF, FM, FC));
alarm.setCategories(new HashSet<Category>());
alarm.setCause(cause);
alarm.setConsequence(consequence);
alarm.setProblemDescription(problemDesc);
try {
alarm.setHelpURL(new URL(helpUrl));
} catch (MalformedURLException e) {
alarm.setHelpURL(null);
}
alarm.setInstant(instant);
Location location = new Location("0",loc.getFloor(),loc.getMnemonic(),loc.getPosition(),loc.getRoom());
alarm.setLocation(location);
if (contactPerson.getEmail()!=null) {
alarm.setPiquetEmail(contactPerson.getEmail());
} else {
alarm.setPiquetEmail("");
}
if (contactPerson.getGsm()!=null) {
alarm.setPiquetGSM(contactPerson.getGsm());
} else {
alarm.setPiquetGSM("");
}
alarm.setPriority(priority);
ResponsiblePerson responsible = new ResponsiblePerson(0,contactPerson.getName(),"",contactPerson.getEmail(),contactPerson.getGsm(),"");
alarm.setResponsiblePerson(responsible);
SourceDefinition srcDef = new SourceDefinition(source,"SOURCE","",15,1);
Source src = new Source(srcDef,responsible);
alarm.setSource(src);
alarm.setIdentifier(alarm.getTriplet().toIdentifier());
addAlarmToCache(alarm);
if (!srcDefs.containsKey(source)) {
srcDefs.put(src.getSourceId(),src);
logger.log(AcsLogLevel.DEBUG,"Source "+src.getName()+" (id="+src.getSourceId()+") added");
}
logger.log(AcsLogLevel.DEBUG,"Alarm added "+alarm.getAlarmId());
}
// Add the default
if (defaultFM!=null) {
alma.acs.alarmsystem.generated.Location loc = defaultFM.getLocation();
if (loc==null) {
loc = new alma.acs.alarmsystem.generated.Location();
}
if (loc.getBuilding()==null) {
loc.setBuilding("");
}
if (loc.getFloor()==null) {
loc.setFloor("");
}
if (loc.getMnemonic()==null) {
loc.setMnemonic("");
}
if (loc.getPosition()==null) {
loc.setPosition("");
}
if (loc.getRoom()==null) {
loc.setRoom("");
}
AlarmImpl defaultAlarm = new AlarmImpl();
defaultAlarm.setMultiplicityChildrenIds(new HashSet());
defaultAlarm.setMultiplicityParentIds(new HashSet());
defaultAlarm.setNodeChildrenIds(new HashSet());
defaultAlarm.setNodeParentIds(new HashSet());
defaultAlarm.setAction(action);
defaultAlarm.setCategories(new HashSet<Category>());
defaultAlarm.setCause(cause);
defaultAlarm.setConsequence(consequence);
defaultAlarm.setProblemDescription(problemDesc);
try {
defaultAlarm.setHelpURL(new URL(helpUrl));
} catch (MalformedURLException e) {
defaultAlarm.setHelpURL(null);
}
defaultAlarm.setInstant(instant);
Location location = new Location("0",loc.getFloor(),loc.getMnemonic(),loc.getPosition(),loc.getRoom());
defaultAlarm.setLocation(location);
defaultAlarm.setPiquetEmail(contactPerson.getEmail());
defaultAlarm.setPiquetGSM(contactPerson.getGsm());
defaultAlarm.setPriority(priority);
ResponsiblePerson responsible = new ResponsiblePerson(0,contactPerson.getName(),"",contactPerson.getEmail(),contactPerson.getGsm(),"");
defaultAlarm.setResponsiblePerson(responsible);
SourceDefinition srcDef = new SourceDefinition(source,"SOURCE","",15,1);
Source src = new Source(srcDef,responsible);
defaultAlarm.setSource(src);
defaultAlarm.setIdentifier(defaultAlarm.getTriplet().toIdentifier());
Triplet triplet = new Triplet(FF,DEFAULT_FM,FC);
defaultAlarm.setTriplet(triplet);
defaultAlarm.setIdentifier(triplet.toIdentifier());
addAlarmToCache(defaultAlarm);
if (!srcDefs.containsKey(source)) {
srcDefs.put(src.getSourceId(),src);
logger.log(AcsLogLevel.DEBUG,"Source "+src.getName()+" (id="+src.getSourceId()+") added");
}
logger.log(AcsLogLevel.DEBUG,"Default alarm added "+defaultAlarm.getAlarmId());
}
}
}
}
public ReductionDefinitions getReductionDefinitions()
{
if (conf==null) {
throw new IllegalStateException("Missing dal");
}
String xml;
try {
xml=conf.getConfiguration(REDUCTION_DEFINITION_PATH);
} catch (CDBRecordDoesNotExistEx cdbEx) {
// No reduction rules defined in CDB
logger.log(AcsLogLevel.WARNING,"No reduction rules defined in CDB");
return null;
} catch (Exception e) {
throw new RuntimeException("Couldn't read "+REDUCTION_DEFINITION_PATH, e);
}
ReductionDefinitions rds = null;
try {
rds=(ReductionDefinitions) ReductionDefinitions.unmarshalReductionDefinitions(new StringReader(xml));
} catch (Exception e) {
throw new RuntimeException("Couldn't parse "+REDUCTION_DEFINITION_PATH, e);
}
return rds;
}
/**
* Update the reduction rules.
* <P>
* Reduction rules have the property that the parent is:
* <UL>
* <LI>always one single node
* <LI>is never a wildcard neither a regular expression
* </UL>
*
* <P>
* <I>Performance notes</I>: at the OSF we had problems loading the configuration and
* creating an alarm from the default. In both cases the problems were in this method.
* To improve performances we made several changes and found that
* <UL>
* <LI>iterate over an array is faster then iterating over a {@link Collection}
* <LI>comparing String seems slower then checking regurlar expression (once that it has been compiled into a pattern)
* <UL>
*/
private void updateReductionRules() {
Collection<Alarm> cc=alarmDefs.values();
AlarmImpl[] allAlarms=new AlarmImpl[cc.size()];
cc.toArray(allAlarms);
LinkSpec[] ls=new LinkSpec[reductionRules.size()];
reductionRules.toArray(ls);
int num=allAlarms.length;
logger.log(AcsLogLevel.DEBUG, "Updating all expanded alarms with RR information");
// Iterate over the alarms
for (int a=0; a<num; a++) {
for (LinkSpec lsb: ls) {
if (lsb.matchChild(allAlarms[a])) {
// This alarm is a child in this reduction rule lsb, let's
// get the parent from the reduction rule itself
String alarmParentID=lsb._parent.getMatcherAlarmID();
Alarm parent = alarmDefs.get(alarmParentID);
if (parent!=null) {
if (lsb.isMultiplicity()) {
addMultiplicityChild(parent, allAlarms[a]);
parent.setMultiplicityThreshold(theThreshods.get(parent.getAlarmId()));
} else {
addNodeChild(parent, allAlarms[a]);
}
} else {
}
}
}
}
logger.log(AcsLogLevel.DEBUG, "All alarms updated with RR information");
}
/**
* Load the reduction rules from the CDB.
*
* Read the reduction rules from the CDB and set up the alarms accordingly
*/
private void loadReductionRules()
{
ReductionDefinitions rds = getReductionDefinitions();
if (rds == null)
return;
// Read the links to create from the CDB
ReductionLinkDefinitionListType ltc=rds.getLinksToCreate();
// Read the thresholds from the CDB
Thresholds thresholds = rds.getThresholds();
if (thresholds!=null) {
// Store the thresholds in the HashMap
Threshold[] threshold = thresholds.getThreshold();
for (Threshold t: threshold) {
StringBuilder alarmID= new StringBuilder();
alarmID.append(t.getAlarmDefinition().getFaultFamily());
alarmID.append(':');
alarmID.append(t.getAlarmDefinition().getFaultMember());
alarmID.append(':');
alarmID.append(t.getAlarmDefinition().getFaultCode());
Integer thresholdValue = Integer.valueOf(t.getValue());
theThreshods.put(alarmID.toString(), thresholdValue);
}
}
if (ltc!=null) {
ReductionLinkType[] rls=ltc.getReductionLink();
for (ReductionLinkType link: rls) {
LinkSpec newRule =new LinkSpec(link);
reductionRules.add(newRule);
if( logger.isLoggable(AcsLogLevel.DEBUG) ) {
Parent p=link.getParent();
Child c=link.getChild();
StringBuffer buf = new StringBuffer();
buf.replace(0, buf.length(), "");
if (newRule._isMultiplicity) {
buf.append("Found MULTIPLICITY RR: parent <");
} else {
buf.append("Found NODE RR: parent=<");
}
buf.append(p.getAlarmDefinition().getFaultFamily());
buf.append(", ");
buf.append(p.getAlarmDefinition().getFaultMember());
buf.append(", ");
buf.append(p.getAlarmDefinition().getFaultCode());
buf.append("> child=<");
buf.append(c.getAlarmDefinition().getFaultFamily());
buf.append(", ");
buf.append(c.getAlarmDefinition().getFaultMember());
buf.append(", ");
buf.append(c.getAlarmDefinition().getFaultCode());
buf.append('>');
logger.log(AcsLogLevel.DEBUG,buf.toString());
}
}
}
logger.log(AcsLogLevel.DEBUG,reductionRules.size()+" reduction rules read from CDB");
updateReductionRules();
}
/**
* Update the threshold for the passed alarm
*
* @param alarm The alarm to update the threshold
*/
private void updateAlarmThreshold(Alarm alarm) {
Integer thresholdValue=theThreshods.get(alarm.getAlarmId());
if (thresholdValue!=null) {
alarm.setMultiplicityThreshold(thresholdValue);
}
}
/**
* Update the reduction rules involving the passed alarm
*
* @param alarm The parent alarm whose reduction rule has to be
* updated
*/
private void updateAlarmReductionRule(AlarmImpl alarm) {
if (alarm==null) {
throw new IllegalArgumentException("The passed alarm can't be null");
}
Collection<Alarm> cc=alarmDefs.values();
AlarmImpl[] allAlarms=new AlarmImpl[cc.size()];
cc.toArray(allAlarms);
int num=allAlarms.length;
LinkSpec[] ls=new LinkSpec[reductionRules.size()];
reductionRules.toArray(ls);
for (LinkSpec lsb: ls) {
if (lsb.matchChild(alarm)) {
AlarmRefMatcher parentMatcher=lsb._parent;
boolean isMulti=lsb.isMultiplicity();
for (int c=0; c<num; c++) {
if (alarm.getAlarmId().equals(allAlarms[c].getAlarmId())) {
continue;
}
AlarmImpl aic=allAlarms[c];
if (parentMatcher.isMatch(aic)) {
if (isMulti) {
addMultiplicityChild(aic,alarm);
aic.setMultiplicityThreshold(theThreshods.get(aic.getAlarmId()));
} else {
addNodeChild(aic,alarm);
}
}
}
} else if (lsb.matchParent(alarm)) {
AlarmRefMatcher childMatcher=lsb._child;
boolean isMulti=lsb.isMultiplicity();
for (int c=0; c<num; c++) {
if (alarm.getAlarmId().equals(allAlarms[c].getAlarmId())) {
continue;
}
AlarmImpl aic=allAlarms[c];
if (childMatcher.isMatch(aic)) {
if (isMulti) {
addMultiplicityChild(alarm, aic);
alarm.setMultiplicityThreshold(theThreshods.get(alarm.getAlarmId()));
} else {
addNodeChild(alarm, aic);
}
}
}
}
}
}
/**
* Add the child to the parent in the node reduction
* <P>
* It checks if the definition of the parent and/or the definition of the child
* change after the updating and call a replace(...) in the cache to trigger
* the notification to the clients.
*
* @param parent The parent of the node reduction
* @param child The child of the node reduction
*/
private void addNodeChild(Alarm parent, Alarm child) {
boolean notifyParent=!((AlarmImpl)parent).getNodeChildrenIds().contains(child.getAlarmId());
boolean notifyChild=!((AlarmImpl)child).getNodeParentIds().contains(parent.getAlarmId());
parent.addNodeChild(child);
logger.log(AcsLogLevel.DEBUG,"Added NODE RR node child "+child.getAlarmId()+" to "+parent.getAlarmId());
if (notifyParent && alarmCache!=null) {
try {
alarmCache.replace(parent);
if (messageProcessor!=null) {
messageProcessor.updateReductionStatus(parent);
}
} catch (Throwable t) {
System.err.println("Error updating a node child:"+t.getMessage());
t.printStackTrace();
}
}
if (notifyChild && alarmCache!=null) {
try {
alarmCache.replace(child);
if (messageProcessor!=null) {
messageProcessor.updateReductionStatus(child);
}
} catch (Throwable t) {
System.err.println("Error updating a node child:"+t.getMessage());
t.printStackTrace();
}
}
}
private void addMultiplicityChild(Alarm parent, Alarm child) {
boolean notifyParent=!((AlarmImpl)parent).getMultiplicityChildrenIds().contains(child.getAlarmId());
boolean notifyChild=!((AlarmImpl)child).getMultiplicityParentIds().contains(parent.getAlarmId());
parent.addMultiplicityChild(child);
if (notifyParent && alarmCache!=null) {
try {
alarmCache.replace(parent);
if (messageProcessor!=null) {
messageProcessor.updateReductionStatus(parent);
}
} catch (Throwable t) {
System.err.println("Error updating a node child:"+t.getMessage());
t.printStackTrace();
}
}
if (notifyChild && alarmCache!=null) {
try {
alarmCache.replace(child);
if (messageProcessor!=null) {
messageProcessor.updateReductionStatus(child);
}
} catch (Throwable t) {
System.err.println("Error updating a node child:"+t.getMessage());
t.printStackTrace();
}
}
}
private void saveAllIDs()
{
if (conf==null) {
throw new IllegalStateException("null ConfigurationAccessor");
}
if (!conf.isWriteable()) {
throw new RuntimeException("ConfigurationAccessor is not writeable");
}
StringBuffer result=new StringBuffer();
result.append("<?xml version=\"1.0\"?>\n");
result.append("<alarm-definition-list>\n");
Iterator<Alarm> i=alarmDefs.values().iterator();
while (i.hasNext()) {
Alarm a = i.next();
Triplet t = a.getTriplet();
result.append("\t<alarm-definition fault-family=\"");
DAOUtil.escapeXMLEntities(result, t.getFaultFamily());
result.append("\" fault-member=\"");
DAOUtil.escapeXMLEntities(result, t.getFaultMember());
result.append("\" fault-code=\"");
result.append(t.getFaultCode().intValue());
result.append("\" />\n");
}
result.append("</alarm-definition-list>\n");
try {
conf.setConfiguration("/alarms", result.toString());
} catch (Exception e) {
throw new RuntimeException("Could not write alarm list", e);
}
}
static String memberFromAlarmID(String alarmId)
{
int prev=alarmId.indexOf(':');
int next=alarmId.lastIndexOf(':');
if (!(prev>0 && next>0 && next>prev))
throw new IllegalStateException();
return alarmId.substring(prev+1, next);
}
public Alarm findAlarm(String alarmId)
{
Alarm res=getAlarm(alarmId);
if (res==null) {
throw new LaserObjectNotFoundException("Alarm ID "+alarmId+" expected, but not found");
}
return res;
}
/**
* Get an alarm from the cache.
*
* Get an alarm from the cache. If the alarm with the given triplet is not in the cache then it
* looks for a default alarm before returning null.
*
* If a default alarm is found, then a new alarm is created by cloning the default alarm.
* The triplet of this new alarm is set to be equal to the passed alarm ID.
*
* @param alarmId The ID of the alarm
* @return An alarm with the given ID if it exists in the CDB
* If an alarm with the give ID does not exist but a matching default alarm
* is defined then it return a clone of the default alarm
* null If the alarm is not defined in the CDB and a default alarm does not exist
*
*
*/
public Alarm getAlarm(String alarmId)
{
if (conf==null) {
throw new IllegalStateException("Missing dal");
}
if (alarmId==null) {
throw new IllegalArgumentException("Invalid null alarm ID");
}
AlarmImpl alarm =(AlarmImpl)alarmDefs.get(alarmId);
if (alarm==null) {
// The alarm is not in the HashMap
//
// Does it exist a default alarm?
String[] tripletItems = alarmId.split(":");
if (tripletItems.length!=3) {
logger.log(AcsLogLevel.ERROR,"Malformed alarm ID: "+alarmId);
return null;
}
// Build the default alarm ID by replacing the FM with DEFAULT_FM
String defaultTripletID=tripletItems[0]+":"+DEFAULT_FM+":"+tripletItems[2];
logger.log(AcsLogLevel.DEBUG,alarmId+" not found: looking for default alarm "+defaultTripletID);
AlarmImpl defaultalarm=(AlarmImpl)alarmDefs.get(defaultTripletID);
if (defaultalarm==null) {
// No available default alarm for this triplet
logger.log(AcsLogLevel.WARNING,"No default alarm found for "+alarmId);
return null;
}
logger.log(AcsLogLevel.DEBUG,"Default alarm found for "+alarmId);
System.out.println("Default alarm found for "+alarmId);
alarm=(AlarmImpl)defaultalarm.clone();
Triplet alarmTriplet = new Triplet(tripletItems[0],tripletItems[1],Integer.parseInt(tripletItems[2]));
alarm.setTriplet(alarmTriplet);
alarm.setAlarmId(
Triplet.toIdentifier(
alarmTriplet.getFaultFamily(),
alarmTriplet.getFaultMember(),
alarmTriplet.getFaultCode()));
// Add the alarm in the HashMap
//
// addAlarmToCache trigger the sending of the alarm to the clients
// i.e. a default alarm is sent to the client twice
addAlarmToCache(alarm);
// Refresh the reduction rules with the newly added alarm
updateAlarmReductionRule(alarm);
updateAlarmThreshold(alarm);
//dumpReductionRules();
}
return alarm;
}
Building loadBuilding(String buildingID)
{
if (buildingID.equals(theBuilding.getBuildingNumber()))
return theBuilding;
return null;
}
public String[] findAlarmIdsByPriority(Integer priority)
{
int p=priority.intValue();
ArrayList<String> result=null;
Iterator<Entry<String, Alarm>> i=alarmDefs.entrySet().iterator();
while (i.hasNext()) {
Entry<String, Alarm> e=i.next();
String id=e.getKey().toString();
AlarmImpl ai=(AlarmImpl) e.getValue();
if (ai.getPriority().intValue()==p) {
if (result==null)
result=new ArrayList<String>();
result.add(id);
}
}
if (result==null) {
return new String[0];
} else {
int s=result.size();
String[] res=new String[s];
result.toArray(res);
return res;
}
}
public String findLaserSurveillanceAlarmId()
{
if (getAlarm(surveillanceAlarmId)==null)
throw new LaserObjectNotFoundException("unable to find laser surveillance alarm");
return surveillanceAlarmId;
}
public void deleteAlarm(Alarm alarm)
{
String member=alarm.getTriplet().getFaultMember();
if (alarmDefs.remove(alarm.getTriplet().toIdentifier())!=null)
saveMemberAlarms(member);
}
public void saveMemberAlarms(String member)
{
return;
}
public void saveAlarm(Alarm alarm)
{
addAlarmToCache(alarm);
saveMemberAlarms(alarm.getTriplet().getFaultMember());
}
static String encodeToXML(Alarm alarm)
{
StringBuffer result=new StringBuffer();
result.append("<?xml version=\"1.0\"?>\n");
encodeToXML(result, alarm);
return result.toString();
}
static String encodeToXML(StringBuffer result, Alarm alarm)
{
result.append("<alarm-definition");
Triplet t=alarm.getTriplet();
if (t==null || t.getFaultCode()==null || t.getFaultFamily()==null || t.getFaultMember()==null)
throw new IllegalArgumentException("Incomplete alarm");
DAOUtil.encodeAttr(result, "fault-family", t.getFaultFamily());
DAOUtil.encodeAttr(result, "fault-member", t.getFaultMember());
DAOUtil.encodeAttr(result, "fault-code", t.getFaultCode().toString());
result.append(">\n");
{
String sn=alarm.getSystemName();
String si=alarm.getIdentifier();
String pd=alarm.getProblemDescription();
if (sn!=null || si!=null || pd!=null) {
result.append("\t<visual-fields>\n");
// schema says all or nothing, but still, let's not be too picky
if (sn!=null)
DAOUtil.encodeElem(result, "system-name", sn, 2);
if (si!=null)
DAOUtil.encodeElem(result, "identifier", si, 2);
if (pd!=null)
DAOUtil.encodeElem(result, "problem-description", pd, 2);
result.append("\t</visual-fields>\n");
}
}
DAOUtil.encodeElemIf(result, "instant", alarm.getInstant(), 1);
DAOUtil.encodeElemIf(result, "cause", alarm.getCause(), 1);
DAOUtil.encodeElemIf(result, "action", alarm.getAction(), 1);
DAOUtil.encodeElemIf(result, "consequence", alarm.getConsequence(), 1);
DAOUtil.encodeElemIf(result, "priority", alarm.getPriority(), 1);
ResponsiblePerson rp=alarm.getResponsiblePerson();
if (rp!=null)
DAOUtil.encodeElemIf(result, "responsible-id", rp.getResponsibleId(), 1);
DAOUtil.encodeElemIf(result, "piquetGSM", alarm.getPiquetGSM(), 1);
DAOUtil.encodeElemIf(result, "help-url", alarm.getHelpURL(), 1);
Source s=alarm.getSource();
if (s!=null)
DAOUtil.encodeElemIf(result, "source-name", s.getName(), 1);
Location l=alarm.getLocation();
if (l!=null) {
result.append("\t<location>\n");
Building b=l.getBuilding();
if (b!=null)
DAOUtil.encodeElemIf(result, "building", b.getBuildingNumber(), 2);
DAOUtil.encodeElemIf(result, "floor", l.getFloor(), 2);
DAOUtil.encodeElemIf(result, "room", l.getRoom(), 2);
DAOUtil.encodeElemIf(result, "mnemonic", l.getMnemonic(), 2);
DAOUtil.encodeElemIf(result, "position", l.getPosition(), 2);
result.append("\t</location>\n");
}
DAOUtil.encodeElemIf(result, "piquetEmail", alarm.getPiquetEmail(), 1);
result.append("</alarm-definition>\n");
return result.toString();
}
public void updateAlarm(Alarm alarm)
{
addAlarmToCache(alarm);
saveMemberAlarms(alarm.getTriplet().getFaultMember());
}
public void updateStatus(Status status)
{
// TODO Auto-generated method stub
}
public Collection search(String select_sql)
{
throw new UnsupportedOperationException();
}
public Collection archiveSearch(String select_sql)
{
throw new UnsupportedOperationException();
}
public Building findBuilding(String building)
{
if (building.equals(theBuilding.getBuildingNumber()))
return theBuilding;
throw new LaserObjectNotFoundException("Couldn't find building "+building);
}
public void setConfAccessor(ConfigurationAccessor conf)
{
this.conf = conf;
}
public void setSurveillanceAlarmId(String surveillanceAlarmId)
{
this.surveillanceAlarmId = surveillanceAlarmId;
}
public void setResponsiblePersonDAO(ResponsiblePersonDAO responsiblePersonDAO)
{
this.responsiblePersonDAO=responsiblePersonDAO;
}
/**
* Add an alarm in cache (<code>alarmDefs</code>)
* <P>
* The {@link Alarm} to add in the cache must be not <code>null</code>
* and with a valid ID otherwise an exception is thrown.
*
* @param alarm The Alarm to add to the cache
*/
private void addAlarmToCache(Alarm alarm) {
if (alarm==null) {
throw new IllegalArgumentException("It is forbidden to add null alarms to cache");
}
String alarmId=alarm.getAlarmId();
if (alarmId==null || alarmId.isEmpty()) {
throw new IllegalStateException("Trying to add an alarm with an invalid ID!");
}
alarmDefs.put(alarmId, alarm);
}
public String[] getAllAlarmIDs()
{
Set<String> keyset=alarmDefs.keySet();
String[] result=new String[keyset.size()];
keyset.toArray(result);
return result;
}
/**
* Getter method
*
* @return The sources
*/
public ConcurrentHashMap<String,Source> getSources() {
return srcDefs;
}
public void setAlarmCache(ACSAlarmCacheImpl alarmCache) {
this.alarmCache=alarmCache;
}
public void setAlarmProcessor(AlarmMessageProcessorImpl processor) {
this.messageProcessor=processor;
}
private void dumpReductionRules() {
Vector<String> keys=new Vector<String>(alarmDefs.keySet());
Collections.sort(keys);
System.out.println("VVVVV Dumping reduction rules VVVVV");
System.out.println("defined reduction rules: "+keys.size());
for (String key: keys) {
AlarmImpl alarm = (AlarmImpl)alarmDefs.get(key);
System.out.println(alarm.getAlarmId());
String[] nodeParents=alarm.getNodeParents();
System.out.println("\tNODE parents");
for (String id: nodeParents) {
System.out.println("\t\t"+id);
}
String[] nodeChilds=alarm.getNodeChildren();
System.out.println("\tNODE childs");
for (String id: nodeChilds) {
System.out.println("\t\t"+id);
}
String[] multiParents=alarm.getMultiplicityParents();
System.out.println("\tMULTIPLICITY parents");
for (String id: multiParents) {
System.out.println("\t\t"+id);
}
String[] multiChilds=alarm.getMultiplicityChildren();
System.out.println("\tMULTIPLICITY childs");
for (String id: multiChilds) {
System.out.println("\t\t"+id);
}
System.out.println("\tMULTIPLICITY threshold: "+alarm.getMultiplicityThreshold());
}
System.out.println("^^^^^ ^^^^^");
}
private void dumpAlarmCache() {
Vector<String> keys=new Vector<String>(alarmDefs.keySet());
Collections.sort(keys);
System.out.println("VVVVV ACSAlarmDAOImpl:: Alarms in cache VVVVV");
System.out.println("Number of alarms in cache: "+keys.size());
for (String key: keys) {
Alarm alarm = alarmDefs.get(key);
System.out.print("\t"+key);
System.out.print(" active="+alarm.getStatus().getActive());
System.out.print(" masked="+alarm.getStatus().getMasked());
System.out.println(" reduced="+alarm.getStatus().getReduced());
}
System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}
}