001package 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
022import java.util.ArrayList;
023import java.util.List;
024
025import 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 */
058public 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}