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