fixed the DestinationMap so that it can hold queues and topics with the same name without intermixing the two trees

git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@365888 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
James Strachan 2006-01-04 10:42:21 +00:00
parent 0a8efc977b
commit 8b28367f3d
3 changed files with 93 additions and 66 deletions

View File

@ -26,31 +26,35 @@ import java.util.TreeSet;
import org.apache.activemq.command.ActiveMQDestination;
/**
* A Map-like data structure allowing values to be indexed by {@link ActiveMQDestination}
* and retrieved by destination - supporting both * and > 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.
*
* A Map-like data structure allowing values to be indexed by
* {@link ActiveMQDestination} 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 {
private DestinationMapNode rootNode = new DestinationMapNode(null);
protected static final String ANY_DESCENDENT = DestinationFilter.ANY_DESCENDENT;
protected static final String ANY_CHILD = DestinationFilter.ANY_CHILD;
private DestinationMapNode queueRootNode = new DestinationMapNode(null);
private DestinationMapNode topicRootNode = new DestinationMapNode(null);
/**
* Looks up the value(s) matching the given Destination key. For simple destinations
* this is typically a List of one single value, for wildcards 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.
* Looks up the value(s) matching the given Destination key. For simple
* destinations this is typically a List of one single value, for wildcards
* 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 get(ActiveMQDestination key) {
if (key.isComposite()) {
@ -81,7 +85,7 @@ public class DestinationMap {
return;
}
String[] paths = key.getDestinationPaths();
rootNode.add(paths, 0, value);
getRootNode(key).add(paths, 0, value);
}
/**
@ -97,20 +101,24 @@ public class DestinationMap {
return;
}
String[] paths = key.getDestinationPaths();
rootNode.remove(paths, 0, value);
getRootNode(key).remove(paths, 0, value);
}
public int getRootChildCount() {
return rootNode.getChildCount();
public int getTopicRootChildCount() {
return topicRootNode.getChildCount();
}
public int getQueueRootChildCount() {
return queueRootNode.getChildCount();
}
// Implementation methods
//-------------------------------------------------------------------------
// -------------------------------------------------------------------------
/**
* A helper method to allow the destination map to be populated from a dependency injection
* framework such as Spring
* A helper method to allow the destination map to be populated from a
* dependency injection framework such as Spring
*/
protected void setEntries(List entries) {
for (Iterator iter = entries.iterator(); iter.hasNext();) {
@ -125,11 +133,12 @@ public class DestinationMap {
}
}
}
/**
* Returns the type of the allowed entries which can be set via the {@link #setEntries(List)} method.
* This allows derived classes to further restrict the type of allowed entries to make a type safe
* destination map for custom policies.
* Returns the type of the allowed entries which can be set via the
* {@link #setEntries(List)} method. This allows derived classes to further
* restrict the type of allowed entries to make a type safe destination map
* for custom policies.
*/
protected Class getEntryClass() {
return DestinationMapEntry.class;
@ -138,7 +147,7 @@ public class DestinationMap {
protected Set findWildcardMatches(ActiveMQDestination key) {
String[] paths = key.getDestinationPaths();
Set answer = new HashSet();
rootNode.appendMatchingValues(answer, paths, 0);
getRootNode(key).appendMatchingValues(answer, paths, 0);
return answer;
}
@ -154,15 +163,16 @@ public class DestinationMap {
return;
}
String[] paths = key.getDestinationPaths();
rootNode.removeAll(paths, 0);
getRootNode(key).removeAll(paths, 0);
}
/**
* 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.
* 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
* @param destination
* the destination to find the value for
* @return the largest matching value or null if no value matches
*/
public Object chooseValue(ActiveMQDestination destination) {
@ -174,4 +184,15 @@ public class DestinationMap {
return sortedSet.last();
}
/**
* Returns the root node for the given destination type
*/
protected DestinationMapNode getRootNode(ActiveMQDestination key) {
if (key.isQueue()) {
return queueRootNode;
}
else {
return topicRootNode;
}
}
}

View File

@ -20,6 +20,7 @@ package org.apache.activemq.filter;
import junit.framework.TestCase;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.apache.activemq.filter.DestinationMap;
@ -45,16 +46,15 @@ public class DestinationMapTest extends TestCase {
protected Object v5 = "value5";
protected Object v6 = "value6";
public void testCompositeDestinations() throws Exception {
ActiveMQDestination d1 = createDestination("TEST.BAR.D2");
ActiveMQDestination d2 = createDestination("TEST.BAR.D3");
map.put(d1,d1);
map.put(d2,d2);
map.put(d1, d1);
map.put(d2, d2);
map.get(createDestination("TEST.BAR.D2,TEST.BAR.D3"));
}
public void testSimpleDestinations() throws Exception {
map.put(d1, v1);
map.put(d2, v2);
@ -65,6 +65,17 @@ public class DestinationMapTest extends TestCase {
assertMapValue(d3, v3);
}
public void testQueueAndTopicWithSameName() throws Exception {
ActiveMQQueue q1 = new ActiveMQQueue("foo");
ActiveMQTopic t1 = new ActiveMQTopic("foo");
map.put(q1, v1);
map.put(t1, v2);
assertMapValue(q1, v1);
assertMapValue(t1, v2);
}
public void testSimpleDestinationsWithMultipleValues() throws Exception {
map.put(d1, v1);
map.put(d2, v2);
@ -122,7 +133,7 @@ public class DestinationMapTest extends TestCase {
map.put(d2, v2);
map.put(d3, v3);
List allValues = Arrays.asList(new Object[]{v1, v2, v3});
List allValues = Arrays.asList(new Object[] { v1, v2, v3 });
assertMapValue(">", allValues);
assertMapValue("TEST.>", allValues);
@ -131,7 +142,6 @@ public class DestinationMapTest extends TestCase {
assertMapValue("FOO.>", null);
}
public void testStoreWildcardWithOneStepPath() throws Exception {
put("TEST.*", v1);
put("TEST.D1", v2);
@ -165,48 +175,46 @@ public class DestinationMapTest extends TestCase {
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("*.*.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 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.getRootChildCount());
assertEquals("Root child count", 1, map.getTopicRootChildCount());
assertMapValue("TEST.D1", v2);
remove("TEST.D1", v2);
assertEquals("Root child count", 0, map.getRootChildCount());
assertEquals("Root child count", 0, map.getTopicRootChildCount());
assertMapValue("TEST.D1", null);
}
public void testStoreAndLookupAllWildcards() throws Exception {
loadSample2();
@ -301,7 +309,6 @@ public class DestinationMapTest extends TestCase {
assertMapValue("TEST.BAR.*", v3, v4);
}
protected void put(String name, Object value) {
map.put(createDestination(name), value);
}
@ -311,26 +318,25 @@ public class DestinationMapTest extends TestCase {
map.remove(destination, value);
}
protected void assertMapValue(String destinationName, Object expected) {
ActiveMQDestination destination = createDestination(destinationName);
assertMapValue(destination, expected);
}
protected void assertMapValue(String destinationName, Object expected1, Object expected2) {
assertMapValue(destinationName, Arrays.asList(new Object[]{expected1, 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}));
assertMapValue(destinationName, 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}));
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}));
assertMapValue(destinationName, Arrays.asList(new Object[] { expected1, expected2, expected3, expected4, expected5 }));
}
protected void assertMapValue(ActiveMQDestination destination, Object expected) {

View File

@ -30,7 +30,7 @@
<strictOrderDispatchPolicy />
</dispatchPolicy>
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix="Test.DLQ." topicPrefix="Test.DLQ." />
<individualDeadLetterStrategy topicPrefix="Test.DLQ." />
</deadLetterStrategy>
</policyEntry>
@ -39,7 +39,7 @@
<strictOrderDispatchPolicy />
</dispatchPolicy>
<deadLetterStrategy>
<individualDeadLetterStrategy queuePrefix="Test.DLQ." topicPrefix="Test.DLQ." />
<individualDeadLetterStrategy queuePrefix="Test.DLQ."/>
</deadLetterStrategy>
</policyEntry>