001 /* $Id: FactoryCreateRule.java 729242 2008-12-24 06:10:07Z rahul $
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 public FactoryCreateRule(Digester digester, String className) {
062
063 this(className);
064
065 }
066
067
068 /**
069 * Construct a factory create rule that will use the specified
070 * class to create an {@link ObjectCreationFactory} which will
071 * then be used to create an object and push it on the stack.
072 *
073 * @param digester The associated Digester
074 * @param clazz Java class name of the object creation factory class
075 *
076 * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
077 * Use {@link #FactoryCreateRule(Class clazz)} instead.
078 */
079 public FactoryCreateRule(Digester digester, Class<?> clazz) {
080
081 this(clazz);
082
083 }
084
085
086 /**
087 * Construct a factory create rule that will use the specified
088 * class name (possibly overridden by the specified attribute if present)
089 * to create an {@link ObjectCreationFactory}, which will then be used
090 * to instantiate an object instance and push it onto the stack.
091 *
092 * @param digester The associated Digester
093 * @param className Default Java class name of the factory class
094 * @param attributeName Attribute name which, if present, contains an
095 * override of the class name of the object creation factory to create.
096 *
097 * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
098 * Use {@link #FactoryCreateRule(String className, String attributeName)} instead.
099 */
100 public FactoryCreateRule(Digester digester,
101 String className, String attributeName) {
102
103 this(className, attributeName);
104
105 }
106
107
108 /**
109 * Construct a factory create rule that will use the specified
110 * class (possibly overridden by the specified attribute if present)
111 * to create an {@link ObjectCreationFactory}, which will then be used
112 * to instantiate an object instance and push it onto the stack.
113 *
114 * @param digester The associated Digester
115 * @param clazz Default Java class name of the factory class
116 * @param attributeName Attribute name which, if present, contains an
117 * override of the class name of the object creation factory to create.
118 *
119 * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
120 * Use {@link #FactoryCreateRule(Class clazz, String attributeName)} instead.
121 */
122 public FactoryCreateRule(Digester digester,
123 Class<?> clazz, String attributeName) {
124
125 this(clazz, attributeName);
126
127 }
128
129
130 /**
131 * Construct a factory create rule using the given, already instantiated,
132 * {@link ObjectCreationFactory}.
133 *
134 * @param digester The associated Digester
135 * @param creationFactory called on to create the object.
136 *
137 * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
138 * Use {@link #FactoryCreateRule(ObjectCreationFactory creationFactory)} instead.
139 */
140 public FactoryCreateRule(Digester digester,
141 ObjectCreationFactory creationFactory) {
142
143 this(creationFactory);
144
145 }
146
147 /**
148 * <p>Construct a factory create rule that will use the specified
149 * class name to create an {@link ObjectCreationFactory} which will
150 * then be used to create an object and push it on the stack.</p>
151 *
152 * <p>Exceptions thrown during the object creation process will be propagated.</p>
153 *
154 * @param className Java class name of the object creation factory class
155 */
156 public FactoryCreateRule(String className) {
157
158 this(className, false);
159
160 }
161
162
163 /**
164 * <p>Construct a factory create rule that will use the specified
165 * class to create an {@link ObjectCreationFactory} which will
166 * then be used to create an object and push it on the stack.</p>
167 *
168 * <p>Exceptions thrown during the object creation process will be propagated.</p>
169 *
170 * @param clazz Java class name of the object creation factory class
171 */
172 public FactoryCreateRule(Class<?> clazz) {
173
174 this(clazz, false);
175
176 }
177
178
179 /**
180 * <p>Construct a factory create rule that will use the specified
181 * class name (possibly overridden by the specified attribute if present)
182 * to create an {@link ObjectCreationFactory}, which will then be used
183 * to instantiate an object instance and push it onto the stack.</p>
184 *
185 * <p>Exceptions thrown during the object creation process will be propagated.</p>
186 *
187 * @param className Default Java class name of the factory class
188 * @param attributeName Attribute name which, if present, contains an
189 * override of the class name of the object creation factory to create.
190 */
191 public FactoryCreateRule(String className, String attributeName) {
192
193 this(className, attributeName, false);
194
195 }
196
197
198 /**
199 * <p>Construct a factory create rule that will use the specified
200 * class (possibly overridden by the specified attribute if present)
201 * to create an {@link ObjectCreationFactory}, which will then be used
202 * to instantiate an object instance and push it onto the stack.</p>
203 *
204 * <p>Exceptions thrown during the object creation process will be propagated.</p>
205 *
206 * @param clazz Default Java class name of the factory class
207 * @param attributeName Attribute name which, if present, contains an
208 * override of the class name of the object creation factory to create.
209 */
210 public FactoryCreateRule(Class<?> clazz, String attributeName) {
211
212 this(clazz, attributeName, false);
213
214 }
215
216
217 /**
218 * <p>Construct a factory create rule using the given, already instantiated,
219 * {@link ObjectCreationFactory}.</p>
220 *
221 * <p>Exceptions thrown during the object creation process will be propagated.</p>
222 *
223 * @param creationFactory called on to create the object.
224 */
225 public FactoryCreateRule(ObjectCreationFactory creationFactory) {
226
227 this(creationFactory, false);
228
229 }
230
231 /**
232 * Construct a factory create rule that will use the specified
233 * class name to create an {@link ObjectCreationFactory} which will
234 * then be used to create an object and push it on the stack.
235 *
236 * @param className Java class name of the object creation factory class
237 * @param ignoreCreateExceptions if true, exceptions thrown by the object
238 * creation factory
239 * will be ignored.
240 */
241 public FactoryCreateRule(String className, boolean ignoreCreateExceptions) {
242
243 this(className, null, ignoreCreateExceptions);
244
245 }
246
247
248 /**
249 * Construct a factory create rule that will use the specified
250 * class to create an {@link ObjectCreationFactory} which will
251 * then be used to create an object and push it on the stack.
252 *
253 * @param clazz Java class name of the object creation factory class
254 * @param ignoreCreateExceptions if true, exceptions thrown by the
255 * object creation factory
256 * will be ignored.
257 */
258 public FactoryCreateRule(Class<?> clazz, boolean ignoreCreateExceptions) {
259
260 this(clazz, null, ignoreCreateExceptions);
261
262 }
263
264
265 /**
266 * Construct a factory create rule that will use the specified
267 * class name (possibly overridden by the specified attribute if present)
268 * to create an {@link ObjectCreationFactory}, which will then be used
269 * to instantiate an object instance and push it onto the stack.
270 *
271 * @param className Default Java class name of the factory class
272 * @param attributeName Attribute name which, if present, contains an
273 * override of the class name of the object creation factory to create.
274 * @param ignoreCreateExceptions if true, exceptions thrown by the object
275 * creation factory will be ignored.
276 */
277 public FactoryCreateRule(
278 String className,
279 String attributeName,
280 boolean ignoreCreateExceptions) {
281
282 this.className = className;
283 this.attributeName = attributeName;
284 this.ignoreCreateExceptions = ignoreCreateExceptions;
285
286 }
287
288
289 /**
290 * Construct a factory create rule that will use the specified
291 * class (possibly overridden by the specified attribute if present)
292 * to create an {@link ObjectCreationFactory}, which will then be used
293 * to instantiate an object instance and push it onto the stack.
294 *
295 * @param clazz Default Java class name of the factory class
296 * @param attributeName Attribute name which, if present, contains an
297 * override of the class name of the object creation factory to create.
298 * @param ignoreCreateExceptions if true, exceptions thrown by the object
299 * creation factory will be ignored.
300 */
301 public FactoryCreateRule(
302 Class<?> clazz,
303 String attributeName,
304 boolean ignoreCreateExceptions) {
305
306 this(clazz.getName(), attributeName, ignoreCreateExceptions);
307
308 }
309
310
311 /**
312 * Construct a factory create rule using the given, already instantiated,
313 * {@link ObjectCreationFactory}.
314 *
315 * @param creationFactory called on to create the object.
316 * @param ignoreCreateExceptions if true, exceptions thrown by the object
317 * creation factory will be ignored.
318 */
319 public FactoryCreateRule(
320 ObjectCreationFactory creationFactory,
321 boolean ignoreCreateExceptions) {
322
323 this.creationFactory = creationFactory;
324 this.ignoreCreateExceptions = ignoreCreateExceptions;
325 }
326
327 // ----------------------------------------------------- Instance Variables
328
329
330 /**
331 * The attribute containing an override class name if it is present.
332 */
333 protected String attributeName = null;
334
335
336 /**
337 * The Java class name of the ObjectCreationFactory to be created.
338 * This class must have a no-arguments constructor.
339 */
340 protected String className = null;
341
342
343 /**
344 * The object creation factory we will use to instantiate objects
345 * as required based on the attributes specified in the matched XML
346 * element.
347 */
348 protected ObjectCreationFactory creationFactory = null;
349
350
351 // --------------------------------------------------------- Public Methods
352
353
354 /**
355 * Process the beginning of this element.
356 *
357 * @param attributes The attribute list of this element
358 */
359 public void begin(String namespace, String name, Attributes attributes) throws Exception {
360
361 if (ignoreCreateExceptions) {
362
363 if (exceptionIgnoredStack == null) {
364 exceptionIgnoredStack = new Stack<Boolean>();
365 }
366
367 try {
368 Object instance = getFactory(attributes).createObject(attributes);
369
370 if (digester.log.isDebugEnabled()) {
371 digester.log.debug("[FactoryCreateRule]{" + digester.match +
372 "} New " + (instance == null ? "null object" :
373 instance.getClass().getName()));
374 }
375 digester.push(instance);
376 exceptionIgnoredStack.push(Boolean.FALSE);
377
378 } catch (Exception e) {
379 // log message and error
380 if (digester.log.isInfoEnabled()) {
381 digester.log.info("[FactoryCreateRule] Create exception ignored: " +
382 ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage()));
383 if (digester.log.isDebugEnabled()) {
384 digester.log.debug("[FactoryCreateRule] Ignored exception:", e);
385 }
386 }
387 exceptionIgnoredStack.push(Boolean.TRUE);
388 }
389
390 } else {
391 Object instance = getFactory(attributes).createObject(attributes);
392
393 if (digester.log.isDebugEnabled()) {
394 digester.log.debug("[FactoryCreateRule]{" + digester.match +
395 "} New " + (instance == null ? "null object" :
396 instance.getClass().getName()));
397 }
398 digester.push(instance);
399 }
400 }
401
402
403 /**
404 * Process the end of this element.
405 */
406 public void end(String namespace, String name) throws Exception {
407
408 // check if object was created
409 // this only happens if an exception was thrown and we're ignoring them
410 if (
411 ignoreCreateExceptions &&
412 exceptionIgnoredStack != null &&
413 !(exceptionIgnoredStack.empty())) {
414
415 if (exceptionIgnoredStack.pop().booleanValue()) {
416 // creation exception was ignored
417 // nothing was put onto the stack
418 if (digester.log.isTraceEnabled()) {
419 digester.log.trace("[FactoryCreateRule] No creation so no push so no pop");
420 }
421 return;
422 }
423 }
424
425 Object top = digester.pop();
426 if (digester.log.isDebugEnabled()) {
427 digester.log.debug("[FactoryCreateRule]{" + digester.match +
428 "} Pop " + top.getClass().getName());
429 }
430
431 }
432
433
434 /**
435 * Clean up after parsing is complete.
436 */
437 public void finish() throws Exception {
438
439 if (attributeName != null) {
440 creationFactory = null;
441 }
442
443 }
444
445
446 /**
447 * Render a printable version of this Rule.
448 */
449 public String toString() {
450
451 StringBuffer sb = new StringBuffer("FactoryCreateRule[");
452 sb.append("className=");
453 sb.append(className);
454 sb.append(", attributeName=");
455 sb.append(attributeName);
456 if (creationFactory != null) {
457 sb.append(", creationFactory=");
458 sb.append(creationFactory);
459 }
460 sb.append("]");
461 return (sb.toString());
462
463 }
464
465
466 // ------------------------------------------------------ Protected Methods
467
468
469 /**
470 * Return an instance of our associated object creation factory,
471 * creating one if necessary.
472 *
473 * @param attributes Attributes passed to our factory creation element
474 *
475 * @exception Exception if any error occurs
476 */
477 protected ObjectCreationFactory getFactory(Attributes attributes)
478 throws Exception {
479
480 if (creationFactory == null) {
481 String realClassName = className;
482 if (attributeName != null) {
483 String value = attributes.getValue(attributeName);
484 if (value != null) {
485 realClassName = value;
486 }
487 }
488 if (digester.log.isDebugEnabled()) {
489 digester.log.debug("[FactoryCreateRule]{" + digester.match +
490 "} New factory " + realClassName);
491 }
492 Class<?> clazz = digester.getClassLoader().loadClass(realClassName);
493 creationFactory = (ObjectCreationFactory)
494 clazz.newInstance();
495 creationFactory.setDigester(digester);
496 }
497 return (creationFactory);
498
499 }
500 }