You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ch...@apache.org on 2009/06/19 13:27:34 UTC

svn commit: r786459 - in /activemq/sandbox/activemq-flow: activemq-broker/src/main/java/org/apache/activemq/apollo/broker/ activemq-broker/src/main/java/org/apache/activemq/filter/ activemq-broker/src/test/java/org/apache/activemq/filter/ activemq-util...

Author: chirino
Date: Fri Jun 19 11:27:33 2009
New Revision: 786459

URL: http://svn.apache.org/viewvc?rev=786459&view=rev
Log:
ported the 5.x DestinationMap impl over.


Added:
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/AnyChildDestinationNode.java
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/CompositeDestinationFilter.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationFilter.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMap.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapEntry.java
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapNode.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationNode.java
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationPath.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/PrefixDestinationFilter.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/SimpleDestinationFilter.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/WildcardDestinationFilter.java   (with props)
    activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/
    activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java
    activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java
    activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTest.java   (with props)
Modified:
    activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/apollo/broker/Destination.java
    activemq/sandbox/activemq-flow/activemq-util/src/main/java/org/apache/activemq/protobuf/Buffer.java
    activemq/sandbox/activemq-flow/webgen/src/todo.page

Modified: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/apollo/broker/Destination.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/apollo/broker/Destination.java?rev=786459&r1=786458&r2=786459&view=diff
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/apollo/broker/Destination.java (original)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/apollo/broker/Destination.java Fri Jun 19 11:27:33 2009
@@ -75,17 +75,10 @@
             setDomain(new AsciiBuffer(domain));
         }
 
-        //        public ActiveMQDestination asActiveMQDestination() {
-        //            if(domain.equals(Router.TOPIC_DOMAIN))
-        //            {
-        //                return new ActiveMQTopic(name.toString());
-        //            }
-        //            else if(domain.equals(Router.QUEUE_DOMAIN))
-        //            {
-        //                return new ActiveMQQueue(name.toString());
-        //            }
-        //            return null;
-        //        }
+        @Override
+        public String toString() {
+        	return ""+domain+":"+name;
+        }
     }
 
     public class MultiDestination implements Destination {
@@ -117,11 +110,11 @@
         {
             destinations.remove(d);
         }
-
-        //        public ActiveMQDestination asActiveMQDestination() {
-        //            throw new UnsupportedOperationException("Not yet implemented");
-        //        }
-
+        
+        @Override
+        public String toString() {
+        	return destinations.toString();
+        }
     }
 
 }

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/AnyChildDestinationNode.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/AnyChildDestinationNode.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/AnyChildDestinationNode.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/AnyChildDestinationNode.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * An implementation of {@link DestinationNode} which navigates all the children of the given node
+ * ignoring the name of the current path (so for navigating using * in a wildcard).
+ *
+ * @version $Revision: 563921 $
+ */
+public class AnyChildDestinationNode<Value> implements DestinationNode<Value> {
+    private DestinationNode<Value> node;
+
+    public AnyChildDestinationNode(DestinationNode<Value> node) {
+        this.node = node;
+    }
+
+    public void appendMatchingValues(Set<Value> answer, String[] paths, int startIndex) {
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            child.appendMatchingValues(answer, paths, startIndex);
+        }
+    }
+
+
+    public void appendMatchingWildcards(Set<Value> answer, String[] paths, int startIndex) {
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            child.appendMatchingWildcards(answer, paths, startIndex);
+        }
+    }
+
+
+    public void appendDescendantValues(Set<Value> answer) {
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            child.appendDescendantValues(answer);
+        }
+    }
+
+    public DestinationNode<Value> getChild(String path) {
+        final Collection<DestinationNode<Value>> list = new ArrayList<DestinationNode<Value>>();
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            DestinationNode<Value> answer = child.getChild(path);
+            if (answer != null) {
+                list.add(answer);
+            }
+        }
+        if (!list.isEmpty()) {
+            return new AnyChildDestinationNode<Value>(this) {
+                protected Collection<DestinationNode<Value>> getChildNodes() {
+                    return list;
+                }
+            };
+        }
+        return null;
+    }
+
+    public Collection<Value> getDesendentValues() {
+        Collection<Value> answer = new ArrayList<Value>();
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            answer.addAll(child.getDesendentValues());
+        }
+        return answer;
+    }
+
+    public Collection<Value> getValues() {
+        Collection<Value> answer = new ArrayList<Value>();
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            answer.addAll(child.getValues());
+        }
+        return answer;
+    }
+
+
+    public Collection<DestinationNode<Value>> getChildren() {
+        Collection<DestinationNode<Value>>  answer = new ArrayList<DestinationNode<Value>> ();
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            answer.addAll(child.getChildren());
+        }
+        return answer;
+    }
+
+    public Collection<Value> removeDesendentValues() {
+        Collection<Value> answer = new ArrayList<Value>();
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            answer.addAll(child.removeDesendentValues());
+        }
+        return answer;
+    }
+
+    public Collection<Value> removeValues() {
+        Collection<Value> answer = new ArrayList<Value>();
+    	for (DestinationNode<Value> child : getChildNodes()) {
+            answer.addAll(child.removeValues());
+        }
+        return answer;
+    }
+
+    protected Collection<DestinationNode<Value>> getChildNodes() {
+        return node.getChildren();
+    }
+}
+
+

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/CompositeDestinationFilter.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/CompositeDestinationFilter.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/CompositeDestinationFilter.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/CompositeDestinationFilter.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.Collection;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+
+/**
+ * A {@link DestinationFilter} used for composite destinations
+ * 
+ * @version $Revision: 1.3 $
+ */
+public class CompositeDestinationFilter extends DestinationFilter {
+
+    private DestinationFilter filters[];
+
+    public CompositeDestinationFilter(Destination destination) {
+    	Collection<Destination> destinations = destination.getDestinations();
+        filters = new DestinationFilter[destinations.size()];
+        int i=0;
+    	for (Destination childDestination : destinations) {
+            filters[i++] = DestinationFilter.parseFilter(childDestination);
+		}
+    }
+
+    public boolean matches(Destination destination) throws FilterException {
+        for (int i = 0; i < filters.length; i++) {
+            if (filters[i].matches(destination)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isWildcard() {
+        return true;
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/CompositeDestinationFilter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationFilter.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationFilter.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationFilter.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationFilter.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.Collection;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+
+/**
+ * Represents a filter which only operates on Destinations
+ * 
+ * @version $Revision: 1.3 $
+ */
+public abstract class DestinationFilter implements BooleanExpression {
+
+    public static final String ANY_DESCENDENT = ">";
+    public static final String ANY_CHILD = "*";
+    
+	public boolean matches(MessageEvaluationContext message) throws FilterException {
+		Destination destination = message.getDestination();
+		return matches(destination);
+	}
+	public Object evaluate(MessageEvaluationContext message) throws FilterException {
+		return matches(message) ? Boolean.TRUE : Boolean.FALSE;
+	}
+	
+    public abstract boolean matches(Destination destination) throws FilterException;
+
+    public static DestinationFilter parseFilter(Destination destination) {
+    	Collection<Destination> destinations = destination.getDestinations();
+        if (destinations!=null) {
+            return new CompositeDestinationFilter(destination);
+        }
+        String[] paths = DestinationPath.getDestinationPaths(destination);
+        int idx = paths.length - 1;
+        if (idx >= 0) {
+            String lastPath = paths[idx];
+            if (lastPath.equals(ANY_DESCENDENT)) {
+                return new PrefixDestinationFilter(paths);
+            } else {
+                while (idx >= 0) {
+                    lastPath = paths[idx--];
+                    if (lastPath.equals(ANY_CHILD)) {
+                        return new WildcardDestinationFilter(paths);
+                    }
+                }
+            }
+        }
+
+        // if none of the paths contain a wildcard then use equality
+        return new SimpleDestinationFilter(destination);
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationFilter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMap.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMap.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMap.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMap.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,163 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+/**
+ * A Map-like data structure allowing values to be indexed by
+ * {@link Destination} and retrieved by destination - supporting both *
+ * and &gt; style of wildcard as well as composite destinations. <br>
+ * This class assumes that the index changes rarely but that fast lookup into
+ * the index is required. So this class maintains a pre-calculated index for
+ * destination steps. So looking up the values for "TEST.*" or "*.TEST" will be
+ * pretty fast. <br>
+ * Looking up of a value could return a single value or a List of matching
+ * values if a wildcard or composite destination is used.
+ * 
+ * @version $Revision: 1.3 $
+ */
+public class DestinationMap<Value> {
+    protected static final String ANY_DESCENDENT = DestinationFilter.ANY_DESCENDENT;
+    protected static final String ANY_CHILD = DestinationFilter.ANY_CHILD;
+
+    private DestinationMapNode<Value> root = new DestinationMapNode<Value>(null);
+
+    /**
+     * Looks up the value(s) matching the given Destination key. For simple
+     * destinations this is typically a List of one single value, for wild cards
+     * or composite destinations this will typically be a List of matching
+     * values.
+     * 
+     * @param key the destination to lookup
+     * @return a List of matching values or an empty list if there are no
+     *         matching values.
+     */
+    public synchronized Set<Value> get(Destination key) {
+    	Collection<Destination> destinations = key.getDestinations();
+        if (destinations!=null) {
+        	HashSet<Value> answer = new HashSet<Value>(destinations.size());
+        	for (Destination childDestination : destinations) {
+                answer.addAll(get(childDestination));
+            }
+            return answer;
+        }
+        return findWildcardMatches(key);
+    }
+
+    public synchronized void put(Destination key, Value value) {
+    	Collection<Destination> destinations = key.getDestinations();
+        if (destinations!=null) {
+        	for (Destination childDestination : destinations) {
+                put(childDestination, value);
+            }
+            return;
+        }
+        String[] paths = DestinationPath.getDestinationPaths(key);
+        getRootNode(key).add(paths, 0, value);
+    }
+
+    /**
+     * Removes the value from the associated destination
+     */
+    public synchronized void remove(Destination key, Value value) {
+    	Collection<Destination> destinations = key.getDestinations();
+        if (destinations!=null) {
+        	for (Destination childDestination : destinations) {
+                remove(childDestination, value);
+            }
+            return;
+        }
+        String[] paths = DestinationPath.getDestinationPaths(key);
+        getRootNode(key).remove(paths, 0, value);
+
+    }
+
+    public DestinationMapNode<Value> getRootNode() {
+        return root;
+    }
+
+    // Implementation methods
+    // -------------------------------------------------------------------------
+
+    /**
+     * A helper method to allow the destination map to be populated from a
+     * dependency injection framework such as Spring
+     */
+    @SuppressWarnings("unchecked")
+	protected void setEntries(List<DestinationMapEntry> entries) {
+    	for (DestinationMapEntry entry : entries) {
+            put(entry.getDestination(), (Value) entry);
+        }
+    }
+
+    protected Set<Value> findWildcardMatches(Destination key) {
+        String[] paths = DestinationPath.getDestinationPaths(key);
+        HashSet<Value> answer = new HashSet<Value>();
+        getRootNode(key).appendMatchingValues(answer, paths, 0);
+        return answer;
+    }
+
+    /**
+     * @param key
+     * @return
+     */
+    public Set<Value> removeAll(Destination key) {
+    	HashSet<Value> rc = new HashSet<Value>();
+    	Collection<Destination> destinations = key.getDestinations();
+        if (destinations!=null) {
+        	for (Destination childDestination : destinations) {
+                rc.addAll(removeAll(childDestination));
+            }
+            return rc;
+        }
+        String[] paths = DestinationPath.getDestinationPaths(key);
+        getRootNode(key).removeAll(rc, paths, 0);
+        return rc;
+    }
+
+    /**
+     * Returns the value which matches the given destination or null if there is
+     * no matching value. If there are multiple values, the results are sorted
+     * and the last item (the biggest) is returned.
+     * 
+     * @param destination the destination to find the value for
+     * @return the largest matching value or null if no value matches
+     */
+    public Value chooseValue(Destination destination) {
+        Set<Value> set = get(destination);
+        if (set == null || set.isEmpty()) {
+            return null;
+        }
+        SortedSet<Value> sortedSet = new TreeSet<Value>(set);
+        return sortedSet.last();
+    }
+
+    /**
+     * Returns the root node for the given destination type
+     */
+    protected DestinationMapNode<Value> getRootNode(Destination key) {
+        return root;
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMap.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapEntry.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapEntry.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapEntry.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapEntry.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,84 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import org.apache.activemq.apollo.broker.Destination;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * A base class for entry objects used to construct a destination based policy
+ * map.
+ * 
+ * @version $Revision: 1.1 $
+ */
+public abstract class DestinationMapEntry implements InitializingBean, Comparable<DestinationMapEntry> {
+
+    private Destination destination;
+
+    public int compareTo(DestinationMapEntry that) {
+    	if( that == null )
+    		return 1;
+        return compare(destination, that.destination);
+    }
+    
+    public static int compare(Destination destination, Destination destination2) {
+        if (destination == destination2) {
+            return 0;
+        }
+        if (destination == null) {
+            return -1;
+        } else if (destination2 == null) {
+            return 1;
+        } else {
+        	int rc = destination.getDomain().compareTo(destination2.getDomain());
+        	if( rc == 0 ) {
+        		rc = destination.getName().compareTo(destination2.getName());;
+        	}
+        	return rc;
+        }
+    }
+    
+
+//    /**
+//     * A helper method to set the destination from a configuration file
+//     */
+//    public void setQueue(String name) {
+//        setDestination(new ActiveMQQueue(name));
+//    }
+//
+//    /**
+//     * A helper method to set the destination from a configuration file
+//     */
+//    public void setTopic(String name) {
+//        setDestination(new ActiveMQTopic(name));
+//    }
+
+    public Destination getDestination() {
+        return destination;
+    }
+
+    public void setDestination(Destination destination) {
+        this.destination = destination;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        if (destination == null) {
+            throw new IllegalArgumentException("You must specify the 'destination' property");
+        }
+    }
+
+}

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapNode.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapNode.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapNode.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapNode.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,274 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An implementation class used to implement {@link DestinationMap}
+ * 
+ * @version $Revision: 1.2 $
+ */
+public class DestinationMapNode<Value> implements DestinationNode<Value> {
+    protected static final String ANY_CHILD = DestinationMap.ANY_CHILD;
+    protected static final String ANY_DESCENDENT = DestinationMap.ANY_DESCENDENT;
+
+    // we synchornize at the DestinationMap level
+    private DestinationMapNode<Value> parent;
+    private List<Value> values = new ArrayList<Value>();
+    private Map<String, DestinationNode<Value>> childNodes = new HashMap<String, DestinationNode<Value>>();
+    private String path = "Root";
+    // private DestinationMapNode anyChild;
+    private int pathLength;
+
+    public DestinationMapNode(DestinationMapNode<Value> parent) {
+        this.parent = parent;
+        if (parent == null) {
+            pathLength = 0;
+        } else {
+            pathLength = parent.pathLength + 1;
+        }
+    }
+
+    /**
+     * Returns the child node for the given named path or null if it does not
+     * exist
+     */
+    public DestinationMapNode<Value> getChild(String path) {
+        return (DestinationMapNode<Value>)childNodes.get(path);
+    }
+
+    /**
+     * Returns the child nodes
+     */
+    public Collection<DestinationNode<Value>> getChildren() {
+        return childNodes.values();
+    }
+
+    public int getChildCount() {
+        return childNodes.size();
+    }
+
+    /**
+     * Returns the child node for the given named path, lazily creating one if
+     * it does not yet exist
+     */
+    public DestinationMapNode<Value> getChildOrCreate(String path) {
+        DestinationMapNode<Value> answer = (DestinationMapNode<Value>)childNodes.get(path);
+        if (answer == null) {
+            answer = createChildNode();
+            answer.path = path;
+            childNodes.put(path, answer);
+        }
+        return answer;
+    }
+
+    /**
+     * Returns the node which represents all children (i.e. the * node)
+     */
+    // public DestinationMapNode getAnyChildNode() {
+    // if (anyChild == null) {
+    // anyChild = createChildNode();
+    // }
+    // return anyChild;
+    // }
+    /**
+     * Returns a mutable List of the values available at this node in the tree
+     */
+    public List<Value> getValues() {
+        return values;
+    }
+
+    /**
+     * Returns a mutable List of the values available at this node in the tree
+     */
+    public List<Value> removeValues() {
+        ArrayList<Value> v = new ArrayList<Value>(values);
+        // parent.getAnyChildNode().getValues().removeAll(v);
+        values.clear();
+        pruneIfEmpty();
+        return v;
+    }
+
+    public Set<Value> removeDesendentValues() {
+        Set<Value> answer = new HashSet<Value>();
+        removeDesendentValues(answer);
+        return answer;
+    }
+
+    protected void removeDesendentValues(Set<Value> answer) {
+        // if (anyChild != null) {
+        // anyChild.removeDesendentValues(answer);
+        // }
+        answer.addAll(removeValues());
+    }
+
+    /**
+     * Returns a list of all the values from this node down the tree
+     */
+    public Set<Value> getDesendentValues() {
+        Set<Value> answer = new HashSet<Value>();
+        appendDescendantValues(answer);
+        return answer;
+    }
+
+    public void add(String[] paths, int idx, Value value) {
+        if (idx >= paths.length) {
+            values.add(value);
+        } else {
+            // if (idx == paths.length - 1) {
+            // getAnyChildNode().getValues().add(value);
+            // }
+            // else {
+            // getAnyChildNode().add(paths, idx + 1, value);
+            // }
+            getChildOrCreate(paths[idx]).add(paths, idx + 1, value);
+        }
+    }
+
+    public void remove(String[] paths, int idx, Value value) {
+        if (idx >= paths.length) {
+            values.remove(value);
+            pruneIfEmpty();
+        } else {
+            // if (idx == paths.length - 1) {
+            // getAnyChildNode().getValues().remove(value);
+            // }
+            // else {
+            // getAnyChildNode().remove(paths, idx + 1, value);
+            // }
+            getChildOrCreate(paths[idx]).remove(paths, ++idx, value);
+        }
+    }
+
+    public void removeAll(Set<Value> answer, String[] paths, int startIndex) {
+        DestinationNode<Value> node = this;
+        int size = paths.length;
+        for (int i = startIndex; i < size && node != null; i++) {
+
+            String path = paths[i];
+            if (path.equals(ANY_DESCENDENT)) {
+                answer.addAll(node.removeDesendentValues());
+                break;
+            }
+
+            node.appendMatchingWildcards(answer, paths, i);
+            if (path.equals(ANY_CHILD)) {
+                // node = node.getAnyChildNode();
+                node = new AnyChildDestinationNode<Value>(node);
+            } else {
+                node = node.getChild(path);
+            }
+        }
+
+        if (node != null) {
+            answer.addAll(node.removeValues());
+        }
+
+    }
+
+    public void appendDescendantValues(Set<Value> answer) {
+        answer.addAll(values);
+
+        // lets add all the children too
+        for (DestinationNode<Value> child : childNodes.values()) {
+			child.appendDescendantValues(answer);
+        }
+
+        // TODO???
+        // if (anyChild != null) {
+        // anyChild.appendDescendantValues(answer);
+        // }
+    }
+
+    /**
+     * Factory method to create a child node
+     */
+    protected DestinationMapNode<Value> createChildNode() {
+        return new DestinationMapNode<Value>(this);
+    }
+
+    /**
+     * Matches any entries in the map containing wildcards
+     */
+    public void appendMatchingWildcards(Set<Value> answer, String[] paths, int idx) {
+        if (idx - 1 > pathLength) {
+            return;
+        }
+        DestinationMapNode<Value> wildCardNode = getChild(ANY_CHILD);
+        if (wildCardNode != null) {
+            wildCardNode.appendMatchingValues(answer, paths, idx + 1);
+        }
+        wildCardNode = getChild(ANY_DESCENDENT);
+        if (wildCardNode != null) {
+            answer.addAll(wildCardNode.getDesendentValues());
+        }
+    }
+
+    public void appendMatchingValues(Set<Value> answer, String[] paths, int startIndex) {
+        DestinationNode<Value> node = this;
+        boolean couldMatchAny = true;
+        int size = paths.length;
+        for (int i = startIndex; i < size && node != null; i++) {
+            String path = paths[i];
+            if (path.equals(ANY_DESCENDENT)) {
+                answer.addAll(node.getDesendentValues());
+                couldMatchAny = false;
+                break;
+            }
+
+            node.appendMatchingWildcards(answer, paths, i);
+
+            if (path.equals(ANY_CHILD)) {
+                node = new AnyChildDestinationNode<Value>(node);
+            } else {
+                node = node.getChild(path);
+            }
+        }
+        if (node != null) {
+            answer.addAll(node.getValues());
+            if (couldMatchAny) {
+                // lets allow FOO.BAR to match the FOO.BAR.> entry in the map
+                DestinationNode<Value> child = node.getChild(ANY_DESCENDENT);
+                if (child != null) {
+                    answer.addAll(child.getValues());
+                }
+            }
+        }
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    protected void pruneIfEmpty() {
+        if (parent != null && childNodes.isEmpty() && values.isEmpty()) {
+            parent.removeChild(this);
+        }
+    }
+
+    protected void removeChild(DestinationMapNode<Value> node) {
+        childNodes.remove(node.getPath());
+        pruneIfEmpty();
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationMapNode.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationNode.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationNode.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationNode.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationNode.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Represents a node in the {@link DestinationMap} tree
+ *
+ * @version $Revision: 563921 $
+ */
+public interface DestinationNode<Value> {
+    void appendMatchingValues(Set<Value> answer, String[] paths, int startIndex);
+
+    void appendMatchingWildcards(Set<Value> answer, String[] paths, int startIndex);
+
+    void appendDescendantValues(Set<Value> answer);
+
+    Collection<Value> getDesendentValues();
+
+    DestinationNode<Value> getChild(String path);
+
+    Collection<Value> getValues();
+
+    Collection<DestinationNode<Value>> getChildren();
+
+    Collection<Value> removeDesendentValues();
+
+    Collection<Value> removeValues();
+}

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationPath.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationPath.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationPath.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationPath.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,80 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+/**
+ * Helper class for decomposing a Destination into a number of paths
+ * 
+ * @version $Revision: 1.3 $
+ */
+public final class DestinationPath {
+    protected static final char SEPARATOR = '.';
+
+    private DestinationPath() {    
+    }
+    
+    public static String[] getDestinationPaths(String subject) {
+        List<String> list = new ArrayList<String>();
+        int previous = 0;
+        int lastIndex = subject.length() - 1;
+        while (true) {
+            int idx = subject.indexOf(SEPARATOR, previous);
+            if (idx < 0) {
+                list.add(subject.substring(previous, lastIndex + 1));
+                break;
+            }
+            list.add(subject.substring(previous, idx));
+            previous = idx + 1;
+        }
+        String[] answer = new String[list.size()];
+        list.toArray(answer);
+        return answer;
+    }
+
+    public static String[] getDestinationPaths(Destination destination) {
+    	// TODO: avoid converting to string..
+        return getDestinationPaths(destination.getName().toString());
+    }
+
+    /**
+     * Converts the paths to a single String seperated by dots.
+     * 
+     * @param paths
+     * @return
+     */
+    public static String toString(String[] paths) {
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < paths.length; i++) {
+            if (i > 0) {
+                buffer.append(SEPARATOR);
+            }
+            String path = paths[i];
+            if (path == null) {
+                buffer.append("*");
+            } else {
+                buffer.append(path);
+            }
+        }
+        return buffer.toString();
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/DestinationPath.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/PrefixDestinationFilter.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/PrefixDestinationFilter.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/PrefixDestinationFilter.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/PrefixDestinationFilter.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,67 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+
+/**
+ * Matches messages which match a prefix like "A.B.>"
+ *
+ * @version $Revision: 1.2 $
+ */
+public class PrefixDestinationFilter extends DestinationFilter {
+
+    private String[] prefixes;
+
+    /**
+     * An array of paths, the last path is '>'
+     *
+     * @param prefixes
+     */
+    public PrefixDestinationFilter(String[] prefixes) {
+        this.prefixes = prefixes;
+    }
+
+    public boolean matches(Destination destination) {
+        String[] path = DestinationPath.getDestinationPaths(destination);
+        int length = prefixes.length;
+        if (path.length >= length) {
+            int size = length - 1;
+            for (int i = 0; i < size; i++) {
+                if (!prefixes[i].equals(path[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    public String getText() {
+        return DestinationPath.toString(prefixes);
+    }
+
+    public String toString() {
+        return super.toString() + "[destination: " + getText() + "]";
+    }
+
+    public boolean isWildcard() {
+        return true;
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/PrefixDestinationFilter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/SimpleDestinationFilter.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/SimpleDestinationFilter.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/SimpleDestinationFilter.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/SimpleDestinationFilter.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+
+/**
+ * Matches messages sent to an exact destination
+ *
+ * @version $Revision: 1.3 $
+ */
+public class SimpleDestinationFilter extends DestinationFilter {
+
+    private Destination destination;
+
+    public SimpleDestinationFilter(Destination destination) {
+        this.destination = destination;
+    }
+
+    public boolean matches(Destination destination) {
+        return this.destination.equals(destination);
+    }
+
+    public boolean isWildcard() {
+        return false;
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/SimpleDestinationFilter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/WildcardDestinationFilter.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/WildcardDestinationFilter.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/WildcardDestinationFilter.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/WildcardDestinationFilter.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import org.apache.activemq.apollo.broker.Destination;
+
+
+
+/**
+ * Matches messages which contain wildcards like "A.B.*.*"
+ *
+ * @version $Revision: 1.2 $
+ */
+public class WildcardDestinationFilter extends DestinationFilter {
+
+    private String[] prefixes;
+
+    /**
+     * An array of paths containing * characters
+     *
+     * @param prefixes
+     */
+    public WildcardDestinationFilter(String[] prefixes) {
+        this.prefixes = new String[prefixes.length];
+        for (int i = 0; i < prefixes.length; i++) {
+            String prefix = prefixes[i];
+            if (!prefix.equals("*")) {
+                this.prefixes[i] = prefix;
+            }
+        }
+    }
+
+    public boolean matches(Destination destination) {
+        String[] path = DestinationPath.getDestinationPaths(destination);
+        int length = prefixes.length;
+        if (path.length == length) {
+            for (int i = 0; i < length; i++) {
+                String prefix = prefixes[i];
+                if (prefix != null && !prefix.equals(path[i])) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+
+    public String getText() {
+        return DestinationPath.toString(prefixes);
+    }
+
+    public String toString() {
+        return super.toString() + "[destination: " + getText() + "]";
+    }
+
+    public boolean isWildcard() {
+        return true;
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/main/java/org/apache/activemq/filter/WildcardDestinationFilter.java
------------------------------------------------------------------------------
    svn:executable = *

Added: activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapMemoryTest.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,51 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import junit.framework.TestCase;
+
+import org.apache.activemq.apollo.broker.Destination;
+import org.apache.activemq.apollo.broker.Router;
+import org.apache.activemq.protobuf.AsciiBuffer;
+
+public class DestinationMapMemoryTest extends TestCase {
+
+    public void testLongDestinationPath() throws Exception {
+    	Destination d1 = new Destination.SingleDestination(Router.TOPIC_DOMAIN, new AsciiBuffer("1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18"));
+        DestinationMap<String> map = new DestinationMap<String>();
+        map.put(d1, "test");
+    }
+
+    public void testVeryLongestinationPaths() throws Exception {
+
+        for (int i = 1; i < 100; i++) {
+            String name = "1";
+            for (int j = 2; j <= i; j++) {
+                name += "." + j;
+            }
+            // System.out.println("Checking: " + name);
+            try {
+            	Destination d1 = new Destination.SingleDestination(Router.TOPIC_DOMAIN, new AsciiBuffer(name));
+                DestinationMap<String> map = new DestinationMap<String>();
+                map.put(d1, "test");
+            } catch (Throwable e) {
+                fail("Destination name too long: " + name + " : " + e);
+            }
+        }
+    }
+
+}

Added: activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTempDestinationTest.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,44 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.activemq.apollo.broker.Destination;
+import org.apache.activemq.apollo.broker.Router;
+import org.apache.activemq.protobuf.AsciiBuffer;
+
+public class DestinationMapTempDestinationTest extends TestCase {
+    
+    public void testtestTempDestinations() throws Exception {
+        DestinationMap<Object> map = new DestinationMap<Object>();
+        Object value = new Object();
+        int count = 1000;
+        for (int i = 0; i < count; i++) {
+            Destination queue = new Destination.SingleDestination(Router.TEMP_QUEUE_DOMAIN, new AsciiBuffer("connection:"+i));
+            map.put(queue, value);
+        }
+        for (int i = 0; i < count; i++) {
+            Destination queue = new Destination.SingleDestination(Router.TEMP_QUEUE_DOMAIN, new AsciiBuffer("connection:"+i));
+            map.remove(queue, value);
+            Set<Object> set = map.get(queue);
+            assertTrue(set.isEmpty());
+        }
+    }
+}
\ No newline at end of file

Added: activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTest.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTest.java?rev=786459&view=auto
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTest.java (added)
+++ activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTest.java Fri Jun 19 11:27:33 2009
@@ -0,0 +1,402 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.activemq.filter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.activemq.apollo.broker.Destination;
+import org.apache.activemq.apollo.broker.Router;
+import org.apache.activemq.protobuf.AsciiBuffer;
+
+public class DestinationMapTest extends TestCase {
+    protected DestinationMap<String> map = new DestinationMap<String>();
+
+    protected Destination d1 = createDestination("TEST.D1");
+    protected Destination d2 = createDestination("TEST.BAR.D2");
+    protected Destination d3 = createDestination("TEST.BAR.D3");
+    protected Destination compositeDestination1 = createDestination("TEST.D1,TEST.BAR.D2");
+    protected Destination compositeDestination2 = createDestination("TEST.D1,TEST.BAR.D3");
+
+    protected String v1 = "value1";
+    protected String v2 = "value2";
+    protected String v3 = "value3";
+    protected String v4 = "value4";
+    protected String v5 = "value5";
+    protected String v6 = "value6";
+
+    public void testCompositeDestinations() throws Exception {
+        Destination d1 = createDestination("TEST.BAR.D2");
+        Destination d2 = createDestination("TEST.BAR.D3");
+        map.put(d1, v1);
+        map.put(d2, v2);
+        map.get(createDestination("TEST.BAR.D2,TEST.BAR.D3"));
+
+    }
+
+    public void testSimpleDestinations() throws Exception {
+        map.put(d1, v1);
+        map.put(d2, v2);
+        map.put(d3, v3);
+
+        assertMapValue(d1, v1);
+        assertMapValue(d2, v2);
+        assertMapValue(d3, v3);
+    }
+
+    public void testSimpleDestinationsWithMultipleValues() throws Exception {
+        map.put(d1, v1);
+        map.put(d2, v2);
+        map.put(d2, v3);
+
+        assertMapValue(d1, v1);
+        assertMapValue("TEST.BAR.D2", v2, v3);
+        assertMapValue(d3, null);
+    }
+
+    public void testSimpleAndCompositeDestinations() throws Exception {
+        map.put(d1, v1);
+        map.put(compositeDestination1, v2);
+        map.put(compositeDestination2, v3);
+
+        Set<String> set = map.get(d1);
+        System.out.println(set);
+        
+        
+        assertMapValue("TEST.D1", v1, v2, v3);
+        assertMapValue(d2, v2);
+        assertMapValue(d3, v3);
+        assertMapValue(compositeDestination1, v1, v2, v3);
+        assertMapValue(compositeDestination2, v1, v2, v3);
+
+        map.remove(compositeDestination1, v2);
+        map.remove(compositeDestination2, v3);
+
+        assertMapValue("TEST.D1", v1);
+    }
+
+    public void testLookupOneStepWildcardDestinations() throws Exception {
+        map.put(d1, v1);
+        map.put(d2, v2);
+        map.put(d3, v3);
+
+        assertMapValue("TEST.D1", v1);
+        assertMapValue("TEST.*", v1);
+        assertMapValue("*.D1", v1);
+        assertMapValue("*.*", v1);
+
+        assertMapValue("TEST.BAR.D2", v2);
+        assertMapValue("TEST.*.D2", v2);
+        assertMapValue("*.BAR.D2", v2);
+        assertMapValue("*.*.D2", v2);
+
+        assertMapValue("TEST.BAR.D3", v3);
+        assertMapValue("TEST.*.D3", v3);
+        assertMapValue("*.BAR.D3", v3);
+        assertMapValue("*.*.D3", v3);
+
+        assertMapValue("TEST.BAR.D4", null);
+
+        assertMapValue("TEST.BAR.*", v2, v3);
+    }
+
+    public void testLookupMultiStepWildcardDestinations() throws Exception {
+        map.put(d1, v1);
+        map.put(d2, v2);
+        map.put(d3, v3);
+
+        List<String> allValues = Arrays.asList(new String[] {v1, v2, v3});
+
+        assertMapValue(">", allValues);
+        assertMapValue("TEST.>", allValues);
+        assertMapValue("*.>", allValues);
+
+        assertMapValue("FOO.>", null);
+    }
+
+    public void testStoreWildcardWithOneStepPath() throws Exception {
+        put("TEST.*", v1);
+        put("TEST.D1", v2);
+        put("TEST.BAR.*", v2);
+        put("TEST.BAR.D3", v3);
+
+        assertMapValue("FOO", null);
+        assertMapValue("TEST.FOO", v1);
+        assertMapValue("TEST.D1", v1, v2);
+
+        assertMapValue("TEST.FOO.FOO", null);
+        assertMapValue("TEST.BAR.FOO", v2);
+        assertMapValue("TEST.BAR.D3", v2, v3);
+
+        assertMapValue("TEST.*", v1, v2);
+        assertMapValue("*.D1", v1, v2);
+        assertMapValue("*.*", v1, v2);
+        assertMapValue("TEST.*.*", v2, v3);
+        assertMapValue("TEST.BAR.*", v2, v3);
+        assertMapValue("*.*.*", v2, v3);
+        assertMapValue("*.BAR.*", v2, v3);
+        assertMapValue("*.BAR.D3", v2, v3);
+        assertMapValue("*.*.D3", v2, v3);
+    }
+
+    public void testStoreWildcardInMiddleOfPath() throws Exception {
+        put("TEST.*", v1);
+        put("TEST.D1", v2);
+        put("TEST.BAR.*", v2);
+        put("TEST.XYZ.D3", v3);
+        put("TEST.XYZ.D4", v4);
+        put("TEST.BAR.D3", v5);
+        put("TEST.*.D2", v6);
+
+        assertMapValue("TEST.*.D3", v2, v3, v5);
+        assertMapValue("TEST.*.D4", v2, v4);
+
+        assertMapValue("TEST.*", v1, v2);
+        assertMapValue("TEST.*.*", v2, v3, v4, v5, v6);
+        assertMapValue("TEST.*.>", v1, v2, v3, v4, v5, v6);
+        assertMapValue("TEST.>", v1, v2, v3, v4, v5, v6);
+        assertMapValue("TEST.>.>", v1, v2, v3, v4, v5, v6);
+        assertMapValue("*.*.D3", v2, v3, v5);
+        assertMapValue("TEST.BAR.*", v2, v5, v6);
+
+        assertMapValue("TEST.BAR.D2", v2, v6);
+        assertMapValue("TEST.*.D2", v2, v6);
+        assertMapValue("TEST.BAR.*", v2, v5, v6);
+    }
+
+    public void testDoubleWildcardDoesNotMatchLongerPattern() throws Exception {
+        put("TEST.*", v1);
+        put("TEST.BAR.D3", v2);
+
+        assertMapValue("*.*.D3", v2);
+    }
+
+    public void testWildcardAtEndOfPathAndAtBeginningOfSearch() throws Exception {
+        put("TEST.*", v1);
+
+        assertMapValue("*.D1", v1);
+    }
+
+    public void testAnyPathWildcardInMap() throws Exception {
+        put("TEST.FOO.>", v1);
+
+        assertMapValue("TEST.FOO.BAR.WHANOT.A.B.C", v1);
+        assertMapValue("TEST.FOO.BAR.WHANOT", v1);
+        assertMapValue("TEST.FOO.BAR", v1);
+
+        assertMapValue("TEST.*.*", v1);
+        assertMapValue("TEST.BAR", null);
+
+        assertMapValue("TEST.FOO", v1);
+    }
+
+    public void testSimpleAddRemove() throws Exception {
+        put("TEST.D1", v2);
+
+        assertEquals("Root child count", 1, map.getRootNode().getChildCount());
+
+        assertMapValue("TEST.D1", v2);
+
+        remove("TEST.D1", v2);
+
+        assertEquals("Root child count", 0, map.getRootNode().getChildCount());
+        assertMapValue("TEST.D1", null);
+    }
+
+    public void testStoreAndLookupAllWildcards() throws Exception {
+        loadSample2();
+
+        assertSample2();
+
+        // lets remove everything and add it back
+        remove("TEST.FOO", v1);
+
+        assertMapValue("TEST.FOO", v2, v3, v4);
+        assertMapValue("TEST.*", v2, v3, v4, v6);
+        assertMapValue("*.*", v2, v3, v4, v6);
+
+        remove("TEST.XYZ", v6);
+
+        assertMapValue("TEST.*", v2, v3, v4);
+        assertMapValue("*.*", v2, v3, v4);
+
+        remove("TEST.*", v2);
+
+        assertMapValue("TEST.*", v3, v4);
+        assertMapValue("*.*", v3, v4);
+
+        remove(">", v4);
+
+        assertMapValue("TEST.*", v3);
+        assertMapValue("*.*", v3);
+
+        remove("TEST.>", v3);
+        remove("TEST.FOO.BAR", v5);
+
+        assertMapValue("FOO", null);
+        assertMapValue("TEST.FOO", null);
+        assertMapValue("TEST.D1", null);
+
+        assertMapValue("TEST.FOO.FOO", null);
+        assertMapValue("TEST.BAR.FOO", null);
+        assertMapValue("TEST.FOO.BAR", null);
+        assertMapValue("TEST.BAR.D3", null);
+
+        assertMapValue("TEST.*", null);
+        assertMapValue("*.*", null);
+        assertMapValue("*.D1", null);
+        assertMapValue("TEST.*.*", null);
+        assertMapValue("TEST.BAR.*", null);
+
+        loadSample2();
+
+        assertSample2();
+
+        remove(">", v4);
+        remove("TEST.*", v2);
+
+        assertMapValue("FOO", null);
+        assertMapValue("TEST.FOO", v1, v3);
+        assertMapValue("TEST.D1", v3);
+
+        assertMapValue("TEST.FOO.FOO", v3);
+        assertMapValue("TEST.BAR.FOO", v3);
+        assertMapValue("TEST.FOO.BAR", v3, v5);
+        assertMapValue("TEST.BAR.D3", v3);
+
+        assertMapValue("TEST.*", v1, v3, v6);
+        assertMapValue("*.*", v1, v3, v6);
+        assertMapValue("*.D1", v3);
+        assertMapValue("TEST.*.*", v3, v5);
+        assertMapValue("TEST.BAR.*", v3);
+    }
+
+    public void testAddAndRemove() throws Exception {
+
+        put("FOO.A", v1);
+        assertMapValue("FOO.>", v1);
+
+        put("FOO.B", v2);
+        assertMapValue("FOO.>", v1, v2);
+
+        map.removeAll(createDestination("FOO.A"));
+
+        assertMapValue("FOO.>", v2);
+
+    }
+
+    protected void loadSample2() {
+        put("TEST.FOO", v1);
+        put("TEST.*", v2);
+        put("TEST.>", v3);
+        put(">", v4);
+        put("TEST.FOO.BAR", v5);
+        put("TEST.XYZ", v6);
+    }
+
+    protected void assertSample2() {
+        assertMapValue("FOO", v4);
+        assertMapValue("TEST.FOO", v1, v2, v3, v4);
+        assertMapValue("TEST.D1", v2, v3, v4);
+
+        assertMapValue("TEST.FOO.FOO", v3, v4);
+        assertMapValue("TEST.BAR.FOO", v3, v4);
+        assertMapValue("TEST.FOO.BAR", v3, v4, v5);
+        assertMapValue("TEST.BAR.D3", v3, v4);
+
+        assertMapValue("TEST.*", v1, v2, v3, v4, v6);
+        assertMapValue("*.*", v1, v2, v3, v4, v6);
+        assertMapValue("*.D1", v2, v3, v4);
+        assertMapValue("TEST.*.*", v3, v4, v5);
+        assertMapValue("TEST.BAR.*", v3, v4);
+    }
+
+    protected void put(String name, String value) {
+        map.put(createDestination(name), value);
+    }
+
+    protected void remove(String name, String value) {
+        Destination destination = createDestination(name);
+        map.remove(destination, value);
+    }
+
+    protected void assertMapValue(String destinationName, Object expected) {
+        Destination destination = createDestination(destinationName);
+        assertMapValue(destination, expected);
+    }
+
+    protected void assertMapValue(String destinationName, Object expected1, Object expected2) {
+        assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2}));
+    }
+
+    protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3) {
+        assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3}));
+    }
+    
+    protected void assertMapValue(Destination destination, Object expected1, Object expected2, Object expected3) {
+        assertMapValue(destination, Arrays.asList(new Object[] {expected1, expected2, expected3}));
+    }
+
+    protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3, Object expected4) {
+        assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3, expected4}));
+    }
+
+    protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3, Object expected4, Object expected5) {
+        assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3, expected4, expected5}));
+    }
+
+    protected void assertMapValue(String destinationName, Object expected1, Object expected2, Object expected3, Object expected4, Object expected5, Object expected6) {
+        assertMapValue(destinationName, Arrays.asList(new Object[] {expected1, expected2, expected3, expected4, expected5, expected6}));
+    }
+
+    @SuppressWarnings("unchecked")
+    protected void assertMapValue(Destination destination, Object expected) {
+        List expectedList = null;
+        if (expected == null) {
+            expectedList = Collections.EMPTY_LIST;
+        } else if (expected instanceof List) {
+            expectedList = (List)expected;
+        } else {
+            expectedList = new ArrayList();
+            expectedList.add(expected);
+        }
+        Collections.sort(expectedList);
+        Set actualSet = map.get(destination);
+        List actual = new ArrayList(actualSet);
+        Collections.sort(actual);
+        assertEquals("map value for destinationName:  " + destination, expectedList, actual);
+    }
+
+    protected Destination createDestination(String name) {
+    	String[] split = name.split(",");
+    	if( split.length == 1 ) {
+    		return new Destination.SingleDestination(Router.QUEUE_DOMAIN, new AsciiBuffer(name));
+    	} else {
+    		Destination.MultiDestination rc =  new Destination.MultiDestination();
+    		for (int i = 0; i < split.length; i++) {
+				rc.add(createDestination(split[i]));
+			}
+    		return rc;
+    	}
+    }
+}

Propchange: activemq/sandbox/activemq-flow/activemq-broker/src/test/java/org/apache/activemq/filter/DestinationMapTest.java
------------------------------------------------------------------------------
    svn:executable = *

Modified: activemq/sandbox/activemq-flow/activemq-util/src/main/java/org/apache/activemq/protobuf/Buffer.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/activemq-util/src/main/java/org/apache/activemq/protobuf/Buffer.java?rev=786459&r1=786458&r2=786459&view=diff
==============================================================================
--- activemq/sandbox/activemq-flow/activemq-util/src/main/java/org/apache/activemq/protobuf/Buffer.java (original)
+++ activemq/sandbox/activemq-flow/activemq-util/src/main/java/org/apache/activemq/protobuf/Buffer.java Fri Jun 19 11:27:33 2009
@@ -179,6 +179,9 @@
     }
 
     public int compareTo(Buffer o) {
+    	if( this == o )
+    		return 0;
+    	
         int minLength = Math.min(length, o.length);
         if (offset == o.offset) {
             int pos = offset;

Modified: activemq/sandbox/activemq-flow/webgen/src/todo.page
URL: http://svn.apache.org/viewvc/activemq/sandbox/activemq-flow/webgen/src/todo.page?rev=786459&r1=786458&r2=786459&view=diff
==============================================================================
--- activemq/sandbox/activemq-flow/webgen/src/todo.page (original)
+++ activemq/sandbox/activemq-flow/webgen/src/todo.page Fri Jun 19 11:27:33 2009
@@ -79,6 +79,8 @@
 
 * InactivityMonitor needs to get inserted for OpenWire on the server side of MultiWireFormat negotiation.
 * BIO SSL Transport does not currently pass Client Certificate chain in OpenWire ConnectionInfo command. This used to be done by the SSL transport but this shouldn't have OpenWire dependencies; instead protocol handler should be able to retrieve it from the underlying transport as needed. 
+* Add javadoc to all classes
+* Add nice toString() methods to aid when debugging.
 
 h2. General Cleanup / Abstraction Leaks / Smelly Stuff