001 /* $Id: PluginManager.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
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 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 = 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 = 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 }