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