001    /* $Id: WithDefaultsRulesWrapper.java 729104 2008-12-23 20:45:23Z rahul $
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><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    
049    public 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    }