Coverage Report - org.apache.commons.betwixt.io.BeanWriter

Classes in this File Line Coverage Branch Coverage Complexity
BeanWriter
63% 
65% 
1.703

 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;
 19  
 import java.io.BufferedWriter;
 20  
 import java.io.IOException;
 21  
 import java.io.OutputStream;
 22  
 import java.io.OutputStreamWriter;
 23  
 import java.io.UnsupportedEncodingException;
 24  
 import java.io.Writer;
 25  
 
 26  
 import org.apache.commons.betwixt.XMLUtils;
 27  
 import org.apache.commons.betwixt.strategy.MixedContentEncodingStrategy;
 28  
 import org.apache.commons.logging.Log;
 29  
 import org.apache.commons.logging.LogFactory;
 30  
 import org.xml.sax.Attributes;
 31  
 import org.xml.sax.SAXException;
 32  
 
 33  
 /** <p><code>BeanWriter</code> outputs beans as XML to an io stream.</p>
 34  
   *
 35  
   * <p>The output for each bean is an xml fragment
 36  
   * (rather than a well-formed xml-document).
 37  
   * This allows bean representations to be appended to a document 
 38  
   * by writing each in turn to the stream.
 39  
   * So to create a well formed xml document, 
 40  
   * you'll need to write the prolog to the stream first.
 41  
   * If you append more than one bean to the stream, 
 42  
   * then you'll need to add a wrapping root element as well.
 43  
   *
 44  
   * <p> The line ending to be used is set by {@link #setEndOfLine}. 
 45  
   * 
 46  
   * <p> The output can be formatted (with whitespace) for easy reading 
 47  
   * by calling {@link #enablePrettyPrint}. 
 48  
   * The output will be indented. 
 49  
   * The indent string used is set by {@link #setIndent}.
 50  
   *
 51  
   * <p> Bean graphs can sometimes contain cycles. 
 52  
   * Care must be taken when serializing cyclic bean graphs
 53  
   * since this can lead to infinite recursion. 
 54  
   * The approach taken by <code>BeanWriter</code> is to automatically
 55  
   * assign an <code>ID</code> attribute value to beans.
 56  
   * When a cycle is encountered, 
 57  
   * an element is written that has the <code>IDREF</code> attribute set to the 
 58  
   * id assigned earlier.
 59  
   *
 60  
   * <p> The names of the <code>ID</code> and <code>IDREF</code> attributes used 
 61  
   * can be customized by the <code>XMLBeanInfo</code>.
 62  
   * The id's used can also be customized by the user 
 63  
   * via <code>IDGenerator</code> subclasses.
 64  
   * The implementation used can be set by the <code>IdGenerator</code> property.
 65  
   * BeanWriter defaults to using <code>SequentialIDGenerator</code> 
 66  
   * which supplies id values in numeric sequence.
 67  
   * 
 68  
   * <p>If generated <code>ID</code> attribute values are not acceptable in the output,
 69  
   * then this can be disabled by setting the <code>WriteIDs</code> property to false.
 70  
   * If a cyclic reference is encountered in this case then a
 71  
   * <code>CyclicReferenceException</code> will be thrown. 
 72  
   * When the <code>WriteIDs</code> property is set to false,
 73  
   * it is recommended that this exception is caught by the caller.
 74  
   * 
 75  
   * 
 76  
   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
 77  
   * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
 78  
   */
 79  695
 public class BeanWriter extends AbstractBeanWriter {
 80  
 
 81  
     /**
 82  
      * Gets the default EOL string. 
 83  
      * @return EOL string, not null
 84  
      */
 85  
     private static final String getEOL() {
 86  
         // just wraps call in an exception check for access restricted environments
 87  695
         String result = "\n";
 88  
         try {
 89  695
             result = System.getProperty( "line.separator", "\n" );
 90  0
         } catch (SecurityException se) {
 91  0
             Log log = LogFactory.getLog( BeanWriter.class );
 92  0
             log.warn("Cannot load line separator property: " + se.getMessage());
 93  0
             log.trace("Caused by: ", se);
 94  
         }
 95  695
         return result;
 96  
     }
 97  
     
 98  
     
 99  
     /** Where the output goes */
 100  
     private Writer writer;    
 101  
     /** text used for end of lines. Defaults to <code>\n</code>*/
 102  695
     private static final String EOL = getEOL();
 103  
     /** text used for end of lines. Defaults to <code>\n</code>*/
 104  1943
     private String endOfLine = EOL;
 105  
     /** Initial level of indentation (starts at 1 with the first element by default) */
 106  1943
     private int initialIndentLevel = 1;
 107  
     /** indentation text */
 108  
     private String indent;
 109  
 
 110  
     /** should we flush after writing bean */
 111  
     private boolean autoFlush;
 112  
     /** Log used for logging (Doh!) */
 113  1943
     private Log log = LogFactory.getLog( BeanWriter.class );
 114  
     /** Has any content (excluding attributes) been written to the current element */
 115  1943
     private boolean currentElementIsEmpty = false;
 116  
     /** Has the current element written any body text */
 117  1943
     private boolean currentElementHasBodyText = false;
 118  
     /** Has the last start tag been closed */
 119  1943
     private boolean closedStartTag = true;
 120  
     /** Should an end tag be added for empty elements? */
 121  1943
     private boolean addEndTagForEmptyElement = false;
 122  
     /** Current level of indentation */
 123  
     private int indentLevel;
 124  
     /** USed to determine how body content should be encoded before being output*/
 125  1943
     private MixedContentEncodingStrategy mixedContentEncodingStrategy 
 126  1943
         = MixedContentEncodingStrategy.DEFAULT;
 127  
     
 128  
     /**
 129  
      * <p> Constructor uses <code>System.out</code> for output.</p>
 130  
      */
 131  
     public BeanWriter() {
 132  39
         this( System.out );
 133  39
     }
 134  
     
 135  
     /**
 136  
      * <p> Constuctor uses given <code>OutputStream</code> for output.</p>
 137  
      *
 138  
      * @param out write out representations to this stream
 139  
      */
 140  52
     public BeanWriter(OutputStream out) {
 141  52
         this.writer = new BufferedWriter( new OutputStreamWriter( out ) );
 142  52
         this.autoFlush = true;
 143  52
     }
 144  
 
 145  
     /**
 146  
      * <p>Constuctor uses given <code>OutputStream</code> for output 
 147  
      * and allows encoding to be set.</p>
 148  
      *
 149  
      * @param out write out representations to this stream
 150  
      * @param enc the name of the encoding to be used. This should be compatible
 151  
      * with the encoding types described in <code>java.io</code>
 152  
      * @throws UnsupportedEncodingException if the given encoding is not supported
 153  
      */
 154  0
     public BeanWriter(OutputStream out, String enc) throws UnsupportedEncodingException {
 155  0
         this.writer = new BufferedWriter( new OutputStreamWriter( out, enc ) );
 156  0
         this.autoFlush = true;
 157  0
     }
 158  
 
 159  
     /**
 160  
      * <p> Constructor sets writer used for output.</p>
 161  
      *
 162  
      * @param writer write out representations to this writer
 163  
      */
 164  1891
     public BeanWriter(Writer writer) {
 165  1891
         this.writer = writer;
 166  1891
     }
 167  
 
 168  
     /**
 169  
      * A helper method that allows you to write the XML Declaration.
 170  
      * This should only be called once before you output any beans.
 171  
      * 
 172  
      * @param xmlDeclaration is the XML declaration string typically of
 173  
      *  the form "&lt;xml version='1.0' encoding='UTF-8' ?&gt;
 174  
      *
 175  
      * @throws IOException when declaration cannot be written
 176  
      */
 177  
     public void writeXmlDeclaration(String xmlDeclaration) throws IOException {
 178  52
         writer.write( xmlDeclaration );
 179  52
         printLine();
 180  52
     }
 181  
     
 182  
     /**
 183  
      * Allows output to be flushed on the underlying output stream
 184  
      * 
 185  
      * @throws IOException when the flush cannot be completed
 186  
      */
 187  
     public void flush() throws IOException {
 188  130
         writer.flush();
 189  130
     }
 190  
     
 191  
     /**
 192  
      * Closes the underlying output stream
 193  
      *
 194  
      * @throws IOException when writer cannot be closed
 195  
      */
 196  
     public void close() throws IOException {
 197  0
         writer.close();
 198  0
     }
 199  
     
 200  
     /**
 201  
      * Write the given object to the stream (and then flush).
 202  
      * 
 203  
      * @param bean write this <code>Object</code> to the stream
 204  
      * @throws IOException if an IO problem causes failure
 205  
      * @throws SAXException if a SAX problem causes failure
 206  
      * @throws IntrospectionException if bean cannot be introspected
 207  
      */
 208  
     public void write(Object bean) throws IOException, SAXException, IntrospectionException  {
 209  
 
 210  1722
         super.write(bean);
 211  
 
 212  1696
         if ( autoFlush ) {
 213  104
             writer.flush();
 214  
         }
 215  1696
     }
 216  
     
 217  
  
 218  
     /**
 219  
      * <p> Switch on formatted output.
 220  
      * This sets the end of line and the indent.
 221  
      * The default is adding 2 spaces and a newline
 222  
      */
 223  
     public void enablePrettyPrint() {
 224  507
         endOfLine = EOL;
 225  507
         indent = "  ";
 226  507
     }
 227  
 
 228  
     /** 
 229  
      * Gets the string used to mark end of lines.
 230  
      *
 231  
      * @return the string used for end of lines 
 232  
      */
 233  
     public String getEndOfLine() {
 234  26
         return endOfLine;
 235  
     }
 236  
     
 237  
     /** 
 238  
      * Sets the string used for end of lines 
 239  
      * Produces a warning the specified value contains an invalid whitespace character
 240  
      *
 241  
      * @param endOfLine the <code>String</code to use 
 242  
      */
 243  
     public void setEndOfLine(String endOfLine) {
 244  702
         this.endOfLine = endOfLine;
 245  1391
         for (int i = 0; i < endOfLine.length(); i++) {
 246  715
             if (!Character.isWhitespace(endOfLine.charAt(i))) {
 247  26
                 log.warn("Invalid EndOfLine character(s)");
 248  26
                 break;
 249  
             }
 250  
         }
 251  
         
 252  702
     }
 253  
 
 254  
     /** 
 255  
      * Gets the initial indent level 
 256  
      *
 257  
      * @return the initial level for indentation 
 258  
      */
 259  
     public int getInitialIndentLevel() {
 260  0
         return initialIndentLevel;
 261  
     }
 262  
     
 263  
     /** 
 264  
      * Sets the initial indent level used for pretty print indents  
 265  
      * @param initialIndentLevel use this <code>int</code> to start with
 266  
      */
 267  
     public void setInitialIndentLevel(int initialIndentLevel) {
 268  0
         this.initialIndentLevel = initialIndentLevel;
 269  0
     }
 270  
 
 271  
 
 272  
     /** 
 273  
      * Gets the indent string 
 274  
      *
 275  
      * @return the string used for indentation 
 276  
      */
 277  
     public String getIndent() {
 278  27820
         return indent;
 279  
     }
 280  
     
 281  
     /** 
 282  
      * Sets the string used for pretty print indents  
 283  
      * @param indent use this <code>string</code> for indents
 284  
      */
 285  
     public void setIndent(String indent) {
 286  65
         this.indent = indent;
 287  65
     }
 288  
 
 289  
     /**
 290  
      * <p> Set the log implementation used. </p>
 291  
      *
 292  
      * @return a <code>org.apache.commons.logging.Log</code> level constant
 293  
      */ 
 294  
     public Log getLog() {
 295  0
         return log;
 296  
     }
 297  
 
 298  
     /**
 299  
      * <p> Set the log implementation used. </p>
 300  
      *
 301  
      * @param log <code>Log</code> implementation to use
 302  
      */ 
 303  
     public void setLog( Log log ) {
 304  13
         this.log = log;
 305  13
     }
 306  
     
 307  
     /**
 308  
      * Gets the encoding strategy for mixed content.
 309  
      * This is used to process body content 
 310  
      * before it is written to the textual output.
 311  
      * @return the <code>MixedContentEncodingStrategy</code>, not null
 312  
      * @since 0.5
 313  
      */
 314  
     public MixedContentEncodingStrategy getMixedContentEncodingStrategy() {
 315  0
         return mixedContentEncodingStrategy;
 316  
     }
 317  
 
 318  
     /**
 319  
      * Sets the encoding strategy for mixed content.
 320  
      * This is used to process body content 
 321  
      * before it is written to the textual output.
 322  
      * @param strategy the <code>MixedContentEncodingStrategy</code>
 323  
      * used to process body content, not null
 324  
      * @since 0.5
 325  
      */
 326  
     public void setMixedContentEncodingStrategy(MixedContentEncodingStrategy strategy) {
 327  26
         mixedContentEncodingStrategy = strategy;
 328  26
     }
 329  
     
 330  
     /**
 331  
      * <p>Should an end tag be added for each empty element?
 332  
      * </p><p>
 333  
      * When this property is false then empty elements will
 334  
      * be written as <code>&lt;<em>element-name</em>/gt;</code>.
 335  
      * When this property is true then empty elements will
 336  
      * be written as <code>&lt;<em>element-name</em>gt;
 337  
      * &lt;/<em>element-name</em>gt;</code>.
 338  
      * </p>
 339  
      * @return true if an end tag should be added
 340  
      */
 341  
     public boolean isEndTagForEmptyElement() {
 342  0
         return addEndTagForEmptyElement;
 343  
     }
 344  
     
 345  
     /**
 346  
      * Sets when an an end tag be added for each empty element.
 347  
      * When this property is false then empty elements will
 348  
      * be written as <code>&lt;<em>element-name</em>/gt;</code>.
 349  
      * When this property is true then empty elements will
 350  
      * be written as <code>&lt;<em>element-name</em>gt;
 351  
      * &lt;/<em>element-name</em>gt;</code>.
 352  
      * @param addEndTagForEmptyElement true if an end tag should be 
 353  
      * written for each empty element, false otherwise
 354  
      */
 355  
     public void setEndTagForEmptyElement(boolean addEndTagForEmptyElement) {
 356  39
         this.addEndTagForEmptyElement = addEndTagForEmptyElement;
 357  39
     }
 358  
     
 359  
     
 360  
     
 361  
     // New API
 362  
     //------------------------------------------------------------------------------
 363  
 
 364  
     
 365  
     /**
 366  
      * Writes the start tag for an element.
 367  
      *
 368  
      * @param uri the element's namespace uri
 369  
      * @param localName the element's local name 
 370  
      * @param qualifiedName the element's qualified name
 371  
      * @param attr the element's attributes
 372  
      * @throws IOException if an IO problem occurs during writing 
 373  
      * @throws SAXException if an SAX problem occurs during writing 
 374  
      * @since 0.5
 375  
      */
 376  
     protected void startElement(
 377  
                                 WriteContext context,
 378  
                                 String uri, 
 379  
                                 String localName, 
 380  
                                 String qualifiedName, 
 381  
                                 Attributes attr)
 382  
                                     throws
 383  
                                         IOException,
 384  
                                         SAXException {
 385  17217
         if ( !closedStartTag ) {
 386  6350
             writer.write( '>' );
 387  6350
             printLine();
 388  
         }
 389  
         
 390  17217
         indentLevel++;
 391  
         
 392  17217
         indent();
 393  17217
         writer.write( '<' );
 394  17217
         writer.write( qualifiedName );
 395  
         
 396  25368
         for ( int i=0; i< attr.getLength(); i++ ) {
 397  8151
             writer.write( ' ' );
 398  8151
             writer.write( attr.getQName(i) );
 399  8151
             writer.write( "=\"" );
 400  8151
             writer.write( XMLUtils.escapeAttributeValue( attr.getValue(i) ) );
 401  8151
             writer.write( '\"' );
 402  
         }
 403  17217
         closedStartTag = false;
 404  17217
         currentElementIsEmpty = true;
 405  17217
         currentElementHasBodyText = false;
 406  17217
     }
 407  
     
 408  
     /**
 409  
      * Writes the end tag for an element
 410  
      *
 411  
      * @param uri the element's namespace uri
 412  
      * @param localName the element's local name 
 413  
      * @param qualifiedName the element's qualified name
 414  
      *
 415  
      * @throws IOException if an IO problem occurs during writing 
 416  
      * @throws SAXException if an SAX problem occurs during writing 
 417  
      * @since 0.5
 418  
      */
 419  
     protected void endElement(
 420  
                                 WriteContext context,
 421  
                                 String uri, 
 422  
                                 String localName, 
 423  
                                 String qualifiedName)
 424  
                                     throws
 425  
                                         IOException,
 426  
                                         SAXException {
 427  
         if ( 
 428  17035
             !addEndTagForEmptyElement
 429  17009
             && !closedStartTag 
 430  3886
             && currentElementIsEmpty ) {
 431  
         
 432  3886
             writer.write( "/>" );
 433  3886
             closedStartTag = true;
 434  
             
 435  
         } else {
 436  
 
 437  
             if (
 438  13149
                     addEndTagForEmptyElement
 439  26
                     && !closedStartTag ) {
 440  26
                  writer.write( ">" );
 441  26
                  closedStartTag = true;                 
 442  
             }
 443  13123
             else if (!currentElementHasBodyText) {
 444  6194
                 indent();
 445  
             }
 446  13149
             writer.write( "</" );
 447  13149
             writer.write( qualifiedName );
 448  13149
             writer.write( '>' );
 449  
             
 450  
         }
 451  
         
 452  17035
         indentLevel--;
 453  17035
         printLine();
 454  
         
 455  17035
         currentElementHasBodyText = false;
 456  17035
     }
 457  
 
 458  
     /** 
 459  
      * Write element body text 
 460  
      *
 461  
      * @param text write out this body text
 462  
      * @throws IOException when the stream write fails
 463  
      * @since 0.5
 464  
      */
 465  
     protected void bodyText(WriteContext context, String text) throws IOException {
 466  6942
         if ( text == null ) {
 467  
             // XXX This is probably a programming error
 468  0
             log.error( "[expressBodyText]Body text is null" );
 469  
             
 470  
         } else {
 471  6942
             if ( !closedStartTag ) {
 472  6929
                 writer.write( '>' );
 473  6929
                 closedStartTag = true;
 474  
             }
 475  13884
             writer.write( 
 476  13884
                 mixedContentEncodingStrategy.encode(
 477  6942
                     text, 
 478  6942
                     context.getCurrentDescriptor()) );
 479  6942
             currentElementIsEmpty = false;
 480  6942
             currentElementHasBodyText = true;
 481  
         }
 482  6942
     }
 483  
     
 484  
     /** Writes out an empty line.
 485  
      * Uses current <code>endOfLine</code>.
 486  
      *
 487  
      * @throws IOException when stream write fails
 488  
      */
 489  
     private void printLine() throws IOException {
 490  23437
         if ( endOfLine != null ) {
 491  23437
             writer.write( endOfLine );
 492  
         }
 493  23437
     }
 494  
     
 495  
     /** 
 496  
      * Writes out <code>indent</code>'s to the current <code>indentLevel</code>
 497  
      *
 498  
      * @throws IOException when stream write fails
 499  
      */
 500  
     private void indent() throws IOException {
 501  23411
         if ( indent != null ) {
 502  37076
             for ( int i = 1 - initialIndentLevel; i < indentLevel; i++ ) {
 503  27820
                 writer.write( getIndent() );
 504  
             }
 505  
         }
 506  23411
     }
 507  
 
 508  
     // OLD API (DEPRECATED)
 509  
     //----------------------------------------------------------------------------
 510  
 
 511  
             
 512  
     /** Writes out an empty line.
 513  
      * Uses current <code>endOfLine</code>.
 514  
      *
 515  
      * @throws IOException when stream write fails
 516  
      * @deprecated 0.5 replaced by new SAX inspired API
 517  
      */
 518  
     protected void writePrintln() throws IOException {
 519  0
         if ( endOfLine != null ) {
 520  0
             writer.write( endOfLine );
 521  
         }
 522  0
     }
 523  
     
 524  
     /** 
 525  
      * Writes out <code>indent</code>'s to the current <code>indentLevel</code>
 526  
      *
 527  
      * @throws IOException when stream write fails
 528  
      * @deprecated 0.5 replaced by new SAX inspired API
 529  
      */
 530  
     protected void writeIndent() throws IOException {
 531  0
         if ( indent != null ) {
 532  0
             for ( int i = 0; i < indentLevel; i++ ) {
 533  0
                 writer.write( getIndent() );
 534  
             }
 535  
         }
 536  0
     }
 537  
     
 538  
     /** 
 539  
      * <p>Escape the <code>toString</code> of the given object.
 540  
      * For use as body text.</p>
 541  
      *
 542  
      * @param value escape <code>value.toString()</code>
 543  
      * @return text with escaped delimiters 
 544  
      * @deprecated 0.5 moved into utility class {@link XMLUtils#escapeBodyValue}
 545  
      */
 546  
     protected String escapeBodyValue(Object value) {
 547  0
         return XMLUtils.escapeBodyValue(value);
 548  
     }
 549  
 
 550  
     /** 
 551  
      * <p>Escape the <code>toString</code> of the given object.
 552  
      * For use in an attribute value.</p>
 553  
      *
 554  
      * @param value escape <code>value.toString()</code>
 555  
      * @return text with characters restricted (for use in attributes) escaped
 556  
      *
 557  
      * @deprecated 0.5 moved into utility class {@link XMLUtils#escapeAttributeValue}
 558  
      */
 559  
     protected String escapeAttributeValue(Object value) {
 560  0
         return XMLUtils.escapeAttributeValue(value);
 561  
     }  
 562  
 
 563  
     /** 
 564  
      * Express an element tag start using given qualified name 
 565  
      *
 566  
      * @param qualifiedName the fully qualified name of the element to write
 567  
      * @throws IOException when stream write fails
 568  
      * @deprecated 0.5 replaced by new SAX inspired API
 569  
      */
 570  
     protected void expressElementStart(String qualifiedName) throws IOException {
 571  0
         if ( qualifiedName == null ) {
 572  
             // XXX this indicates a programming error
 573  0
             log.fatal( "[expressElementStart]Qualified name is null." );
 574  0
             throw new RuntimeException( "Qualified name is null." );
 575  
         }
 576  
         
 577  0
         writePrintln();
 578  0
         writeIndent();
 579  0
         writer.write( '<' );
 580  0
         writer.write( qualifiedName );
 581  0
     }
 582  
     
 583  
     /** 
 584  
      * Write a tag close to the stream
 585  
      *
 586  
      * @throws IOException when stream write fails
 587  
      * @deprecated 0.5 replaced by new SAX inspired API
 588  
      */
 589  
     protected void expressTagClose() throws IOException {
 590  0
         writer.write( '>' );
 591  0
     }
 592  
     
 593  
     /** 
 594  
      * Write an element end tag to the stream
 595  
      *
 596  
      * @param qualifiedName the name of the element
 597  
      * @throws IOException when stream write fails
 598  
      * @deprecated 0.5 replaced by new SAX inspired API
 599  
      */
 600  
     protected void expressElementEnd(String qualifiedName) throws IOException {
 601  0
         if (qualifiedName == null) {
 602  
             // XXX this indicates a programming error
 603  0
             log.fatal( "[expressElementEnd]Qualified name is null." );
 604  0
             throw new RuntimeException( "Qualified name is null." );
 605  
         }
 606  
         
 607  0
         writer.write( "</" );
 608  0
         writer.write( qualifiedName );
 609  0
         writer.write( '>' );
 610  0
     }    
 611  
     
 612  
     /**  
 613  
      * Write an empty element end to the stream
 614  
      *
 615  
      * @throws IOException when stream write fails
 616  
      * @deprecated 0.5 replaced by new SAX inspired API
 617  
      */
 618  
     protected void expressElementEnd() throws IOException {
 619  0
         writer.write( "/>" );
 620  0
     }
 621  
 
 622  
     /** 
 623  
      * Write element body text 
 624  
      *
 625  
      * @param text write out this body text
 626  
      * @throws IOException when the stream write fails
 627  
      * @deprecated 0.5 replaced by new SAX inspired API
 628  
      */
 629  
     protected void expressBodyText(String text) throws IOException {
 630  0
         if ( text == null ) {
 631  
             // XXX This is probably a programming error
 632  0
             log.error( "[expressBodyText]Body text is null" );
 633  
             
 634  
         } else {
 635  0
             writer.write( XMLUtils.escapeBodyValue(text) );
 636  
         }
 637  0
     }
 638  
     
 639  
     /** 
 640  
      * Writes an attribute to the stream.
 641  
      *
 642  
      * @param qualifiedName fully qualified attribute name
 643  
      * @param value attribute value
 644  
      * @throws IOException when the stream write fails
 645  
      * @deprecated 0.5 replaced by new SAX inspired API
 646  
      */
 647  
     protected void expressAttribute(
 648  
                                 String qualifiedName, 
 649  
                                 String value) 
 650  
                                     throws
 651  
                                         IOException{
 652  0
         if ( value == null ) {
 653  
             // XXX probably a programming error
 654  0
             log.error( "Null attribute value." );
 655  0
             return;
 656  
         }
 657  
         
 658  0
         if ( qualifiedName == null ) {
 659  
             // XXX probably a programming error
 660  0
             log.error( "Null attribute value." );
 661  0
             return;
 662  
         }
 663  
                 
 664  0
         writer.write( ' ' );
 665  0
         writer.write( qualifiedName );
 666  0
         writer.write( "=\"" );
 667  0
         writer.write( XMLUtils.escapeAttributeValue(value) );
 668  0
         writer.write( '\"' );
 669  0
     }
 670  
 
 671  
 
 672  
 }