
org.objectweb.dream.queue.buffer.AbstractBuffer Maven / Gradle / Ivy
/**
* Dream
* Copyright (C) 2003-2004 INRIA Rhone-Alpes
*
* 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 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
*
* Contact: [email protected]
*
* Initial developer(s): Vivien Quema
* Contributor(s): Romain Lenglet
*/
package org.objectweb.dream.queue.buffer;
import org.objectweb.dream.message.Message;
import org.objectweb.dream.message.MessageManagerType;
import org.objectweb.fractal.fraclet.annotation.annotations.Attribute;
import org.objectweb.dream.dreamannotation.DreamComponent;
import org.objectweb.fractal.fraclet.annotation.annotations.Requires;
/**
* Abstract implementation of a buffer. It implements the {@link BufferAdd } and
* {@link BufferRemove } interfaces.
*
* The add
and remove
methods are implemented as
* follows
*
* - The
add
method checks for available space and then calls
* the doAdd
method to add the message to the buffer.
* - The
remove
method checks for available messages and then
* calls the doRemove
method to remove a message from the buffer.
*
*
*
* Buffer developers can inherit this class. They must implement several
* methods:
*
* canAdd(message)
returns a boolean indicating whether the
* given message can be added into the buffer.
* doAdd(message)
adds the given message into the buffer.
*
* hasAvailableMessage()
returns a boolean indicating
* whether there is an available message.
* doRemove()
removes a message from the buffer.
* - etc.
*
*
* Moreover developers must use the incrementAvailableMessagesCount
* and incrementStoredMessagesCount
methods to increment
* indicators on stored messages, available messages and available space.
*
* Note: the add
and remove
methods should
* not be overridden.
*/
@DreamComponent()
public abstract class AbstractBuffer
implements
BufferAdd,
BufferRemove,
BufferMonitoring
{
// ------------------------------------------------------------------------
// Client interfaces
// ------------------------------------------------------------------------
/**
* Can be used by subclasses to create aggregated messages in {@link
* BufferRemove#removeAll()}.
*/
@Requires(name = "message-manager")
protected MessageManagerType messageManagerItf;
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
/**
* The maximal capacity of the buffer.
*/
@Attribute(argument = "maxCapacity")
protected int maxCapacity = 0;
// ------------------------------------------------------------------------
// Fields
// ------------------------------------------------------------------------
/**
* The lock object.
*/
protected final Object lock = new Object();
/**
* The count of available messages in the buffer. This attribute should only
* be updated using the {@link #incrementAvailableMessagesCount(int)}method.
*/
protected int availableMessagesCount = 0;
/**
* The count of stored messages into the buffer. This attribute should only be
* updated using the {@link #incrementStoredMessagesCount(int)}method.
*/
protected int storedMessagesCount = 0;
// ------------------------------------------------------------------------
// Implementation of the BufferAdd interface
// ------------------------------------------------------------------------
/**
* @see BufferAdd#add(Message)
*/
public final void add(Message message) throws InterruptedException
{
synchronized (lock)
{
while (!canAdd(message))
{
lock.wait();
}
doAdd(message);
lock.notifyAll();
}
}
/**
* @see BufferAdd#tryAdd(Message)
*/
public boolean tryAdd(Message message)
{
synchronized (lock)
{
if (canAdd(message))
{
doAdd(message);
lock.notifyAll();
return true;
}
return false;
}
}
// ------------------------------------------------------------------------
// Implementation of the BufferRemove interface
// ------------------------------------------------------------------------
/**
* @see BufferRemove#remove()
*/
public final Message remove() throws InterruptedException
{
synchronized (lock)
{
while (!hasAvailableMessage())
{
lock.wait();
}
final Message m = doRemove();
lock.notifyAll();
return m;
}
}
/**
* @see BufferRemove#tryRemove()
*/
public Message tryRemove()
{
synchronized (lock)
{
if (hasAvailableMessage())
{
final Message m = doRemove();
lock.notifyAll();
return m;
}
return null;
}
}
/**
* @see BufferRemove#get()
*/
public Message get() throws InterruptedException
{
synchronized (lock)
{
while (!hasAvailableMessage())
{
lock.wait();
}
final Message m = doGet();
return m;
}
}
/**
* @see BufferRemove#tryGet()
*/
public Message tryGet()
{
synchronized (lock)
{
if (hasAvailableMessage())
{
final Message m = doGet();
return m;
}
return null;
}
}
/**
* @see BufferRemove#removeAll()
*/
public Message removeAll()
{
synchronized (lock)
{
final Message m = doRemoveAll();
lock.notifyAll();
return m;
}
}
// ------------------------------------------------------------------------
// Methods that must be implemented by concrete sub classes.
// ------------------------------------------------------------------------
/**
* Adds a message to the buffer. This method should not check if there is
* enough available space provided it has already been done in the
* {@link #add}method. The {@link #lock lock}has been acquired when this
* method is called.
*
* @param message the message to be added.
*/
protected abstract void doAdd(Message message);
/**
* Removes a message from the buffer. This method should not check if there is
* a message available provided it has already been done in the
* {@link #remove}method. The {@link #lock lock}has been acquired when this
* method is called.
*
* @return a message.
*/
protected abstract Message doRemove();
/**
* Removes all the messages stored into the buffer. The {@link #lock lock}has
* been acquired when this method is called.
*
* @return an aggregated message.
*/
protected abstract Message doRemoveAll();
/**
* Gets a message from the buffer. This method should not check if there is a
* message available provided it has already been done in the {@link #get}
* method. The {@link #lock lock}has been acquired when this method is
* called.
*
* @return a message.
*/
protected abstract Message doGet();
// ------------------------------------------------------------------------
// Methods that may be overridden by concrete sub classes.
// ------------------------------------------------------------------------
/**
* Checks whether the given message can be added into the buffer. The
* {@link #lock lock}has been acquired when this method is called.
*
* @param message the message to be tested.
* @return true
if the message can be added.
*/
protected boolean canAdd(Message message)
{
if (maxCapacity > 0 && (maxCapacity - storedMessagesCount <= 0))
{
return false;
}
return true;
}
/**
* Checks whether there is a message available to get or remove.
*
* @return true
if there is an available message.
*/
public boolean hasAvailableMessage()
{
return (availableMessagesCount > 0);
}
// ------------------------------------------------------------------------
// Utility methods.
// ------------------------------------------------------------------------
protected int availableSpace()
{
if (maxCapacity <= 0)
{
return Integer.MAX_VALUE;
}
return maxCapacity - storedMessagesCount;
}
/**
* Increments the count of available messages. When calling this method, the
* {@link #lock lock}must have already been acquired.
*
* @param delta the value that must be added to the previous count.
*/
protected void incrementAvailableMessagesCount(int delta)
{
availableMessagesCount += delta;
/*
* It is assumed that the locked has already been acquired.
*/
lock.notifyAll();
}
/**
* Increments the count of stored messages. When calling this method, the
* {@link #lock lock}must have already been acquired.
*
* @param delta the value that must be added to previous indicator.
*/
protected void incrementStoredMessagesCount(int delta)
{
storedMessagesCount += delta;
/*
* It is assumed that the locked has already been acquired.
*/
lock.notifyAll();
}
// ------------------------------------------------------------------------
// Overriding of the AttributeController interface
// generated by fraclet
// ------------------------------------------------------------------------
/**
* BufferMonitoring#setMaxCapacity(int)
*/
public void setMaxCapacity(int maxCapacity)
{
synchronized (lock)
{
int previousCapacity = this.maxCapacity;
this.maxCapacity = maxCapacity;
if (maxCapacity > previousCapacity)
{
lock.notifyAll();
}
}
}
// ------------------------------------------------------------------------
// Implementation of the BufferMonitoring interface.
// ------------------------------------------------------------------------
/**
* @see BufferMonitoring#getCurrentSize()
*/
public int getCurrentSize()
{
return storedMessagesCount;
}
}