001    package org.apache.commons.digester3.plugins.strategies;
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.io.IOException;
023    import java.io.InputStream;
024    import java.util.Properties;
025    
026    import org.apache.commons.digester3.Digester;
027    import org.apache.commons.digester3.plugins.PluginException;
028    import org.apache.commons.digester3.plugins.RuleFinder;
029    import org.apache.commons.digester3.plugins.RuleLoader;
030    
031    /**
032     * A rule-finding algorithm which expects the user to specify a resource name (ie a file in the classpath). The file is
033     * expected to contain Digester rules in xmlrules format.
034     * 
035     * @since 1.6
036     */
037    public class FinderFromResource
038        extends RuleFinder
039    {
040    
041        /**
042         * Default name of xml attribute on the plugin declaration which is used to configure rule-loading
043         * for that declaration.
044         */
045        private static final String DFLT_RESOURCE_ATTR = "resource";
046    
047        /** See {@link #findLoader}. */
048        private final String resourceAttr;
049    
050        /** Constructor. */
051        public FinderFromResource()
052        {
053            this( DFLT_RESOURCE_ATTR );
054        }
055    
056        /**
057         * See {@link #findLoader}.
058         *
059         * @param resourceAttr Name of xml attribute on the plugin declaration which is used to configure rule-loading
060         *        for that declaration
061         */
062        public FinderFromResource( String resourceAttr )
063        {
064            this.resourceAttr = resourceAttr;
065        }
066    
067        /**
068         * If there exists a property with the name matching constructor param resourceAttr, then load that file, run it
069         * through the xmlrules module and return an object encapsulating those rules.
070         * <p>
071         * If there is no matching property provided, then just return null.
072         * <p>
073         * The returned object (when non-null) will add the selected rules to the digester whenever its addRules method is
074         * invoked.
075         *
076         * @param d The digester instance where locating plugin classes
077         * @param pluginClass The plugin Java class
078         * @param p The properties object that holds any xml attributes the user may have specified on the plugin
079         *          declaration in order to indicate how to locate the plugin rules.
080         * @return a source of digester rules for the specified plugin class.
081         * @throws PluginException if the algorithm finds a source of rules, but there is something invalid
082         *         about that source.
083         */
084        @Override
085        public RuleLoader findLoader( Digester d, Class<?> pluginClass, Properties p )
086            throws PluginException
087        {
088            String resourceName = p.getProperty( resourceAttr );
089            if ( resourceName == null )
090            {
091                // nope, user hasn't requested dynamic rules to be loaded
092                // from a specific file.
093                return null;
094            }
095    
096            InputStream is = pluginClass.getClassLoader().getResourceAsStream( resourceName );
097    
098            if ( is == null )
099            {
100                throw new PluginException( "Resource " + resourceName + " not found." );
101            }
102    
103            return loadRules( d, pluginClass, is, resourceName );
104        }
105    
106        /**
107         * Open the specified resource file (ie a file in the classpath, including being within a jar in the classpath), run
108         * it through the xmlrules module and return an object encapsulating those rules.
109         * 
110         * @param d is the digester into which rules will eventually be loaded.
111         * @param pluginClass is the class whose xml params the rules are parsing.
112         * @param is is where the xmlrules will be read from, and must be non-null.
113         * @param resourceName is a string describing the source of the xmlrules, for use in generating error messages.
114         * @return a source of digester rules for the specified plugin class.
115         * @throws PluginException if any error occurs
116         */
117        public static RuleLoader loadRules( Digester d, Class<?> pluginClass, InputStream is, String resourceName )
118            throws PluginException
119        {
120            try
121            {
122                RuleLoader loader = new LoaderFromStream( is );
123                return loader;
124            }
125            catch ( Exception e )
126            {
127                throw new PluginException( "Unable to load xmlrules from resource [" + resourceName + "]", e );
128            }
129            finally
130            {
131                try
132                {
133                    is.close();
134                }
135                catch ( IOException ioe )
136                {
137                    throw new PluginException( "Unable to close stream for resource [" + resourceName + "]", ioe );
138                }
139            }
140        }
141    
142    }