001 package org.apache.commons.digester3.plugins; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.util.HashMap; 023 import java.util.Iterator; 024 import java.util.List; 025 import java.util.Properties; 026 027 import org.apache.commons.digester3.Digester; 028 import org.apache.commons.logging.Log; 029 030 /** 031 * Coordinates between PluginDeclarationRule and PluginCreateRule objects, providing a place to share data between 032 * instances of these rules. 033 * <p> 034 * One instance of this class exists per PluginRules instance. 035 * 036 * @since 1.6 037 */ 038 public class PluginManager 039 { 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 Digester instance. 052 */ 053 private PluginContext pluginContext; 054 055 // ------------------- constructors --------------------------------------- 056 057 /** 058 * Construct a "root" PluginManager, ie one with no parent. 059 * 060 * @param r The object containing data that should only exist once for each Digester instance. 061 */ 062 public PluginManager( PluginContext r ) 063 { 064 pluginContext = r; 065 } 066 067 /** 068 * Construct a "child" PluginManager. When declarations are added to a "child", they are stored within the child and 069 * do not modify the parent, so when the child goes out of scope, those declarations disappear. When asking a 070 * "child" to retrieve a declaration, it delegates the search to its parent if it does not hold a matching entry 071 * itself. 072 * <p> 073 * 074 * @param parent must be non-null. 075 */ 076 public PluginManager( PluginManager parent ) 077 { 078 this.parent = parent; 079 this.pluginContext = parent.pluginContext; 080 } 081 082 // ------------------- methods -------------------------------------------- 083 084 /** 085 * Add the declaration to the set of known declarations. 086 * <p> 087 * TODO: somehow get a reference to a Digester object so that we can really log here. Currently, all logging is 088 * disabled from this method. 089 * 090 * @param decl an object representing a plugin class. 091 */ 092 public void addDeclaration( Declaration decl ) 093 { 094 Log log = LogUtils.getLogger( null ); 095 boolean debug = log.isDebugEnabled(); 096 097 Class<?> pluginClass = decl.getPluginClass(); 098 String id = decl.getId(); 099 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 }