View Javadoc

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 }