KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > betwixt > io > AbstractBeanWriter


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.betwixt.io;
17
18 import java.beans.IntrospectionException JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24
25 import org.apache.commons.betwixt.AttributeDescriptor;
26 import org.apache.commons.betwixt.BindingConfiguration;
27 import org.apache.commons.betwixt.Descriptor;
28 import org.apache.commons.betwixt.ElementDescriptor;
29 import org.apache.commons.betwixt.XMLBeanInfo;
30 import org.apache.commons.betwixt.XMLIntrospector;
31 import org.apache.commons.betwixt.digester.XMLIntrospectorHelper;
32 import org.apache.commons.betwixt.expression.Context;
33 import org.apache.commons.betwixt.expression.Expression;
34 import org.apache.commons.betwixt.io.id.SequentialIDGenerator;
35 import org.apache.commons.collections.ArrayStack;
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.xml.sax.Attributes JavaDoc;
39 import org.xml.sax.SAXException JavaDoc;
40 import org.xml.sax.helpers.AttributesImpl JavaDoc;
41
42 // FIX ME!!!
43
// Logging logic!
44

45 // FIX ME!!
46
// Error handling strategy!
47
// i'm going to add SAXExceptions everywhere since it's the easiest way to make things work quick
48
// but this is a poor strategy
49

50 /**
51   * <p>Abstract superclass for bean writers.
52   * This class encapsulates the processing logic.
53   * Subclasses provide implementations for the actual expression of the xml.</p>
54   * <h5>SAX Inspired Writing API</h5>
55   * <p>
56   * This class is intended to be used by subclassing:
57   * concrete subclasses perform the actual writing by providing
58   * suitable implementations for the following methods inspired
59   * by <a HREF='http://www.saxproject.org'>SAX</a>:
60   * </p>
61   * <ul>
62   * <li> {@link #start} - called when processing begins</li>
63   * <li> {@link #startElement(WriteContext, String, String, String, Attributes)}
64   * - called when the start of an element
65   * should be written</li>
66   * <li> {@link #bodyText(WriteContext, String)}
67   * - called when the start of an element
68   * should be written</li>
69   * <li> {@link #endElement(WriteContext, String, String, String)}
70   * - called when the end of an element
71   * should be written</li>
72   * <li> {@link #end} - called when processing has been completed</li>
73   * </ul>
74   * <p>
75   * <strong>Note</strong> that this class contains many deprecated
76   * versions of the writing API. These will be removed soon so care
77   * should be taken to use the latest version.
78   * </p>
79   * <p>
80   * <strong>Note</strong> that this class is designed to be used
81   * in a single threaded environment. When used in multi-threaded
82   * environments, use of a common <code>XMLIntrospector</code>
83   * and pooled writer instances should be considered.
84   * </p>
85   *
86   * @author <a HREF="mailto:rdonkin@apache.org">Robert Burrell Donkin</a>
87   */

88 public abstract class AbstractBeanWriter {
89
90     /** Introspector used */
91     private XMLIntrospector introspector = new XMLIntrospector();
92
93     /** Log used for logging (Doh!) */
94     private Log log = LogFactory.getLog( AbstractBeanWriter.class );
95     /** Map containing ID attribute values for beans */
96     private HashMap JavaDoc idMap = new HashMap JavaDoc();
97     /** Stack containing beans - used to detect cycles */
98     private ArrayStack beanStack = new ArrayStack();
99     /** Used to generate ID attribute values*/
100     private IDGenerator idGenerator = new SequentialIDGenerator();
101     /** Should empty elements be written out? */
102     private boolean writeEmptyElements = true;
103     /** Dynamic binding configuration settings */
104     private BindingConfiguration bindingConfiguration = new BindingConfiguration();
105     /** <code>WriteContext</code> implementation reused curing writing */
106     private WriteContextImpl writeContext = new WriteContextImpl();
107     /** Collection of namespaces which have already been declared */
108     private Collection JavaDoc namespacesDeclared = new ArrayList JavaDoc();
109     
110     /**
111      * Marks the start of the bean writing.
112      * By default doesn't do anything, but can be used
113      * to do extra start processing
114      * @throws IOException if an IO problem occurs during writing
115      * @throws SAXException if an SAX problem occurs during writing
116      */

117     public void start() throws IOException JavaDoc, SAXException JavaDoc {
118     }
119     
120     /**
121      * Marks the start of the bean writing.
122      * By default doesn't do anything, but can be used
123      * to do extra end processing
124      * @throws IOException if an IO problem occurs during writing
125      * @throws SAXException if an SAX problem occurs during writing
126      */

127     
128     public void end() throws IOException JavaDoc, SAXException JavaDoc {
129     }
130         
131     /**
132      * <p> Writes the given bean to the current stream using the XML introspector.</p>
133      *
134      * <p> This writes an xml fragment representing the bean to the current stream.</p>
135      *
136      * <p>This method will throw a <code>CyclicReferenceException</code> when a cycle
137      * is encountered in the graph <strong>only</strong> if the <code>getMapIDs()</code>
138      * setting of the </code>BindingConfiguration</code> is false.</p>
139      *
140      * @throws IOException if an IO problem occurs during writing
141      * @throws SAXException if an SAX problem occurs during writing
142      * @throws IntrospectionException if a java beans introspection problem occurs
143      *
144      * @param bean write out representation of this bean
145      */

146     public void write(Object JavaDoc bean) throws
147                                         IOException JavaDoc,
148                                         SAXException JavaDoc,
149                                         IntrospectionException JavaDoc {
150         if (log.isDebugEnabled()) {
151             log.debug( "Writing bean graph..." );
152             log.debug( bean );
153         }
154         start();
155         writeBean( null, null, null, bean, makeContext( bean ) );
156         end();
157         if (log.isDebugEnabled()) {
158             log.debug( "Finished writing bean graph." );
159         }
160     }
161     
162     /**
163      * <p>Writes the given bean to the current stream
164      * using the given <code>qualifiedName</code>.</p>
165      *
166      * <p>This method will throw a <code>CyclicReferenceException</code> when a cycle
167      * is encountered in the graph <strong>only</strong> if the <code>getMapIDs()</code>
168      * setting of the <code>BindingConfiguration</code> is false.</p>
169      *
170      * @param qualifiedName the string naming root element
171      * @param bean the <code>Object</code> to write out as xml
172      *
173      * @throws IOException if an IO problem occurs during writing
174      * @throws SAXException if an SAX problem occurs during writing
175      * @throws IntrospectionException if a java beans introspection problem occurs
176      */

177     public void write(
178                 String JavaDoc qualifiedName,
179                 Object JavaDoc bean)
180                     throws
181                         IOException JavaDoc,
182                         SAXException JavaDoc,
183                         IntrospectionException JavaDoc {
184         start();
185         writeBean( "", qualifiedName, qualifiedName, bean, makeContext( bean ) );
186         end();
187     }
188     
189     /**
190      * <p>Writes the given bean to the current stream
191      * using the given <code>qualifiedName</code>.</p>
192      *
193      * <p>This method will throw a <code>CyclicReferenceException</code> when a cycle
194      * is encountered in the graph <strong>only</strong> if the <code>getMapIDs()</code>
195      * setting of the <code>BindingConfiguration</code> is false.</p>
196      *
197      * @param namespaceUri the namespace uri
198      * @param localName the local name
199      * @param qualifiedName the string naming root element
200      * @param bean the <code>Object</code> to write out as xml
201      * @param context not null
202      *
203      * @throws IOException if an IO problem occurs during writing
204      * @throws SAXException if an SAX problem occurs during writing
205      * @throws IntrospectionException if a java beans introspection problem occurs
206      */

207     private void writeBean (
208                 String JavaDoc namespaceUri,
209                 String JavaDoc localName,
210                 String JavaDoc qualifiedName,
211                 Object JavaDoc bean,
212                 Context context)
213                     throws
214                         IOException JavaDoc,
215                         SAXException JavaDoc,
216                         IntrospectionException JavaDoc {
217         
218         if ( log.isTraceEnabled() ) {
219             log.trace( "Writing bean graph (qualified name '" + qualifiedName + "'" );
220         }
221         
222         // introspect to obtain bean info
223
XMLBeanInfo beanInfo = introspector.introspect( bean );
224         if ( beanInfo != null ) {
225             ElementDescriptor elementDescriptor = beanInfo.getElementDescriptor();
226             if ( elementDescriptor != null ) {
227                 context = context.newContext( bean );
228                 if ( qualifiedName == null ) {
229                     qualifiedName = elementDescriptor.getQualifiedName();
230                 }
231                 if ( namespaceUri == null ) {
232                     namespaceUri = elementDescriptor.getURI();
233                 }
234                 if ( localName == null ) {
235                     localName = elementDescriptor.getLocalName();
236                 }
237
238                 String JavaDoc ref = null;
239                 String JavaDoc id = null;
240                 
241                 // simple type should not have IDs
242
if ( elementDescriptor.isSimple() ) {
243                     // write without an id
244
writeElement(
245                         namespaceUri,
246                         localName,
247                         qualifiedName,
248                         elementDescriptor,
249                         context );
250                         
251                 } else {
252                     pushBean ( context.getBean() );
253                     if ( getBindingConfiguration().getMapIDs() ) {
254                         ref = (String JavaDoc) idMap.get( context.getBean() );
255                     }
256                     if ( ref == null ) {
257                         // this is the first time that this bean has be written
258
AttributeDescriptor idAttribute = beanInfo.getIDAttribute();
259                         if (idAttribute == null) {
260                             // use a generated id
261
id = idGenerator.nextId();
262                             idMap.put( bean, id );
263                             
264                             if ( getBindingConfiguration().getMapIDs() ) {
265                                 // write element with id
266
writeElement(
267                                     namespaceUri,
268                                     localName,
269                                     qualifiedName,
270                                     elementDescriptor,
271                                     context ,
272                                     beanInfo.getIDAttributeName(),
273                                     id);
274                                     
275                             } else {
276                                 // write element without ID
277
writeElement(
278                                     namespaceUri,
279                                     localName,
280                                     qualifiedName,
281                                     elementDescriptor,
282                                     context );
283                             }
284                                                         
285                         } else {
286                             // use id from bean property
287
// it's up to the user to ensure uniqueness
288
// XXX should we trap nulls?
289
Object JavaDoc exp = idAttribute.getTextExpression().evaluate( context );
290                             if (exp == null) {
291                                 // we'll use a random id
292
log.debug("Using random id");
293                                 id = idGenerator.nextId();
294                                 
295                             } else {
296                                 // convert to string
297
id = exp.toString();
298                             }
299                             idMap.put( bean, id);
300                             
301                             // the ID attribute should be written automatically
302
writeElement(
303                                 namespaceUri,
304                                 localName,
305                                 qualifiedName,
306                                 elementDescriptor,
307                                 context );
308                         }
309                     } else {
310                         
311                         if ( !ignoreElement( elementDescriptor, context )) {
312                             // we've already written this bean so write an IDREF
313
writeIDREFElement(
314                                             elementDescriptor,
315                                             namespaceUri,
316                                             localName,
317                                             qualifiedName,
318                                             beanInfo.getIDREFAttributeName(),
319                                             ref);
320                         }
321                     }
322                     popBean();
323                 }
324             }
325         }
326         
327         log.trace( "Finished writing bean graph." );
328     }
329     
330     /**
331       * Get <code>IDGenerator</code> implementation used to
332       * generate <code>ID</code> attribute values .
333       *
334       * @return implementation used for <code>ID</code> attribute generation
335       */

336     public IDGenerator getIdGenerator() {
337         return idGenerator;
338     }
339     
340     /**
341       * Set <code>IDGenerator</code> implementation
342       * used to generate <code>ID</code> attribute values.
343       * This property can be used to customize the algorithm used for generation.
344       *
345       * @param idGenerator use this implementation for <code>ID</code> attribute generation
346       */

347     public void setIdGenerator(IDGenerator idGenerator) {
348         this.idGenerator = idGenerator;
349     }
350     
351     
352     
353     /**
354      * Gets the dynamic configuration setting to be used for bean reading.
355      * @return the BindingConfiguration settings, not null
356      * @since 0.5
357      */

358     public BindingConfiguration getBindingConfiguration() {
359         return bindingConfiguration;
360     }
361     
362     /**
363      * Sets the dynamic configuration setting to be used for bean reading.
364      * @param bindingConfiguration the BindingConfiguration settings, not null
365      * @since 0.5
366      */

367     public void setBindingConfiguration(BindingConfiguration bindingConfiguration) {
368         this.bindingConfiguration = bindingConfiguration;
369     }
370     
371     /**
372      * <p>Should generated <code>ID</code> attribute values be added to the elements?</p>
373      *
374      * <p>If IDs are not being written then if a cycle is encountered in the bean graph,
375      * then a {@link CyclicReferenceException} will be thrown by the write method.</p>
376      *
377      * @return true if <code>ID</code> and <code>IDREF</code> attributes are to be written
378      * @deprecated 0.5 use {@link BindingConfiguration#getMapIDs}
379      */

380     public boolean getWriteIDs() {
381         return getBindingConfiguration().getMapIDs();
382     }
383
384     /**
385      * Set whether generated <code>ID</code> attribute values should be added to the elements
386      * If this property is set to false, then <code>CyclicReferenceException</code>
387      * will be thrown whenever a cyclic occurs in the bean graph.
388      *
389      * @param writeIDs true if <code>ID</code>'s and <code>IDREF</code>'s should be written
390      * @deprecated 0.5 use {@link BindingConfiguration#setMapIDs}
391      */

392     public void setWriteIDs(boolean writeIDs) {
393         getBindingConfiguration().setMapIDs( writeIDs );
394     }
395     
396     /**
397      * <p>Gets whether empty elements should be written into the output.</p>
398      *
399      * <p>An empty element is one that has no attributes, no child elements
400      * and no body text.
401      * For example, <code>&lt;element/&gt;</code> is an empty element but
402      * <code>&lt;element attr='value'/&gt;</code> is not.</p>
403      *
404      * @return true if empty elements will be written into the output
405      * @since 0.5
406      */

407     public boolean getWriteEmptyElements() {
408         return writeEmptyElements;
409     }
410     
411     /**
412      * <p>Sets whether empty elements should be written into the output.</p>
413      *
414      * <p>An empty element is one that has no attributes, no child elements
415      * and no body text.
416      * For example, <code>&lt;element/&gt;</code> is an empty element but
417      * <code>&lt;element attr='value'/&gt;</code> is not.
418      *
419      * @param writeEmptyElements true if empty elements should be written into the output
420      * @since 0.5
421      */

422     public void setWriteEmptyElements(boolean writeEmptyElements) {
423         this.writeEmptyElements = writeEmptyElements;
424     }
425
426     /**
427      * <p>Gets the introspector used.</p>
428      *
429      * <p>The {@link XMLBeanInfo} used to map each bean is
430      * created by the <code>XMLIntrospector</code>.
431      * One way in which the mapping can be customized is
432      * by altering the <code>XMLIntrospector</code>. </p>
433      *
434      * @return the <code>XMLIntrospector</code> used for introspection
435      */

436     public XMLIntrospector getXMLIntrospector() {
437         return introspector;
438     }
439     
440
441     /**
442      * <p>Sets the introspector to be used.</p>
443      *
444      * <p>The {@link XMLBeanInfo} used to map each bean is
445      * created by the <code>XMLIntrospector</code>.
446      * One way in which the mapping can be customized is by
447      * altering the <code>XMLIntrospector</code>. </p>
448      *
449      * @param introspector use this introspector
450      */

451     public void setXMLIntrospector(XMLIntrospector introspector) {
452         this.introspector = introspector;
453     }
454
455     /**
456      * <p>Gets the current logging implementation.</p>
457      *
458      * @return the <code>Log</code> implementation which this class logs to
459      */

460     public final Log getAbstractBeanWriterLog() {
461         return log;
462     }
463
464     /**
465      * <p> Set the current logging implementation. </p>
466      *
467      * @param log <code>Log</code> implementation to use
468      */

469     public final void setAbstractBeanWriterLog(Log log) {
470         this.log = log;
471     }
472         
473     // SAX-style methods
474
//-------------------------------------------------------------------------
475

476     /**
477      * Writes the start tag for an element.
478      *
479      * @param uri the element's namespace uri
480      * @param localName the element's local name
481      * @param qName the element's qualified name
482      * @param attr the element's attributes
483      *
484      * @throws IOException if an IO problem occurs during writing
485      * @throws SAXException if an SAX problem occurs during writing
486      * @since 0.5
487      */

488     protected void startElement(
489                                 WriteContext context,
490                                 String JavaDoc uri,
491                                 String JavaDoc localName,
492                                 String JavaDoc qName,
493                                 Attributes JavaDoc attr)
494                                     throws
495                                         IOException JavaDoc,
496                                         SAXException JavaDoc {
497         // for backwards compatbility call older methods
498
startElement(uri, localName, qName, attr);
499     }
500     
501     /**
502      * Writes the end tag for an element
503      *
504      * @param uri the element's namespace uri
505      * @param localName the element's local name
506      * @param qName the element's qualified name
507      *
508      * @throws IOException if an IO problem occurs during writing
509      * @throws SAXException if an SAX problem occurs during writing
510      * @since 0.5
511      */

512     protected void endElement(
513                                 WriteContext context,
514                                 String JavaDoc uri,
515                                 String JavaDoc localName,
516                                 String JavaDoc qName)
517                                     throws
518                                         IOException JavaDoc,
519                                         SAXException JavaDoc {
520         // for backwards compatibility call older interface
521
endElement(uri, localName, qName);
522     }
523     
524     /**
525      * Writes body text
526      *
527      * @param text the body text to be written
528      *
529      * @throws IOException if an IO problem occurs during writing
530      * @throws SAXException if an SAX problem occurs during writing
531      * @since 0.5
532      */

533     protected void bodyText(WriteContext context, String JavaDoc text)
534                                 throws IOException JavaDoc, SAXException JavaDoc {
535         // for backwards compatibility call older interface
536
bodyText(text);
537     }
538         
539     // Older SAX-style methods
540
//-------------------------------------------------------------------------
541

542     /**
543      * Writes the start tag for an element.
544      *
545      * @param uri the element's namespace uri
546      * @param localName the element's local name
547      * @param qName the element's qualified name
548      * @param attr the element's attributes
549      *
550      * @throws IOException if an IO problem occurs during writing
551      * @throws SAXException if an SAX problem occurs during writing
552      * @deprecated 0.5 use {@link #startElement(WriteContext, String, String, String, Attributes)}
553      */

554     protected void startElement(
555                                 String JavaDoc uri,
556                                 String JavaDoc localName,
557                                 String JavaDoc qName,
558                                 Attributes JavaDoc attr)
559                                     throws
560                                         IOException JavaDoc,
561                                         SAXException JavaDoc {}
562     
563     /**
564      * Writes the end tag for an element
565      *
566      * @param uri the element's namespace uri
567      * @param localName the element's local name
568      * @param qName the element's qualified name
569      *
570      * @throws IOException if an IO problem occurs during writing
571      * @throws SAXException if an SAX problem occurs during writing
572      * @deprecated 0.5 use {@link #endElement(WriteContext, String, String, String)}
573      */

574     protected void endElement(
575                                 String JavaDoc uri,
576                                 String JavaDoc localName,
577                                 String JavaDoc qName)
578                                     throws
579                                         IOException JavaDoc,
580                                         SAXException JavaDoc {}
581     
582     /**
583      * Writes body text
584      *
585      * @param text the body text to be written
586      *
587      * @throws IOException if an IO problem occurs during writing
588      * @throws SAXException if an SAX problem occurs during writing
589      * @deprecated 0.5 use {@link #bodyText(WriteContext, String)}
590      */

591     protected void bodyText(String JavaDoc text) throws IOException JavaDoc, SAXException JavaDoc {}
592     
593     // Implementation methods
594
//-------------------------------------------------------------------------
595

596     /**
597      * Writes the given element
598      *
599      * @param namespaceUri the namespace uri
600      * @param localName the local name
601      * @param qualifiedName qualified name to use for the element
602      * @param elementDescriptor the <code>ElementDescriptor</code> describing the element
603      * @param context the <code>Context</code> to use to evaluate the bean expressions
604      * @throws IOException if an IO problem occurs during writing
605      * @throws SAXException if an SAX problem occurs during writing
606      * @throws IntrospectionException if a java beans introspection problem occurs
607      */

608     private void writeElement(
609                             String JavaDoc namespaceUri,
610                             String JavaDoc localName,
611                             String JavaDoc qualifiedName,
612                             ElementDescriptor elementDescriptor,
613                             Context context )
614                                 throws
615                                     IOException JavaDoc,
616                                     SAXException JavaDoc,
617                                     IntrospectionException JavaDoc {
618         if( log.isTraceEnabled() ) {
619             log.trace( "Writing: " + qualifiedName + " element: " + elementDescriptor );
620         }
621                 
622         if ( !ignoreElement( elementDescriptor, context )) {
623             if ( log.isTraceEnabled() ) {
624                 log.trace( "Element " + elementDescriptor + " is empty." );
625             }
626         
627             Attributes JavaDoc attributes = addNamespaceDeclarations(
628                 new ElementAttributes( elementDescriptor, context ), namespaceUri);
629             writeContext.setCurrentDescriptor(elementDescriptor);
630             startElement(
631                             writeContext,
632                             namespaceUri,
633                             localName,
634                             qualifiedName,
635                             attributes);
636            
637             writeElementContent( elementDescriptor, context ) ;
638             writeContext.setCurrentDescriptor(elementDescriptor);
639             endElement( writeContext, namespaceUri, localName, qualifiedName );
640             
641         }
642     }
643     
644     /**
645      * Adds namespace declarations (if any are needed) to the given attributes.
646      * @param attributes Attributes, not null
647      * @param elementNamespaceUri the URI for the enclosing element, possibly null
648      * @return Attributes, not null
649      */

650     private Attributes JavaDoc addNamespaceDeclarations(Attributes JavaDoc attributes, String JavaDoc elementNamespaceUri) {
651         Attributes JavaDoc result = attributes;
652         AttributesImpl JavaDoc withDeclarations = null;
653         for (int i=-1, size=attributes.getLength(); i<size ; i++) {
654             String JavaDoc uri = null;
655             if (i == -1) {
656                 uri = elementNamespaceUri;
657             } else {
658                 uri = attributes.getURI(i);
659             }
660             if (uri != null && !"".equals(uri) && !namespacesDeclared.contains(uri)) {
661                 if (withDeclarations == null) {
662                     withDeclarations = new AttributesImpl JavaDoc(attributes);
663                 }
664                 withDeclarations.addAttribute("", "", "xmlns:"
665                     + getXMLIntrospector().getConfiguration().getPrefixMapper().getPrefix(uri), "NOTATION", uri);
666                 namespacesDeclared.add(uri);
667             }
668         }
669         
670         if (withDeclarations != null) {
671             result = withDeclarations;
672         }
673         return result;
674     }
675     
676     
677     /**
678      * Writes the given element adding an ID attribute
679      *
680      * @param namespaceUri the namespace uri
681      * @param localName the local name
682      * @param qualifiedName the qualified name
683      * @param elementDescriptor the ElementDescriptor describing this element
684      * @param context the context being evaliated against
685      * @param idAttribute the qualified name of the <code>ID</code> attribute
686      * @param idValue the value for the <code>ID</code> attribute
687      * @throws IOException if an IO problem occurs during writing
688      * @throws SAXException if an SAX problem occurs during writing
689      * @throws IntrospectionException if a java beans introspection problem occurs
690      */

691     private void writeElement(
692                             String JavaDoc namespaceUri,
693                             String JavaDoc localName,
694                             String JavaDoc qualifiedName,
695                             ElementDescriptor elementDescriptor,
696                             Context context,
697                             String JavaDoc idAttribute,
698                             String JavaDoc idValue )
699                                 throws
700                                     IOException JavaDoc,
701                                     SAXException JavaDoc,
702                                     IntrospectionException JavaDoc {
703                    
704         if ( !ignoreElement( elementDescriptor, context ) ) {
705             writeContext.setCurrentDescriptor(elementDescriptor);
706             Attributes JavaDoc attributes = new IDElementAttributes(
707                         elementDescriptor,
708                         context,
709                         idAttribute,
710                         idValue );
711             startElement(
712                         writeContext,
713                         namespaceUri,
714                         localName,
715                         qualifiedName,
716                         addNamespaceDeclarations(attributes, namespaceUri));
717     
718             writeElementContent( elementDescriptor, context ) ;
719             writeContext.setCurrentDescriptor(elementDescriptor);
720             endElement( writeContext, namespaceUri, localName, qualifiedName );
721
722         } else if ( log.isTraceEnabled() ) {
723             log.trace( "Element " + qualifiedName + " is empty." );
724         }
725     }
726     
727
728     /**
729      * Write attributes, child elements and element end
730      *
731      * @param uri the element namespace uri
732      * @param localName the local name of the element
733      * @param qualifiedName the qualified name of the element
734      * @param elementDescriptor the descriptor for this element
735      * @param context evaluate against this context
736      * @throws IOException if an IO problem occurs during writing
737      * @throws SAXException if an SAX problem occurs during writing
738      * @throws IntrospectionException if a java beans introspection problem occurs
739      */

740     private void writeRestOfElement(
741                             String JavaDoc uri,
742                             String JavaDoc localName,
743                             String JavaDoc qualifiedName,
744                             ElementDescriptor elementDescriptor,
745                             Context context )
746                                 throws
747                                     IOException JavaDoc,
748                                     SAXException JavaDoc,
749                                     IntrospectionException JavaDoc {
750
751         writeElementContent( elementDescriptor, context );
752     }
753
754     /**
755      * Writes an element with a <code>IDREF</code> attribute
756      *
757      * @param uri the namespace uri
758      * @param localName the local name
759      * @param qualifiedName of the element with <code>IDREF</code> attribute
760      * @param idrefAttributeName the qualified name of the <code>IDREF</code> attribute
761      * @param idrefAttributeValue the value for the <code>IDREF</code> attribute
762      * @throws IOException if an IO problem occurs during writing
763      * @throws SAXException if an SAX problem occurs during writing
764      * @throws IntrospectionException if a java beans introspection problem occurs
765      */

766     private void writeIDREFElement(
767                                     ElementDescriptor elementDescriptor,
768                                     String JavaDoc uri,
769                                     String JavaDoc localName,
770                                     String JavaDoc qualifiedName,
771                                     String JavaDoc idrefAttributeName,
772                                     String JavaDoc idrefAttributeValue )
773                                         throws
774                                             IOException JavaDoc,
775                                             SAXException JavaDoc,
776                                             IntrospectionException JavaDoc {
777
778         
779         
780         // write IDREF element
781
AttributesImpl JavaDoc attributes = new AttributesImpl JavaDoc();
782         // XXX for the moment, assign IDREF to default namespace
783
attributes.addAttribute(
784                                 "",
785                                 idrefAttributeName,
786                                 idrefAttributeName,
787                                 "IDREF",
788                                 idrefAttributeValue);
789         writeContext.setCurrentDescriptor(elementDescriptor);
790         startElement( writeContext, uri, localName, qualifiedName, addNamespaceDeclarations(attributes, uri));
791         endElement( writeContext, uri, localName, qualifiedName );
792     }
793     
794     /**
795      * Writes the element content.
796      *
797      * @param elementDescriptor the <code>ElementDescriptor</code> to write as xml
798      * @param context the <code>Context</code> to use to evaluate the bean expressions
799      *
800      * @throws IOException if an IO problem occurs during writing
801      * @throws SAXException if an SAX problem occurs during writing
802      * @throws IntrospectionException if a java beans introspection problem occurs
803      */

804     private void writeElementContent(
805                         ElementDescriptor elementDescriptor,
806                         Context context )
807                             throws
808                                 IOException JavaDoc,
809                                 SAXException JavaDoc,
810                                 IntrospectionException JavaDoc {
811         writeContext.setCurrentDescriptor( elementDescriptor );
812         Descriptor[] childDescriptors = elementDescriptor.getContentDescriptors();
813         if ( childDescriptors != null && childDescriptors.length > 0 ) {
814             // process child elements
815
for ( int i = 0, size = childDescriptors.length; i < size; i++ ) {
816                 if (childDescriptors[i] instanceof ElementDescriptor) {
817                     // Element content
818
ElementDescriptor childDescriptor = (ElementDescriptor) childDescriptors[i];
819                     Context childContext = context;
820                     Expression childExpression = childDescriptor.getContextExpression();
821                     if ( childExpression != null ) {
822                         Object JavaDoc childBean = childExpression.evaluate( context );
823                         if ( childBean != null ) {
824                             String JavaDoc qualifiedName = childDescriptor.getQualifiedName();
825                             String JavaDoc namespaceUri = childDescriptor.getURI();
826                             String JavaDoc localName = childDescriptor.getLocalName();
827                             // XXXX: should we handle nulls better
828
if ( childBean instanceof Iterator JavaDoc ) {
829                                 for ( Iterator JavaDoc iter = (Iterator JavaDoc) childBean; iter.hasNext(); ) {
830                                     Object JavaDoc object = iter.next();
831                                     if (object == null) {
832                                         continue;
833                                     }
834                                     writeBean(
835                                             namespaceUri,
836                                             localName,
837                                             qualifiedName,
838                                             object,
839                                             context );
840                                 }
841                             } else {
842                                 writeBean(
843                                             namespaceUri,
844                                             localName,
845                                             qualifiedName,
846                                             childBean,
847                                             context );
848                             }
849                         }
850                     } else {
851                         writeElement(
852                                     childDescriptor.getURI(),
853                                     childDescriptor.getLocalName(),
854                                     childDescriptor.getQualifiedName(),
855                                     childDescriptor,
856                                     childContext );
857                     }
858                 } else {
859                     // Mixed text content
860
// evaluate the body text
861
Expression expression = childDescriptors[i].getTextExpression();
862                     if ( expression != null ) {
863                         Object JavaDoc value = expression.evaluate( context );
864                         String JavaDoc text = convertToString(
865                                                         value,
866                                                         childDescriptors[i],
867                                                         context );
868                         if ( text != null && text.length() > 0 ) {;
869                             bodyText( writeContext, text );
870                         }
871                     }
872                 }
873             }
874         } else {
875             // evaluate the body text
876
Expression expression = elementDescriptor.getTextExpression();
877             if ( expression != null ) {
878                 Object JavaDoc value = expression.evaluate( context );
879                 String JavaDoc text = convertToString( value, elementDescriptor, context );
880                 if ( text != null && text.length() > 0 ) {
881                     bodyText( writeContext, text );
882                 }
883             }
884         }
885     }
886
887     /**
888      * Pushes the bean onto the ancestry stack.
889      * If IDs are not being written, then check for cyclic references.
890      *
891      * @param bean push this bean onto the ancester stack
892      */

893     protected void pushBean( Object JavaDoc bean ) {
894         // check that we don't have a cyclic reference when we're not writing IDs
895
if ( !getBindingConfiguration().getMapIDs() ) {
896             Iterator JavaDoc it = beanStack.iterator();
897             while ( it.hasNext() ) {
898                 Object JavaDoc next = it.next();
899                 // use absolute equality rather than equals
900
// we're only really bothered if objects are actually the same
901
if ( bean == next ) {
902                     if ( log.isDebugEnabled() ) {
903                         log.debug("Element stack: ");
904                         Iterator JavaDoc debugStack = beanStack.iterator();
905                         while ( debugStack.hasNext() ) {
906                             log.debug(debugStack.next());
907                         }
908                     }
909                     log.error("Cyclic reference at bean: " + bean);
910                     throw new CyclicReferenceException();
911                 }
912             }
913         }
914         if (log.isTraceEnabled()) {
915             log.trace( "Pushing onto object stack: " + bean );
916         }
917         beanStack.push( bean );
918     }
919     
920     /**
921      * Pops the top bean off from the ancestry stack
922      *
923      * @return the last object pushed onto the ancester stack
924      */

925     protected Object JavaDoc popBean() {
926         Object JavaDoc bean = beanStack.pop();
927         if (log.isTraceEnabled()) {
928             log.trace( "Popped from object stack: " + bean );
929         }
930         return bean;
931     }
932     
933     /**
934      * Should this element (and children) be written out?
935      *
936      * @param descriptor the <code>ElementDescriptor</code> to evaluate
937      * @param context the <code>Context</code> against which the element will be evaluated
938      * @return true if this element should be written out
939      */

940     private boolean ignoreElement( ElementDescriptor descriptor, Context context ) {
941         if ( ! getWriteEmptyElements() ) {
942             return isEmptyElement( descriptor, context );
943         }
944         return false;
945     }
946     
947     /**
948      * <p>Will evaluating this element against this context result in an empty element?</p>
949      *
950      * <p>An empty element is one that has no attributes, no child elements
951      * and no body text.
952      * For example, <code>&lt;element/&gt;</code> is an empty element but
953      * <code>&lt;element attr='value'/&gt;</code> is not.</p>
954      *
955      * @param descriptor the <code>ElementDescriptor</code> to evaluate
956      * @param context the <code>Context</code> against which the element will be evaluated
957      * @return true if this element is empty on evaluation
958      */

959     private boolean isEmptyElement( ElementDescriptor descriptor, Context context ) {
960         if ( log.isTraceEnabled() ) {
961             log.trace( "Is " + descriptor + " empty?" );
962         }
963         
964         // an element which has attributes is not empty
965
if ( descriptor.hasAttributes() ) {
966             log.trace( "Element has attributes." );
967             return false;
968         }
969         
970         // an element is not empty if it has a non-empty body
971
Expression expression = descriptor.getTextExpression();
972         if ( expression != null ) {
973             Object JavaDoc value = expression.evaluate( context );
974             String JavaDoc text = convertToString( value, descriptor, context );
975             if ( text != null && text.length() > 0 ) {
976                 log.trace( "Element has body text which isn't empty." );
977                 return false;
978             }
979         }
980         
981         // always write out loops - even when they have no elements
982
if ( XMLIntrospectorHelper.isLoopType( descriptor.getPropertyType() ) ) {
983             log.trace("Loop type so not empty.");
984             return false;
985         }
986         
987         // now test child elements
988
// an element is empty if it has no non-empty child elements
989
if ( descriptor.hasChildren() ) {
990             for ( int i=0, size=descriptor.getElementDescriptors().length; i<size; i++ ) {
991                 if ( ! isEmptyElement( descriptor.getElementDescriptors()[i], context ) ) {
992                     log.trace( "Element has child which isn't empty." );
993                     return false;
994                 }
995             }
996         }
997         
998         log.trace( "Element is empty." );
999         return true;
1000    }
1001    
1002    
1003    /**
1004     * Attributes backed by attribute descriptors.
1005     * ID/IDREFs not set.
1006     */

1007    private class ElementAttributes implements Attributes JavaDoc {
1008        /** Attribute descriptors backing the <code>Attributes</code> */
1009        private AttributeDescriptor[] attributes;
1010        /** Context to be evaluated when finding values */
1011        private Context context;
1012
1013        
1014        
1015        /**
1016         * Construct attributes for element and context.
1017         *
1018         * @param descriptor the <code>ElementDescriptor</code> describing the element
1019         * @param context evaluate against this context
1020         */

1021        ElementAttributes( ElementDescriptor descriptor, Context context ) {
1022            attributes = descriptor.getAttributeDescriptors();
1023            this.context = context;
1024        }
1025        
1026        /**
1027         * Gets the index of an attribute by qualified name.
1028         *
1029         * @param qName the qualified name of the attribute
1030         * @return the index of the attribute - or -1 if there is no matching attribute
1031         */

1032        public int getIndex( String JavaDoc qName ) {
1033            for ( int i=0; i<attributes.length; i++ ) {
1034                if (attributes[i].getQualifiedName() != null
1035                       && attributes[i].getQualifiedName().equals( qName )) {
1036                    return i;
1037                }
1038            }
1039            return -1;
1040        }
1041        
1042        /**
1043         * Gets the index of an attribute by namespace name.
1044         *
1045         * @param uri the namespace uri of the attribute
1046         * @param localName the local name of the attribute
1047         * @return the index of the attribute - or -1 if there is no matching attribute
1048         */

1049        public int getIndex( String JavaDoc uri, String JavaDoc localName ) {
1050            for ( int i=0; i<attributes.length; i++ ) {
1051                if (
1052                        attributes[i].getURI() != null
1053                        && attributes[i].getURI().equals(uri)
1054                        && attributes[i].getLocalName() != null
1055                        && attributes[i].getURI().equals(localName)) {
1056                    return i;
1057                }
1058            }
1059            
1060            return -1;
1061        }
1062        
1063        /**
1064         * Gets the number of attributes in the list.
1065         *
1066         * @return the number of attributes in this list
1067         */

1068        public int getLength() {
1069            return attributes.length;
1070        }
1071        
1072        /**
1073         * Gets the local name by index.
1074         *
1075         * @param index the attribute index (zero based)
1076         * @return the attribute local name - or null if the index is out of range
1077         */

1078        public String JavaDoc getLocalName( int index ) {
1079            if ( indexInRange( index ) ) {
1080                return attributes[index].getLocalName();
1081            }
1082            
1083            return null;
1084        }
1085        
1086        /**
1087         * Gets the qualified name by index.
1088         *
1089         * @param index the attribute index (zero based)
1090         * @return the qualified name of the element - or null if the index is our of range
1091         */

1092        public String JavaDoc getQName( int index ) {
1093            if ( indexInRange( index ) ) {
1094                return attributes[index].getQualifiedName();
1095            }
1096            
1097            return null;
1098        }
1099        
1100        /**
1101         * Gets the attribute SAX type by namespace name.
1102         *
1103         * @param index the attribute index (zero based)
1104         * @return the attribute type (as a string) or null if the index is out of range
1105         */

1106        public String JavaDoc getType( int index ) {
1107            if ( indexInRange( index ) ) {
1108                return "CDATA";
1109            }
1110            return null;
1111        }
1112        
1113        /**
1114         * Gets the attribute SAX type by qualified name.
1115         *
1116         * @param qName the qualified name of the attribute
1117         * @return the attribute type (as a string) or null if the attribute is not in the list
1118         */

1119        public String JavaDoc getType( String JavaDoc qName ) {
1120            return getType( getIndex( qName ) );
1121        }
1122        
1123        /**
1124         * Gets the attribute SAX type by namespace name.
1125         *
1126         * @param uri the namespace uri of the attribute
1127         * @param localName the local name of the attribute
1128         * @return the attribute type (as a string) or null if the attribute is not in the list
1129         */

1130        public String JavaDoc getType( String JavaDoc uri, String JavaDoc localName ) {
1131            return getType( getIndex( uri, localName ));
1132        }
1133        
1134        /**
1135         * Gets the namespace URI for attribute at the given index.
1136         *
1137         * @param index the attribute index (zero-based)
1138         * @return the namespace URI (empty string if none is available)
1139         * or null if the index is out of range
1140         */

1141        public String JavaDoc getURI( int index ) {
1142            if ( indexInRange( index ) ) {
1143                return attributes[index].getURI();
1144            }
1145            return null;
1146        }
1147        
1148        /**
1149         * Gets the value for the attribute at given index.
1150         *
1151         * @param index the attribute index (zero based)
1152         * @return the attribute value or null if the index is out of range
1153         * @todo add value caching
1154         */

1155        public String JavaDoc getValue( int index ) {
1156            if ( indexInRange( index )) {
1157                Expression expression = attributes[index].getTextExpression();
1158                if ( expression != null ) {
1159                    Object JavaDoc value = expression.evaluate( context );
1160                    return convertToString( value, attributes[index], context );
1161                }
1162                
1163                return "";
1164            }
1165            return null;
1166        }
1167        
1168        /**
1169         * Gets the value for the attribute by qualified name.
1170         *
1171         * @param qName the qualified name
1172         * @return the attribute value or null if there are no attributes
1173         * with the given qualified name
1174         * @todo add value caching
1175         */

1176        public String JavaDoc getValue( String JavaDoc qName ) {
1177            return getValue( getIndex( qName ) );
1178        }
1179        
1180        /**
1181         * Gets the value for the attribute by namespace name.
1182         *
1183         * @param uri the namespace URI of the attribute
1184         * @param localName the local name of the attribute
1185         * @return the attribute value or null if there are not attributes
1186         * with the given namespace and local name
1187         * @todo add value caching
1188         */

1189        public String JavaDoc getValue( String JavaDoc uri, String JavaDoc localName ) {
1190            return getValue( getIndex( uri, localName ) );
1191        }
1192        
1193        /**
1194         * Is the given index within the range of the attribute list
1195         *
1196         * @param index the index whose range will be checked
1197         * @return true if the index with within the range of the attribute list
1198         */

1199        private boolean indexInRange( int index ) {
1200            return ( index >= 0 && index < attributes.length );
1201        }
1202    }
1203    
1204    /**
1205     * Attributes with generate ID/IDREF attributes
1206     * //TODO: refactor the ID/REF generation so that it's fixed at introspection
1207     * and the generators are placed into the Context.
1208     * @author <a HREF='http://jakarta.apache.org/'>Jakarta Commons Team</a>
1209     * @version $Revision: 1.28 $
1210     */

1211    private class IDElementAttributes extends ElementAttributes {
1212        /** ID attribute value */
1213        private String JavaDoc idValue;
1214        /** ID attribute name */
1215        private String JavaDoc idAttributeName;
1216
1217        private boolean matchingAttribute = false;
1218        private int length;
1219        private int idIndex;
1220        
1221        /**
1222         * Construct attributes for element and context.
1223         *
1224         * @param descriptor the <code>ElementDescriptor</code> describing the element
1225         * @param context evaluate against this context
1226         * @param idAttributeName the name of the id attribute
1227         * @param idValue the ID attribute value
1228         */

1229        IDElementAttributes(
1230                            ElementDescriptor descriptor,
1231                            Context context,
1232                            String JavaDoc idAttributeName,
1233                            String JavaDoc idValue) {
1234            super(descriptor, context);
1235            this.idValue = idValue;
1236            this.idAttributeName = idAttributeName;
1237            
1238            // see if we have already have a matching attribute descriptor
1239
AttributeDescriptor[] attributeDescriptors = descriptor.getAttributeDescriptors();
1240            length = attributeDescriptors.length;
1241            for (int i=0; i<length; i++) {
1242                if (idAttributeName.equals(attributeDescriptors[i])) {
1243                    matchingAttribute = true;
1244                    idIndex = i;
1245                    break;
1246                }
1247            }
1248            if (!matchingAttribute) {
1249                length += 1;
1250                idIndex = length-1;
1251            }
1252        }
1253        
1254        public int getIndex(String JavaDoc uri, String JavaDoc localName) {
1255            if (localName.equals(idAttributeName)) {
1256                return idIndex;
1257            }
1258            
1259            return super.getIndex(uri, localName);
1260        }
1261
1262        public int getIndex(String JavaDoc qName) {
1263            if (qName.equals(idAttributeName)) {
1264                return idIndex;
1265            }
1266            
1267            return super.getIndex(qName);
1268        }
1269
1270        public int getLength() {
1271            return length;
1272        }
1273
1274        public String JavaDoc getLocalName(int index) {
1275            if (index == idIndex) {
1276                return idAttributeName;
1277            }
1278            return super.getLocalName(index);
1279        }
1280
1281        public String JavaDoc getQName(int index) {
1282            if (index == idIndex) {
1283                return idAttributeName;
1284            }
1285            return super.getQName(index);
1286        }
1287
1288        public String JavaDoc getType(int index) {
1289            if (index == idIndex) {
1290                return "ID";
1291            }
1292            return super.getType(index);
1293        }
1294
1295        public String JavaDoc getType(String JavaDoc uri, String JavaDoc localName) {
1296            return getType(getIndex(uri, localName));
1297        }
1298
1299        public String JavaDoc getType(String JavaDoc qName) {
1300            return getType(getIndex(qName));
1301        }
1302
1303        public String JavaDoc getURI(int index) {
1304            //TODO: this is probably wrong
1305
// probably need to move ID management into introspection
1306
// before we can handle this namespace bit correctly
1307
if (index == idIndex) {
1308                return "";
1309            }
1310            return super.getURI(index);
1311        }
1312
1313        public String JavaDoc getValue(int index) {
1314            if (index == idIndex) {
1315                return idValue;
1316            }
1317            return super.getValue(index);
1318        }
1319
1320        public String JavaDoc getValue(String JavaDoc uri, String JavaDoc localName) {
1321            return getValue(getIndex(uri, localName));
1322        }
1323
1324        public String JavaDoc getValue(String JavaDoc qName) {
1325            return getValue(getIndex(qName));
1326        }
1327
1328    }
1329    
1330    
1331    // OLD API (DEPRECATED)
1332
// --------------------------------------------------------------------------------------
1333

1334    
1335    /**
1336     * Get the indentation for the current element.
1337     * Used for pretty priting.
1338     *
1339     * @return the amount that the current element is indented
1340     * @deprecated 0.5 replaced by new SAX inspired API
1341     */

1342    protected int getIndentLevel() {
1343        return 0;
1344    }
1345    
1346    // Expression methods
1347
//-------------------------------------------------------------------------
1348

1349    /**
1350     * Express an element tag start using given qualified name.
1351     *
1352     * @param qualifiedName the qualified name of the element to be expressed
1353     * @throws IOException if an IO problem occurs during writing
1354     * @throws SAXException if an SAX problem occurs during writing
1355     * @deprecated 0.5 replaced by new SAX inspired API
1356     */

1357    protected void expressElementStart(String JavaDoc qualifiedName)
1358                                        throws IOException JavaDoc, SAXException JavaDoc {
1359        // do nothing
1360
}
1361                                        
1362    /**
1363     * Express an element tag start using given qualified name.
1364     *
1365     * @param uri the namespace uri
1366     * @param localName the local name for this element
1367     * @param qualifiedName the qualified name of the element to be expressed
1368     * @throws IOException if an IO problem occurs during writing
1369     * @throws SAXException if an SAX problem occurs during writing
1370     * @deprecated 0.5 replaced by new SAX inspired API
1371     */

1372    protected void expressElementStart(String JavaDoc uri, String JavaDoc localName, String JavaDoc qualifiedName)
1373                                        throws IOException JavaDoc, SAXException JavaDoc {
1374        expressElementStart( qualifiedName );
1375    }
1376    
1377     /**
1378     * Express a closing tag.
1379     *
1380     * @throws IOException if an IO problem occurs during writing
1381     * @throws SAXException if an SAX problem occurs during writing
1382     * @deprecated 0.5 replaced by new SAX inspired API
1383     */

1384    protected void expressTagClose() throws IOException JavaDoc, SAXException JavaDoc {}
1385    
1386    /**
1387     * Express an element end tag (with given name)
1388     *
1389     * @param qualifiedName the qualified name for the element to be closed
1390     *
1391     * @throws IOException if an IO problem occurs during writing
1392     * @throws SAXException if an SAX problem occurs during writing
1393     * @deprecated 0.5 replaced by new SAX inspired API
1394     */

1395    protected void expressElementEnd(String JavaDoc qualifiedName)
1396                                              throws IOException JavaDoc, SAXException JavaDoc {
1397        // do nothing
1398
}
1399    
1400    /**
1401     * Express an element end tag (with given name)
1402     *
1403     * @param uri the namespace uri of the element close tag
1404     * @param localName the local name of the element close tag
1405     * @param qualifiedName the qualified name for the element to be closed
1406     *
1407     * @throws IOException if an IO problem occurs during writing
1408     * @throws SAXException if an SAX problem occurs during writing
1409     * @deprecated 0.5 replaced by new SAX inspired API
1410     */

1411    protected void expressElementEnd(
1412                                                String JavaDoc uri,
1413                                                String JavaDoc localName,
1414                                                String JavaDoc qualifiedName)
1415                                                    throws
1416                                                        IOException JavaDoc,
1417                                                        SAXException JavaDoc {
1418        expressElementEnd(qualifiedName);
1419    }
1420                                              
1421    
1422    /**
1423     * Express an empty element end.
1424     *
1425     * @throws IOException if an IO problem occurs during writing
1426     * @throws SAXException if an SAX problem occurs during writing
1427     * @deprecated 0.5 replaced by new SAX inspired API
1428     */

1429    protected void expressElementEnd() throws IOException JavaDoc, SAXException JavaDoc {}
1430
1431    /**
1432     * Express body text
1433     *
1434     * @param text the string to write out as the body of the current element
1435     *
1436     * @throws IOException if an IO problem occurs during writing
1437     * @throws SAXException if an SAX problem occurs during writing
1438     * @deprecated 0.5 replaced by new SAX inspired API
1439     */

1440    protected void expressBodyText(String JavaDoc text) throws IOException JavaDoc, SAXException JavaDoc {}
1441    
1442    /**
1443     * Express an attribute
1444     *
1445     * @param qualifiedName the qualified name of the attribute
1446     * @param value the attribute value
1447     * @throws IOException if an IO problem occurs during writing
1448     * @throws SAXException if an SAX problem occurs during writing
1449     * @deprecated 0.5 replaced by new SAX inspired API
1450     */

1451    protected void expressAttribute(
1452                                String JavaDoc qualifiedName,
1453                                String JavaDoc value)
1454                                    throws
1455                                        IOException JavaDoc,
1456                                        SAXException JavaDoc {
1457        // Do nothing
1458
}
1459
1460    /**
1461     * Express an attribute
1462     *
1463     * @param namespaceUri the namespace uri
1464     * @param localName the local name
1465     * @param qualifiedName the qualified name of the attribute
1466     * @param value the attribute value
1467     * @throws IOException if an IO problem occurs during writing
1468     * @throws SAXException if an SAX problem occurs during writing
1469     * @deprecated 0.5 replaced by new SAX inspired API
1470     */

1471    protected void expressAttribute(
1472                                String JavaDoc namespaceUri,
1473                                String JavaDoc localName,
1474                                String JavaDoc qualifiedName,
1475                                String JavaDoc value)
1476                                    throws
1477                                        IOException JavaDoc,
1478                                        SAXException JavaDoc {
1479        expressAttribute(qualifiedName, value);
1480    }
1481    
1482    
1483    /**
1484     * Writes the given element
1485     *
1486     * @param qualifiedName qualified name to use for the element
1487     * @param elementDescriptor the <code>ElementDescriptor</code> describing the element
1488     * @param context the <code>Context</code> to use to evaluate the bean expressions
1489     * @throws IOException if an IO problem occurs during writing
1490     * @throws SAXException if an SAX problem occurs during writing
1491     * @throws IntrospectionException if a java beans introspection problem occurs
1492     * @deprecated 0.5 replaced by new SAX inspired API
1493     */

1494    protected void write(
1495                            String JavaDoc qualifiedName,
1496                            ElementDescriptor elementDescriptor,
1497                            Context context )
1498                                throws
1499                                    IOException JavaDoc,
1500                                    SAXException JavaDoc,
1501                                    IntrospectionException JavaDoc {
1502        writeElement( "", qualifiedName, qualifiedName, elementDescriptor, context );
1503    }
1504    
1505    /**
1506     * Writes the given element adding an ID attribute
1507     *
1508     * @param qualifiedName qualified name to use for the element
1509     * @param elementDescriptor the <code>ElementDescriptor</code> describing the element
1510     * @param context the <code>Context</code> to use to evaluate the bean expressions
1511     * @param idAttribute the qualified name of the <code>ID</code> attribute
1512     * @param idValue the value for the <code>ID</code> attribute
1513     * @throws IOException if an IO problem occurs during writing
1514     * @throws SAXException if an SAX problem occurs during writing
1515     * @throws IntrospectionException if a java beans introspection problem occurs
1516     * @deprecated 0.5 replaced by new SAX inspired API
1517     */

1518    protected void write(
1519                            String JavaDoc qualifiedName,
1520                            ElementDescriptor elementDescriptor,
1521                            Context context,
1522                            String JavaDoc idAttribute,
1523                            String JavaDoc idValue )
1524                                throws
1525                                    IOException JavaDoc,
1526                                    SAXException JavaDoc,
1527                                    IntrospectionException JavaDoc {
1528        writeElement(
1529                    "",
1530                    qualifiedName,
1531                    qualifiedName,
1532                    elementDescriptor,
1533                    context,
1534                    idAttribute,
1535                    idValue );
1536    }
1537    
1538    /**
1539     * Write attributes, child elements and element end
1540     *
1541     * @param qualifiedName qualified name to use for the element
1542     * @param elementDescriptor the <code>ElementDescriptor</code> describing the element
1543     * @param context the <code>Context</code> to use to evaluate the bean expressions
1544     * @throws IOException if an IO problem occurs during writing
1545     * @throws SAXException if an SAX problem occurs during writing
1546     * @throws IntrospectionException if a java beans introspection problem occurs
1547     * @deprecated 0.5 replaced by new SAX inspired API
1548     */

1549    protected void writeRestOfElement(
1550                            String JavaDoc qualifiedName,
1551                            ElementDescriptor elementDescriptor,
1552                            Context context )
1553                                throws
1554                                    IOException JavaDoc,
1555                                    SAXException JavaDoc,
1556                                    IntrospectionException JavaDoc {
1557        writeRestOfElement( "", qualifiedName, qualifiedName, elementDescriptor, context );
1558    }
1559
1560    /**
1561     * Writes an element with a <code>IDREF</code> attribute
1562     *
1563     * @param qualifiedName of the element with <code>IDREF</code> attribute
1564     * @param idrefAttributeName the qualified name of the <code>IDREF</code> attribute
1565     * @param idrefAttributeValue the value for the <code>IDREF</code> attribute
1566     * @throws IOException if an IO problem occurs during writing
1567     * @throws SAXException if an SAX problem occurs during writing
1568     * @throws IntrospectionException if a java beans introspection problem occurs
1569     * @deprecated 0.5 replaced by new SAX inspired API
1570     */

1571    protected void writeIDREFElement(
1572                                    String JavaDoc qualifiedName,
1573                                    String JavaDoc idrefAttributeName,
1574                                    String JavaDoc idrefAttributeValue )
1575                                        throws
1576                                            IOException JavaDoc,
1577                                            SAXException JavaDoc,
1578                                            IntrospectionException JavaDoc {
1579        // deprecated
1580
AttributesImpl JavaDoc attributes = new AttributesImpl JavaDoc();
1581       attributes.addAttribute(
1582                               "",
1583                               idrefAttributeName,
1584                               idrefAttributeName,
1585                               "IDREF",
1586                               idrefAttributeValue);
1587       startElement( "", qualifiedName, qualifiedName, attributes);
1588       endElement( "", qualifiedName, qualifiedName );
1589    }
1590
1591        
1592    /**
1593     * Writes the element content.
1594     *
1595     * @param elementDescriptor the <code>ElementDescriptor</code> to write as xml
1596     * @param context the <code>Context</code> to use to evaluate the bean expressions
1597     * @return true if some content was written
1598     * @throws IOException if an IO problem occurs during writing
1599     * @throws SAXException if an SAX problem occurs during writing
1600     * @throws IntrospectionException if a java beans introspection problem occurs
1601     * @deprecated 0.5 replaced by new SAX inspired API
1602     */

1603    protected boolean writeContent(
1604                        ElementDescriptor elementDescriptor,
1605                        Context context )
1606                            throws
1607                                IOException JavaDoc,
1608                                SAXException JavaDoc,
1609                                IntrospectionException JavaDoc {
1610        return false;
1611    }
1612
1613    
1614    /**
1615     * Writes the attribute declarations
1616     *
1617     * @param elementDescriptor the <code>ElementDescriptor</code> to be written out as xml
1618     * @param context the <code>Context</code> to use to evaluation bean expressions
1619     * @throws IOException if an IO problem occurs during writing
1620     * @throws SAXException if an SAX problem occurs during writing
1621     * @deprecated 0.5 replaced by new SAX inspired API
1622     */

1623    protected void writeAttributes(
1624                    ElementDescriptor elementDescriptor,
1625                    Context context )
1626                        throws
1627                            IOException JavaDoc, SAXException JavaDoc {
1628        if (!elementDescriptor.isWrapCollectionsInElement()) {
1629            return;
1630        }
1631            
1632        AttributeDescriptor[] attributeDescriptors = elementDescriptor.getAttributeDescriptors();
1633        if ( attributeDescriptors != null ) {
1634            for ( int i = 0, size = attributeDescriptors.length; i < size; i++ ) {
1635                AttributeDescriptor attributeDescriptor = attributeDescriptors[i];
1636                writeAttribute( attributeDescriptor, context );
1637            }
1638        }
1639    }
1640
1641    
1642    /**
1643     * Writes an attribute declaration
1644     *
1645     * @param attributeDescriptor the <code>AttributeDescriptor</code> to be written as xml
1646     * @param context the <code>Context</code> to use to evaluation bean expressions
1647     * @throws IOException if an IO problem occurs during writing
1648     * @throws SAXException if an SAX problem occurs during writing
1649     * @deprecated 0.5 replaced by new SAX inspired API
1650     */

1651    protected void writeAttribute(
1652                        AttributeDescriptor attributeDescriptor,
1653                        Context context )
1654                            throws
1655                                IOException JavaDoc, SAXException JavaDoc {
1656        Expression expression = attributeDescriptor.getTextExpression();
1657        if ( expression != null ) {
1658            Object JavaDoc value = expression.evaluate( context );
1659            if ( value != null ) {
1660                String JavaDoc text = value.toString();
1661                if ( text != null && text.length() > 0 ) {
1662                    expressAttribute(
1663                                    attributeDescriptor.getURI(),
1664                                    attributeDescriptor.getLocalName(),
1665                                    attributeDescriptor.getQualifiedName(),
1666                                    text);
1667                }
1668            }
1669        }
1670    }
1671    /**
1672     * Writes a empty line.
1673     * This implementation does nothing but can be overridden by subclasses.
1674     *
1675     * @throws IOException if the line cannot be written
1676     * @deprecated 0.5 replaced by new SAX inspired API
1677     */

1678    protected void writePrintln() throws IOException JavaDoc {}
1679    
1680    /**
1681     * Writes an indentation.
1682     * This implementation does nothing but can be overridden by subclasses.
1683     *
1684     * @throws IOException if the indent cannot be written
1685     * @deprecated 0.5 replaced by new BeanWriter API
1686     */

1687    protected void writeIndent() throws IOException JavaDoc {}
1688    
1689    /**
1690      * Converts an object to a string.
1691      *
1692      * @param value the Object to represent as a String, possibly null
1693      * @param descriptor writing out this descriptor not null
1694      * @param context not null
1695      * @return String representation, not null
1696      */

1697    private String JavaDoc convertToString( Object JavaDoc value , Descriptor descriptor, Context context ) {
1698        return getBindingConfiguration()
1699            .getObjectStringConverter()
1700                .objectToString( value, descriptor.getPropertyType(), null, context );
1701    }
1702    
1703    /**
1704      * Factory method for new contexts.
1705      * Ensure that they are correctly configured.
1706      * @param bean make a new Context for this bean
1707      * @return not null
1708      */

1709    private Context makeContext(Object JavaDoc bean) {
1710        return new Context( bean, log, bindingConfiguration );
1711    }
1712
1713    
1714    /**
1715     * Basic mutable implementation of <code>WriteContext</code>.
1716     */

1717    private static class WriteContextImpl extends WriteContext {
1718
1719        private ElementDescriptor currentDescriptor;
1720
1721        /**
1722         * @see org.apache.commons.betwixt.io.WriteContext#getCurrentDescriptor()
1723         */

1724        public ElementDescriptor getCurrentDescriptor() {
1725            return currentDescriptor;
1726        }
1727        
1728        /**
1729         * Sets the descriptor for the current element.
1730         * @param currentDescriptor
1731         */

1732        public void setCurrentDescriptor(ElementDescriptor currentDescriptor) {
1733            this.currentDescriptor = currentDescriptor;
1734        }
1735        
1736    }
1737}
1738
Popular Tags