001    /* $Id: RegexRules.java 471661 2006-11-06 08:09:25Z skitching $
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     * 
010     *      http://www.apache.org/licenses/LICENSE-2.0
011     * 
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */ 
018    
019    package org.apache.commons.digester;
020    
021    import java.util.ArrayList;
022    import java.util.Iterator;
023    import java.util.List;
024    
025    /**
026     * <p>Rules implementation that uses regular expression matching for paths.</p>
027     *
028     * <p>The regex implementation is pluggable, allowing different strategies to be used.
029     * The basic way that this class work does not vary.
030     * All patterns are tested to see if they match the path using the regex matcher.
031     * All those that do are return in the order which the rules were added.</p>
032     *
033     * @since 1.5
034     */
035    
036    public class RegexRules extends AbstractRulesImpl {
037    
038        // --------------------------------------------------------- Fields
039        
040        /** All registered <code>Rule</code>'s  */
041        private ArrayList registeredRules = new ArrayList();
042        /** The regex strategy used by this RegexRules */
043        private RegexMatcher matcher;
044    
045        // --------------------------------------------------------- Constructor
046    
047        /**
048         * Construct sets the Regex matching strategy.
049         *
050         * @param matcher the regex strategy to be used, not null
051         * @throws IllegalArgumentException if the strategy is null
052         */
053        public RegexRules(RegexMatcher matcher) {
054            setRegexMatcher(matcher);
055        }
056    
057        // --------------------------------------------------------- Properties
058        
059        /** 
060         * Gets the current regex matching strategy.
061         */
062        public RegexMatcher getRegexMatcher() {
063            return matcher;
064        }
065        
066        /** 
067         * Sets the current regex matching strategy.
068         *
069         * @param matcher use this RegexMatcher, not null
070         * @throws IllegalArgumentException if the strategy is null
071         */
072        public void setRegexMatcher(RegexMatcher matcher) {
073            if (matcher == null) {
074                throw new IllegalArgumentException("RegexMatcher must not be null.");
075            }
076            this.matcher = matcher;
077        }
078        
079        // --------------------------------------------------------- Public Methods
080    
081        /**
082         * Register a new Rule instance matching the specified pattern.
083         *
084         * @param pattern Nesting pattern to be matched for this Rule
085         * @param rule Rule instance to be registered
086         */
087        protected void registerRule(String pattern, Rule rule) {
088            registeredRules.add(new RegisteredRule(pattern, rule));
089        }
090    
091        /**
092         * Clear all existing Rule instance registrations.
093         */
094        public void clear() {
095            registeredRules.clear();
096        }
097    
098        /**
099         * Finds matching rules by using current regex matching strategy.
100         * The rule associated with each path that matches is added to the list of matches.
101         * The order of matching rules is the same order that they were added.
102         *
103         * @param namespaceURI Namespace URI for which to select matching rules,
104         *  or <code>null</code> to match regardless of namespace URI
105         * @param pattern Nesting pattern to be matched
106         * @return a list of matching <code>Rule</code>'s
107         */
108        public List match(String namespaceURI, String pattern) {
109            //
110            // not a particularly quick implementation
111            // regex is probably going to be slower than string equality
112            // so probably should have a set of strings
113            // and test each only once
114            //
115            // XXX FIX ME - Time And Optimize
116            //
117            ArrayList rules = new ArrayList(registeredRules.size());
118            Iterator it = registeredRules.iterator();
119            while (it.hasNext()) {
120                RegisteredRule next = (RegisteredRule) it.next();
121                if (matcher.match(pattern, next.pattern)) {
122                    rules.add(next.rule);
123                }
124            }
125            return rules;
126        }
127    
128    
129        /**
130         * Return a List of all registered Rule instances, or a zero-length List
131         * if there are no registered Rule instances.  If more than one Rule
132         * instance has been registered, they <strong>must</strong> be returned
133         * in the order originally registered through the <code>add()</code>
134         * method.
135         */
136        public List rules() {
137            ArrayList rules = new ArrayList(registeredRules.size());
138            Iterator it = registeredRules.iterator();
139            while (it.hasNext()) {
140                rules.add(((RegisteredRule) it.next()).rule);
141            }
142            return rules;
143        }
144        
145        /** Used to associate rules with paths in the rules list */
146        private class RegisteredRule {
147            String pattern;
148            Rule rule;
149            
150            RegisteredRule(String pattern, Rule rule) {
151                this.pattern = pattern;
152                this.rule = rule;
153            }
154        }
155    }