View Javadoc
1   /*
2    * Copyright (c) 2012-2022, jcabi.com
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met: 1) Redistributions of source code must retain the above
8    * copyright notice, this list of conditions and the following
9    * disclaimer. 2) Redistributions in binary form must reproduce the above
10   * copyright notice, this list of conditions and the following
11   * disclaimer in the documentation and/or other materials provided
12   * with the distribution. 3) Neither the name of the jcabi.com nor
13   * the names of its contributors may be used to endorse or promote
14   * products derived from this software without specific prior written
15   * permission.
16   *
17   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
19   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
22   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28   * OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package com.jcabi.xml;
31  
32  import java.io.BufferedInputStream;
33  import java.io.File;
34  import java.io.FileInputStream;
35  import java.io.FileNotFoundException;
36  import java.io.IOException;
37  import java.io.InputStream;
38  import java.net.URI;
39  import java.net.URL;
40  import java.nio.charset.StandardCharsets;
41  import java.util.Scanner;
42  import lombok.EqualsAndHashCode;
43  
44  /**
45   * Represent a given resource (InputStream, URL/URI location content, File)
46   * as a string. UTF-8 encoding is used.
47   *
48   * <p>Objects of this class are immutable and thread-safe.
49   *
50   * @since 0.1
51   */
52  @EqualsAndHashCode(of = "content")
53  final class TextResource {
54  
55      /**
56       * The text representation.
57       */
58      private final transient String content;
59  
60      /**
61       * Private constructor, used for initializing the field text content.
62       * @param text The text content
63       */
64      private TextResource(final String text) {
65          this.content = text;
66      }
67  
68      /**
69       * Public constructor, represent an InputStream as a text resource.
70       *
71       * <p>The provided input stream will be closed automatically after
72       * getting data from it.
73       * @param stream Stream to represent as text.
74       */
75      TextResource(final InputStream stream) {
76          this(TextResource.readAsString(stream));
77      }
78  
79      /**
80       * Public constructor, represent a File as a text resource.
81       * @param file File to represent as text.
82       * @throws FileNotFoundException If file not found
83       */
84      TextResource(final File file) throws FileNotFoundException {
85          this(
86              TextResource.readAsString(
87                  new BufferedInputStream(new FileInputStream(file))
88              )
89          );
90      }
91  
92      /**
93       * Public constructor, represent a URL location as a text resource.
94       * @param url URL to represent as text.
95       * @throws IOException If an IO problem occurs.
96       */
97      TextResource(final URL url) throws IOException {
98          this(TextResource.readAsString(url));
99      }
100 
101     /**
102      * Public constructor, represent a URI location as a text resource.
103      * @param uri URI to represent as text.
104      * @throws IOException If an IO problem occurs.
105      */
106     TextResource(final URI uri) throws IOException {
107         this(TextResource.readAsString(uri.toURL()));
108     }
109 
110     @Override
111     public String toString() {
112         return this.content;
113     }
114 
115     /**
116      * Reads an entire stream's contents into a string.
117      * @param stream The stream to read
118      * @return The stream content, in String form
119      */
120     private static String readAsString(final InputStream stream) {
121         final Scanner scanner = new Scanner(
122             stream, StandardCharsets.UTF_8.name()
123         ).useDelimiter("\\A");
124         final String result;
125         try {
126             if (scanner.hasNext()) {
127                 result = scanner.next();
128             } else {
129                 result = "";
130             }
131         } finally {
132             scanner.close();
133         }
134         return result;
135     }
136 
137     /**
138      * Reads URI contents into a string.
139      * @param url The URL to read
140      * @return The stream content, in String form
141      * @throws IOException if an IO exception occurs
142      */
143     private static String readAsString(final URL url) throws IOException {
144         return TextResource.readAsString(
145             new BufferedInputStream(url.openStream())
146         );
147     }
148 }