Package org.codehaus.activemq.service.boundedvm

Source Code of org.codehaus.activemq.service.boundedvm.TransientQueueBoundedMessageManager

/**
*
* Copyright 2004 Protique Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**/

package org.codehaus.activemq.service.boundedvm;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.jms.Destination;
import javax.jms.JMSException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.activemq.broker.BrokerClient;
import org.codehaus.activemq.filter.AndFilter;
import org.codehaus.activemq.filter.DestinationMap;
import org.codehaus.activemq.filter.Filter;
import org.codehaus.activemq.filter.FilterFactory;
import org.codehaus.activemq.filter.FilterFactoryImpl;
import org.codehaus.activemq.filter.NoLocalFilter;
import org.codehaus.activemq.message.ActiveMQDestination;
import org.codehaus.activemq.message.ActiveMQMessage;
import org.codehaus.activemq.message.ConsumerInfo;
import org.codehaus.activemq.message.MessageAck;
import org.codehaus.activemq.message.util.MemoryBoundedQueue;
import org.codehaus.activemq.message.util.MemoryBoundedQueueManager;
import org.codehaus.activemq.service.MessageContainer;
import org.codehaus.activemq.service.MessageContainerManager;
import org.codehaus.activemq.service.impl.DispatcherImpl;
import org.codehaus.activemq.service.impl.MessageContainerManagerSupport;
import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;

/**
* A MessageContainerManager for transient queues
*
* @version $Revision: 1.4 $
*/
/**
* A manager of MessageContainer instances
*/
public class TransientQueueBoundedMessageManager implements MessageContainerManager, Runnable {
    private static final int GARBAGE_COLLECTION_CAPACITY_LIMIT = 20;
    private static final Log log = LogFactory.getLog(TransientQueueBoundedMessageManager.class);
    private MemoryBoundedQueueManager queueManager;
    private ConcurrentHashMap containers;
    private ConcurrentHashMap subscriptions;
    private FilterFactory filterFactory;
    private SynchronizedBoolean started;
    private SynchronizedBoolean doingGarbageCollection;
    private Map destinations;
    private DestinationMap destinationMap;
    private Thread garbageCollectionThread;

    /**
     * Constructor for TransientQueueBoundedMessageManager
     *
     * @param mgr
     */
    public TransientQueueBoundedMessageManager(MemoryBoundedQueueManager mgr) {
        this.queueManager = mgr;
        this.containers = new ConcurrentHashMap();
        this.destinationMap = new DestinationMap();
        this.destinations = new ConcurrentHashMap();
        this.subscriptions = new ConcurrentHashMap();
        this.filterFactory = new FilterFactoryImpl();
        this.started = new SynchronizedBoolean(false);
        this.doingGarbageCollection = new SynchronizedBoolean(false);
    }

    /**
     * start the manager
     *
     * @throws JMSException
     */
    public void start() throws JMSException {
        if (started.commit(false, true)) {
            for (Iterator i = containers.values().iterator();i.hasNext();) {
                TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                container.start();
            }
            garbageCollectionThread = new Thread(this);
            garbageCollectionThread.setName("TQMCMGarbageCollector");
            garbageCollectionThread.start();
        }
    }

    /**
     * stop the manager
     *
     * @throws JMSException
     */
    public void stop() throws JMSException {
        if (started.commit(true, false)) {
            for (Iterator i = containers.values().iterator();i.hasNext();) {
                TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                container.stop();
            }
            if (garbageCollectionThread != null) {
                garbageCollectionThread.interrupt();
            }
        }
    }

    /**
     * collect expired messages
     */
    public void run() {
        while (started.get()) {
            doGarbageCollection();
            try {
                Thread.sleep(2000);
            }
            catch (InterruptedException e) {
            }
        }
    }

    /**
     * Add a consumer if appropiate
     *
     * @param client
     * @param info
     * @throws JMSException
     */
    public synchronized void addMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
        ActiveMQDestination destination = info.getDestination();
        if (destination.isQueue()) {
            TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) containers
                    .get(destination);
            if (container == null) {
                MemoryBoundedQueue queue = queueManager.getMemoryBoundedQueue(client.toString());
                container = new TransientQueueBoundedMessageContainer(queueManager, destination);
                addContainer(container);
                if (started.get()) {
                    container.start();
                }
            }
            TransientQueueSubscription ts = container.addConsumer(createFilter(info), info, client);
            if (ts != null) {
                subscriptions.put(info.getConsumerId(), ts);
            }
            String name = destination.getPhysicalName();
            if (!destinations.containsKey(name)) {
                destinations.put(name, destination);
            }
        }
    }

    /**
     * @param client
     * @param info
     * @throws JMSException
     */
    public synchronized void removeMessageConsumer(BrokerClient client, ConsumerInfo info) throws JMSException {
        ActiveMQDestination destination = info.getDestination();
        if (destination.isQueue()) {
            for (Iterator i = containers.values().iterator();i.hasNext();) {
                TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                if (container != null) {
                    container.removeConsumer(info);
                }
            }
            subscriptions.remove(info.getConsumerId());
        }
    }

    /**
     * Delete a durable subscriber
     *
     * @param clientId
     * @param subscriberName
     * @throws JMSException if the subscriber doesn't exist or is still active
     */
    public void deleteSubscription(String clientId, String subscriberName) throws JMSException {
    }

    /**
     * @param client
     * @param message
     * @throws JMSException
     */
    public void sendMessage(BrokerClient client, ActiveMQMessage message) throws JMSException {
        if (message != null && message.getJMSActiveMQDestination().isQueue() && (message.isTemporary())) {
            if (queueManager.getCurrentCapacity() <= GARBAGE_COLLECTION_CAPACITY_LIMIT) {
                doGarbageCollection();
            }
            Set set = destinationMap.get(message.getJMSActiveMQDestination());
            for (Iterator i = set.iterator();i.hasNext();) {
                TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                container.enqueue(message);
            }
        }
    }

    /**
     * @param client
     * @param ack
     * @throws JMSException
     */
    public void acknowledgeMessage(BrokerClient client, MessageAck ack) throws JMSException {
        TransientQueueSubscription ts = (TransientQueueSubscription) subscriptions.get(ack.getConsumerId());
        if (ts != null) {
            ActiveMQMessage message = ts.acknowledgeMessage(ack.getMessageID());
            if (message != null && !ack.isMessageRead()){
                message.setJMSRedelivered(true);
                Set set = destinationMap.get(message.getJMSActiveMQDestination());
                for (Iterator i = set.iterator();i.hasNext();) {
                    TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                    container.enqueueFirst(message);
                    break;
                }
            } 
        }
    }

    /**
     * @param client
     * @param transactionId
     * @param ack
     * @throws JMSException
     */
    public void acknowledgeTransactedMessage(BrokerClient client, String transactionId, MessageAck ack)
            throws JMSException {
    }

    /**
     * @param client
     * @param ack
     * @throws JMSException
     */
    public void redeliverMessage(BrokerClient client, MessageAck ack) throws JMSException {
        TransientQueueSubscription ts = (TransientQueueSubscription) subscriptions.get(ack.getConsumerId());
        if (ts != null) {
            ActiveMQMessage message = ts.acknowledgeMessage(ack.getMessageID());
            if (message != null){
                message.setJMSRedelivered(true);
                Set set = destinationMap.get(message.getJMSActiveMQDestination());
                for (Iterator i = set.iterator();i.hasNext();) {
                    TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                    container.enqueueFirst(message);
                    break;
                }
            } 
        }
    }

    /**
     * @throws JMSException
     */
    public void poll() throws JMSException {
    }

    /**
     * A hook when the transaction is about to be commited; so apply all outstanding commands to the Journal if using a
     * Journal (transaction log)
     *
     * @param client
     * @param transactionId
     * @throws JMSException
     */
    public void commitTransaction(BrokerClient client, String transactionId) throws JMSException {
    }

    /**
     * A hook when the transaction is about to be rolled back; so discard all outstanding commands that are pending to
     * be written to the Journal
     *
     * @param client
     * @param transactionId
     */
    public void rollbackTransaction(BrokerClient client, String transactionId) {
    }

    /**
     * @param physicalName
     * @return @throws JMSException
     */
    public MessageContainer getContainer(String physicalName) throws JMSException {
        Object key = destinations.get(physicalName);
        if (key != null) {
            return (MessageContainer) containers.get(key);
        }
        return null;
    }

    /**
     * @return a map of destinations
     */
    public Map getDestinations() {
        return Collections.unmodifiableMap(destinations);
    }

    /**
     * Create filter for a Consumer
     *
     * @param info
     * @return the Fitler
     * @throws javax.jms.JMSException
     */
    protected Filter createFilter(ConsumerInfo info) throws JMSException {
        Filter filter = filterFactory.createFilter(info.getDestination(), info.getSelector());
        if (info.isNoLocal()) {
            filter = new AndFilter(filter, new NoLocalFilter(info.getClientId()));
        }
        return filter;
    }

    private void doGarbageCollection() {
        if (doingGarbageCollection.commit(true, false)) {
            if (queueManager.getCurrentCapacity() <= GARBAGE_COLLECTION_CAPACITY_LIMIT) {
                for (Iterator i = containers.values().iterator();i.hasNext();) {
                    TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                    container.removeExpiredMessages();
                }
            }
            //if still below the limit - clear queues with no subscribers
            if (queueManager.getCurrentCapacity() <= GARBAGE_COLLECTION_CAPACITY_LIMIT) {
                for (Iterator i = containers.values().iterator();i.hasNext();) {
                    TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                    if (!container.hasActiveSubscribers()) {
                        container.clear();
                    }
                }
            }
            for (Iterator i = containers.values().iterator();i.hasNext();) {
                TransientQueueBoundedMessageContainer container = (TransientQueueBoundedMessageContainer) i.next();
                if (container.isInactive()) {
                    try {
                        container.close();
                        log.info("closed inactive transient queue container: " + container.getDestinationName());
                    }
                    catch (JMSException e) {
                        log.warn("failure closing container", e);
                    }
                    removeContainer(container);
                }
            }
            //now close any inactive queues
            doingGarbageCollection.set(false);
        }
    }

    private synchronized void addContainer(TransientQueueBoundedMessageContainer container) {
        containers.put(container.getDestination(), container);
        destinationMap.put(container.getDestination(), container);
    }

    private synchronized void removeContainer(TransientQueueBoundedMessageContainer container) {
        containers.remove(container.getDestination());
        destinationMap.remove(container.getDestination(), container);
    }

   
    protected Destination createDestination(String destinationName) {
        return null;
    }

    protected MessageContainer createContainer(String destinationName) throws JMSException {
        return null;
    }
}
TOP

Related Classes of org.codehaus.activemq.service.boundedvm.TransientQueueBoundedMessageManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.