1 /***
2 *
3 * Copyright 2004 Protique Ltd
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 **/
18 package org.codehaus.activemq.filter;
19
20 import org.codehaus.activemq.message.ActiveMQDestination;
21
22 import java.util.HashSet;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Set;
26
27 /***
28 * A Map-like data structure allowing values to be indexed by {@link ActiveMQDestination}
29 * and retrieved by destination - supporting both * and > style of wildcard
30 * as well as composite destinations.
31 * <br>
32 * This class assumes that the index changes rarely but that fast lookup into the index is required.
33 * So this class maintains a pre-calculated index for destination steps. So looking up the values
34 * for "TEST.*" or "*.TEST" will be pretty fast.
35 * <br>
36 * Looking up of a value could return a single value or a List of matching values if a wildcard or
37 * composite destination is used.
38 *
39 * @version $Revision: 1.5 $
40 */
41 public class DestinationMap {
42 private DestinationMapNode rootNode = new DestinationMapNode();
43 protected static final String ANY_DESCENDENT = DestinationFilter.ANY_DESCENDENT;
44 protected static final String ANY_CHILD = DestinationFilter.ANY_CHILD;
45
46 /***
47 * Looks up the value(s) matching the given Destination key. For simple destinations
48 * this is typically a List of one single value, for wildcards or composite destinations this will typically be
49 * a List of matching values.
50 *
51 * @param key the destination to lookup
52 * @return a List of matching values or an empty list if there are no matching values.
53 */
54 public synchronized Set get(ActiveMQDestination key) {
55 if (key.isComposite()) {
56 List childDestinations = key.getChildDestinations();
57 Set answer = new HashSet(childDestinations.size());
58 for (Iterator iter = childDestinations.iterator(); iter.hasNext();) {
59 ActiveMQDestination childDestination = (ActiveMQDestination) iter.next();
60 Object value = get(childDestination);
61 if (value instanceof Set) {
62 answer.addAll((Set) value);
63 }
64 else if (value != null) {
65 answer.add(value);
66 }
67 return answer;
68 }
69 }
70 return findWildcardMatches(key);
71 }
72
73 public synchronized void put(ActiveMQDestination key, Object value) {
74 if (key.isComposite()) {
75 List childDestinations = key.getChildDestinations();
76 for (Iterator iter = childDestinations.iterator(); iter.hasNext();) {
77 ActiveMQDestination childDestination = (ActiveMQDestination) iter.next();
78 put(childDestination, value);
79 }
80 return;
81 }
82 String[] paths = key.getDestinationPaths();
83 rootNode.add(paths, 0, value);
84 }
85
86 /***
87 * Removes the value from the associated destination
88 */
89 public synchronized void remove(ActiveMQDestination key, Object value) {
90 if (key.isComposite()) {
91 List childDestinations = key.getChildDestinations();
92 for (Iterator iter = childDestinations.iterator(); iter.hasNext();) {
93 ActiveMQDestination childDestination = (ActiveMQDestination) iter.next();
94 remove(childDestination, value);
95 }
96 return;
97 }
98 String[] paths = key.getDestinationPaths();
99 rootNode.remove(paths, 0, value);
100
101 }
102
103
104
105 protected Set findWildcardMatches(ActiveMQDestination key) {
106 String[] paths = key.getDestinationPaths();
107 Set answer = new HashSet();
108 rootNode.appendMatchingValues(answer, paths, 0);
109 return answer;
110 }
111
112 }