001 /* $Id: Declaration.java 992060 2010-09-02 19:09:47Z simonetripodi $
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one or more
004 * contributor license agreements. See the NOTICE file distributed with
005 * this work for additional information regarding copyright ownership.
006 * The ASF licenses this file to You under the Apache License, Version 2.0
007 * (the "License"); you may not use this file except in compliance with
008 * the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 package org.apache.commons.digester.plugins;
019
020 import java.util.Properties;
021
022 import org.apache.commons.logging.Log;
023 import org.apache.commons.digester.Digester;
024
025 /**
026 * Represents a Class that can be instantiated by a PluginCreateRule, plus
027 * info on how to load custom digester rules for mapping xml into that
028 * plugged-in class.
029 *
030 * @since 1.6
031 */
032 public class Declaration {
033
034 /** The class of the object to be instantiated. */
035 private Class<?> pluginClass;
036
037 /** The name of the class of the object to be instantiated. */
038 private String pluginClassName;
039
040 /** See {@link #setId}. */
041 private String id;
042
043 /** See {@link #setProperties}. */
044 private Properties properties = new Properties();
045
046 /** See {@link #init}. */
047 private boolean initialized = false;
048
049 /**
050 * Class which is responsible for dynamically loading this
051 * plugin's rules on demand.
052 */
053 private RuleLoader ruleLoader = null;
054
055 //---------------------- constructors ----------------------------------
056
057 /**
058 * Constructor.
059 */
060 public Declaration(String pluginClassName) {
061 // We can't load the pluginClass at this time, because we don't
062 // have a digester instance yet to load it through. So just
063 // save the name away, and we'll load the Class object in the
064 // init method.
065 this.pluginClassName = pluginClassName;
066 }
067
068 /**
069 * Constructor.
070 */
071 public Declaration(Class<?> pluginClass) {
072 this.pluginClass = pluginClass;
073 this.pluginClassName = pluginClass.getName();
074 }
075
076 /**
077 * Create an instance where a fully-initialised ruleLoader instance
078 * is provided by the caller instead of having the PluginManager
079 * "discover" an appropriate one.
080 */
081 public Declaration(Class<?> pluginClass, RuleLoader ruleLoader) {
082 this.pluginClass = pluginClass;
083 this.pluginClassName = pluginClass.getName();
084 this.ruleLoader = ruleLoader;
085 }
086
087 //---------------------- properties -----------------------------------
088
089 /**
090 * The id that the user associated with a particular plugin declaration
091 * in the input xml. This id is later used in the input xml to refer
092 * back to the original declaration.
093 * <p>
094 * For plugins declared "in-line", the id is null.
095 */
096 public void setId(String id) {
097 this.id = id;
098 }
099
100 /**
101 * Return the id associated with this declaration. For plugins
102 * declared "inline", null will be returned.
103 *
104 * @return The id value. May be null.
105 */
106 public String getId() {
107 return id;
108 }
109
110 /**
111 * Copy all (key,value) pairs in the param into the properties member of
112 * this object.
113 * <p>
114 * The declaration properties cannot be explicit member variables,
115 * because the set of useful properties a user can provide on a declaration
116 * depends on what RuleFinder classes are available - and extra RuleFinders
117 * can be added by the user. So here we keep a map of the settings, and
118 * let the RuleFinder objects look for whatever properties they consider
119 * significant.
120 * <p>
121 * The "id" and "class" properties are treated differently.
122 */
123 public void setProperties(Properties p) {
124 properties.putAll(p);
125 }
126
127 /**
128 * Return plugin class associated with this declaration.
129 *
130 * @return The pluginClass.
131 */
132 public Class<?> getPluginClass() {
133 return pluginClass;
134 }
135
136 //---------------------- methods -----------------------------------
137
138 /**
139 * Must be called exactly once, and must be called before any call
140 * to the configure method.
141 */
142 public void init(Digester digester, PluginManager pm) throws PluginException {
143 Log log = digester.getLogger();
144 boolean debug = log.isDebugEnabled();
145 if (debug) {
146 log.debug("init being called!");
147 }
148
149 if (initialized) {
150 throw new PluginAssertionFailure("Init called multiple times.");
151 }
152
153 if ((pluginClass == null) && (pluginClassName != null)) {
154 try {
155 // load the plugin class object
156 pluginClass =
157 digester.getClassLoader().loadClass(pluginClassName);
158 } catch(ClassNotFoundException cnfe) {
159 throw new PluginException(
160 "Unable to load class " + pluginClassName, cnfe);
161 }
162 }
163
164 if (ruleLoader == null) {
165 // the caller didn't provide a ruleLoader to the constructor,
166 // so get the plugin manager to "discover" one.
167 log.debug("Searching for ruleloader...");
168 ruleLoader = pm.findLoader(digester, id, pluginClass, properties);
169 } else {
170 log.debug("This declaration has an explicit ruleLoader.");
171 }
172
173 if (debug) {
174 if (ruleLoader == null) {
175 log.debug(
176 "No ruleLoader found for plugin declaration"
177 + " id [" + id + "]"
178 + ", class [" + pluginClass.getClass().getName() + "].");
179 } else {
180 log.debug(
181 "RuleLoader of type [" + ruleLoader.getClass().getName()
182 + "] associated with plugin declaration"
183 + " id [" + id + "]"
184 + ", class [" + pluginClass.getClass().getName() + "].");
185 }
186 }
187
188 initialized = true;
189 }
190
191 /**
192 * Attempt to load custom rules for the target class at the specified
193 * pattern.
194 * <p>
195 * On return, any custom rules associated with the plugin class have
196 * been loaded into the Rules object currently associated with the
197 * specified digester object.
198 */
199
200 public void configure(Digester digester, String pattern)
201 throws PluginException {
202 Log log = digester.getLogger();
203 boolean debug = log.isDebugEnabled();
204 if (debug) {
205 log.debug("configure being called!");
206 }
207
208 if (!initialized) {
209 throw new PluginAssertionFailure("Not initialized.");
210 }
211
212 if (ruleLoader != null) {
213 ruleLoader.addRules(digester, pattern);
214 }
215 }
216 }