001    /**
002     * 
003     * Copyright 2004 Protique Ltd
004     * 
005     * Licensed under the Apache License, Version 2.0 (the "License"); 
006     * you may not use this file except in compliance with the License. 
007     * You may obtain a copy of the License at 
008     * 
009     * http://www.apache.org/licenses/LICENSE-2.0
010     * 
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS, 
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
014     * See the License for the specific language governing permissions and 
015     * limitations under the License. 
016     * 
017     **/
018    package org.activemq.filter;
019    
020    import java.util.ArrayList;
021    import java.util.HashMap;
022    import java.util.HashSet;
023    import java.util.List;
024    import java.util.Map;
025    import java.util.Set;
026    
027    /**
028     * An implementation class used to implement {@link DestinationMap}
029     *
030     * @version $Revision: 1.1.1.1 $
031     */
032    public class DestinationMapNode {
033        // we synchornize at the DestinationMap level
034        private List values = new ArrayList();
035        private Map childNodes = new HashMap();
036        private DestinationMapNode anyChild;
037        protected static final String ANY_CHILD = DestinationMap.ANY_CHILD;
038        protected static final String ANY_DESCENDENT = DestinationMap.ANY_DESCENDENT;
039    
040    
041        /**
042         * Returns the child node for the given named path or null if it does not exist
043         */
044        public DestinationMapNode getChild(String path) {
045            return (DestinationMapNode) childNodes.get(path);
046        }
047    
048        /**
049         * Returns the child node for the given named path, lazily creating one if it does
050         * not yet exist
051         */
052        public DestinationMapNode getChildOrCreate(String path) {
053            DestinationMapNode answer = (DestinationMapNode) childNodes.get(path);
054            if (answer == null) {
055                answer = createChildNode();
056                childNodes.put(path, answer);
057            }
058            return answer;
059        }
060    
061        /**
062         * Returns the node which represents all children (i.e. the * node)
063         */
064        public DestinationMapNode getAnyChildNode() {
065            if (anyChild == null) {
066                anyChild = createChildNode();
067            }
068            return anyChild;
069        }
070    
071        /**
072         * Returns a mutable List of the values available at this node in the tree
073         */
074        public List getValues() {
075            return values;
076        }
077    
078        /**
079         * Returns a list of all the values from this node down the tree
080         */
081        public Set getDesendentValues() {
082            Set answer = new HashSet();
083            appendDescendantValues(answer);
084            return answer;
085        }
086    
087        public void add(String[] paths, int idx, Object value) {
088            if (idx >= paths.length) {
089                values.add(value);
090            }
091            else {
092                if (idx == paths.length - 1) {
093                    getAnyChildNode().getValues().add(value);
094                }
095                else {
096                    getAnyChildNode().add(paths, idx + 1, value);
097                }
098                getChildOrCreate(paths[idx]).add(paths, idx + 1, value);
099            }
100        }
101    
102        public void remove(String[] paths, int idx, Object value) {
103            if (idx >= paths.length) {
104                values.remove(value);
105            }
106            else {
107                if (idx == paths.length - 1) {
108                    getAnyChildNode().getValues().remove(value);
109                }
110                else {
111                    getAnyChildNode().remove(paths, idx + 1, value);
112                }
113                getChildOrCreate(paths[idx]).remove(paths, ++idx, value);
114            }
115        }
116    
117        public void removeAll(String[] paths, int idx) {
118            if (idx >= paths.length) {
119                values.clear();
120            }
121            else {
122                if (idx == paths.length - 1) {
123                    getAnyChildNode().getValues().clear();
124                }
125                else {
126                    getAnyChildNode().removeAll(paths, idx + 1);
127                }
128                getChildOrCreate(paths[idx]).removeAll(paths, ++idx);
129            }
130        }
131    
132        protected void appendDescendantValues(Set answer) {
133            answer.addAll(values);
134            if (anyChild != null) {
135                anyChild.appendDescendantValues(answer);
136            }
137        }
138    
139        /**
140         * Factory method to create a child node
141         */
142        protected DestinationMapNode createChildNode() {
143            return new DestinationMapNode();
144        }
145    
146        public void appendMatchingWildcards(Set answer, String[] paths, int idx) {
147            DestinationMapNode wildCardNode = getChild(ANY_CHILD);
148            if (wildCardNode != null) {
149                wildCardNode.appendMatchingValues(answer, paths, idx + 1);
150            }
151            wildCardNode = getChild(ANY_DESCENDENT);
152            if (wildCardNode != null) {
153                answer.addAll(wildCardNode.getDesendentValues());
154            }
155        }
156    
157        public void appendMatchingValues(Set answer, String[] paths, int startIndex) {
158            DestinationMapNode node = this;
159            for (int i = startIndex, size = paths.length; i < size && node != null; i++) {
160                String path = paths[i];
161                if (path.equals(ANY_DESCENDENT)) {
162                    answer.addAll(node.getDesendentValues());
163                    break;
164                }
165    
166                node.appendMatchingWildcards(answer, paths, i);
167                if (path.equals(ANY_CHILD)) {
168                    node = node.getAnyChildNode();
169                }
170                else {
171                    node = node.getChild(path);
172                }
173            }
174            if (node != null) {
175                answer.addAll(node.getValues());
176            }
177        }
178    
179    }