Package net.timewalker.ffmq3.local.destination

Source Code of net.timewalker.ffmq3.local.destination.LocalTopic

/*
* This file is part of FFMQ.
*
* FFMQ 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.
*
* FFMQ 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 FFMQ; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/
package net.timewalker.ffmq3.local.destination;

import java.util.Hashtable;
import java.util.Map;
import java.util.Set;

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Topic;

import net.timewalker.ffmq3.FFMQException;
import net.timewalker.ffmq3.common.message.AbstractMessage;
import net.timewalker.ffmq3.common.message.MessageSelector;
import net.timewalker.ffmq3.local.destination.subscription.LocalTopicSubscription;
import net.timewalker.ffmq3.local.session.LocalMessageConsumer;
import net.timewalker.ffmq3.local.session.LocalSession;
import net.timewalker.ffmq3.management.destination.definition.TopicDefinition;
import net.timewalker.ffmq3.storage.message.MessageSerializationLevel;
import net.timewalker.ffmq3.utils.ErrorTools;
import net.timewalker.ffmq3.utils.concurrent.CopyOnWriteList;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* <p>Implementation for a local JMS {@link Topic}</p>
*/
public final class LocalTopic extends AbstractLocalDestination implements Topic, LocalTopicMBean
{   
    private static final Log log = LogFactory.getLog(LocalTopic.class);
   
    // Definition
    private TopicDefinition topicDef;
   
    // Subscribers map
    private CopyOnWriteList subscriptions = new CopyOnWriteList();
    private Map subscriptionMap = new Hashtable();
   
    // Stats
    private volatile long sentToTopicCount = 0;
    private volatile long dispatchedFromTopicCount = 0;
   
    /**
     * Constructor
     */
    public LocalTopic( TopicDefinition topicDef )
    {
        super(topicDef);
        this.topicDef = topicDef;
    }
       
    /**
     * Get the queue definition
     */
    public TopicDefinition getDefinition()
    {
        return topicDef;
    }
   
    /*
     * (non-Javadoc)
     * @see javax.jms.Topic#getTopicName()
     */
    public String getTopicName()
    {
        return getName();
    }
   
    /* (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.AbstractLocalDestination#registerConsumer(net.timewalker.ffmq3.local.session.LocalMessageConsumer)
     */
    public void registerConsumer(LocalMessageConsumer consumer)
    {
        super.registerConsumer(consumer);
        synchronized (subscriptionMap)
    {
          LocalTopicSubscription subscription = new LocalTopicSubscription(consumer);
          subscriptions.add(subscription);
          subscriptionMap.put(consumer.getSubscriberId(),subscription);
    }
    }

    /* (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.AbstractLocalDestination#unregisterConsumer(net.timewalker.ffmq3.local.session.LocalMessageConsumer)
     */
    public void unregisterConsumer(LocalMessageConsumer consumer)
    {
        super.unregisterConsumer(consumer);
        if (!consumer.isDurable())
        {
            log.debug("Removing non-durable subscription "+consumer.getSubscriberId());
            synchronized (subscriptionMap)
        {
              LocalTopicSubscription subscription = (LocalTopicSubscription)subscriptionMap.remove(consumer.getSubscriberId());
              if (subscription != null)
                subscriptions.remove(subscription);
        }
        }
    }

    /**
     * Unsubscribe all durable consumers for a given client ID and subscription name
     */
    public void unsubscribe( String clientID , String subscriptionName  ) throws JMSException
    {
      String subscriberID = clientID+"-"+subscriptionName;
     
      LocalTopicSubscription subscription = (LocalTopicSubscription)subscriptionMap.get(subscriberID);
      if (subscription == null)
        return;
     
      if (isConsumerRegistered(subscriberID))
        throw new FFMQException("Subscription "+subscriptionName+" is still in use","SUBSCRIPTION_STILL_IN_USE");
       
      synchronized (subscriptionMap)
    {
          subscriptionMap.remove(subscriberID);
           subscriptions.remove(subscription);
    }
    }
   
    /**
     * Put a message in the topic.
     * Message copies are immediately delivered to all consumers.
     */
    public void put( AbstractMessage srcMessage, LocalSession session , Set committables ) throws JMSException
    {
      checkNotClosed();
   
      // Check delivery mode
      if (!topicDef.supportDeliveryMode(srcMessage.getJMSDeliveryMode()))
        throw new FFMQException("Topic does not support this delivery mode : "+
            (srcMessage.getJMSDeliveryMode() == DeliveryMode.NON_PERSISTENT ?
                    "DeliveryMode.NON_PERSISTENT" : "DeliveryMode.PERSISTENT"),
                    "INVALID_DELIVERY_MODE");
     
        String connectionID = session.getConnection().getId();
       
        CopyOnWriteList subscriptionsSnapshot;
        synchronized (subscriptionMap)
        {
          sentToTopicCount++;
          if (subscriptions.isEmpty())
            return;
         
          subscriptionsSnapshot = subscriptions.fastCopy();
        }
       
        for (int i = 0; i < subscriptionsSnapshot.size(); i++)
    {
        LocalTopicSubscription subscription = (LocalTopicSubscription)subscriptionsSnapshot.get(i);
           
            // No-local filtering
            if (subscription.getNoLocal() && subscription.getConnectionID().equals(connectionID))
                continue;

            try
            {
                // Message selector filtering
                MessageSelector selector = subscription.getMessageSelector();
                if (selector != null)
                {
                  srcMessage.ensureDeserializationLevel(MessageSerializationLevel.ALL_HEADERS);
                  if (!selector.matches(srcMessage))
                    continue;
                }
               
              if (subscription.getLocalQueue().put(srcMessage))
              {
                // Only require a commit if the subscription is declared as durable
                if (committables != null && subscription.isDurable())
                  committables.add(subscription.getLocalQueue());
              }
             
              dispatchedFromTopicCount++;
            }
            catch (JMSException e)
            {
              ErrorTools.log(e, log);
            }
        }
    }
   
    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.LocalDestinationMBean#getSize()
     */
    public int getSize()
    {
      int size = 0;
      synchronized (subscriptionMap)
        {
        for (int i = 0; i < subscriptions.size(); i++)
        {
            LocalTopicSubscription subscription = (LocalTopicSubscription)subscriptions.get(i);
                size += subscription.getLocalQueue().getSize();
            }
        }
      return size;
    }
   
    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.LocalDestinationMBean#resetStats()
     */
    public void resetStats()
    {
      sentToTopicCount = 0;
      dispatchedFromTopicCount = 0;
    }
   
    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.LocalTopicMBean#getSentToTopicCount()
     */
    public long getSentToTopicCount()
    {
        return sentToTopicCount;
    }

    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.LocalTopicMBean#getDispatchedFromTopicCount()
     */
    public long getDispatchedFromTopicCount()
    {
        return dispatchedFromTopicCount;
    }

    /*
     *  (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    public String toString()
    {
       StringBuffer sb = new StringBuffer();
      
       sb.append("Topic{");
       sb.append(getName());
       sb.append("}[size=");
       sb.append(getSize());
       sb.append(",consumers=");
       sb.append(localConsumers.size());
       sb.append(",in=");
       sb.append(sentToTopicCount);
       sb.append(",out=");
       sb.append(dispatchedFromTopicCount);
       sb.append("]");

       return sb.toString();
    }

    public String getConsumersSummary()
    {
        StringBuffer sb = new StringBuffer();
       
        synchronized (subscriptionMap)
        {
            for (int i = 0; i < subscriptions.size(); i++)
            {
                LocalTopicSubscription subscription = (LocalTopicSubscription)subscriptions.get(i);
               
                if (i>0)
                    sb.append("\n");
                sb.append(subscription);
            }
        }
       
        return sb.toString();
    }
   
    /*
     * (non-Javadoc)
     * @see net.timewalker.ffmq3.local.destination.AbstractLocalDestination#close()
     */
    public final void close() throws JMSException
    {
      synchronized (closeLock)
    {
        if (closed)
          return;
        closed = true;
    }
    }
}
TOP

Related Classes of net.timewalker.ffmq3.local.destination.LocalTopic

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.