/*
* Created on Feb 22, 2007 Copyright (C) 2001-6, Anthony Harrison anh23@pitt.edu
* (jactr.org) 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 org.jactr.tools.tracer.sinks;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javolution.util.FastList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.concurrent.ExecutorServices;
import org.jactr.tools.async.controller.RemoteInterface;
import org.jactr.tools.async.message.BulkMessage;
import org.jactr.tools.async.message.IMessage;
import org.jactr.tools.tracer.ITraceSink;
import org.jactr.tools.tracer.transformer.ITransformedEvent;
/**
* @author developer
*/
public class NetworkedSink implements ITraceSink
{
/**
* logger definition
*/
static private final Log LOGGER = LogFactory
.getLog(NetworkedSink.class);
private long _maximumDelay = 500; // ms
private int MAXIMUM_BUFFER_SIZE = 25;
private Collection<IMessage> _messageBuffer;
private Runnable _autoFlush;
private RemoteInterface _interface;
private volatile boolean _scheduled = false;
public NetworkedSink()
{
_interface = RemoteInterface.getActiveRemoteInterface();
if (_interface == null)
throw new RuntimeException(
"A RemoteInterface must be active before instantiating this sink");
try
{
MAXIMUM_BUFFER_SIZE = Integer.parseInt(System
.getProperty("jACTR:MaximumBufferSize"));
}
catch (NumberFormatException nfe)
{
MAXIMUM_BUFFER_SIZE = 25;
}
_messageBuffer = Collections
.synchronizedCollection(new FastList<IMessage>());
_autoFlush = new Runnable() {
public void run()
{
// no need for this to be safe..
_scheduled = false;
try
{
flush();
}
catch (Exception e)
{
LOGGER.error(".run threw Exception : ", e);
}
}
};
}
protected boolean shouldFlush()
{
synchronized (_messageBuffer)
{
return _messageBuffer.size() >= MAXIMUM_BUFFER_SIZE;
}
}
/*
* use a delay to trigger the flush..
*/
protected void scheduleFlush(long delay)
{
if (_scheduled) return;
_scheduled = true;
ScheduledExecutorService executor = (ScheduledExecutorService) ExecutorServices
.getExecutor(ExecutorServices.PERIODIC);
try
{
executor.schedule(_autoFlush, delay, TimeUnit.MILLISECONDS);
}
catch (RejectedExecutionException ree)
{
if (LOGGER.isDebugEnabled())
LOGGER
.debug(
String
.format("Networked flush rejected, probably in the mids of shutdown"),
ree);
}
}
/**
* @see org.jactr.tools.tracer.ITraceSink#add(org.jactr.tools.tracer.transformer.ITransformedEvent)
*/
public void add(ITransformedEvent event)
{
if (event == null)
{
LOGGER.error("null message received ", new NullPointerException());
return;
}
_messageBuffer.add(event);
if (shouldFlush())
try
{
flush();
}
catch (Exception e)
{
LOGGER.error("Could not flush after capacity is exceeded ", e);
}
else
scheduleFlush(_maximumDelay);
}
/**
* @see org.jactr.tools.tracer.ITraceSink#flush()
*/
public void flush() throws Exception
{
if (!isOpen())
{
_messageBuffer.clear();
return;
}
BulkMessage message = null;
synchronized (_messageBuffer)
{
if (_messageBuffer.size() > 0)
{
message = new BulkMessage(_messageBuffer);
_messageBuffer.clear();
}
}
if (message != null)
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Sending bulk message " + message.getSize());
_interface.getActiveSession().write(message);
}
}
public boolean isOpen()
{
return _interface.getActiveSession() != null;
}
}