001    /* $Id: RegexRules.java 992060 2010-09-02 19:09:47Z simonetripodi $
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.List;
023    
024    /**
025     * <p>Rules implementation that uses regular expression matching for paths.</p>
026     *
027     * <p>The regex implementation is pluggable, allowing different strategies to be used.
028     * The basic way that this class work does not vary.
029     * All patterns are tested to see if they match the path using the regex matcher.
030     * All those that do are return in the order which the rules were added.</p>
031     *
032     * @since 1.5
033     */
034    
035    public class RegexRules extends AbstractRulesImpl {
036    
037        // --------------------------------------------------------- Fields
038        
039        /** All registered <code>Rule</code>'s  */
040        private ArrayList<RegisteredRule> registeredRules = new ArrayList<RegisteredRule>();
041        /** The regex strategy used by this RegexRules */
042        private RegexMatcher matcher;
043    
044        // --------------------------------------------------------- Constructor
045    
046        /**
047         * Construct sets the Regex matching strategy.
048         *
049         * @param matcher the regex strategy to be used, not null
050         * @throws IllegalArgumentException if the strategy is null
051         */
052        public RegexRules(RegexMatcher matcher) {
053            setRegexMatcher(matcher);
054        }
055    
056        // --------------------------------------------------------- Properties
057        
058        /** 
059         * Gets the current regex matching strategy.
060         */
061        public RegexMatcher getRegexMatcher() {
062            return matcher;
063        }
064        
065        /** 
066         * Sets the current regex matching strategy.
067         *
068         * @param matcher use this RegexMatcher, not null
069         * @throws IllegalArgumentException if the strategy is null
070         */
071        public void setRegexMatcher(RegexMatcher matcher) {
072            if (matcher == null) {
073                throw new IllegalArgumentException("RegexMatcher must not be null.");
074            }
075            this.matcher = matcher;
076        }
077        
078        // --------------------------------------------------------- Public Methods
079    
080        /**
081         * Register a new Rule instance matching the specified pattern.
082         *
083         * @param pattern Nesting pattern to be matched for this Rule
084         * @param rule Rule instance to be registered
085         */
086        @Override
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        @Override
095        public void clear() {
096            registeredRules.clear();
097        }
098    
099        /**
100         * Finds matching rules by using current regex matching strategy.
101         * The rule associated with each path that matches is added to the list of matches.
102         * The order of matching rules is the same order that they were added.
103         *
104         * @param namespaceURI Namespace URI for which to select matching rules,
105         *  or <code>null</code> to match regardless of namespace URI
106         * @param pattern Nesting pattern to be matched
107         * @return a list of matching <code>Rule</code>'s
108         */
109        @Override
110        public List<Rule> match(String namespaceURI, String pattern) {
111            //
112            // not a particularly quick implementation
113            // regex is probably going to be slower than string equality
114            // so probably should have a set of strings
115            // and test each only once
116            //
117            // XXX FIX ME - Time And Optimize
118            //
119            ArrayList<Rule> rules = new ArrayList<Rule>(registeredRules.size());
120            for (RegisteredRule rr : registeredRules) {
121                if (matcher.match(pattern, rr.pattern)) {
122                    rules.add(rr.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        @Override
137        public List<Rule> rules() {
138            ArrayList<Rule> rules = new ArrayList<Rule>(registeredRules.size());
139            for (RegisteredRule rr : registeredRules) {
140                rules.add(rr.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    }