001    /* $Id: Declaration.java 729120 2008-12-23 21:11:38Z rahul $
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    }