1 package org.apache.lucene.util;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.io.BufferedReader;
21 import java.io.Closeable;
23 import java.io.FileInputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.InputStreamReader;
27 import java.io.Reader;
28 import java.lang.reflect.Method;
29 import java.nio.charset.Charset;
30 import java.nio.charset.CharsetDecoder;
31 import java.nio.charset.CodingErrorAction;
33 /** This class emulates the new Java 7 "Try-With-Resources" statement.
34 * Remove once Lucene is on Java 7.
36 public final class IOUtils {
39 * UTF-8 charset string
40 * @see Charset#forName(String)
42 public static final String UTF_8 = "UTF-8";
45 * UTF-8 {@link Charset} instance to prevent repeated
46 * {@link Charset#forName(String)} lookups
48 public static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
49 private IOUtils() {} // no instance
52 * <p>Closes all given <tt>Closeable</tt>s, suppressing all thrown exceptions. Some of the <tt>Closeable</tt>s
53 * may be null, they are ignored. After everything is closed, method either throws <tt>priorException</tt>,
54 * if one is supplied, or the first of suppressed exceptions, or completes normally.</p>
55 * <p>Sample usage:<br/>
57 * Closeable resource1 = null, resource2 = null, resource3 = null;
58 * ExpectedException priorE = null;
60 * resource1 = ...; resource2 = ...; resource3 = ...; // Acquisition may throw ExpectedException
61 * ..do..stuff.. // May throw ExpectedException
62 * } catch (ExpectedException e) {
65 * closeSafely(priorE, resource1, resource2, resource3);
69 * @param priorException <tt>null</tt> or an exception that will be rethrown after method completion
70 * @param objects objects to call <tt>close()</tt> on
72 public static <E extends Exception> void closeWhileHandlingException(E priorException, Closeable... objects) throws E, IOException {
75 for (Closeable object : objects) {
80 } catch (Throwable t) {
81 addSuppressed((priorException == null) ? th : priorException, t);
88 if (priorException != null) {
90 } else if (th != null) {
91 if (th instanceof IOException) throw (IOException) th;
92 if (th instanceof RuntimeException) throw (RuntimeException) th;
93 if (th instanceof Error) throw (Error) th;
94 throw new RuntimeException(th);
98 /** @see #closeWhileHandlingException(Exception, Closeable...) */
99 public static <E extends Exception> void closeWhileHandlingException(E priorException, Iterable<Closeable> objects) throws E, IOException {
102 for (Closeable object : objects) {
104 if (object != null) {
107 } catch (Throwable t) {
108 addSuppressed((priorException == null) ? th : priorException, t);
115 if (priorException != null) {
116 throw priorException;
117 } else if (th != null) {
118 if (th instanceof IOException) throw (IOException) th;
119 if (th instanceof RuntimeException) throw (RuntimeException) th;
120 if (th instanceof Error) throw (Error) th;
121 throw new RuntimeException(th);
126 * Closes all given <tt>Closeable</tt>s. Some of the
127 * <tt>Closeable</tt>s may be null; they are
128 * ignored. After everything is closed, the method either
129 * throws the first exception it hit while closing, or
130 * completes normally if there were no exceptions.
133 * objects to call <tt>close()</tt> on
135 public static void close(Closeable... objects) throws IOException {
138 for (Closeable object : objects) {
140 if (object != null) {
143 } catch (Throwable t) {
144 addSuppressed(th, t);
152 if (th instanceof IOException) throw (IOException) th;
153 if (th instanceof RuntimeException) throw (RuntimeException) th;
154 if (th instanceof Error) throw (Error) th;
155 throw new RuntimeException(th);
160 * @see #close(Closeable...)
162 public static void close(Iterable<? extends Closeable> objects) throws IOException {
165 for (Closeable object : objects) {
167 if (object != null) {
170 } catch (Throwable t) {
171 addSuppressed(th, t);
179 if (th instanceof IOException) throw (IOException) th;
180 if (th instanceof RuntimeException) throw (RuntimeException) th;
181 if (th instanceof Error) throw (Error) th;
182 throw new RuntimeException(th);
187 * Closes all given <tt>Closeable</tt>s, suppressing all thrown exceptions.
188 * Some of the <tt>Closeable</tt>s may be null, they are ignored.
191 * objects to call <tt>close()</tt> on
193 public static void closeWhileHandlingException(Closeable... objects) throws IOException {
194 for (Closeable object : objects) {
196 if (object != null) {
199 } catch (Throwable t) {
205 * @see #closeWhileHandlingException(Closeable...)
207 public static void closeWhileHandlingException(Iterable<? extends Closeable> objects) throws IOException {
208 for (Closeable object : objects) {
210 if (object != null) {
213 } catch (Throwable t) {
218 /** This reflected {@link Method} is {@code null} before Java 7 */
219 private static final Method SUPPRESS_METHOD;
223 m = Throwable.class.getMethod("addSuppressed", Throwable.class);
224 } catch (Exception e) {
230 /** adds a Throwable to the list of suppressed Exceptions of the first Throwable (if Java 7 is detected)
231 * @param exception this exception should get the suppressed one added
232 * @param suppressed the suppressed exception
234 private static final void addSuppressed(Throwable exception, Throwable suppressed) {
235 if (SUPPRESS_METHOD != null && exception != null && suppressed != null) {
237 SUPPRESS_METHOD.invoke(exception, suppressed);
238 } catch (Exception e) {
239 // ignore any exceptions caused by invoking (e.g. security constraints)
245 * Wrapping the given {@link InputStream} in a reader using a {@link CharsetDecoder}.
246 * Unlike Java's defaults this reader will throw an exception if your it detects
247 * the read charset doesn't match the expected {@link Charset}.
249 * Decoding readers are useful to load configuration files, stopword lists or synonym files
250 * to detect character set problems. However, its not recommended to use as a common purpose
253 * @param stream the stream to wrap in a reader
254 * @param charSet the expected charset
255 * @return a wrapping reader
257 public static Reader getDecodingReader(InputStream stream, Charset charSet) {
258 final CharsetDecoder charSetDecoder = charSet.newDecoder()
259 .onMalformedInput(CodingErrorAction.REPORT)
260 .onUnmappableCharacter(CodingErrorAction.REPORT);
261 return new BufferedReader(new InputStreamReader(stream, charSetDecoder));
265 * Opens a Reader for the given {@link File} using a {@link CharsetDecoder}.
266 * Unlike Java's defaults this reader will throw an exception if your it detects
267 * the read charset doesn't match the expected {@link Charset}.
269 * Decoding readers are useful to load configuration files, stopword lists or synonym files
270 * to detect character set problems. However, its not recommended to use as a common purpose
272 * @param file the file to open a reader on
273 * @param charSet the expected charset
274 * @return a reader to read the given file
276 public static Reader getDecodingReader(File file, Charset charSet) throws IOException {
277 FileInputStream stream = null;
278 boolean success = false;
280 stream = new FileInputStream(file);
281 final Reader reader = getDecodingReader(stream, charSet);
287 IOUtils.close(stream);
293 * Opens a Reader for the given resource using a {@link CharsetDecoder}.
294 * Unlike Java's defaults this reader will throw an exception if your it detects
295 * the read charset doesn't match the expected {@link Charset}.
297 * Decoding readers are useful to load configuration files, stopword lists or synonym files
298 * to detect character set problems. However, its not recommended to use as a common purpose
300 * @param clazz the class used to locate the resource
301 * @param resource the resource name to load
302 * @param charSet the expected charset
303 * @return a reader to read the given file
306 public static Reader getDecodingReader(Class<?> clazz, String resource, Charset charSet) throws IOException {
307 InputStream stream = null;
308 boolean success = false;
311 .getResourceAsStream(resource);
312 final Reader reader = getDecodingReader(stream, charSet);
317 IOUtils.close(stream);