/*
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration)
* and Cosylab 2002, 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.logging.engine.ACS;
import java.util.Random;
import org.omg.CosNotification.StructuredEvent;
import org.omg.CosNotifyChannelAdmin.ClientType;
import org.omg.CosNotifyChannelAdmin.ProxySupplier;
import org.omg.CosNotifyChannelAdmin.StructuredProxyPushSupplier;
import org.omg.CosNotifyChannelAdmin.StructuredProxyPushSupplierHelper;
import org.omg.CosNotifyComm.StructuredPushConsumerPOA;
import alma.Logging.XmlLogRecord;
import alma.Logging.XmlLogRecordSeqHelper;
/**
* ACSStructuredPushConsumer gets logs from the NC
* and stores them in a list called receivedLogs.
*
* It supports binary and XML formats.
*/
public final class ACSStructuredPushConsumer extends StructuredPushConsumerPOA
{
protected static final Random random = new Random(System.currentTimeMillis());
protected StructuredProxyPushSupplier structuredProxyPushSupplier = null;
protected boolean isConnected = false;
protected boolean isEventSetup = false;
protected boolean isInitialized = false;
private ACSRemoteAccess acsra = null;
/**
* If it is suspended then the incoming messages are discarded
* instead of being notified to the listeners
*/
private boolean suspended=false;
// The object to dispatch messages to the listeners
private ACSListenersDispatcher listenersDispatcher = null;
// This boolean signal that the object has been closed:
// all the logs received while closed will be discarded
private volatile boolean closed=false;
// The object to send new logs to
private ACSLogRetrieval logRetrieval;
/**
* StructuredPushConsumer constructor comment.
*
* @param acsra The remote access obj to ACS NC
* @param theEngine The LCEngine
*/
public ACSStructuredPushConsumer(ACSRemoteAccess acsra, ACSListenersDispatcher listenersDispatcher, ACSLogRetrieval logRetrieval)
{
if (acsra==null || listenersDispatcher==null) {
throw new IllegalArgumentException("Illegal null argument");
}
if (logRetrieval==null) {
throw new IllegalArgumentException("The ACSLogRetrieval can't be null");
}
this.acsra = acsra;
this.listenersDispatcher=listenersDispatcher;
this.logRetrieval = logRetrieval;
initialize();
}
/**
* Connects the push supplier to the push consumer.
*/
public void connect()
{
try
{
structuredProxyPushSupplier.connect_structured_push_consumer(this._this(acsra.getORB()));
}
catch (Exception e)
{
listenersDispatcher.publishReport("Exception occurred when connecting to structured push consumer.");
System.out.println("Exception in ACSStructuredPushConsumer::connect(): " + e);
return;
}
isConnected = true;
}
public void destroy()
{
try {
teardownEvents();
structuredProxyPushSupplier.disconnect_structured_push_supplier();
acsra.getConsumerAdmin().destroy();
} catch (Throwable t) {
System.out.println("Exception in ACSStructuredPushConsumer::destroy(): " + t);
t.printStackTrace();
}
}
public void disconnect_structured_push_consumer()
{
System.out.println(">>>disconnect_structured_push_consumer called.");
}
/**
* Initializes the parser.
* Creation date: (10/24/2001 12:48:32 PM)
*/
private void initialize()
{
org.omg.CORBA.IntHolder proxyId = new org.omg.CORBA.IntHolder();
ProxySupplier proxySupplier = null;
try
{
proxySupplier =
acsra.getConsumerAdmin().obtain_named_notification_push_supplier(ClientType.STRUCTURED_EVENT, proxyId, createUniqueClientName());
}
catch (Exception e)
{
listenersDispatcher.publishReport("Exception occurred when obtaining notification push supplier.");
System.out.println("Exception in ACSStructuredPushConsumer::initialize(): " + e);
return;
}
structuredProxyPushSupplier = StructuredProxyPushSupplierHelper.narrow(proxySupplier);
isInitialized = true;
}
public boolean isInitialized()
{
return isInitialized;
}
public void offer_change(org.omg.CosNotification.EventType[] added, org.omg.CosNotification.EventType[] removed)
throws org.omg.CosNotifyComm.InvalidEventType
{
// not implemented...
}
/**
* Adds all the logs to a list in a synchronized manner.
*/
public void push_structured_event(StructuredEvent event) throws org.omg.CosEventComm.Disconnected
{
if (suspended || closed) {
return;
}
try{
String xmlLog = event.remainder_of_body.extract_string();
logRetrieval.addLog(xmlLog);
}catch(org.omg.CORBA.BAD_OPERATION ex){
XmlLogRecord[] xmlLogs = XmlLogRecordSeqHelper.extract(event.remainder_of_body);
for(int i = 0; i < xmlLogs.length ; i++)
logRetrieval.addLog(xmlLogs[i].xml);
}
}
/**
* Changes subscription on ConsumerAdmin.
*/
public void setupEvents()
{
org.omg.CosNotification.EventType[] added = new org.omg.CosNotification.EventType[1];
org.omg.CosNotification.EventType[] removed = new org.omg.CosNotification.EventType[0];
added[0] = new org.omg.CosNotification.EventType();
added[0].domain_name = "*";
added[0].type_name = "*";
try
{
acsra.getConsumerAdmin().subscription_change(added, removed);
}
catch (Exception e)
{
listenersDispatcher.publishReport("Exception occurred when changing subscription on Consumer Admin.");
System.out.println("Exception in ACSStructuredPushConsumer::setupEvents(): " + e);
return;
}
isEventSetup = true;
}
/**
* Remove subscription on ConsumerAdmin.
*/
public void teardownEvents()
{
org.omg.CosNotification.EventType[] added = new org.omg.CosNotification.EventType[0];
org.omg.CosNotification.EventType[] removed = new org.omg.CosNotification.EventType[1];
removed[0] = new org.omg.CosNotification.EventType();
removed[0].domain_name = "*";
removed[0].type_name = "*";
try
{
acsra.getConsumerAdmin().subscription_change(added, removed);
}
catch (Exception e)
{
listenersDispatcher.publishReport("Exception occurred when changing subscription on Consumer Admin.");
System.out.println("Exception in ACSStructuredPushConsumer::setupEvents(): " + e);
return;
}
isEventSetup = true;
}
/**
* Check if the consumer is connected by reconnecting the channel
*
* @return true if the consumer is connected
*/
public boolean isConnected() {
if (structuredProxyPushSupplier==null) {
isConnected=false;
return false;
}
try {
structuredProxyPushSupplier.resume_connection();
} catch ( org.omg.CosNotifyChannelAdmin.ConnectionAlreadyActive caa) {
isConnected=true;
return true;
} catch (Exception e) {
isConnected=false;
return false;
}
// No exceptions so the pusher reconnected
isConnected=true;
return true;
}
/**
*
* @return true if the consumer is suspened
*/
public boolean isSuspended() {
return suspended;
}
/**
* Suspend the notification of the incoming logs
* The logs received while suspended discarded
* (i.e. lost forever)
*
* @see LCEngine
* @param suspend If true suspend the notification of new logs
*/
public void setSupended(boolean suspended) {
this.suspended=suspended;
if (suspended) {
listenersDispatcher.publishSuspended();
} else {
listenersDispatcher.publishConnected(true);
}
}
/**
* Close the threads and free all the resources
* @param sync If it is true wait the termination of the threads before returning
*/
public void close(boolean sync) {
closed=true;
}
/**
* Copied from jcontnc :: Helper, which we cannot use here because of build order issues.
* <p>
* We need to have a unique client name, even though every jlog instance uses its own consumer admin object.
* This is different from jcontnc's NCSubscriber class who started with this unique name business.
* The reason is the TAO MC API "ConsumerNames" statistics used by the eventGUI. It returns
* "factoryName/channelName/supplierProxyName", which leaves out the admin object,
* and returns this string only once even if this same path applies to several proxies.
*/
public static synchronized String createUniqueClientName() {
StringBuffer clientNameSB = new StringBuffer("jlog");
clientNameSB.append('-');
clientNameSB.append(String.format("%05d", random.nextInt(Integer.MAX_VALUE)));
return clientNameSB.toString();
}
}