Coverage Report - org.apache.maven.shared.utils.xml.PrettyPrintXMLWriter
 
Classes in this File Line Coverage Branch Coverage Complexity
PrettyPrintXMLWriter
81%
85/104
66%
20/30
1.955
 
 1  
 package org.apache.maven.shared.utils.xml;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *  http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.PrintWriter;
 23  
 import java.io.Writer;
 24  
 import java.util.LinkedList;
 25  
 
 26  
 import org.apache.maven.shared.utils.Os;
 27  
 
 28  
 /**
 29  
  * XMLWriter with nice indentation
 30  
  */
 31  
 public class PrettyPrintXMLWriter
 32  
     implements XMLWriter
 33  
 {
 34  
     private PrintWriter writer;
 35  
 
 36  32
     private LinkedList<String> elementStack = new LinkedList<String>();
 37  
 
 38  32
     private boolean processingElement = false;
 39  
 
 40  32
     private boolean documentStarted = false;
 41  
 
 42  32
     private boolean endOnSameLine = false;
 43  
 
 44  32
     private int depth = 0;
 45  
 
 46  
     private String lineIndent;
 47  
 
 48  
     private String lineSeparator;
 49  
 
 50  
     private String encoding;
 51  
 
 52  
     private String docType;
 53  
 
 54  
     /**
 55  
      * @param writer not null
 56  
      * @param lineIndent could be null, but the normal way is some spaces.
 57  
      */
 58  
     public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent )
 59  
     {
 60  0
         this( writer, lineIndent, null, null );
 61  0
     }
 62  
 
 63  
     /**
 64  
      * @param writer not null
 65  
      * @param lineIndent could be null, but the normal way is some spaces.
 66  
      */
 67  
     public PrettyPrintXMLWriter( Writer writer, String lineIndent )
 68  
     {
 69  0
         this( new PrintWriter( writer ), lineIndent );
 70  0
     }
 71  
 
 72  
     /**
 73  
      * @param writer not null
 74  
      */
 75  
     public PrettyPrintXMLWriter( PrintWriter writer )
 76  
     {
 77  31
         this( writer, null, null );
 78  31
     }
 79  
 
 80  
     /**
 81  
      * @param writer not null
 82  
      */
 83  
     public PrettyPrintXMLWriter( Writer writer )
 84  
     {
 85  31
         this( new PrintWriter( writer ) );
 86  31
     }
 87  
 
 88  
     /**
 89  
      * @param writer not null
 90  
      * @param lineIndent could be null, but the normal way is some spaces.
 91  
      * @param encoding could be null or invalid.
 92  
      * @param doctype could be null.
 93  
      */
 94  
     public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent, String encoding, String doctype )
 95  
     {
 96  32
         this( writer, lineIndent, Os.LINE_SEP, encoding, doctype );
 97  32
     }
 98  
 
 99  
     /**
 100  
      * @param writer not null
 101  
      * @param lineIndent could be null, but the normal way is some spaces.
 102  
      * @param encoding could be null or invalid.
 103  
      * @param doctype could be null.
 104  
      */
 105  
     public PrettyPrintXMLWriter( Writer writer, String lineIndent, String encoding, String doctype )
 106  
     {
 107  0
         this( new PrintWriter( writer ), lineIndent, encoding, doctype );
 108  0
     }
 109  
 
 110  
     /**
 111  
      * @param writer not null
 112  
      * @param encoding could be null or invalid.
 113  
      * @param doctype could be null.
 114  
      */
 115  
     public PrettyPrintXMLWriter( PrintWriter writer, String encoding, String doctype )
 116  
     {
 117  32
         this( writer, "  ", encoding, doctype );
 118  32
     }
 119  
 
 120  
     /**
 121  
      * @param writer not null
 122  
      * @param encoding could be null or invalid.
 123  
      * @param doctype could be null.
 124  
      */
 125  
     public PrettyPrintXMLWriter( Writer writer, String encoding, String doctype )
 126  
     {
 127  1
         this( new PrintWriter( writer ), encoding, doctype );
 128  1
     }
 129  
 
 130  
     /**
 131  
      * @param writer not null
 132  
      * @param lineIndent could be null, but the normal way is some spaces.
 133  
      * @param lineSeparator could be null, but the normal way is valid line separator
 134  
      * @param encoding could be null or the encoding to use.
 135  
      * @param doctype could be null.
 136  
      */
 137  
     public PrettyPrintXMLWriter( PrintWriter writer, String lineIndent, String lineSeparator, String encoding,
 138  
                                  String doctype )
 139  32
     {
 140  32
         this.writer = writer;
 141  32
         this.lineIndent = lineIndent;
 142  32
         this.lineSeparator = lineSeparator;
 143  32
         this.encoding = encoding;
 144  32
         this.docType = doctype;
 145  
 
 146  32
         depth = 0;
 147  32
     }
 148  
 
 149  
     public void addAttribute( String key, String value )
 150  
     {
 151  19
         if ( !processingElement )
 152  
         {
 153  0
             throw new IllegalStateException( "currently processing no element" );
 154  
         }
 155  
 
 156  19
         writer.write( ' ' );
 157  19
         writer.write( key );
 158  19
         writer.write( '=' );
 159  19
         writer.write( XMLEncode.xmlEncodeTextForAttribute( value, '"' ) );
 160  19
     }
 161  
 
 162  
     public void setEncoding( String encoding )
 163  
     {
 164  0
         if ( documentStarted )
 165  
         {
 166  0
             throw new IllegalStateException( "Document headers already written!" );
 167  
         }
 168  
 
 169  0
         this.encoding = encoding;
 170  0
     }
 171  
 
 172  
     public void setDocType( String docType )
 173  
     {
 174  0
         if ( documentStarted )
 175  
         {
 176  0
             throw new IllegalStateException( "Document headers already written!" );
 177  
         }
 178  
 
 179  0
         this.docType = docType;
 180  0
     }
 181  
 
 182  
     public void setLineSeparator( String lineSeparator )
 183  
     {
 184  1
         if ( documentStarted )
 185  
         {
 186  0
             throw new IllegalStateException( "Document headers already written!" );
 187  
         }
 188  
 
 189  1
         this.lineSeparator = lineSeparator;
 190  1
     }
 191  
 
 192  
     public void setLineIndenter( String lineIndent )
 193  
     {
 194  1
         if ( documentStarted )
 195  
         {
 196  0
             throw new IllegalStateException( "Document headers already written!" );
 197  
         }
 198  
 
 199  1
         this.lineIndent = lineIndent;
 200  1
     }
 201  
 
 202  
     public void startElement( String elementName )
 203  
     {
 204  39
         boolean firstLine = ensureDocumentStarted();
 205  
 
 206  39
         completePreviouslyOpenedElement();
 207  
 
 208  39
         if ( !firstLine )
 209  
         {
 210  30
             newLine();
 211  
         }
 212  
 
 213  39
         writer.write( '<' );
 214  39
         writer.write( elementName );
 215  
 
 216  39
         processingElement = true;
 217  39
         depth++;
 218  
 
 219  39
         elementStack.addLast( elementName );
 220  39
     }
 221  
 
 222  
     public void writeText( String text )
 223  
     {
 224  21
         ensureDocumentStarted();
 225  
 
 226  21
         completePreviouslyOpenedElement();
 227  
 
 228  21
         writer.write( XMLEncode.xmlEncodeText( text ) );
 229  
 
 230  21
         endOnSameLine = true;
 231  21
     }
 232  
 
 233  
     public void writeMarkup( String markup )
 234  
     {
 235  83
         ensureDocumentStarted();
 236  
 
 237  83
         completePreviouslyOpenedElement();
 238  
 
 239  83
         writer.write( markup );
 240  83
     }
 241  
 
 242  
     public void endElement()
 243  
     {
 244  39
         depth--;
 245  
 
 246  39
         if ( processingElement )
 247  
         {
 248  
             // this means we don't have any content yet so we just add a />
 249  9
             writer.write( "/>" );
 250  
 
 251  9
             elementStack.removeLast();
 252  9
             processingElement = false;
 253  
         }
 254  
         else
 255  
         {
 256  30
             if ( !endOnSameLine )
 257  
             {
 258  15
                 newLine();
 259  
             }
 260  
 
 261  
             // otherwise we need a full closing tag for that element
 262  30
             writer.write( "</" + elementStack.removeLast() + ">" );
 263  
         }
 264  
 
 265  39
         endOnSameLine = false;
 266  39
     }
 267  
 
 268  
     /**
 269  
      * Write the documents if not already done.
 270  
      * 
 271  
      * @return <code>true</code> if the document headers have freshly been written.
 272  
      */
 273  
     private boolean ensureDocumentStarted()
 274  
     {
 275  143
         if ( !documentStarted )
 276  
         {
 277  32
             if ( docType != null || encoding != null )
 278  
             {
 279  1
                 writeDocumentHeader();
 280  
             }
 281  
 
 282  32
             documentStarted = true;
 283  
 
 284  32
             return true;
 285  
         }
 286  
 
 287  111
         return false;
 288  
     }
 289  
 
 290  
     private void writeDocumentHeader()
 291  
     {
 292  1
         writer.write( "<?xml version=\"1.0\"" );
 293  
 
 294  1
         if ( encoding != null )
 295  
         {
 296  1
             writer.write( " encoding=\"" + encoding + "\"" );
 297  
         }
 298  
 
 299  1
         writer.write( "?>" );
 300  
 
 301  1
         newLine();
 302  
 
 303  1
         if ( docType != null )
 304  
         {
 305  0
             newLine();
 306  0
             writer.write( "<!DOCTYPE " + docType + ">" );
 307  
         }
 308  1
     }
 309  
 
 310  
     private void newLine()
 311  
     {
 312  46
         writer.write( lineSeparator );
 313  
 
 314  109
         for ( int i = 0; i < depth; i++ )
 315  
         {
 316  63
             writer.write( lineIndent );
 317  
         }
 318  46
     }
 319  
 
 320  
     private void completePreviouslyOpenedElement()
 321  
     {
 322  143
         if ( processingElement )
 323  
         {
 324  30
             writer.write( '>' );
 325  30
             processingElement = false;
 326  
         }
 327  143
     }
 328  
 
 329  
 }