1 package org.apache.commons.digester3.plugins; 2 3 /* 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance 10 * with the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, 15 * software distributed under the License is distributed on an 16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 * KIND, either express or implied. See the License for the 18 * specific language governing permissions and limitations 19 * under the License. 20 */ 21 22 import java.util.HashMap; 23 import java.util.Iterator; 24 import java.util.List; 25 import java.util.Properties; 26 27 import org.apache.commons.digester3.Digester; 28 import org.apache.commons.logging.Log; 29 30 /** 31 * Coordinates between PluginDeclarationRule and PluginCreateRule objects, providing a place to share data between 32 * instances of these rules. 33 * <p> 34 * One instance of this class exists per PluginRules instance. 35 * 36 * @since 1.6 37 */ 38 public class PluginManager 39 { 40 41 /** Map of classname->Declaration */ 42 private HashMap<String, Declaration> declarationsByClass = new HashMap<String, Declaration>(); 43 44 /** Map of id->Declaration */ 45 private HashMap<String, Declaration> declarationsById = new HashMap<String, Declaration>(); 46 47 /** the parent manager to which this one may delegate lookups. */ 48 private PluginManager parent; 49 50 /** 51 * The object containing data that should only exist once for each Digester instance. 52 */ 53 private PluginContext pluginContext; 54 55 // ------------------- constructors --------------------------------------- 56 57 /** 58 * Construct a "root" PluginManager, ie one with no parent. 59 * 60 * @param r The object containing data that should only exist once for each Digester instance. 61 */ 62 public PluginManager( PluginContext r ) 63 { 64 pluginContext = r; 65 } 66 67 /** 68 * Construct a "child" PluginManager. When declarations are added to a "child", they are stored within the child and 69 * do not modify the parent, so when the child goes out of scope, those declarations disappear. When asking a 70 * "child" to retrieve a declaration, it delegates the search to its parent if it does not hold a matching entry 71 * itself. 72 * <p> 73 * 74 * @param parent must be non-null. 75 */ 76 public PluginManager( PluginManager parent ) 77 { 78 this.parent = parent; 79 this.pluginContext = parent.pluginContext; 80 } 81 82 // ------------------- methods -------------------------------------------- 83 84 /** 85 * Add the declaration to the set of known declarations. 86 * <p> 87 * TODO: somehow get a reference to a Digester object so that we can really log here. Currently, all logging is 88 * disabled from this method. 89 * 90 * @param decl an object representing a plugin class. 91 */ 92 public void addDeclaration( Declaration decl ) 93 { 94 Log log = LogUtils.getLogger( null ); 95 boolean debug = log.isDebugEnabled(); 96 97 Class<?> pluginClass = decl.getPluginClass(); 98 String id = decl.getId(); 99 100 declarationsByClass.put( pluginClass.getName(), decl ); 101 102 if ( id != null ) 103 { 104 declarationsById.put( id, decl ); 105 if ( debug ) 106 { 107 log.debug( "Indexing plugin-id [" + id + "]" + " -> class [" + pluginClass.getName() + "]" ); 108 } 109 } 110 } 111 112 /** 113 * Return the declaration object with the specified class. If no such plugin is known, null is returned. 114 * 115 * @param className The {@link Declaration} class name 116 * @return The Declaration instance obtained by the input class name 117 */ 118 public Declaration getDeclarationByClass( String className ) 119 { 120 Declaration decl = declarationsByClass.get( className ); 121 122 if ( ( decl == null ) && ( parent != null ) ) 123 { 124 decl = parent.getDeclarationByClass( className ); 125 } 126 127 return decl; 128 } 129 130 /** 131 * Return the declaration object with the specified id. If no such plugin is known, null is returned. 132 * 133 * @param id Description of the Parameter 134 * @return The declaration value 135 */ 136 public Declaration getDeclarationById( String id ) 137 { 138 Declaration decl = declarationsById.get( id ); 139 140 if ( ( decl == null ) && ( parent != null ) ) 141 { 142 decl = parent.getDeclarationById( id ); 143 } 144 145 return decl; 146 } 147 148 /** 149 * Given a plugin class and some associated properties, scan the list of known RuleFinder instances until one 150 * detects a source of custom rules for this plugin (aka a RuleLoader). 151 * <p> 152 * If no source of custom rules can be found, null is returned. 153 * 154 * @param digester The digester instance where locating plugin classes 155 * @param id The id that the user associated with a particular plugin declaration in the input xml 156 * @param pluginClass The plugin Java class 157 * @param props The properties object that holds any xml attributes the user may have specified on the plugin 158 * declaration in order to indicate how to locate the plugin rules. 159 * @return The discovered Rule loader instance 160 * @throws PluginException if any error occurs while finding the loader 161 */ 162 public RuleLoader findLoader( Digester digester, String id, Class<?> pluginClass, Properties props ) 163 throws PluginException 164 { 165 166 // iterate over the list of RuleFinders, trying each one 167 // until one of them locates a source of dynamic rules given 168 // this specific plugin class and the associated declaration 169 // properties. 170 Log log = LogUtils.getLogger( digester ); 171 boolean debug = log.isDebugEnabled(); 172 log.debug( "scanning ruleFinders to locate loader.." ); 173 174 List<RuleFinder> ruleFinders = pluginContext.getRuleFinders(); 175 RuleLoader ruleLoader = null; 176 for ( Iterator<RuleFinder> i = ruleFinders.iterator(); i.hasNext() && ruleLoader == null; ) 177 { 178 179 RuleFinder finder = i.next(); 180 if ( debug ) 181 { 182 log.debug( "checking finder of type " + finder.getClass().getName() ); 183 } 184 try 185 { 186 ruleLoader = finder.findLoader( digester, pluginClass, props ); 187 } 188 catch ( PluginException e ) 189 { 190 throw new PluginException( "Unable to locate plugin rules for plugin" + " with id [" + id + "]" 191 + ", and class [" + pluginClass.getName() + "]" + ":" + e.getMessage(), e.getCause() ); 192 } 193 } 194 log.debug( "scanned ruleFinders." ); 195 196 return ruleLoader; 197 } 198 199 }