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 }