/******************************************************************************* * ALMA - Atacama Large Millimeter Array * Copyright (c) ESO - European Southern Observatory, 2011 * (in the framework of the ALMA collaboration). * 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 alma.alarmsystem.source; import java.io.StringReader; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import com.cosylab.CDB.DAL; import alma.JavaContainerError.wrappers.AcsJContainerServicesEx; import alma.acs.alarmsystem.source.AlarmSource; import alma.acs.alarmsystem.source.AlarmSourceFactory; import alma.acs.container.ContainerServicesBase; import alma.acs.logging.AcsLogLevel; import alma.acsErrTypeAlarmSourceFactory.ACSASFactoryNotInitedEx; import alma.acsErrTypeAlarmSourceFactory.FaultStateCreationErrorEx; import alma.acsErrTypeAlarmSourceFactory.SourceCreationErrorEx; import alma.acsErrTypeAlarmSourceFactory.wrappers.AcsJACSASFactoryNotInitedEx; import alma.acsErrTypeAlarmSourceFactory.wrappers.AcsJFaultStateCreationErrorEx; import alma.acsErrTypeAlarmSourceFactory.wrappers.AcsJSourceCreationErrorEx; /** * ACSAlarmSystemInterfaceFactory extends the CERN AlarmSystemInterfaceFactory * to create sources with different implementations depending on the actual * configuration in the CDB. *

* The type of implementation is in AlarmSystemConfiguration.xml: a property named * Implementation. * CERN implementation is used only if the value of such property is CERN. * If the property is not found, is ACS or the CDB record does not exist then the * ACS implementation for sources is used. *

* ACSAlarmSystemInterfaceFactory owns the instances of the {@link AlarmSource} * created by the component or containers. in this way it is possible to control the cleanup * of the alarm sources when a component is unloaded or the ACSAlarmSystemInterfaceFactory * terminates. * * @author acaproni * */ public class ACSAlarmSystemInterfaceFactory { /** * The path in the CDB of the AS configuration */ private static final String CONFIGURATION_PATH="Alarms/Administrative/AlarmSystemConfiguration"; /** * It is true if ACS implementation for sources must be used; * false means CERN implementation. *

* It is null if it has not yet been initialized. */ private static Boolean useACSAlarmSystem = null; /** * At the present, while using the CERN implementation, * we use the same source for sending all the alarms * so we can use a singleton and return the same object * to all the clients. * * @see AlarmSystemInterfaceProxy */ private static ACSAlarmSystemInterface source=null; /** * The logger */ private static Logger logger=null; /** * Container services */ private static ContainerServicesBase containerServices; /** * The factory to keep track of all the existing {@link AlarmSource} objects. */ private static AlarmSourceFactory alarmSourceFactory; /** * Init the static variables of the class * This method has to be called before executing any other * method. * * @param logger The logger * @param dal The DAL to init the AS with CERN or ACS implementation * @throws AcsJContainerServicesEx */ public static void init(ContainerServicesBase containerServices) throws AcsJContainerServicesEx { if (containerServices==null) { throw new AcsJContainerServicesEx(new Exception("Invalid null ContainerServicesBase")); } ACSAlarmSystemInterfaceFactory.containerServices=containerServices; ACSAlarmSystemInterfaceFactory.logger = containerServices.getLogger(); DAL dal = containerServices.getCDB(); if (logger==null || dal==null) { throw new IllegalArgumentException("Invalid DAL or Logger from ContainerServicesBase"); } alarmSourceFactory = new AlarmSourceFactory(containerServices); useACSAlarmSystem = retrieveImplementationType(dal); if (logger!=null) { if (useACSAlarmSystem) { logger.log(AcsLogLevel.DEBUG,"Alarm system type: ACS"); } else { logger.log(AcsLogLevel.DEBUG,"Alarm system type: CERN"); try { initCmwMom(); } catch (Throwable t) { throw new AcsJContainerServicesEx(new Exception("Error initing cmw-mom",t)); } } } } /** * Initialize cmw-mom (that in turn inits acs-jms) by setting the container services. * * The container services must be set in a cmw-mom static variable in order the * messages are published into the NC. * The container services will be passed from this class down to the acs-jms classes. * * @see cern.cmw.mom.pubsub.impl.ACSJMSTopicConnectionImpl */ private static void initCmwMom() throws Exception { if (containerServices==null) { throw new IllegalStateException("Trying to init cmw-mom with null ContainerServicesBase"); } try { Thread t = Thread.currentThread(); ClassLoader loader = t.getContextClassLoader(); Class cl =loader.loadClass("cern.cmw.mom.pubsub.impl.ACSJMSTopicConnectionImpl"); Field var = cl.getField("containerServices"); var.set(null, containerServices); logger.log(AcsLogLevel.DEBUG,"cmw-mom/acs-jms initialized"); } catch (Throwable t) { throw new Exception("Error setting ContainerServices into cmw-mom",t); } } /** * Cleanup the class. * This method has to be called outside of the class and performs all the necessary * clean up * */ public static void done() { if (containerServices==null) { throw new IllegalStateException("Trying close with null ContainerServicesBase"); } alarmSourceFactory.tearDown(); if (useACSAlarmSystem!=null) { if (source!=null) { source.close(); source=null; } useACSAlarmSystem=null; } } /** * Read the Implementation property from the Alarm System Configuration * * @param dal The DAL * * @return false if the Implementation property is CERN * true otherwise */ private static boolean retrieveImplementationType(DAL dal) { if (dal==null) { return true; } String dao; try { dao = dal.get_DAO(CONFIGURATION_PATH); } catch (Exception e) { return true; } String implementation = getProperty(dao,"Implementation"); return implementation==null || !implementation.equals("CERN"); } /** * Get the value of a property from the DAO. * * @param dao The dao (XML string) * @param propName The name of the property * @return The value of the property with the given name * null if the property doesn't exist */ private static String getProperty(String dao, String propName) { if (dao==null || propName==null) { return null; } DocumentBuilder builder = null; DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { builder = factory.newDocumentBuilder(); } catch (Exception e) { System.out.println("Error instantiating the document builder"); System.out.println(e.getMessage()); e.printStackTrace(); return null; } Document doc; try { doc = builder.parse(new InputSource(new StringReader(dao))); } catch (Exception e) { System.out.println("Error parsing the DAO: ["+dao+"]"); System.out.println(e.getMessage()); e.printStackTrace(); return null; } NodeList propNodeList = doc.getElementsByTagName("configuration-property"); String val = null; // The value of the property to return for (int t=0; t