001    package org.apache.commons.digester3;
002    
003    /*
004     * Licensed to the Apache Software Foundation (ASF) under one
005     * or more contributor license agreements.  See the NOTICE file
006     * distributed with this work for additional information
007     * regarding copyright ownership.  The ASF licenses this file
008     * to you under the Apache License, Version 2.0 (the
009     * "License"); you may not use this file except in compliance
010     * with the License.  You may obtain a copy of the License at
011     *
012     *   http://www.apache.org/licenses/LICENSE-2.0
013     *
014     * Unless required by applicable law or agreed to in writing,
015     * software distributed under the License is distributed on an
016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017     * KIND, either express or implied.  See the License for the
018     * specific language governing permissions and limitations
019     * under the License.
020     */
021    
022    import java.util.ArrayList;
023    import java.util.List;
024    
025    import org.xml.sax.Attributes;
026    
027    /**
028     * <p>
029     * <code>Rules</code> <em>Decorator</em> that returns default rules when no matches are returned by the wrapped
030     * implementation.
031     * </p>
032     * <p>
033     * This allows default <code>Rule</code> instances to be added to any existing <code>Rules</code> implementation. These
034     * default <code>Rule</code> instances will be returned for any match for which the wrapped implementation does not
035     * return any matches.
036     * </p>
037     * <p>
038     * For example,
039     * 
040     * <pre>
041     *   Rule alpha;
042     *   ...
043     *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
044     *   rules.addDefault(alpha);
045     *   ...
046     *   digester.setRules(rules);
047     *   ...
048     * </pre>
049     * 
050     * when a pattern does not match any other rule, then rule alpha will be called.
051     * </p>
052     * <p>
053     * <code>WithDefaultsRulesWrapper</code> follows the <em>Decorator</em> pattern.
054     * </p>
055     * 
056     * @since 1.6
057     */
058    public class WithDefaultsRulesWrapper
059        implements Rules
060    {
061    
062        // --------------------------------------------------------- Fields
063    
064        /** The Rules implementation that this class wraps. */
065        private Rules wrappedRules;
066    
067        /** Rules to be fired when the wrapped implementations returns none. */
068        private List<Rule> defaultRules = new ArrayList<Rule>();
069    
070        /** All rules (preserves order in which they were originally added) */
071        private List<Rule> allRules = new ArrayList<Rule>();
072    
073        // --------------------------------------------------------- Constructor
074    
075        /**
076         * Base constructor.
077         *
078         * @param wrappedRules the wrapped <code>Rules</code> implementation, not null
079         */
080        public WithDefaultsRulesWrapper( Rules wrappedRules )
081        {
082            if ( wrappedRules == null )
083            {
084                throw new IllegalArgumentException( "Wrapped rules must not be null" );
085            }
086            this.wrappedRules = wrappedRules;
087        }
088    
089        // --------------------------------------------------------- Properties
090    
091        /**
092         * {@inheritDoc}
093         */
094        public Digester getDigester()
095        {
096            return wrappedRules.getDigester();
097        }
098    
099        /**
100         * {@inheritDoc}
101         */
102        public void setDigester( Digester digester )
103        {
104            wrappedRules.setDigester( digester );
105            for ( Rule rule : defaultRules )
106            {
107                rule.setDigester( digester );
108            }
109        }
110    
111        /**
112         * {@inheritDoc}
113         */
114        public String getNamespaceURI()
115        {
116            return wrappedRules.getNamespaceURI();
117        }
118    
119        /**
120         * {@inheritDoc}
121         */
122        public void setNamespaceURI( String namespaceURI )
123        {
124            wrappedRules.setNamespaceURI( namespaceURI );
125        }
126    
127        /**
128         * Gets Rule's which will be fired when the wrapped implementation returns no matches
129         *
130         * @return Rule's which will be fired when the wrapped implementation returns no matches
131         **/
132        public List<Rule> getDefaults()
133        {
134            return defaultRules;
135        }
136    
137        // --------------------------------------------------------- Public Methods
138    
139        /**
140         * {@inheritDoc}
141         */
142        public List<Rule> match( String namespaceURI, String pattern, String name, Attributes attributes )
143        {
144            List<Rule> matches = wrappedRules.match( namespaceURI, pattern, name, attributes );
145            if ( matches == null || matches.isEmpty() )
146            {
147                // a little bit of defensive programming
148                return new ArrayList<Rule>( defaultRules );
149            }
150            // otherwise
151            return matches;
152        }
153    
154        /**
155         * Adds a rule to be fired when wrapped implementation returns no matches
156         *
157         * @param rule a Rule to be fired when wrapped implementation returns no matches
158         **/
159        public void addDefault( Rule rule )
160        {
161            // set up rule
162            if ( wrappedRules.getDigester() != null )
163            {
164                rule.setDigester( wrappedRules.getDigester() );
165            }
166    
167            if ( wrappedRules.getNamespaceURI() != null )
168            {
169                rule.setNamespaceURI( wrappedRules.getNamespaceURI() );
170            }
171    
172            defaultRules.add( rule );
173            allRules.add( rule );
174        }
175    
176        /**
177         * {@inheritDoc}
178         */
179        public List<Rule> rules()
180        {
181            return allRules;
182        }
183    
184        /**
185         * {@inheritDoc}
186         */
187        public void clear()
188        {
189            wrappedRules.clear();
190            allRules.clear();
191            defaultRules.clear();
192        }
193    
194        /**
195         * {@inheritDoc}
196         */
197        public void add( String pattern, Rule rule )
198        {
199            wrappedRules.add( pattern, rule );
200            allRules.add( rule );
201        }
202    
203    }