001package 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
022import java.io.IOException;
023import java.io.InputStream;
024import java.util.Properties;
025
026import org.apache.commons.digester3.Digester;
027import org.apache.commons.digester3.plugins.PluginException;
028import org.apache.commons.digester3.plugins.RuleFinder;
029import 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 */
037public 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}