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

org.objectweb.dream.queue.keyed.buffer.BufferAscendingKeyKeyChunkAddDoubleKeyedRemove 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.keyed.buffer;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

import org.objectweb.dream.message.AbstractChunk;
import org.objectweb.dream.message.Message;
import org.objectweb.dream.message.MessageManagerType;
import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.fraclet.annotation.annotations.Attribute;
import org.objectweb.fractal.fraclet.annotation.annotations.Service;
import org.objectweb.dream.dreamannotation.DreamComponent;
import org.objectweb.dream.dreamannotation.DreamMonolog;
import org.objectweb.fractal.fraclet.annotation.annotations.Requires;
import org.objectweb.util.monolog.api.Logger;

/**
 * This buffer stores every incoming message according to
 * 
    *
  • a key (keyChunk) that is contained in the message as a * {@link AbstractChunk} which name can be specified as a Fractal component * attribute using the * {@link org.objectweb.dream.queue.keyed.buffer.BufferAttributeControllerKeyChunkAdd} * interface. This method is used when adding the message using the * {@link #add(Message, Object)} method.
  • *
  • a key (key) that is explicitely passed as a parameter, * when adding the message using the {@link #add(Message, Object)} method.
  • *
* Messages can then be removed from the buffer using the * {@link #remove(Object, Object)} method. This method returns the message with * the highest key for the specified keyChunk key. */ @DreamComponent(controllerDesc = "dreamUnstoppablePrimitive") public class BufferAscendingKeyKeyChunkAddDoubleKeyedRemove implements KeyedBufferAdd, DoubleKeyedBufferRemove, BufferMonitoringKeyed { // ------------------------------------------------------------------------ // Client interfaces. // ------------------------------------------------------------------------ /** * Can be used by subclasses to create aggregated messages in {@link * DoubleKeyedBufferRemove#removeAll()}. */ @Requires(name = "message-manager") protected MessageManagerType messageManagerItf; // -------------------------------------------------------------------------- // Services interfaces // -------------------------------------------------------------------------- /** * Component reference */ @Service Component weaveableC; /** * Logger of the component */ @DreamMonolog() protected Logger logger; // ------------------------------------------------------------------------ // Attributes. // ------------------------------------------------------------------------ /** * The maximal capacity of the buffer. */ @Attribute(argument = "maxCapacity") protected int maxCapacity = 0; /** * The count of stored messages into the buffer. This attribute should only be * updated using the {@link #incrementStoredMessagesCount(int, Object)} * method. */ protected int storedMessagesCount = 0; @Attribute(argument = "keyChunkName") protected String keyChunkName = "key-chunk"; // ------------------------------------------------------------------------ // Fields. // ------------------------------------------------------------------------ /** * Used to sort the messages according to the key stored in each message as a * {@link AbstractChunk chunk}. */ protected Map> queue = new HashMap>(); /** * The lock object. */ protected final Object lock = new Object(); // ------------------------------------------------------------------------ // Implementation of the KeyedBufferAdd method. // ------------------------------------------------------------------------ /** * @see KeyedBufferAdd#add(Message, Object) */ public void add(Message message, Object key) throws InterruptedException { synchronized (lock) { while (!canAdd(message)) { lock.wait(); } doAdd(message, key); lock.notifyAll(); } } /** * @see KeyedBufferAdd#tryAdd(Message, Object) */ public boolean tryAdd(Message message, Object key) { synchronized (lock) { if (canAdd(message)) { doAdd(message, key); lock.notifyAll(); return true; } return false; } } // ------------------------------------------------------------------------ // Implementation of the DoubleKeyedBufferRemove method. // ------------------------------------------------------------------------ /** * @see DoubleKeyedBufferRemove#remove(Object, Object) */ public Message remove(Object key1, Object key2) throws InterruptedException { synchronized (lock) { Message message = null; while (message == null) { message = doRemove(key1, key2); if (message == null) { lock.wait(); } } return message; } } /** * @see DoubleKeyedBufferRemove#tryRemove(Object, Object) */ public Message tryRemove(Object key1, Object key2) { synchronized (lock) { Message message = doRemove(key1, key2); return message; } } /** * @see DoubleKeyedBufferRemove#get(Object, Object) */ public Message get(Object key1, Object key2) throws InterruptedException { synchronized (lock) { Message message = null; while (message == null) { message = doGet(key1, key2); if (message == null) { lock.wait(); } } return message; } } /** * @see DoubleKeyedBufferRemove#tryGet(Object, Object) */ public Message tryGet(Object key1, Object key2) { synchronized (lock) { Message message = doGet(key1, key2); return message; } } /** * @see DoubleKeyedBufferRemove#removeAll(Object) */ public Message removeAll(Object key) { throw new UnsupportedOperationException(); } /** * @see DoubleKeyedBufferRemove#removeAll() */ public Message removeAll() { throw new UnsupportedOperationException(); } // ------------------------------------------------------------------------ // 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; } // ------------------------------------------------------------------------ // Utility methods. // ------------------------------------------------------------------------ @SuppressWarnings("unchecked") protected void doAdd(Message message, Object key) { AbstractChunk keyChunk = messageManagerItf.getChunk(message, keyChunkName); TreeMap msgsReceivedFromKey = queue.get(keyChunk); if (msgsReceivedFromKey == null) { msgsReceivedFromKey = new TreeMap(); AbstractChunk clone = messageManagerItf.cloneChunk(keyChunk); queue.put(clone, msgsReceivedFromKey); } if (msgsReceivedFromKey.put(key, message) == null) { incrementStoredMessagesCount(1, key); } } private Message doGet(Object key1, Object key2) { Message message = null; TreeMap msgsReceivedFromKey = queue.get(key1); if (msgsReceivedFromKey != null) { if (key2 == null) { message = msgsReceivedFromKey.get(msgsReceivedFromKey.lastKey()); } else { message = msgsReceivedFromKey.get(key2); } } return message; } private Message doRemove(Object key1, Object key2) { Message message = null; TreeMap msgsReceivedFromKey = queue.get(key1); if (msgsReceivedFromKey != null) { if (key2 == null) { message = msgsReceivedFromKey.remove(msgsReceivedFromKey.lastKey()); } else { message = msgsReceivedFromKey.remove(key2); } } if (message != null) { incrementStoredMessagesCount(-1, msgsReceivedFromKey); } return message; } protected int availableSpace() { if (maxCapacity <= 0) { return Integer.MAX_VALUE; } return maxCapacity - storedMessagesCount; } /** * 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, Object key) { storedMessagesCount += delta; /* * It is assumed that the locked has already been acquired. */ lock.notifyAll(); } // ------------------------------------------------------------------------ // Overriding of the BufferAttributeController interface // generated by fraclet // ------------------------------------------------------------------------ /** * Overriding of the BufferAttributeController interface generated by fraclet. * Synchronized implementation */ public void setMaxCapacity(int maxCapacity) { synchronized (lock) { int previousCapacity = this.maxCapacity; this.maxCapacity = maxCapacity; if (maxCapacity > previousCapacity) { lock.notifyAll(); } } } // ------------------------------------------------------------------------ // Implementation of the BufferMonitoringKeyed interface. // ------------------------------------------------------------------------ /** * @see org.objectweb.dream.queue.buffer.BufferMonitoring#getCurrentSize() */ public int getCurrentSize() { return storedMessagesCount; } /** * @see org.objectweb.dream.queue.keyed.buffer.BufferMonitoringKeyed#getKeys() */ public Object[] getKeys() { synchronized (lock) { return queue.keySet().toArray(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy