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.util.Properties;
023
024 import org.apache.commons.digester3.Digester;
025 import org.apache.commons.digester3.plugins.PluginException;
026 import org.apache.commons.digester3.plugins.RuleFinder;
027 import org.apache.commons.digester3.plugins.RuleLoader;
028
029 /**
030 * A rule-finding algorithm which expects the caller to specify a classname and methodname as plugin properties.
031 *
032 * @since 1.6
033 */
034 public class FinderFromClass
035 extends RuleFinder
036 {
037 private static final String DFLT_RULECLASS_ATTR = "ruleclass";
038
039 private static final String DFLT_METHOD_ATTR = "method";
040
041 private static final String DFLT_METHOD_NAME = "addRules";
042
043 private final String ruleClassAttr;
044
045 private final String methodAttr;
046
047 private final String dfltMethodName;
048
049 /**
050 * See {@link #findLoader}.
051 */
052 public FinderFromClass()
053 {
054 this( DFLT_RULECLASS_ATTR, DFLT_METHOD_ATTR, DFLT_METHOD_NAME );
055 }
056
057 /**
058 * Create a rule-finder which invokes a user-specified method on a user-specified class whenever dynamic rules for a
059 * plugin need to be loaded. See the findRules method for more info.
060 *
061 * @param ruleClassAttr must be non-null.
062 * @param methodAttr may be null.
063 * @param dfltMethodName may be null.
064 */
065 public FinderFromClass( String ruleClassAttr, String methodAttr, String dfltMethodName )
066 {
067 this.ruleClassAttr = ruleClassAttr;
068 this.methodAttr = methodAttr;
069 this.dfltMethodName = dfltMethodName;
070 }
071
072 /**
073 * If there exists a property with the name matching constructor param ruleClassAttr, then load the specified class,
074 * locate the appropriate rules-adding method on that class, and return an object encapsulating that info.
075 * <p>
076 * If there is no matching property provided, then just return null.
077 * <p>
078 * The returned object (when non-null) will invoke the target method on the selected class whenever its addRules
079 * method is invoked. The target method is expected to have the following prototype:
080 * <code> public static void xxxxx(Digester d, String patternPrefix); </code>
081 * <p>
082 * The target method can be specified in several ways. If this object's constructor was passed a non-null methodAttr
083 * parameter, and the properties defines a value with that key, then that is taken as the target method name. If
084 * there is no matching property, or the constructor was passed null for methodAttr, then the dfltMethodName passed
085 * to the constructor is used as the name of the method on the target class. And if that was null, then
086 * DFLT_METHOD_NAME will be used.
087 * <p>
088 * When the user explicitly declares a plugin in the input xml, the xml attributes on the declaration tag are passed
089 * here as properties, so the user can select any class in the classpath (and any method on that class provided it
090 * has the correct prototype) as the source of dynamic rules for the plugged-in class.
091 *
092 * @param digester The digester instance where locating plugin classes
093 * @param pluginClass The plugin Java class
094 * @param p The properties object that holds any xml attributes the user may have specified on the plugin
095 * declaration in order to indicate how to locate the plugin rules.
096 * @return a source of digester rules for the specified plugin class.
097 * @throws PluginException if the algorithm finds a source of rules, but there is something invalid
098 * about that source.
099 */
100 @Override
101 public RuleLoader findLoader( Digester digester, Class<?> pluginClass, Properties p )
102 throws PluginException
103 {
104 String ruleClassName = p.getProperty( ruleClassAttr );
105 if ( ruleClassName == null )
106 {
107 // nope, user hasn't requested dynamic rules to be loaded
108 // from a specific class.
109 return null;
110 }
111
112 // ok, we are in business
113 String methodName = null;
114 if ( methodAttr != null )
115 {
116 methodName = p.getProperty( methodAttr );
117 }
118 if ( methodName == null )
119 {
120 methodName = dfltMethodName;
121 }
122 if ( methodName == null )
123 {
124 methodName = DFLT_METHOD_NAME;
125 }
126
127 Class<?> ruleClass;
128 try
129 {
130 // load the plugin class object
131 ruleClass = digester.getClassLoader().loadClass( ruleClassName );
132 }
133 catch ( ClassNotFoundException cnfe )
134 {
135 throw new PluginException( "Unable to load class " + ruleClassName, cnfe );
136 }
137
138 return new LoaderFromClass( ruleClass, methodName );
139 }
140
141 }