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