Coverage Report - org.apache.commons.io.output.XmlStreamWriter
 
Classes in this File Line Coverage Branch Coverage Complexity
XmlStreamWriter
79%
42/53
66%
16/24
2.2
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.io.output;
 18  
 
 19  
 import java.io.File;
 20  
 import java.io.FileNotFoundException;
 21  
 import java.io.FileOutputStream;
 22  
 import java.io.IOException;
 23  
 import java.io.OutputStream;
 24  
 import java.io.OutputStreamWriter;
 25  
 import java.io.StringWriter;
 26  
 import java.io.Writer;
 27  
 import java.util.regex.Matcher;
 28  
 import java.util.regex.Pattern;
 29  
 
 30  
 import org.apache.commons.io.input.XmlStreamReader;
 31  
 
 32  
 /**
 33  
  * Character stream that handles all the necessary Voodo to figure out the
 34  
  * charset encoding of the XML document written to the stream.
 35  
  *
 36  
  * @version $Id: XmlStreamWriter.java 1415850 2012-11-30 20:51:39Z ggregory $
 37  
  * @see XmlStreamReader
 38  
  * @since 2.0
 39  
  */
 40  
 public class XmlStreamWriter extends Writer {
 41  
     private static final int BUFFER_SIZE = 4096;
 42  
 
 43  
     private final OutputStream out;
 44  
 
 45  
     private final String defaultEncoding;
 46  
 
 47  32
     private StringWriter xmlPrologWriter = new StringWriter(BUFFER_SIZE);
 48  
 
 49  
     private Writer writer;
 50  
 
 51  
     private String encoding;
 52  
 
 53  
     /**
 54  
      * Construct an new XML stream writer for the specified output stream
 55  
      * with a default encoding of UTF-8.
 56  
      *
 57  
      * @param out The output stream
 58  
      */
 59  
     public XmlStreamWriter(final OutputStream out) {
 60  2
         this(out, null);
 61  2
     }
 62  
 
 63  
     /**
 64  
      * Construct an new XML stream writer for the specified output stream
 65  
      * with the specified default encoding.
 66  
      *
 67  
      * @param out The output stream
 68  
      * @param defaultEncoding The default encoding if not encoding could be detected
 69  
      */
 70  32
     public XmlStreamWriter(final OutputStream out, final String defaultEncoding) {
 71  32
         this.out = out;
 72  32
         this.defaultEncoding = defaultEncoding != null ? defaultEncoding : "UTF-8";
 73  32
     }
 74  
 
 75  
     /**
 76  
      * Construct an new XML stream writer for the specified file
 77  
      * with a default encoding of UTF-8.
 78  
      * 
 79  
      * @param file The file to write to
 80  
      * @throws FileNotFoundException if there is an error creating or
 81  
      * opening the file
 82  
      */
 83  
     public XmlStreamWriter(final File file) throws FileNotFoundException {
 84  0
         this(file, null);
 85  0
     }
 86  
 
 87  
     /**
 88  
      * Construct an new XML stream writer for the specified file
 89  
      * with the specified default encoding.
 90  
      * 
 91  
      * @param file The file to write to
 92  
      * @param defaultEncoding The default encoding if not encoding could be detected
 93  
      * @throws FileNotFoundException if there is an error creating or
 94  
      * opening the file
 95  
      */
 96  
     public XmlStreamWriter(final File file, final String defaultEncoding) throws FileNotFoundException {
 97  0
         this(new FileOutputStream(file), defaultEncoding);
 98  0
     }
 99  
 
 100  
     /**
 101  
      * Return the detected encoding.
 102  
      *
 103  
      * @return the detected encoding
 104  
      */
 105  
     public String getEncoding() {
 106  30
         return encoding;
 107  
     }
 108  
 
 109  
     /**
 110  
      * Return the default encoding.
 111  
      *
 112  
      * @return the default encoding
 113  
      */
 114  
     public String getDefaultEncoding() {
 115  0
         return defaultEncoding;
 116  
     }
 117  
 
 118  
     /**
 119  
      * Close the underlying writer.
 120  
      *
 121  
      * @throws IOException if an error occurs closing the underlying writer
 122  
      */
 123  
     @Override
 124  
     public void close() throws IOException {
 125  32
         if (writer == null) {
 126  2
             encoding = defaultEncoding;
 127  2
             writer = new OutputStreamWriter(out, encoding);
 128  2
             writer.write(xmlPrologWriter.toString());
 129  
         }
 130  32
         writer.close();
 131  32
     }
 132  
 
 133  
     /**
 134  
      * Flush the underlying writer.
 135  
      *
 136  
      * @throws IOException if an error occurs flushing the underlying writer
 137  
      */
 138  
     @Override
 139  
     public void flush() throws IOException {
 140  6
         if (writer != null) {
 141  0
             writer.flush();
 142  
         }
 143  6
     }
 144  
 
 145  
     /**
 146  
      * Detect the encoding.
 147  
      *
 148  
      * @param cbuf the buffer to write the characters from
 149  
      * @param off The start offset
 150  
      * @param len The number of characters to write
 151  
      * @throws IOException if an error occurs detecting the encoding
 152  
      */
 153  
     private void detectEncoding(final char[] cbuf, final int off, final int len)
 154  
             throws IOException {
 155  34
         int size = len;
 156  34
         final StringBuffer xmlProlog = xmlPrologWriter.getBuffer();
 157  34
         if (xmlProlog.length() + len > BUFFER_SIZE) {
 158  0
             size = BUFFER_SIZE - xmlProlog.length();
 159  
         }
 160  34
         xmlPrologWriter.write(cbuf, off, size);
 161  
 
 162  
         // try to determine encoding
 163  34
         if (xmlProlog.length() >= 5) {
 164  30
             if (xmlProlog.substring(0, 5).equals("<?xml")) {
 165  
                 // try to extract encoding from XML prolog
 166  28
                 final int xmlPrologEnd = xmlProlog.indexOf("?>");
 167  28
                 if (xmlPrologEnd > 0) {
 168  
                     // ok, full XML prolog written: let's extract encoding
 169  28
                     final Matcher m = ENCODING_PATTERN.matcher(xmlProlog.substring(0,
 170  
                             xmlPrologEnd));
 171  28
                     if (m.find()) {
 172  18
                         encoding = m.group(1).toUpperCase();
 173  18
                         encoding = encoding.substring(1, encoding.length() - 1);
 174  
                     } else {
 175  
                         // no encoding found in XML prolog: using default
 176  
                         // encoding
 177  10
                         encoding = defaultEncoding;
 178  
                     }
 179  28
                 } else {
 180  0
                     if (xmlProlog.length() >= BUFFER_SIZE) {
 181  
                         // no encoding found in first characters: using default
 182  
                         // encoding
 183  0
                         encoding = defaultEncoding;
 184  
                     }
 185  
                 }
 186  28
             } else {
 187  
                 // no XML prolog: using default encoding
 188  2
                 encoding = defaultEncoding;
 189  
             }
 190  30
             if (encoding != null) {
 191  
                 // encoding has been chosen: let's do it
 192  30
                 xmlPrologWriter = null;
 193  30
                 writer = new OutputStreamWriter(out, encoding);
 194  30
                 writer.write(xmlProlog.toString());
 195  30
                 if (len > size) {
 196  0
                     writer.write(cbuf, off + size, len - size);
 197  
                 }
 198  
             }
 199  
         }
 200  34
     }
 201  
 
 202  
     /**
 203  
      * Write the characters to the underlying writer, detecing encoding.
 204  
      * 
 205  
      * @param cbuf the buffer to write the characters from
 206  
      * @param off The start offset
 207  
      * @param len The number of characters to write
 208  
      * @throws IOException if an error occurs detecting the encoding
 209  
      */
 210  
     @Override
 211  
     public void write(final char[] cbuf, final int off, final int len) throws IOException {
 212  34
         if (xmlPrologWriter != null) {
 213  34
             detectEncoding(cbuf, off, len);
 214  
         } else {
 215  0
             writer.write(cbuf, off, len);
 216  
         }
 217  34
     }
 218  
 
 219  2
     static final Pattern ENCODING_PATTERN = XmlStreamReader.ENCODING_PATTERN;
 220  
 }