/*
* 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.acs.lasercore.test.stress;
import java.util.HashSet;
import java.util.Vector;
import alma.acs.container.ContainerServices;
import alma.acs.logging.AcsLogLevel;
import alma.alarmsystem.CERNAlarmService;
import alma.alarmsystem.Category;
import alma.alarmsystem.corbaservice.CernAlarmServiceUtils;
import alma.acs.lasercore.test.stress.category.AlarmView;
import alma.acs.lasercore.test.stress.category.CategoryListener;
import alma.acs.lasercore.test.stress.category.CategorySubscriber;
/**
* A client that listen alarms from all the categories
*
* @author acaproni
*
*/
public class CategoryClient {
// Container services
private ContainerServices contSvc;
// The category root topic
private String categoryRootTopic;
/**
* The categories
* Each category is a notification channel we have to listen to.
* The list of the categories is read from the AlarmServise component
*/
private Category[] categories;
// The consumers to listen to alarms from the categories
private CategorySubscriber[] consumers;
/**
* The alarm service
*/
private CERNAlarmService alarm;
private HashSet<CategoryListener> listeners = new HashSet<CategoryListener>();
/**
* Constructor
*
* @param svc ACS ContainerServices used to access the alarm service component
*/
public CategoryClient(ContainerServices svc) throws Exception {
if (svc==null) {
throw new IllegalArgumentException("Invalid ContainerServices");
}
contSvc=svc;
try {
initialize();
} catch (Throwable t) {
throw new Exception("Error building CategoryClient",t);
}
}
/**
* Connect the AlarmSrevice component
*/
private void getAlarmService() throws Exception {
CernAlarmServiceUtils alarmtUtils= new CernAlarmServiceUtils(contSvc);
alarm=alarmtUtils.getCernAlarmService();
}
/**
* Read the categories and the category root topic from the component
*
* @return The categories
*/
private void getCategories() throws Exception {
if (alarm==null) {
throw new IllegalStateException("No alarm component connected");
}
categoryRootTopic=alarm.getCategoryRootTopic();
categories=alarm.getCategories();
}
/**
* Create the consumers for the passed categories
*
*
* @param categoriesToConnect The categories to connect to
*/
public void connect(Category[] categoriesToConnect) throws Exception {
if (categoriesToConnect==null ||categoriesToConnect.length==0) {
contSvc.getLogger().log(AcsLogLevel.INFO,"No categories to connect to");
return;
}
consumers=new CategorySubscriber[categoriesToConnect.length];
int t=0;
Vector<String> failingConnections = new Vector<String>();
for (Category category: categoriesToConnect) {
try {
consumers[t++]=new CategorySubscriber(contSvc,categoryRootTopic,category.path,this);
contSvc.getLogger().log(AcsLogLevel.DEBUG,"Connected to "+categoryRootTopic+"."+category.path);
} catch (Throwable throwable) {
failingConnections.add("Error subscribing to "+categoryRootTopic+"."+category.path+": "+throwable.getMessage());
}
}
if (failingConnections.size()>0) {
System.err.println("Error connecting categories: ");
for (String str: failingConnections) {
System.err.println("\t"+str);
}
throw new Exception("Error connecting categories");
}
}
/**
* Connect to all available categories
*
*/
public void connect() throws Exception {
connect(categories);
}
/**
* Disconnect all the categories
*/
public void disconnect() {
for (CategorySubscriber cat: consumers) {
cat.close();
}
alarm=null;
}
/**
* Dumps the category
*
*/
private void dumpCategories() {
if (categories==null) {
contSvc.getLogger().log(AcsLogLevel.DEBUG,"Categories null");
return;
}
if (categories.length==0) {
contSvc.getLogger().log(AcsLogLevel.DEBUG, "Categories empty");
return;
}
System.out.println("Category root topic="+categoryRootTopic);
for (Category cat: categories) {
contSvc.getLogger().log(AcsLogLevel.DEBUG, "Category name="+cat.name+"\tpath="+cat.path+"\tdescription="+cat.description);
}
}
/**
* Initialize the client.
* It connects to the alarm component, get the list of the categories and release
* the component.
*
*/
private void initialize() throws Exception {
// Get the AlarmService
try {
getAlarmService();
} catch (Exception e) {
contSvc.getLogger().log(AcsLogLevel.ERROR,"Error getting the AlarmSystem component: "+e.getMessage());
throw new Exception("Error getting the AlarmSystem component: "+e.getMessage(),e);
}
if (alarm==null) {
contSvc.getLogger().log(AcsLogLevel.ERROR,"Unknown error getting the AlarmService");
throw new Exception("Unknown error getting the AlarmService");
}
// Read the available categories
try {
getCategories();
} catch (Exception e) {
contSvc.getLogger().log(AcsLogLevel.ERROR,"Error getting the categories from AlarmService");
throw new Exception("Error getting the categories from AlarmService",e);
}
dumpCategories();
if (categories==null || categories.length==0) {
contSvc.getLogger().log(AcsLogLevel.INFO,"No alarm categories to subscribe to");
}
}
/**
* Add a listener for the alarms.
*
* Add the listeners to the set of listeners to be notified when
* a new alarms is received from the categories.
*
* @param newListener The listener for alarms from categories
*/
public void addAlarmListener(CategoryListener newListener) {
if (newListener==null) {
throw new IllegalArgumentException("Invalid null listener");
}
synchronized(listeners) {
listeners.add(newListener);
}
}
/**
* Remove a listener from the list of listeners to be notified
* when a new alarm is received
*
* @param listener The not null listener to remove
* @return true if thle list of isteners contained the specified listener
*/
public boolean removeListener(CategoryListener listener) {
if (listener==null) {
throw new IllegalArgumentException("Invalid null listener");
}
boolean ret;
synchronized(listeners) {
ret=listeners.remove(listener);
}
return ret;
}
/**
* This method is called by categories when a new message arrives and dispatches
* the alarm to the listeners.
*
* @param newAlarm The alarm to send to the listeners
*/
public synchronized void dispatchAlarm(AlarmView newAlarm) {
if (newAlarm==null) {
throw new IllegalArgumentException("Invalid null alarm to dispatch");
}
synchronized(listeners) {
for (CategoryListener listener: listeners) {
listener.alarmReceived(newAlarm);
}
}
}
/**
* Close all the subscribers
*/
public void close() {
for (CategorySubscriber cs: consumers) {
cs.close();
}
}
}