All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.objectweb.dream.queue.buffer.BufferMatching 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): Romain Lenglet
 * Contributor(s):
 */

package org.objectweb.dream.queue.buffer;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.objectweb.dream.message.Message;
import org.objectweb.dream.queue.MessageMatcher;
import org.objectweb.dream.dreamannotation.DreamComponent;
import org.objectweb.fractal.fraclet.annotation.annotations.Requires;

/**
 * A buffer in which stored messages are available  to {@link #get() get}
 * or {@link #remove() remove} only if they are {@link
 * MessageMatcher#acceptMessage(Message) accepted} by the {@link MessageMatcher
 * message matcher} bound to this component. 

If the availability criteria of * the message matcher are modified while {@link #get()} calls and/or * {@link #remove()} calls are blocked waiting for available messages, and the * message matcher criteria modification would let them return messages, the * blocked calls can be unblocked by calling {@link #tryGet()} after the message * matcher has been modified. */ @DreamComponent(controllerDesc = "dreamUnstoppablePrimitive") public class BufferMatching extends AbstractBuffer { // FIXME: how to get or remove unmatched messages? // FIXME: if we don't do anything, the unmatched messages remain in the // buffer infinitely and may overflow the buffer! // FIXME: refactor the commented 'remove' method // ------------------------------------------------------------------------ // Client interface // ------------------------------------------------------------------------ /** * The message matcher that is used to select the messages that can be * returned by calls to {@link #get()}, {@link #tryGet()}, {@link #remove()}, * {@link #tryRemove()} and {@link #removeAll()}. This is the client * interface named "message-matcher". */ @Requires(name = MessageMatcher.ITF_NAME) protected MessageMatcher messageMatcherItf; // ------------------------------------------------------------------------ // Fields // ------------------------------------------------------------------------ /** * The messages stored in this buffer, in adding order (FIFO). */ protected LinkedList messages = new LinkedList(); /** * Messages that have matched {@link #messageMatcherItf} and that are ready to * be returned. The messages are in adding order (FIFO). */ protected LinkedList messagesToBeReturned = new LinkedList(); /** * The number of calls that are waiting to remove matching messages. */ protected int removersCount = 0; /** * The number of calls that are waiting to get (not remove) matching messages. */ protected int gettersCount = 0; // --------------------------------------------------------------------------- // Implementation of the AbstractBuffer methods. // --------------------------------------------------------------------------- protected void doAdd(Message message) { messages.add(message); incrementStoredMessagesCount(1); searchMessagesToBeReturned(); } // /** // * @see BufferRemove#remove() // */ // public Message remove() throws InterruptedException // { // synchronized (lock) // { // removersCount++; // Message message = null; // try // { // message = super.remove(); // } // catch (InterruptedException e) // { // throw e; // } // finally // { // removersCount--; // } // return message; // } // } protected Message doRemove() { Message message = messagesToBeReturned.remove(0); incrementStoredMessagesCount(-1); incrementAvailableMessagesCount(-1); return message; } protected Message doRemoveAll() { Message aggregatedMessage = null; /* First, remove all already available messages. */ Iterator messagesIterator = messagesToBeReturned.iterator(); while (messagesIterator.hasNext()) { Message message = (Message) messagesIterator.next(); if (aggregatedMessage == null) { aggregatedMessage = messageManagerItf.createMessage(); } messageManagerItf.addSubMessage(aggregatedMessage, message); messagesIterator.remove(); } /* Now look into stored messages for messages that may now match. */ messagesIterator = messages.iterator(); while (messagesIterator.hasNext()) { Message message = (Message) messagesIterator.next(); if (messageMatcherItf.acceptMessage(message)) { if (aggregatedMessage == null) { aggregatedMessage = messageManagerItf.createMessage(); } messageManagerItf.addSubMessage(aggregatedMessage, message); messagesIterator.remove(); } } availableMessagesCount = 0; storedMessagesCount = messages.size(); return aggregatedMessage; } /** * @see BufferRemove#get() */ public Message get() throws InterruptedException { synchronized (lock) { gettersCount++; Message message = null; try { message = super.get(); } catch (InterruptedException e) { throw e; } finally { gettersCount--; } return message; } } protected Message doGet() { Message message = messagesToBeReturned.getFirst(); /* * Notify any remover that may be waiting for the message that we are going * to return, so that it can remove it. */ searchMessagesToBeReturned(); return message; } public boolean hasAvailableMessage() { /* * Retry an iteration over the messages, in case the matching criteria have * changed. Maybe messages will be matched this time. */ searchMessagesToBeReturned(); return super.hasAvailableMessage(); } // --------------------------------------------------------------------------- // Utility methods. // --------------------------------------------------------------------------- /** * If there are waiting removers (i.e., if {@link #removersCount} * > 0 * or if {@link #gettersCount} > 0), iterate over * {@link #messages the received messages}, and test each message by calling * {@link MessageMatcher#acceptMessage(Message)} using * {@link #messageMatcherItf the bound matcher}, until at most enough matching * messages for waiting removers and getters have been found. The matching * messages are put in the same order into {@link #messagesToBeReturned}, * then removers are notified. The {@link #lock lock} has been acquired when * this method is called. */ protected void searchMessagesToBeReturned() { /* Local variable copy of attribute, for optimization. */ int localRemoversCount = removersCount; /* We need at least one message for all getters. */ boolean thereAreGetters = (gettersCount > 0); /* * If there are no waiting getters or removers, no need to search for * messages. */ if ((!thereAreGetters) || (localRemoversCount < 1)) { return; } /* Local variable copy of attribute, for optimization. */ List localMessagesToBeReturned = messagesToBeReturned; int messagesToMatchCount = (thereAreGetters ? 1 : 0) + localRemoversCount - localMessagesToBeReturned.size(); /* * If there are already enough messages selected for all waiting removers, * do nothing. Simply notify them. Otherwise, iterate over the list of * received messages, and select enough matching messages. */ if (messagesToMatchCount > 0) { /* Local variable copy of attribute, for optimization. */ MessageMatcher localMessageMatcher = messageMatcherItf; Iterator messagesIterator = messages.iterator(); while ((messagesToMatchCount > 0) && messagesIterator.hasNext()) { Message message = messagesIterator.next(); /* * If the message matches, transfer it from the list of received * messages to the list of messages ready to be returned. */ if (localMessageMatcher.acceptMessage(message)) { messagesToMatchCount--; localMessagesToBeReturned.add(message); messagesIterator.remove(); incrementAvailableMessagesCount(1); } } } /* * Notify waiting removers if there are messages ready to be returned. */ if (!localMessagesToBeReturned.isEmpty()) { lock.notifyAll(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy