View Javadoc
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  
18  package org.apache.any23.util;
19  
20  import org.apache.commons.io.ByteOrderMark;
21  import org.apache.commons.io.input.BOMInputStream;
22  import org.apache.xerces.impl.io.MalformedByteSequenceException;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.w3c.dom.Document;
26  import org.xml.sax.SAXException;
27  
28  import java.io.BufferedReader;
29  import java.io.ByteArrayInputStream;
30  import java.io.ByteArrayOutputStream;
31  import java.io.Closeable;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.io.InputStreamReader;
35  import java.nio.charset.StandardCharsets;
36  import java.util.ArrayList;
37  import java.util.List;
38  
39  import javax.xml.parsers.DocumentBuilder;
40  import javax.xml.parsers.DocumentBuilderFactory;
41  import javax.xml.parsers.ParserConfigurationException;
42  import javax.xml.transform.Result;
43  import javax.xml.transform.Source;
44  import javax.xml.transform.TransformerConfigurationException;
45  import javax.xml.transform.TransformerException;
46  import javax.xml.transform.TransformerFactory;
47  import javax.xml.transform.TransformerFactoryConfigurationError;
48  import javax.xml.transform.dom.DOMSource;
49  import javax.xml.transform.stream.StreamResult;
50  
51  /**
52   * Contains general utility functions for handling streams.
53   *
54   * @author Michele Mostarda (mostarda@fbk.eu)
55   */
56  public class StreamUtils {
57  
58      private static final Logger logger = LoggerFactory.getLogger(StreamUtils.class);
59  
60      private StreamUtils() {
61      }
62  
63      /**
64       * Returns all the lines read from an input stream.
65       *
66       * @param is
67       *            input stream.
68       * 
69       * @return list of not <code>null</code> lines.
70       * 
71       * @throws IOException
72       *             if an error occurs while consuming the <code>is</code> stream.
73       */
74      public static String[] asLines(InputStream is) throws IOException {
75          final BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
76          final List<String> lines = new ArrayList<String>();
77          try {
78              String line;
79              while ((line = br.readLine()) != null) {
80                  lines.add(line);
81              }
82              return lines.toArray(new String[lines.size()]);
83          } finally {
84              closeGracefully(br);
85          }
86      }
87  
88      /**
89       * Returns the string content of a stream.
90       *
91       * @param is
92       *            input stream.
93       * @param preserveNL
94       *            preserves new line chars.
95       * 
96       * @return the string content.
97       * 
98       * @throws IOException
99       *             if an error occurs while consuming the <code>is</code> stream.
100      */
101     public static String asString(InputStream is, boolean preserveNL) throws IOException {
102         if (is == null) {
103             throw new NullPointerException("input stream is null.");
104         }
105         final BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
106         try {
107             final StringBuilder content = new StringBuilder();
108             String line;
109             while ((line = br.readLine()) != null) {
110                 content.append(line);
111                 if (preserveNL)
112                     content.append('\n');
113             }
114             return content.toString();
115         } finally {
116             closeGracefully(br);
117         }
118     }
119 
120     /**
121      * Returns the string content of a stream, new line chars will be removed.
122      *
123      * @param is
124      *            input stream.
125      * 
126      * @return the string content.
127      * 
128      * @throws IOException
129      *             if an error occurs while consuming the <code>is</code> stream.
130      */
131     public static String asString(InputStream is) throws IOException {
132         return asString(is, false);
133     }
134 
135     /**
136      * Closes the closable interface and reports error if any.
137      *
138      * @param closable
139      *            the closable object to be closed.
140      */
141     public static void closeGracefully(Closeable closable) {
142         if (closable != null) {
143             try {
144                 closable.close();
145             } catch (Exception e) {
146                 logger.error("Error while closing object " + closable, e);
147             }
148         }
149     }
150 
151     /**
152      * Converts a {@link org.w3c.dom.Document} to an {@link java.io.InputStream}
153      * 
154      * @param doc
155      *            the {@link org.w3c.dom.Document} to convert
156      * 
157      * @return an {@link java.io.InputStream} representing the contents of the input {@link org.w3c.dom.Document}
158      * 
159      * @throws TransformerFactoryConfigurationError
160      *             thrown when there is a problem with configuration with the Transformer Factories
161      * @throws TransformerConfigurationException
162      *             thrown when a serious configuration error exists
163      */
164     public static InputStream documentToInputStream(Document doc)
165             throws TransformerConfigurationException, TransformerFactoryConfigurationError {
166         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
167         Source xmlSource = new DOMSource(doc);
168         Result outputTarget = new StreamResult(outputStream);
169         try {
170             TransformerFactory.newInstance().newTransformer().transform(xmlSource, outputTarget);
171         } catch (TransformerException e) {
172             logger.error("Error during transformation: {}", e);
173         }
174         return new ByteArrayInputStream(outputStream.toByteArray());
175     }
176 
177     public static Document inputStreamToDocument(InputStream is) throws MalformedByteSequenceException {
178         DocumentBuilderFactory factory = null;
179         DocumentBuilder builder = null;
180         Document doc = null;
181 
182         try {
183             factory = DocumentBuilderFactory.newInstance();
184             factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
185             builder = factory.newDocumentBuilder();
186         } catch (ParserConfigurationException e) {
187             logger.error("Error converting InputStream to Document: {}", e);
188         }
189 
190         try {
191             BOMInputStream bomIn = new BOMInputStream(is, ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE,
192                     ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_32BE, ByteOrderMark.UTF_32LE);
193             if (bomIn.hasBOM()) {
194                 @SuppressWarnings("unused")
195                 int firstNonBOMByte = bomIn.read(); // Skips BOM
196             }
197             doc = builder.parse(bomIn);
198         } catch (SAXException | IOException e) {
199             logger.error("Error converting InputStream to Document: {}", e);
200         }
201         return doc;
202     }
203 }