/* * ALMA - Atacama Large Millimiter Array Copyright (c) ESO - European Southern Observatory, 2005 * * 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.nc; import org.omg.CORBA.portable.IDLEntity; import org.omg.CosNaming.NamingContext; import org.omg.CosNotification.StructuredEvent; import alma.ACSErrTypeCommon.wrappers.AcsJCouldntPerformActionEx; import alma.ACSErrTypeCommon.wrappers.AcsJIllegalStateEventEx; import alma.acs.container.ContainerServicesBase; import alma.acs.exceptions.AcsJException; import alma.acscommon.ACS_NC_DOMAIN_ARCHIVING; import alma.acscommon.ARCHIVING_CHANNEL_NAME; import alma.acsnc.EventDescription; /** * ArchiveConsumer is designed solely for the purpose * of processing notification channel structured events sent automatically by * BACI properties under certain conditions. * Calls are delegated to the encapsulated TweakedNCSubscriber instance that inherits from NCSubscriber. * This way we don't have to expose NCSubscriber methods that make no sense for this special subscriber. * <p> * These events are not IDL-defined structs! * The type parameter IDLEntity is therefore cheating, to get by the checks in the base class. * This is OK because we intercept the events at the 'push_structured_event_called' level, * before any event type information gets applied in the processing. * See ACS/Documents/Logging_and_Archiving.doc (currently a bit outdated) * and archiveevents :: archiveeventsArchiveSupplier.cpp for detail of the sender code. * Filtering using the extended trader constraint language should work. * <p> * Basically all one has to do to use * this class is create an ArchiveConsumer object providing an ArchiveReceiver callback, * and then invoke the startReceivingEvents() method. * <p> * Note that in Alma the archiving NC has been replaced by the TMCDB monitoring framework. * The eventGUI is the only known Java client for the old archiving NC, thus we continue * supporting this class at medium inspiration level. * <p> * * @author dfugate, hsommer */ public class ArchiveConsumer { /** * The client must implement this callback */ public static interface ArchiveReceiver { public void receive(long timeStamp, String device, String property, Object value); } private final NCSubscriber<IDLEntity> delegate; /** * Creates a new instance of ArchiveConsumer. * * @param services * @param receiver * @throws AcsJException */ public ArchiveConsumer(ArchiveReceiver receiver, ContainerServicesBase services, NamingContext namingService) throws AcsJException { delegate = new ArchiveTweakedNCSubscriber(receiver, services, namingService, ArchiveConsumer.class.getSimpleName()); } public final void startReceivingEvents() throws AcsJIllegalStateEventEx, AcsJCouldntPerformActionEx { delegate.startReceivingEvents(); } public final void disconnect() throws AcsJIllegalStateEventEx, AcsJCouldntPerformActionEx { delegate.disconnect(); } private static class ArchiveTweakedNCSubscriber extends NCSubscriber<IDLEntity> { /** * There is exactly one receiver that will be used by each ArchiveConsumer object. */ private final ArchiveReceiver userReceiver; public ArchiveTweakedNCSubscriber(ArchiveReceiver userReceiver, ContainerServicesBase services, NamingContext namingService, String clientName) throws AcsJException { super(ARCHIVING_CHANNEL_NAME.value, ACS_NC_DOMAIN_ARCHIVING.value, services, namingService, clientName, IDLEntity.class); this.userReceiver = userReceiver; GenericCallback internalDummyReceiver = new GenericCallback() { @Override public void receiveGeneric(Object event, EventDescription eventDescrip) { logger.warning("Unexpected call to 'receiveGeneric', which should not happen with our non-standard use of NCSubscriber."); } }; addGenericSubscription(internalDummyReceiver); } /** * @param structuredEvent CORBA NC StructuredEvent with special format. */ @Override protected boolean push_structured_event_called(StructuredEvent structuredEvent) { // String containerName = ""; String device = "?"; String property = "?"; // ArchiveSupplier codes this as "container:component:property" to avoid a few Corba Anys String abusedEventName = structuredEvent.header.fixed_header.event_name; String[] locationInfo = abusedEventName.split(":"); if (locationInfo.length == 3) { // containerName = locationInfo[0]; device = locationInfo[1]; property = locationInfo[2]; } else { // TODO: error log with repeat guard } // extract the useful info Long timeStamp = (Long) anyAide.corbaAnyToObject(structuredEvent.filterable_data[0].value); // Property name is "time_stamp" Object value = anyAide.corbaAnyToObject(structuredEvent.filterable_data[1].value); // Property name is "value" // give it to the receiver userReceiver.receive(timeStamp, device, property, value); return false; } } }