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.Properties; 023 024 import org.apache.commons.logging.Log; 025 import org.apache.commons.digester3.Digester; 026 027 /** 028 * Represents a Class that can be instantiated by a PluginCreateRule, plus info on how to load custom digester rules for 029 * mapping xml into that plugged-in class. 030 * 031 * @since 1.6 032 */ 033 public class Declaration 034 { 035 036 /** The class of the object to be instantiated. */ 037 private Class<?> pluginClass; 038 039 /** The name of the class of the object to be instantiated. */ 040 private String pluginClassName; 041 042 /** See {@link #setId}. */ 043 private String id; 044 045 /** See {@link #setProperties}. */ 046 private Properties properties = new Properties(); 047 048 /** See {@link #init}. */ 049 private boolean initialized = false; 050 051 /** 052 * Class which is responsible for dynamically loading this plugin's rules on demand. 053 */ 054 private RuleLoader ruleLoader = null; 055 056 // ---------------------- constructors ---------------------------------- 057 058 /** 059 * Constructor. 060 * 061 * @param pluginClassName The name of the class of the object to be instantiated (will be load in the init method) 062 */ 063 public Declaration( String pluginClassName ) 064 { 065 // We can't load the pluginClass at this time, because we don't 066 // have a digester instance yet to load it through. So just 067 // save the name away, and we'll load the Class object in the 068 // init method. 069 this.pluginClassName = pluginClassName; 070 } 071 072 /** 073 * Constructor. 074 * 075 * @param pluginClass The class of the object to be instantiated (will be load in the init method) 076 */ 077 public Declaration( Class<?> pluginClass ) 078 { 079 this.pluginClass = pluginClass; 080 this.pluginClassName = pluginClass.getName(); 081 } 082 083 /** 084 * Create an instance where a fully-initialised ruleLoader instance is provided by the caller instead of having the 085 * PluginManager "discover" an appropriate one. 086 * 087 * @param pluginClass The class of the object to be instantiated (will be load in the init method) 088 * @param ruleLoader Class which is responsible for dynamically loading this plugin's rules on demand 089 */ 090 public Declaration( Class<?> pluginClass, RuleLoader ruleLoader ) 091 { 092 this.pluginClass = pluginClass; 093 this.pluginClassName = pluginClass.getName(); 094 this.ruleLoader = ruleLoader; 095 } 096 097 // ---------------------- properties ----------------------------------- 098 099 /** 100 * The id that the user associated with a particular plugin declaration in the input xml. This id is later used in 101 * the input xml to refer back to the original declaration. 102 * <p> 103 * For plugins declared "in-line", the id is null. 104 * 105 * @param id The id that the user associated with a particular plugin declaration in the input xml 106 */ 107 public void setId( String id ) 108 { 109 this.id = id; 110 } 111 112 /** 113 * Return the id associated with this declaration. For plugins declared "inline", null will be returned. 114 * 115 * @return The id value. May be null. 116 */ 117 public String getId() 118 { 119 return id; 120 } 121 122 /** 123 * Copy all (key,value) pairs in the param into the properties member of this object. 124 * <p> 125 * The declaration properties cannot be explicit member variables, because the set of useful properties a user can 126 * provide on a declaration depends on what RuleFinder classes are available - and extra RuleFinders can be added by 127 * the user. So here we keep a map of the settings, and let the RuleFinder objects look for whatever properties they 128 * consider significant. 129 * <p> 130 * The "id" and "class" properties are treated differently. 131 * 132 * @param p The properties have to be copied into the properties member of this object 133 */ 134 public void setProperties( Properties p ) 135 { 136 properties.putAll( p ); 137 } 138 139 /** 140 * Return plugin class associated with this declaration. 141 * 142 * @return The pluginClass. 143 */ 144 public Class<?> getPluginClass() 145 { 146 return pluginClass; 147 } 148 149 // ---------------------- methods ----------------------------------- 150 151 /** 152 * Must be called exactly once, and must be called before any call to the configure method. 153 * 154 * @param digester The Digester instance where plugin has to be plugged 155 * @param pm The plugin manager reference 156 * @throws PluginException if any error occurs while loading the rules 157 */ 158 public void init( Digester digester, PluginManager pm ) 159 throws PluginException 160 { 161 Log log = digester.getLogger(); 162 boolean debug = log.isDebugEnabled(); 163 if ( debug ) 164 { 165 log.debug( "init being called!" ); 166 } 167 168 if ( initialized ) 169 { 170 throw new PluginAssertionFailure( "Init called multiple times." ); 171 } 172 173 if ( ( pluginClass == null ) && ( pluginClassName != null ) ) 174 { 175 try 176 { 177 // load the plugin class object 178 pluginClass = digester.getClassLoader().loadClass( pluginClassName ); 179 } 180 catch ( ClassNotFoundException cnfe ) 181 { 182 throw new PluginException( "Unable to load class " + pluginClassName, cnfe ); 183 } 184 } 185 186 if ( ruleLoader == null ) 187 { 188 // the caller didn't provide a ruleLoader to the constructor, 189 // so get the plugin manager to "discover" one. 190 log.debug( "Searching for ruleloader..." ); 191 ruleLoader = pm.findLoader( digester, id, pluginClass, properties ); 192 } 193 else 194 { 195 log.debug( "This declaration has an explicit ruleLoader." ); 196 } 197 198 if ( debug ) 199 { 200 if ( ruleLoader == null ) 201 { 202 log.debug( "No ruleLoader found for plugin declaration" + " id [" + id + "]" + ", class [" 203 + pluginClass.getClass().getName() + "]." ); 204 } 205 else 206 { 207 log.debug( "RuleLoader of type [" + ruleLoader.getClass().getName() 208 + "] associated with plugin declaration" + " id [" + id + "]" + ", class [" 209 + pluginClass.getClass().getName() + "]." ); 210 } 211 } 212 213 initialized = true; 214 } 215 216 /** 217 * Attempt to load custom rules for the target class at the specified pattern. 218 * <p> 219 * On return, any custom rules associated with the plugin class have been loaded into the Rules object currently 220 * associated with the specified digester object. 221 * 222 * @param digester The Digester instance where plugin has to be plugged 223 * @param pattern The pattern the custom rules have to be bound 224 * @throws PluginException if any error occurs 225 */ 226 public void configure( Digester digester, String pattern ) 227 throws PluginException 228 { 229 Log log = digester.getLogger(); 230 boolean debug = log.isDebugEnabled(); 231 if ( debug ) 232 { 233 log.debug( "configure being called!" ); 234 } 235 236 if ( !initialized ) 237 { 238 throw new PluginAssertionFailure( "Not initialized." ); 239 } 240 241 if ( ruleLoader != null ) 242 { 243 ruleLoader.addRules( digester, pattern ); 244 } 245 } 246 247 }