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
019package org.apache.commons.digester;
020
021import java.util.ArrayList;
022import java.util.Iterator;
023import 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
036public 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}