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