001/* $Id: WithDefaultsRulesWrapper.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><code>Rules</code> <em>Decorator</em> that returns default rules 
027 * when no matches are returned by the wrapped implementation.</p>
028 *
029 * <p>This allows default <code>Rule</code> instances to be added to any 
030 * existing <code>Rules</code> implementation. These default <code>Rule</code> 
031 * instances will be returned for any match for which the wrapped 
032 * implementation does not return any matches.</p>
033 * <p> For example,
034 * <pre>
035 *   Rule alpha;
036 *   ...
037 *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
038 *   rules.addDefault(alpha);
039 *   ...
040 *   digester.setRules(rules);
041 *   ...
042 * </pre>
043 * when a pattern does not match any other rule, then rule alpha will be called.
044 * </p>
045 * <p><code>WithDefaultsRulesWrapper</code> follows the <em>Decorator</em> pattern.</p>
046 *
047 * @since 1.6
048 */
049
050public class WithDefaultsRulesWrapper implements Rules {
051
052    // --------------------------------------------------------- Fields
053    
054    /** The Rules implementation that this class wraps. */
055    private Rules wrappedRules;
056    /** Rules to be fired when the wrapped implementations returns none. */
057    private List defaultRules = new ArrayList();
058    /** All rules (preserves order in which they were originally added) */
059    private List allRules = new ArrayList();
060    
061    // --------------------------------------------------------- Constructor
062    
063    /** 
064     * Base constructor.
065     *
066     * @param wrappedRules the wrapped <code>Rules</code> implementation, not null
067     * @throws IllegalArgumentException when <code>wrappedRules</code> is null
068     */
069    public WithDefaultsRulesWrapper(Rules wrappedRules) {
070        if (wrappedRules == null) {
071            throw new IllegalArgumentException("Wrapped rules must not be null");
072        }
073        this.wrappedRules = wrappedRules;
074    }
075
076    // --------------------------------------------------------- Properties
077    
078    /** Gets digester using these Rules */
079    public Digester getDigester() {
080        return wrappedRules.getDigester();
081    }
082    
083    /** Sets digeseter using these Rules */
084    public void setDigester(Digester digester) {
085        wrappedRules.setDigester(digester);
086        Iterator it = defaultRules.iterator();
087        while (it.hasNext()) {
088            Rule rule = (Rule) it.next();
089            rule.setDigester(digester);
090        }
091    }
092    
093    /** Gets namespace to apply to Rule's added */
094    public String getNamespaceURI() {
095        return wrappedRules.getNamespaceURI();
096    }
097    
098    /** Sets namespace to apply to Rule's added subsequently */
099    public void setNamespaceURI(String namespaceURI) {
100        wrappedRules.setNamespaceURI(namespaceURI);
101    }
102    
103    /** Gets Rule's which will be fired when the wrapped implementation returns no matches */
104    public List getDefaults() {
105        return defaultRules;
106    }
107    
108    // --------------------------------------------------------- Public Methods
109    
110    public List match(String pattern) {
111        return match("", pattern);
112    }
113    
114    /**
115     * Return list of rules matching given pattern.
116     * If wrapped implementation returns any matches return those.
117     * Otherwise, return default matches.
118     */
119    public List match(String namespaceURI, String pattern) {
120        List matches = wrappedRules.match(namespaceURI, pattern);
121        if (matches ==  null || matches.isEmpty()) {
122            // a little bit of defensive programming
123            return new ArrayList(defaultRules);
124        }
125        // otherwise
126        return matches;
127    }
128    
129    /** Adds a rule to be fired when wrapped implementation returns no matches */
130    public void addDefault(Rule rule) {
131        // set up rule
132        if (wrappedRules.getDigester() != null) {
133            rule.setDigester(wrappedRules.getDigester());
134        }
135        
136        if (wrappedRules.getNamespaceURI() != null) {
137            rule.setNamespaceURI(wrappedRules.getNamespaceURI());
138        }
139        
140        defaultRules.add(rule);
141        allRules.add(rule);
142    }
143    
144    /** Gets all rules */
145    public List rules() {
146        return allRules;
147    }
148    
149    /** Clears all Rule's */
150    public void clear() {
151        wrappedRules.clear();
152        allRules.clear();
153        defaultRules.clear();
154    }
155    
156    /** 
157     * Adds a Rule to be fired on given pattern.
158     * Pattern matching is delegated to wrapped implementation.
159     */
160    public void add(String pattern, Rule rule) {
161        wrappedRules.add(pattern, rule);
162        allRules.add(rule);
163    }
164}