    001    /* $Id: PluginManager.java 729122 2008-12-23 21:14:13Z 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
    019    package org.apache.commons.digester.plugins;
    020
    021    import java.util.HashMap;
    022    import java.util.List;
    023    import java.util.Properties;
    024    import java.util.Iterator;
    025
    026    import org.apache.commons.digester.Digester;
    027
    028    import org.apache.commons.logging.Log;
    029
    030    /**
    031     * Coordinates between PluginDeclarationRule and PluginCreateRule objects,
    032     * providing a place to share data between instances of these rules.
    033     * <p>
    034     * One instance of this class exists per PluginRules instance.
    035     *
    036     * @since 1.6
    037     */
    038
    039    public class PluginManager {
    040
    041        /** Map of classname->Declaration */
    042        private HashMap<String, Declaration> declarationsByClass = new HashMap<String, Declaration>();
    043
    044        /** Map of id->Declaration  */
    045        private HashMap<String, Declaration> declarationsById = new HashMap<String, Declaration>();
    046
    047        /** the parent manager to which this one may delegate lookups. */
    048        private PluginManager parent;
    049
    050        /**
    051         * The object containing data that should only exist once for each
    052         * Digester instance.
    053         */
    054        private PluginContext pluginContext;
    055
    056        //------------------- constructors ---------------------------------------
    057
    058        /** Construct a "root" PluginManager, ie one with no parent. */
    059        public PluginManager(PluginContext r) {
    060            pluginContext = r;
    061        }
    062
    063        /**
    064         * Construct a "child" PluginManager. When declarations are added to
    065         * a "child", they are stored within the child and do not modify the
    066         * parent, so when the child goes out of scope, those declarations
    067         * disappear. When asking a "child" to retrieve a declaration, it
    068         * delegates the search to its parent if it does not hold a matching
    069         * entry itself.
    070         * <p>
    071         * @param parent must be non-null.
    072         */
    073        public PluginManager(PluginManager parent) {
    074            this.parent = parent;
    075            this.pluginContext = parent.pluginContext;
    076        }
    077
    078        //------------------- methods --------------------------------------------
    079
    080        /**
    081         * Add the declaration to the set of known declarations.
    082         * <p>
    083         * TODO: somehow get a reference to a Digester object
    084         * so that we can really log here. Currently, all
    085         * logging is disabled from this method.
    086         *
    087         *@param decl an object representing a plugin class.
    088         */
    089        public void addDeclaration(Declaration decl) {
    090            Log log = LogUtils.getLogger(null);
    091            boolean debug = log.isDebugEnabled();
    092
    093            Class<?> pluginClass = decl.getPluginClass();
    094            String id = decl.getId();
    095
    096            declarationsByClass.put(pluginClass.getName(), decl);
    097
    098            if (id != null) {
    099                declarationsById.put(id, decl);
    100                if (debug) {
    101                    log.debug(
    102                        "Indexing plugin-id [" + id + "]" +
    103                        " -> class [" + pluginClass.getName() + "]");
    104                }
    105            }
    106        }
    107
    108        /**
    109         * Return the declaration object with the specified class.
    110         * If no such plugin is known, null is returned.
    111         */
    112        public Declaration getDeclarationByClass(String className) {
    113            Declaration decl =
    114                (Declaration) declarationsByClass.get(className);
    115
    116            if ((decl == null) && (parent != null)) {
    117                decl = parent.getDeclarationByClass(className);
    118            }
    119
    120            return decl;
    121        }
    122
    123        /**
    124         * Return the declaration object with the specified id.
    125         * If no such plugin is known, null is returned.
    126         *
    127         *@param id Description of the Parameter
    128         *@return The declaration value
    129         */
    130        public Declaration getDeclarationById(String id) {
    131            Declaration decl = (Declaration) declarationsById.get(id);
    132
    133            if ((decl == null) && (parent != null)) {
    134                decl = parent.getDeclarationById(id);
    135            }
    136
    137            return decl;
    138        }
    139
    140        /**
    141         * Given a plugin class and some associated properties, scan the
    142         * list of known RuleFinder instances until one detects a source of
    143         * custom rules for this plugin (aka a RuleLoader).
    144         * <p>
    145         * If no source of custom rules can be found, null is returned.
    146         */
    147        public RuleLoader findLoader(Digester digester, String id,
    148                            Class<?> pluginClass, Properties props)
    149                            throws PluginException {
    150
    151            // iterate over the list of RuleFinders, trying each one
    152            // until one of them locates a source of dynamic rules given
    153            // this specific plugin class and the associated declaration
    154            // properties.
    155            Log log = LogUtils.getLogger(digester);
    156            boolean debug = log.isDebugEnabled();
    157            log.debug("scanning ruleFinders to locate loader..");
    158
    159            List<RuleFinder> ruleFinders = pluginContext.getRuleFinders();
    160            RuleLoader ruleLoader = null;
    161            try {
    162                for(Iterator<RuleFinder> i = ruleFinders.iterator();
    163                    i.hasNext() && ruleLoader == null; ) {
    164
    165                    RuleFinder finder = (RuleFinder) i.next();
    166                    if (debug) {
    167                        log.debug("checking finder of type " + finder.getClass().getName());
    168                    }
    169                    ruleLoader = finder.findLoader(digester, pluginClass, props);
    170                }
    171            }
    172            catch(PluginException e) {
    173                throw new PluginException(
    174                    "Unable to locate plugin rules for plugin"
    175                    + " with id [" + id + "]"
    176                    + ", and class [" + pluginClass.getName() + "]"
    177                    + ":" + e.getMessage(), e.getCause());
    178            }
    179            log.debug("scanned ruleFinders.");
    180
    181            return ruleLoader;
    182        }
    183    }