/** 
 * 
 * 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.activemq.message;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import javax.jms.Topic;
import org.activemq.ActiveMQSession;
import org.activemq.filter.DestinationFilter;
import org.activemq.filter.DestinationPath;
import org.activemq.jndi.JNDIBaseStorable;
import org.activemq.management.JMSDestinationStats;

/**
 * A <CODE>Destination</CODE> object encapsulates a provider-specific
 * address.
 * The JMS API does not define a standard address syntax. Although a standard
 * address syntax was considered, it was decided that the differences in
 * address semantics between existing message-oriented middleware (MOM)
 * products were too wide to bridge with a single syntax.
 * <p/>
 * <P>Since <CODE>Destination</CODE> is an administered object, it may
 * contain
 * provider-specific configuration information in addition to its address.
 * <p/>
 * <P>The JMS API also supports a client's use of provider-specific address
 * names.
 * <p/>
 * <P><CODE>Destination</CODE> objects support concurrent use.
 * <p/>
 * <P>A <CODE>Destination</CODE> object is a JMS administered object.
 * <p/>
 * <P>JMS administered objects are objects containing configuration
 * information that are created by an administrator and later used by
 * JMS clients. They make it practical to administer the JMS API in the
 * enterprise.
 * <p/>
 * <P>Although the interfaces for administered objects do not explicitly
 * depend on the Java Naming and Directory Interface (JNDI) API, the JMS API
 * establishes the convention that JMS clients find administered objects by
 * looking them up in a JNDI namespace.
 * <p/>
 * <P>An administrator can place an administered object anywhere in a
 * namespace. The JMS API does not define a naming policy.
 * <p/>
 * <P>It is expected that JMS providers will provide the tools an
 * administrator needs to create and configure administered objects in a
 * JNDI namespace. JMS provider implementations of administered objects
 * should implement the <CODE>javax.naming.Referenceable</CODE> and
 * <CODE>java.io.Serializable</CODE> interfaces so that they can be stored in
 * all JNDI naming contexts. In addition, it is recommended that these
 * implementations follow the JavaBeans<SUP><FONT SIZE="-2">TM</FONT></SUP>
 * design patterns.
 * <p/>
 * <P>This strategy provides several benefits:
 * <p/>
 * <UL>
 * <LI>It hides provider-specific details from JMS clients.
 * <LI>It abstracts JMS administrative information into objects in the Java
 * programming language ("Java objects")
 * that are easily organized and administered from a common
 * management console.
 * <LI>Since there will be JNDI providers for all popular naming
 * services, JMS providers can deliver one implementation
 * of administered objects that will run everywhere.
 * </UL>
 * <p/>
 * <P>An administered object should not hold on to any remote resources.
 * Its lookup should not use remote resources other than those used by the
 * JNDI API itself.
 * <p/>
 * <P>Clients should think of administered objects as local Java objects.
 * Looking them up should not have any hidden side effects or use surprising
 * amounts of local resources.
 */

public abstract class ActiveMQDestination extends JNDIBaseStorable implements Destination, Comparable, Serializable {

    /**
     * Topic Destination object
     */
    public static final int ACTIVEMQ_TOPIC = 1;
    /**
     * Temporary Topic Destination object
     */
    public static final int ACTIVEMQ_TEMPORARY_TOPIC = 2;

    /**
     * Queue Destination object
     */
    public static final int ACTIVEMQ_QUEUE = 3;
    /**
     * Temporary Queue Destination object
     */
    public static final int ACTIVEMQ_TEMPORARY_QUEUE = 4;
    
    /**
     * prefix for Advisory message destinations
     */
    public static final String ADVISORY_PREFIX = "ActiveMQ.Advisory.";
    
    /**
     * prefix for connection advisory destinations
     */
    public static final String CONNECTION_ADVISORY_PREFIX = ADVISORY_PREFIX + "Connections.";
    
    /**
     * prefix for consumer advisory destinations
     * @deprecated Use {@see #getDestinationForConsumerAdvisory()} instead.
     */
    public static final String CONSUMER_ADVISORY_PREFIX = ADVISORY_PREFIX + "Consumers.";
    
    /**
     * prefix for producer advisory destinations
     * @deprecated Use {@see #getDestinationForProducerAdvisory()} instead.
     */
    public static final String PRODUCER_ADVISORY_PREFIX = ADVISORY_PREFIX + "Producers.";
    
    /**
     * prefix for connection advisory destinations
     * @deprecated Use {@see #getDestinationForTempAdvisory()} instead.
     */
    public static final String TEMP_DESTINATION_ADVISORY_PREFIX = ADVISORY_PREFIX + "TempDestinations.";
    
    /**
     * The default target for ordered destinations
     */
    public static final String DEFAULT_ORDERED_TARGET = "coordinator";

    private static final int NULL_DESTINATION = 10;

    private static final String TEMP_PREFIX = "{TD{";
    private static final String TEMP_POSTFIX = "}TD}";
    private static final String COMPOSITE_SEPARATOR = ",";
    
    private static final String QUEUE_PREFIX = "queue://";
    private static final String TOPIC_PREFIX = "topic://";    

    private String physicalName = "";

    // Cached transient data
    private transient DestinationFilter filter;
    private transient JMSDestinationStats stats;
    private transient String[] paths;
    // Used track consumers of temporary topics.
    private transient int consumerCounter;
    private transient boolean deleted;
    //additional for defining 'exotic' behaviour
    private boolean exclusive;
    private boolean ordered;
    private boolean advisory;
    private boolean wildcard;
    private boolean composite;
    private String  orderedTarget = DEFAULT_ORDERED_TARGET;
    //used client-side only
    private transient ActiveMQSession sessionCreatedBy;
    
    /**
     * @return Returns the orginatingSession.
     */
    public ActiveMQSession getSessionCreatedBy() {
        return sessionCreatedBy;
    }
    /**
     * @param orginatingSession The orginatingSession to set.
     */
    public void setSessionCreatedBy(ActiveMQSession orginatingSession) {
        this.sessionCreatedBy = orginatingSession;
    }
    /**
     * The Default Constructor
     */
    protected ActiveMQDestination() {
    }

    /**
     * Construct the ActiveMQDestination with a defined physical name;
     *
     * @param name
     */

    protected ActiveMQDestination(String name) {
        setPhysicalName(name);
    }

    /**
     * @return Returns the advisory.
     */
    public final boolean isAdvisory() {
        return advisory;
    }
    /**
     * @param advisory The advisory to set.
     */
    public final void setAdvisory(boolean advisory) {
        this.advisory = advisory;
    }
    
    /**
     * @return true if this is a destination for Consumer advisories
     */
    public boolean isConsumerAdvisory(){
        return isAdvisory() && physicalName.startsWith(ActiveMQDestination.CONSUMER_ADVISORY_PREFIX);
    }
    
    /**
     * @return true if this is a destination for Producer advisories
     */
    public boolean isProducerAdvisory(){
        return isAdvisory() && physicalName.startsWith(ActiveMQDestination.PRODUCER_ADVISORY_PREFIX);
    }
    
    /**
     * @return true if this is a destination for Connection advisories
     */
    public boolean isConnectionAdvisory(){
        return isAdvisory() && physicalName.startsWith(ActiveMQDestination.CONNECTION_ADVISORY_PREFIX);
    }
    
    /**
     * @return true if this a destination for Tempoary Destination advisories
     */
    public final boolean isTempDestinationAdvisory(){
        return advisory && physicalName.startsWith(ActiveMQDestination.TEMP_DESTINATION_ADVISORY_PREFIX);
    }
    
    /**
     * @return Returns the exclusive.
     */
    public final boolean isExclusive() {
        return exclusive;
    }
    /**
     * @param exclusive The exclusive to set.
     */
    public final void setExclusive(boolean exclusive) {
        this.exclusive = exclusive;
    }
    /**
     * @return Returns the ordered.
     */
    public final boolean isOrdered() {
        return ordered;
    }
    /**
     * @param ordered The ordered to set.
     */
    public final void setOrdered(boolean ordered) {
        this.ordered = ordered;
    }
    /**
     * @return Returns the orderedTarget.
     */
    public String getOrderedTarget() {
        return orderedTarget;
    }
    /**
     * @param orderedTarget The orderedTarget to set.
     */
    public void setOrderedTarget(String orderedTarget) {
        this.orderedTarget = orderedTarget;
    }
    /**
     * A helper method to return a descriptive string for the topic or queue
     * @param destination
     *
     * @return a descriptive string for this queue or topic
     */
    public static String inspect(Destination destination) {
        if (destination instanceof Topic) {
            return "Topic(" + destination.toString() + ")";
        }
        else {
            return "Queue(" + destination.toString() + ")";
        }
    }

    /**
     * @param destination
     * @return @throws JMSException
     * @throws javax.jms.JMSException
     */
    public static ActiveMQDestination transformDestination(Destination destination) throws JMSException {
        ActiveMQDestination result = null;
        if (destination != null) {
            if (destination instanceof ActiveMQDestination) {
                result = (ActiveMQDestination) destination;
            }
            else {
                if (destination instanceof TemporaryQueue) {
                    result = new ActiveMQTemporaryQueue(((Queue) destination).getQueueName());
                }
                else if (destination instanceof TemporaryTopic) {
                    result = new ActiveMQTemporaryTopic(((Topic) destination).getTopicName());
                }
                else if (destination instanceof Queue) {
                    result = new ActiveMQTemporaryQueue(((Queue) destination).getQueueName());
                }
                else if (destination instanceof Topic) {
                    result = new ActiveMQTemporaryTopic(((Topic) destination).getTopicName());
                }
            }
        }
        return result;
    }

    /**
     * Write an ActiveMQDestination to a Stream
     *
     * @param destination
     * @param dataOut
     * @throws IOException
     */

    public static void writeToStream(ActiveMQDestination destination, DataOutput dataOut) throws IOException {
        if (destination != null) {
            dataOut.writeByte(destination.getDestinationType());
            String physicalName = destination.getPhysicalName();
            boolean writeOrderedTarget = destination.orderedTarget != null && !destination.orderedTarget.equals(DEFAULT_ORDERED_TARGET);
            byte byte1 = 0;
            if (physicalName != null || physicalName.length() > 0) byte1 |= 1;
            if (destination.ordered) byte1 |= 2;
            if(destination.exclusive) byte1 |= 4;
            if (writeOrderedTarget) byte1 |= 8;
            if (destination.advisory) byte1 |= 16;
            if (destination.deleted) byte1 |= 32;
            if (destination.composite) byte1 |= 64;
            if (destination.wildcard) byte1 |= 128;
            dataOut.writeByte(byte1);
            if (physicalName != null || physicalName.length() > 0){
                dataOut.writeUTF(physicalName);
            }
            if (writeOrderedTarget){
                dataOut.writeUTF(destination.orderedTarget);
            }
        }
        else {
            dataOut.write(NULL_DESTINATION);
        }
    }

    /**
     * Read an ActiveMQDestination  from a Stream
     *
     * @param dataIn
     * @return the ActiveMQDestination
     * @throws IOException
     */

    public static ActiveMQDestination readFromStream(DataInput dataIn) throws IOException {

        int type = dataIn.readByte();
        if (type == NULL_DESTINATION) {
            return null;
        }
        ActiveMQDestination result = null;
        if (type == ACTIVEMQ_TOPIC) {
            result = new ActiveMQTopic();
        }
        else if (type == ACTIVEMQ_TEMPORARY_TOPIC) {
            result = new ActiveMQTemporaryTopic();
        }
        else if (type == ACTIVEMQ_QUEUE) {
            result = new ActiveMQQueue();
        }
        else {
            result = new ActiveMQTemporaryQueue();
        }
        byte byte1 = dataIn.readByte();
        if ((byte1 & 1) == 1){
            result.physicalName = dataIn.readUTF();
        }
        result.setOrdered((byte1 & 2) == 2);
        result.setExclusive((byte1 & 4) == 4);
        if ((byte1 & 8) == 8){
            result.setOrderedTarget(dataIn.readUTF());
        }
        result.advisory = (byte1 & 16)==16;
        result.deleted = (byte1 & 32)==32;
        result.composite = (byte1 & 64)==64;
        result.wildcard = (byte1 & 128)==128;
        return result;
    }
    
    /**
     * Create a Destination
     * @param type
     * @param pyhsicalName
     * @return
     */
    public static ActiveMQDestination createDestination(int type,String pyhsicalName){
        ActiveMQDestination result = null;
        if (type == ACTIVEMQ_TOPIC) {
            result = new ActiveMQTopic(pyhsicalName);
        }
        else if (type == ACTIVEMQ_TEMPORARY_TOPIC) {
            result = new ActiveMQTemporaryTopic(pyhsicalName);
        }
        else if (type == ACTIVEMQ_QUEUE) {
            result = new ActiveMQQueue(pyhsicalName);
        }
        else {
            result = new ActiveMQTemporaryQueue(pyhsicalName);
        }
        return result;
    }

    /**
     * Create a temporary name from the clientId
     *
     * @param clientId
     * @return
     */
    public static String createTemporaryName(String clientId) {
        return TEMP_PREFIX + clientId + TEMP_POSTFIX;
    }

    /**
     * From a temporary destination find the clientId of the Connection that created it
     *
     * @param destination
     * @return the clientId or null if not a temporary destination
     */
    public static String getClientId(ActiveMQDestination destination) {
        String answer = null;
        if (destination != null && destination.isTemporary()) {
            String name = destination.getPhysicalName();
            int start = name.indexOf(TEMP_PREFIX);
            if (start >= 0) {
                start += TEMP_PREFIX.length();
                int stop = name.lastIndexOf(TEMP_POSTFIX);
                if (stop > start && stop < name.length()) {
                    answer = name.substring(start, stop);
                }
            }
        }
        return answer;
    }


    /**
     * @param o object to compare
     * @return 1 if this > o else 0 if they are equal or -1 if this < o
     */
    public int compareTo(Object o) {
        if (o instanceof ActiveMQDestination) {
            return compareTo((ActiveMQDestination) o);
        }
        return -1;
    }

    /**
     * Lets sort by name first then lets sort topics greater than queues
     *
     * @param that another destination to compare against
     * @return 1 if this > that else 0 if they are equal or -1 if this < that
     */
    public int compareTo(ActiveMQDestination that) {
        int answer = 0;
        if (physicalName != that.physicalName) {
            if (physicalName == null) {
                return -1;
            }
            else if (that.physicalName == null) {
                return 1;
            }
            answer = physicalName.compareTo(that.physicalName);
        }
        if (answer == 0) {
            if (isTopic()) {
                if (that.isQueue()) {
                    return 1;
                }
            }
            else {
                if (that.isTopic()) {
                    return -1;
                }
            }
        }
        return answer;
    }


    /**
     * @return Returns the Destination type
     */

    public abstract int getDestinationType();


    /**
     * @return Returns the physicalName.
     */
    public String getPhysicalName() {
        return this.physicalName;
    }

    /**
     * @param name The physicalName to set.
     */
    public void setPhysicalName(String name) {
        this.physicalName = name;
        this.advisory = name != null && name.startsWith(ADVISORY_PREFIX);
        this.composite = name != null && name.indexOf(COMPOSITE_SEPARATOR) > 0;
        this.wildcard = name != null
                && (name.indexOf(DestinationFilter.ANY_CHILD) >= 0 || name.indexOf(DestinationFilter.ANY_DESCENDENT) >= 0);
    }

    /**
     * Returns true if a temporary Destination
     *
     * @return true/false
     */

    public boolean isTemporary() {
        return false;
    }

    /**
     * Returns true if a Topic Destination
     *
     * @return true/false
     */

    public boolean isTopic() {
        return true;
    }

    /**
     * Returns true if a Queue Destination
     *
     * @return true/false
     */
    public boolean isQueue() {
        return false;
    }

    /**
     * Returns true if this destination represents a collection of
     * destinations; allowing a set of destinations to be published to or subscribed
     * from in one JMS operation.
     * <p/>
     * If this destination is a composite then you can call {@link #getChildDestinations()}
     * to return the list of child destinations.
     *
     * @return true if this destination represents a collection of child destinations.
     */
    public final boolean isComposite() {
        return composite;
    }

    /**
     * Returns a list of child destinations if this destination represents a composite
     * destination.
     *
     * @return
     */
    public List getChildDestinations() {
        List answer = new ArrayList();
        StringTokenizer iter = new StringTokenizer(physicalName, COMPOSITE_SEPARATOR);
        while (iter.hasMoreTokens()) {
            String name = iter.nextToken();
            Destination child = null;
            if (name.startsWith(QUEUE_PREFIX)) {
                child = new ActiveMQQueue(name.substring(QUEUE_PREFIX.length()));
            }
            else if (name.startsWith(TOPIC_PREFIX)) {
                child = new ActiveMQTopic(name.substring(TOPIC_PREFIX.length()));
            }
            else {
                child = createDestination(name);
            }
            answer.add(child);
        }
        if (answer.size() == 1) {
            // lets put ourselves inside the collection
            // as we are not really a composite destination
            answer.set(0, this);
        }
        return answer;
    }
    
    public void setChildDestinations(ActiveMQDestination[] children) {
        if( children==null )
            throw new IllegalArgumentException("children array cannot be null.");
        if( children.length == 0 )
            throw new IllegalArgumentException("children array size must be 1 or greater.");
        
        StringBuffer rc = new StringBuffer();
        for (int i = 0; i < children.length; i++) {
            if(i!=0)
                rc.append(COMPOSITE_SEPARATOR);
            if( children[i].isTopic() ) {
                rc.append(TOPIC_PREFIX);
            } else if( children[i].isQueue() ) {
                rc.append(QUEUE_PREFIX);
            }
            rc.append(children[i].getPhysicalName());            
        }
        
        setPhysicalName(rc.toString());
    }

    /**
     * @return string representation of this instance
     */

    public String toString() {
        return this.physicalName;
    }

    /**
     * @return hashCode for this instance
     */

    public int hashCode() {
        int answer = 0xcafebabe;

        if (this.physicalName != null) {
            answer = physicalName.hashCode();
        }
        if (isTopic()) {
            answer ^= 0xfabfab;
        }
        return answer;
    }

    /**
     * if the object passed in is equivalent, return true
     *
     * @param obj the object to compare
     * @return true if this instance and obj are equivalent
     */

    public boolean equals(Object obj) {
        boolean result = this == obj;
        if (!result && obj != null && obj instanceof ActiveMQDestination) {
            ActiveMQDestination other = (ActiveMQDestination) obj;
            result = this.getDestinationType() == other.getDestinationType() &&
                    this.physicalName.equals(other.physicalName);
        }
        return result;
    }


    /**
     * @return true if the destination matches multiple possible destinations
     */
    public boolean isWildcard() {
        return wildcard;
    }

    /**
     * @param destination
     * @return  true if the given destination matches this destination; including wildcards
     */
    public boolean matches(ActiveMQDestination destination) {
        if (isWildcard()) {
            return getDestinationFilter().matches(destination);
        }
        else {
            return equals(destination);
        }
    }
    

    /**
     * @return the DestinationFilter
     */
    public DestinationFilter getDestinationFilter() {
        if (filter == null) {
            filter = DestinationFilter.parseFilter(this);
        }
        return filter;
    }

    /**
     * @return the associated paths associated with this Destination
     */
    public String[] getDestinationPaths() {
        if (paths == null) {
            paths = DestinationPath.getDestinationPaths(physicalName);
        }
        return paths;
    }

    /**
     * @return stats for this destination
     */
    public JMSDestinationStats getStats() {
        if (stats == null) {
            stats = createDestinationStats();
        }
        return stats;
    }


    /**
     * @param stats
     */
    public void setStats(JMSDestinationStats stats) {
        this.stats = stats;
    }

    /**
     * increment counter for number of interested consumers
     */
    synchronized public void incrementConsumerCounter() {
    	consumerCounter++;
    }

    /**
     * descrement counter for number interested consumers
     */
    synchronized public void decrementConsumerCounter() {
    	consumerCounter--;
    }
    
    /**
     * @return true if this destination is deleted
     */
    synchronized public boolean isDeleted() {
    	return deleted;
    }
    
    /**
     * det the deleted flag to the new value
     * @param value
     */
    synchronized public void setDeleted(boolean value){
        deleted = value;
    }
    
    /**
     * Used to Deletes a temporary destination. If there are existing consumers
     * still using it, a <CODE>JMSException</CODE> will be thrown.
     *
     * @throws JMSException if the JMS provider fails to delete the
     *                      temporary queue due to some internal error.
     */
    synchronized public void delete() throws JMSException {
        if (consumerCounter != 0) {
            throw new JMSException("A consumer is still using this temporary queue.");
        }
        if (sessionCreatedBy != null) {
            sessionCreatedBy.removeTemporaryDestination(this);
        }
        deleted = true;
    }    
    
    
    // Implementation methods
    //-------------------------------------------------------------------------


    /**
     * Factory method to create a child destination if this destination is a composite
     * @param name
     * @return the created Destination
     */
    protected abstract Destination createDestination(String name);

    /**
     * Factory method to create a statistics counter object
     *
     * @return
     */
    protected abstract JMSDestinationStats createDestinationStats();

    /**
     * Set the properties that will represent the instance in JNDI
     *
     * @param props
     */
    protected void buildFromProperties(Properties props) {
        this.physicalName = props.getProperty("physicalName", this.physicalName);

    }

    /**
     * Initialize the instance from properties stored in JNDI
     *
     * @param props
     */

    protected void populateProperties(Properties props) {
        props.put("physicalName", this.physicalName);
    }

    /**
     * @return the topic that is used for this destination's temporary destination advisories.
     */
    public ActiveMQTopic getTopicForTempAdvisory() {
        String destName = ActiveMQDestination.TEMP_DESTINATION_ADVISORY_PREFIX+getAdvisoryDestinationTypePrefix()+getPhysicalName();
        return new ActiveMQTopic(destName);
    }
    
    /**
     * @return the topic that is used for this destination's consumer advisories.
     */
    public ActiveMQTopic getTopicForConsumerAdvisory() {
        String destName = ActiveMQDestination.CONSUMER_ADVISORY_PREFIX+getAdvisoryDestinationTypePrefix()+getPhysicalName();
        return new ActiveMQTopic(destName);
    }
    
    /**
     * @return the topic that is used for this destination's producer advisories.
     */
    public ActiveMQTopic getTopicForProducerAdvisory() {
        String destName = ActiveMQDestination.PRODUCER_ADVISORY_PREFIX+getAdvisoryDestinationTypePrefix()+getPhysicalName();
        return new ActiveMQTopic(destName);
    }
    
    /**
     * @return null if this destination is not an advisory topic, else it returns the 
     * destination that the advisories are related.
     */
    public ActiveMQDestination getDestinationBeingAdvised() {
        if( isConnectionAdvisory() ) {
            return null;
        } else if( isConsumerAdvisory() ) {
            String matchName = physicalName.substring(ActiveMQDestination.CONSUMER_ADVISORY_PREFIX.length());            
            return createDestinationFromAdvisoryName(matchName);            
        } else if ( isProducerAdvisory() ) {
            String matchName = physicalName.substring(ActiveMQDestination.PRODUCER_ADVISORY_PREFIX.length());
            return createDestinationFromAdvisoryName(matchName);            
        } else if ( isTempDestinationAdvisory() ) {
            String matchName = physicalName.substring(ActiveMQDestination.TEMP_DESTINATION_ADVISORY_PREFIX.length());
            return createDestinationFromAdvisoryName(matchName);            
        }
        return null;
    }
    
    private String getAdvisoryDestinationTypePrefix() {
        switch( getDestinationType() ) {
            case ACTIVEMQ_TOPIC:
                return "topic.";
            case ACTIVEMQ_QUEUE:
                return "queue.";
            case ACTIVEMQ_TEMPORARY_TOPIC:            
                return "temp-topic.";
            case ACTIVEMQ_TEMPORARY_QUEUE:
                return "temp-queue.";
        }
        throw new RuntimeException("Invlaid destiantion type: "+getDestinationType());
    }
    
    /**
     * @param advisoryName
     * @return
     */
    private ActiveMQDestination createDestinationFromAdvisoryName(String advisoryName) {
        if( advisoryName.startsWith("topic.") ) {
            String name = advisoryName.substring("topic.".length());     
            return createDestination(ACTIVEMQ_TOPIC, name);
        } else if( advisoryName.startsWith("queue.") ) {
            String name = advisoryName.substring("queue.".length());            
            return createDestination(ACTIVEMQ_QUEUE, name);
        } else if( advisoryName.startsWith("temp-topic.") ) {
            String name = advisoryName.substring("temp-topic.".length());            
            return createDestination(ACTIVEMQ_TEMPORARY_TOPIC, name);
        } else if( advisoryName.startsWith("temp-queue.") ) {            
            String name = advisoryName.substring("temp-queue.".length());            
            return createDestination(ACTIVEMQ_TEMPORARY_QUEUE, name);
        } 
        return null;
    }
}
