001 /* $Id: FactoryCreateRule.java 992060 2010-09-02 19:09:47Z simonetripodi $ 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 020 package org.apache.commons.digester; 021 022 import java.util.Stack; 023 024 import org.xml.sax.Attributes; 025 026 027 /** 028 * <p>Rule implementation that uses an {@link ObjectCreationFactory} to create 029 * a new object which it pushes onto the object stack. When the element is 030 * complete, the object will be popped.</p> 031 * 032 * <p>This rule is intended in situations where the element's attributes are 033 * needed before the object can be created. A common senario is for the 034 * ObjectCreationFactory implementation to use the attributes as parameters 035 * in a call to either a factory method or to a non-empty constructor. 036 */ 037 038 public class FactoryCreateRule extends Rule { 039 040 // ----------------------------------------------------------- Fields 041 042 /** Should exceptions thrown by the factory be ignored? */ 043 private boolean ignoreCreateExceptions; 044 /** Stock to manage */ 045 private Stack<Boolean> exceptionIgnoredStack; 046 047 // ----------------------------------------------------------- Constructors 048 049 050 /** 051 * Construct a factory create rule that will use the specified 052 * class name to create an {@link ObjectCreationFactory} which will 053 * then be used to create an object and push it on the stack. 054 * 055 * @param digester The associated Digester 056 * @param className Java class name of the object creation factory class 057 * 058 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 059 * Use {@link #FactoryCreateRule(String className)} instead. 060 */ 061 @Deprecated 062 public FactoryCreateRule(Digester digester, String className) { 063 064 this(className); 065 066 } 067 068 069 /** 070 * Construct a factory create rule that will use the specified 071 * class to create an {@link ObjectCreationFactory} which will 072 * then be used to create an object and push it on the stack. 073 * 074 * @param digester The associated Digester 075 * @param clazz Java class name of the object creation factory class 076 * 077 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 078 * Use {@link #FactoryCreateRule(Class clazz)} instead. 079 */ 080 @Deprecated 081 public FactoryCreateRule(Digester digester, Class<?> clazz) { 082 083 this(clazz); 084 085 } 086 087 088 /** 089 * Construct a factory create rule that will use the specified 090 * class name (possibly overridden by the specified attribute if present) 091 * to create an {@link ObjectCreationFactory}, which will then be used 092 * to instantiate an object instance and push it onto the stack. 093 * 094 * @param digester The associated Digester 095 * @param className Default Java class name of the factory class 096 * @param attributeName Attribute name which, if present, contains an 097 * override of the class name of the object creation factory to create. 098 * 099 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 100 * Use {@link #FactoryCreateRule(String className, String attributeName)} instead. 101 */ 102 @Deprecated 103 public FactoryCreateRule(Digester digester, 104 String className, String attributeName) { 105 106 this(className, attributeName); 107 108 } 109 110 111 /** 112 * Construct a factory create rule that will use the specified 113 * class (possibly overridden by the specified attribute if present) 114 * to create an {@link ObjectCreationFactory}, which will then be used 115 * to instantiate an object instance and push it onto the stack. 116 * 117 * @param digester The associated Digester 118 * @param clazz Default Java class name of the factory class 119 * @param attributeName Attribute name which, if present, contains an 120 * override of the class name of the object creation factory to create. 121 * 122 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 123 * Use {@link #FactoryCreateRule(Class clazz, String attributeName)} instead. 124 */ 125 @Deprecated 126 public FactoryCreateRule(Digester digester, 127 Class<?> clazz, String attributeName) { 128 129 this(clazz, attributeName); 130 131 } 132 133 134 /** 135 * Construct a factory create rule using the given, already instantiated, 136 * {@link ObjectCreationFactory}. 137 * 138 * @param digester The associated Digester 139 * @param creationFactory called on to create the object. 140 * 141 * @deprecated The digester instance is now set in the {@link Digester#addRule} method. 142 * Use {@link #FactoryCreateRule(ObjectCreationFactory creationFactory)} instead. 143 */ 144 @Deprecated 145 public FactoryCreateRule(Digester digester, 146 ObjectCreationFactory creationFactory) { 147 148 this(creationFactory); 149 150 } 151 152 /** 153 * <p>Construct a factory create rule that will use the specified 154 * class name to create an {@link ObjectCreationFactory} which will 155 * then be used to create an object and push it on the stack.</p> 156 * 157 * <p>Exceptions thrown during the object creation process will be propagated.</p> 158 * 159 * @param className Java class name of the object creation factory class 160 */ 161 public FactoryCreateRule(String className) { 162 163 this(className, false); 164 165 } 166 167 168 /** 169 * <p>Construct a factory create rule that will use the specified 170 * class to create an {@link ObjectCreationFactory} which will 171 * then be used to create an object and push it on the stack.</p> 172 * 173 * <p>Exceptions thrown during the object creation process will be propagated.</p> 174 * 175 * @param clazz Java class name of the object creation factory class 176 */ 177 public FactoryCreateRule(Class<?> clazz) { 178 179 this(clazz, false); 180 181 } 182 183 184 /** 185 * <p>Construct a factory create rule that will use the specified 186 * class name (possibly overridden by the specified attribute if present) 187 * to create an {@link ObjectCreationFactory}, which will then be used 188 * to instantiate an object instance and push it onto the stack.</p> 189 * 190 * <p>Exceptions thrown during the object creation process will be propagated.</p> 191 * 192 * @param className Default Java class name of the factory class 193 * @param attributeName Attribute name which, if present, contains an 194 * override of the class name of the object creation factory to create. 195 */ 196 public FactoryCreateRule(String className, String attributeName) { 197 198 this(className, attributeName, false); 199 200 } 201 202 203 /** 204 * <p>Construct a factory create rule that will use the specified 205 * class (possibly overridden by the specified attribute if present) 206 * to create an {@link ObjectCreationFactory}, which will then be used 207 * to instantiate an object instance and push it onto the stack.</p> 208 * 209 * <p>Exceptions thrown during the object creation process will be propagated.</p> 210 * 211 * @param clazz Default Java class name of the factory class 212 * @param attributeName Attribute name which, if present, contains an 213 * override of the class name of the object creation factory to create. 214 */ 215 public FactoryCreateRule(Class<?> clazz, String attributeName) { 216 217 this(clazz, attributeName, false); 218 219 } 220 221 222 /** 223 * <p>Construct a factory create rule using the given, already instantiated, 224 * {@link ObjectCreationFactory}.</p> 225 * 226 * <p>Exceptions thrown during the object creation process will be propagated.</p> 227 * 228 * @param creationFactory called on to create the object. 229 */ 230 public FactoryCreateRule(ObjectCreationFactory creationFactory) { 231 232 this(creationFactory, false); 233 234 } 235 236 /** 237 * Construct a factory create rule that will use the specified 238 * class name to create an {@link ObjectCreationFactory} which will 239 * then be used to create an object and push it on the stack. 240 * 241 * @param className Java class name of the object creation factory class 242 * @param ignoreCreateExceptions if true, exceptions thrown by the object 243 * creation factory 244 * will be ignored. 245 */ 246 public FactoryCreateRule(String className, boolean ignoreCreateExceptions) { 247 248 this(className, null, ignoreCreateExceptions); 249 250 } 251 252 253 /** 254 * Construct a factory create rule that will use the specified 255 * class to create an {@link ObjectCreationFactory} which will 256 * then be used to create an object and push it on the stack. 257 * 258 * @param clazz Java class name of the object creation factory class 259 * @param ignoreCreateExceptions if true, exceptions thrown by the 260 * object creation factory 261 * will be ignored. 262 */ 263 public FactoryCreateRule(Class<?> clazz, boolean ignoreCreateExceptions) { 264 265 this(clazz, null, ignoreCreateExceptions); 266 267 } 268 269 270 /** 271 * Construct a factory create rule that will use the specified 272 * class name (possibly overridden by the specified attribute if present) 273 * to create an {@link ObjectCreationFactory}, which will then be used 274 * to instantiate an object instance and push it onto the stack. 275 * 276 * @param className Default Java class name of the factory class 277 * @param attributeName Attribute name which, if present, contains an 278 * override of the class name of the object creation factory to create. 279 * @param ignoreCreateExceptions if true, exceptions thrown by the object 280 * creation factory will be ignored. 281 */ 282 public FactoryCreateRule( 283 String className, 284 String attributeName, 285 boolean ignoreCreateExceptions) { 286 287 this.className = className; 288 this.attributeName = attributeName; 289 this.ignoreCreateExceptions = ignoreCreateExceptions; 290 291 } 292 293 294 /** 295 * Construct a factory create rule that will use the specified 296 * class (possibly overridden by the specified attribute if present) 297 * to create an {@link ObjectCreationFactory}, which will then be used 298 * to instantiate an object instance and push it onto the stack. 299 * 300 * @param clazz Default Java class name of the factory class 301 * @param attributeName Attribute name which, if present, contains an 302 * override of the class name of the object creation factory to create. 303 * @param ignoreCreateExceptions if true, exceptions thrown by the object 304 * creation factory will be ignored. 305 */ 306 public FactoryCreateRule( 307 Class<?> clazz, 308 String attributeName, 309 boolean ignoreCreateExceptions) { 310 311 this(clazz.getName(), attributeName, ignoreCreateExceptions); 312 313 } 314 315 316 /** 317 * Construct a factory create rule using the given, already instantiated, 318 * {@link ObjectCreationFactory}. 319 * 320 * @param creationFactory called on to create the object. 321 * @param ignoreCreateExceptions if true, exceptions thrown by the object 322 * creation factory will be ignored. 323 */ 324 public FactoryCreateRule( 325 ObjectCreationFactory creationFactory, 326 boolean ignoreCreateExceptions) { 327 328 this.creationFactory = creationFactory; 329 this.ignoreCreateExceptions = ignoreCreateExceptions; 330 } 331 332 // ----------------------------------------------------- Instance Variables 333 334 335 /** 336 * The attribute containing an override class name if it is present. 337 */ 338 protected String attributeName = null; 339 340 341 /** 342 * The Java class name of the ObjectCreationFactory to be created. 343 * This class must have a no-arguments constructor. 344 */ 345 protected String className = null; 346 347 348 /** 349 * The object creation factory we will use to instantiate objects 350 * as required based on the attributes specified in the matched XML 351 * element. 352 */ 353 protected ObjectCreationFactory creationFactory = null; 354 355 356 // --------------------------------------------------------- Public Methods 357 358 359 /** 360 * Process the beginning of this element. 361 * 362 * @param attributes The attribute list of this element 363 */ 364 @Override 365 public void begin(String namespace, String name, Attributes attributes) throws Exception { 366 367 if (ignoreCreateExceptions) { 368 369 if (exceptionIgnoredStack == null) { 370 exceptionIgnoredStack = new Stack<Boolean>(); 371 } 372 373 try { 374 Object instance = getFactory(attributes).createObject(attributes); 375 376 if (digester.log.isDebugEnabled()) { 377 digester.log.debug("[FactoryCreateRule]{" + digester.match + 378 "} New " + (instance == null ? "null object" : 379 instance.getClass().getName())); 380 } 381 digester.push(instance); 382 exceptionIgnoredStack.push(Boolean.FALSE); 383 384 } catch (Exception e) { 385 // log message and error 386 if (digester.log.isInfoEnabled()) { 387 digester.log.info("[FactoryCreateRule] Create exception ignored: " + 388 ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage())); 389 if (digester.log.isDebugEnabled()) { 390 digester.log.debug("[FactoryCreateRule] Ignored exception:", e); 391 } 392 } 393 exceptionIgnoredStack.push(Boolean.TRUE); 394 } 395 396 } else { 397 Object instance = getFactory(attributes).createObject(attributes); 398 399 if (digester.log.isDebugEnabled()) { 400 digester.log.debug("[FactoryCreateRule]{" + digester.match + 401 "} New " + (instance == null ? "null object" : 402 instance.getClass().getName())); 403 } 404 digester.push(instance); 405 } 406 } 407 408 409 /** 410 * Process the end of this element. 411 */ 412 @Override 413 public void end(String namespace, String name) throws Exception { 414 415 // check if object was created 416 // this only happens if an exception was thrown and we're ignoring them 417 if ( 418 ignoreCreateExceptions && 419 exceptionIgnoredStack != null && 420 !(exceptionIgnoredStack.empty())) { 421 422 if (exceptionIgnoredStack.pop().booleanValue()) { 423 // creation exception was ignored 424 // nothing was put onto the stack 425 if (digester.log.isTraceEnabled()) { 426 digester.log.trace("[FactoryCreateRule] No creation so no push so no pop"); 427 } 428 return; 429 } 430 } 431 432 Object top = digester.pop(); 433 if (digester.log.isDebugEnabled()) { 434 digester.log.debug("[FactoryCreateRule]{" + digester.match + 435 "} Pop " + top.getClass().getName()); 436 } 437 438 } 439 440 441 /** 442 * Clean up after parsing is complete. 443 */ 444 @Override 445 public void finish() throws Exception { 446 447 if (attributeName != null) { 448 creationFactory = null; 449 } 450 451 } 452 453 454 /** 455 * Render a printable version of this Rule. 456 */ 457 @Override 458 public String toString() { 459 460 StringBuffer sb = new StringBuffer("FactoryCreateRule["); 461 sb.append("className="); 462 sb.append(className); 463 sb.append(", attributeName="); 464 sb.append(attributeName); 465 if (creationFactory != null) { 466 sb.append(", creationFactory="); 467 sb.append(creationFactory); 468 } 469 sb.append("]"); 470 return (sb.toString()); 471 472 } 473 474 475 // ------------------------------------------------------ Protected Methods 476 477 478 /** 479 * Return an instance of our associated object creation factory, 480 * creating one if necessary. 481 * 482 * @param attributes Attributes passed to our factory creation element 483 * 484 * @exception Exception if any error occurs 485 */ 486 protected ObjectCreationFactory getFactory(Attributes attributes) 487 throws Exception { 488 489 if (creationFactory == null) { 490 String realClassName = className; 491 if (attributeName != null) { 492 String value = attributes.getValue(attributeName); 493 if (value != null) { 494 realClassName = value; 495 } 496 } 497 if (digester.log.isDebugEnabled()) { 498 digester.log.debug("[FactoryCreateRule]{" + digester.match + 499 "} New factory " + realClassName); 500 } 501 Class<?> clazz = digester.getClassLoader().loadClass(realClassName); 502 creationFactory = (ObjectCreationFactory) 503 clazz.newInstance(); 504 creationFactory.setDigester(digester); 505 } 506 return (creationFactory); 507 508 } 509 }