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 static org.apache.commons.beanutils.MethodUtils.getAccessibleMethod;
023
024import java.lang.reflect.Method;
025
026import org.apache.commons.digester3.Digester;
027import org.apache.commons.digester3.plugins.PluginException;
028import org.apache.commons.digester3.plugins.RuleLoader;
029import org.apache.commons.logging.Log;
030
031/**
032 * A RuleLoader which invokes a static method on a target class, leaving that method to actually instantiate and add new
033 * rules to a Digester instance.
034 * 
035 * @since 1.6
036 */
037public class LoaderFromClass
038    extends RuleLoader
039{
040
041    private final Class<?> rulesClass;
042
043    private final Method rulesMethod;
044
045    /**
046     * Constructor.
047     *
048     * @param rulesClass The target class
049     * @param rulesMethod The method has to be invoked
050     */
051    public LoaderFromClass( Class<?> rulesClass, Method rulesMethod )
052    {
053        this.rulesClass = rulesClass;
054        this.rulesMethod = rulesMethod;
055    }
056
057    /**
058     * Constructor.
059     *
060     * @param rulesClass The target class
061     * @param methodName The method name has to be invoked
062     * @throws PluginException if input method can't be located inside the given class
063     */
064    public LoaderFromClass( Class<?> rulesClass, String methodName )
065        throws PluginException
066    {
067
068        Method method = locateMethod( rulesClass, methodName );
069
070        if ( method == null )
071        {
072            throw new PluginException( "rule class " + rulesClass.getName() + " does not have method " + methodName
073                + " or that method has an invalid signature." );
074        }
075
076        this.rulesClass = rulesClass;
077        this.rulesMethod = method;
078    }
079
080    /**
081     * {@inheritDoc}
082     */
083    @Override
084    public void addRules( Digester d, String path )
085        throws PluginException
086    {
087        Log log = d.getLogger();
088        boolean debug = log.isDebugEnabled();
089        if ( debug )
090        {
091            log.debug( "LoaderFromClass loading rules for plugin at path [" + path + "]" );
092        }
093
094        try
095        {
096            Object[] params = { d, path };
097            rulesMethod.invoke( null, params );
098        }
099        catch ( Exception e )
100        {
101            throw new PluginException(
102                                       "Unable to invoke rules method " + rulesMethod + " on rules class " + rulesClass,
103                                       e );
104        }
105    }
106
107    /**
108     * Find a method on the specified class whose name matches methodName, and whose signature is:
109     * <code> public static void foo(Digester d, String patternPrefix);</code>.
110     *
111     * @param rulesClass The target class
112     * @param methodName The method name has to be invoked
113     * @return The method name has to be invoked, or null if no such method exists.
114     * @throws PluginException if any error occurs while discovering the method
115     */
116    public static Method locateMethod( Class<?> rulesClass, String methodName )
117        throws PluginException
118    {
119        Class<?>[] paramSpec = { Digester.class, String.class };
120        Method rulesMethod = getAccessibleMethod( rulesClass, methodName, paramSpec );
121
122        return rulesMethod;
123    }
124
125}