001 package org.apache.commons.digester3.plugins;
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.logging.Log;
025 import org.apache.commons.digester3.Digester;
026
027 /**
028 * Represents a Class that can be instantiated by a PluginCreateRule, plus info on how to load custom digester rules for
029 * mapping xml into that plugged-in class.
030 *
031 * @since 1.6
032 */
033 public class Declaration
034 {
035
036 /** The class of the object to be instantiated. */
037 private Class<?> pluginClass;
038
039 /** The name of the class of the object to be instantiated. */
040 private String pluginClassName;
041
042 /** See {@link #setId}. */
043 private String id;
044
045 /** See {@link #setProperties}. */
046 private Properties properties = new Properties();
047
048 /** See {@link #init}. */
049 private boolean initialized = false;
050
051 /**
052 * Class which is responsible for dynamically loading this plugin's rules on demand.
053 */
054 private RuleLoader ruleLoader = null;
055
056 // ---------------------- constructors ----------------------------------
057
058 /**
059 * Constructor.
060 *
061 * @param pluginClassName The name of the class of the object to be instantiated (will be load in the init method)
062 */
063 public Declaration( String pluginClassName )
064 {
065 // We can't load the pluginClass at this time, because we don't
066 // have a digester instance yet to load it through. So just
067 // save the name away, and we'll load the Class object in the
068 // init method.
069 this.pluginClassName = pluginClassName;
070 }
071
072 /**
073 * Constructor.
074 *
075 * @param pluginClass The class of the object to be instantiated (will be load in the init method)
076 */
077 public Declaration( Class<?> pluginClass )
078 {
079 this.pluginClass = pluginClass;
080 this.pluginClassName = pluginClass.getName();
081 }
082
083 /**
084 * Create an instance where a fully-initialised ruleLoader instance is provided by the caller instead of having the
085 * PluginManager "discover" an appropriate one.
086 *
087 * @param pluginClass The class of the object to be instantiated (will be load in the init method)
088 * @param ruleLoader Class which is responsible for dynamically loading this plugin's rules on demand
089 */
090 public Declaration( Class<?> pluginClass, RuleLoader ruleLoader )
091 {
092 this.pluginClass = pluginClass;
093 this.pluginClassName = pluginClass.getName();
094 this.ruleLoader = ruleLoader;
095 }
096
097 // ---------------------- properties -----------------------------------
098
099 /**
100 * The id that the user associated with a particular plugin declaration in the input xml. This id is later used in
101 * the input xml to refer back to the original declaration.
102 * <p>
103 * For plugins declared "in-line", the id is null.
104 *
105 * @param id The id that the user associated with a particular plugin declaration in the input xml
106 */
107 public void setId( String id )
108 {
109 this.id = id;
110 }
111
112 /**
113 * Return the id associated with this declaration. For plugins declared "inline", null will be returned.
114 *
115 * @return The id value. May be null.
116 */
117 public String getId()
118 {
119 return id;
120 }
121
122 /**
123 * Copy all (key,value) pairs in the param into the properties member of this object.
124 * <p>
125 * The declaration properties cannot be explicit member variables, because the set of useful properties a user can
126 * provide on a declaration depends on what RuleFinder classes are available - and extra RuleFinders can be added by
127 * the user. So here we keep a map of the settings, and let the RuleFinder objects look for whatever properties they
128 * consider significant.
129 * <p>
130 * The "id" and "class" properties are treated differently.
131 *
132 * @param p The properties have to be copied into the properties member of this object
133 */
134 public void setProperties( Properties p )
135 {
136 properties.putAll( p );
137 }
138
139 /**
140 * Return plugin class associated with this declaration.
141 *
142 * @return The pluginClass.
143 */
144 public Class<?> getPluginClass()
145 {
146 return pluginClass;
147 }
148
149 // ---------------------- methods -----------------------------------
150
151 /**
152 * Must be called exactly once, and must be called before any call to the configure method.
153 *
154 * @param digester The Digester instance where plugin has to be plugged
155 * @param pm The plugin manager reference
156 * @throws PluginException if any error occurs while loading the rules
157 */
158 public void init( Digester digester, PluginManager pm )
159 throws PluginException
160 {
161 Log log = digester.getLogger();
162 boolean debug = log.isDebugEnabled();
163 if ( debug )
164 {
165 log.debug( "init being called!" );
166 }
167
168 if ( initialized )
169 {
170 throw new PluginAssertionFailure( "Init called multiple times." );
171 }
172
173 if ( ( pluginClass == null ) && ( pluginClassName != null ) )
174 {
175 try
176 {
177 // load the plugin class object
178 pluginClass = digester.getClassLoader().loadClass( pluginClassName );
179 }
180 catch ( ClassNotFoundException cnfe )
181 {
182 throw new PluginException( "Unable to load class " + pluginClassName, cnfe );
183 }
184 }
185
186 if ( ruleLoader == null )
187 {
188 // the caller didn't provide a ruleLoader to the constructor,
189 // so get the plugin manager to "discover" one.
190 log.debug( "Searching for ruleloader..." );
191 ruleLoader = pm.findLoader( digester, id, pluginClass, properties );
192 }
193 else
194 {
195 log.debug( "This declaration has an explicit ruleLoader." );
196 }
197
198 if ( debug )
199 {
200 if ( ruleLoader == null )
201 {
202 log.debug( "No ruleLoader found for plugin declaration" + " id [" + id + "]" + ", class ["
203 + pluginClass.getClass().getName() + "]." );
204 }
205 else
206 {
207 log.debug( "RuleLoader of type [" + ruleLoader.getClass().getName()
208 + "] associated with plugin declaration" + " id [" + id + "]" + ", class ["
209 + pluginClass.getClass().getName() + "]." );
210 }
211 }
212
213 initialized = true;
214 }
215
216 /**
217 * Attempt to load custom rules for the target class at the specified pattern.
218 * <p>
219 * On return, any custom rules associated with the plugin class have been loaded into the Rules object currently
220 * associated with the specified digester object.
221 *
222 * @param digester The Digester instance where plugin has to be plugged
223 * @param pattern The pattern the custom rules have to be bound
224 * @throws PluginException if any error occurs
225 */
226 public void configure( Digester digester, String pattern )
227 throws PluginException
228 {
229 Log log = digester.getLogger();
230 boolean debug = log.isDebugEnabled();
231 if ( debug )
232 {
233 log.debug( "configure being called!" );
234 }
235
236 if ( !initialized )
237 {
238 throw new PluginAssertionFailure( "Not initialized." );
239 }
240
241 if ( ruleLoader != null )
242 {
243 ruleLoader.addRules( digester, pattern );
244 }
245 }
246
247 }