pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / src / java / org / apache / lucene / util / IOUtils.java
1 package org.apache.lucene.util;
2
3 /**
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  */
19
20 import java.io.BufferedReader;
21 import java.io.Closeable;
22 import java.io.File;
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;
32
33 /** This class emulates the new Java 7 "Try-With-Resources" statement.
34  * Remove once Lucene is on Java 7.
35  * @lucene.internal */
36 public final class IOUtils {
37   
38   /**
39    * UTF-8 charset string
40    * @see Charset#forName(String)
41    */
42   public static final String UTF_8 = "UTF-8";
43   
44   /**
45    * UTF-8 {@link Charset} instance to prevent repeated
46    * {@link Charset#forName(String)} lookups
47    */
48   public static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
49   private IOUtils() {} // no instance
50
51   /**
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/>
56    * <pre>
57    * Closeable resource1 = null, resource2 = null, resource3 = null;
58    * ExpectedException priorE = null;
59    * try {
60    *   resource1 = ...; resource2 = ...; resource3 = ...; // Acquisition may throw ExpectedException
61    *   ..do..stuff.. // May throw ExpectedException
62    * } catch (ExpectedException e) {
63    *   priorE = e;
64    * } finally {
65    *   closeSafely(priorE, resource1, resource2, resource3);
66    * }
67    * </pre>
68    * </p>
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
71    */
72   public static <E extends Exception> void closeWhileHandlingException(E priorException, Closeable... objects) throws E, IOException {
73     Throwable th = null;
74
75     for (Closeable object : objects) {
76       try {
77         if (object != null) {
78           object.close();
79         }
80       } catch (Throwable t) {
81         addSuppressed((priorException == null) ? th : priorException, t);
82         if (th == null) {
83           th = t;
84         }
85       }
86     }
87
88     if (priorException != null) {
89       throw priorException;
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);
95     }
96   }
97
98   /** @see #closeWhileHandlingException(Exception, Closeable...) */
99   public static <E extends Exception> void closeWhileHandlingException(E priorException, Iterable<Closeable> objects) throws E, IOException {
100     Throwable th = null;
101
102     for (Closeable object : objects) {
103       try {
104         if (object != null) {
105           object.close();
106         }
107       } catch (Throwable t) {
108         addSuppressed((priorException == null) ? th : priorException, t);
109         if (th == null) {
110           th = t;
111         }
112       }
113     }
114
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);
122     }
123   }
124
125   /**
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.
131    * 
132    * @param objects
133    *          objects to call <tt>close()</tt> on
134    */
135   public static void close(Closeable... objects) throws IOException {
136     Throwable th = null;
137
138     for (Closeable object : objects) {
139       try {
140         if (object != null) {
141           object.close();
142         }
143       } catch (Throwable t) {
144         addSuppressed(th, t);
145         if (th == null) {
146           th = t;
147         }
148       }
149     }
150
151     if (th != null) {
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);
156     }
157   }
158   
159   /**
160    * @see #close(Closeable...)
161    */
162   public static void close(Iterable<? extends Closeable> objects) throws IOException {
163     Throwable th = null;
164
165     for (Closeable object : objects) {
166       try {
167         if (object != null) {
168           object.close();
169         }
170       } catch (Throwable t) {
171         addSuppressed(th, t);
172         if (th == null) {
173           th = t;
174         }
175       }
176     }
177
178     if (th != null) {
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);
183     }
184   }
185
186   /**
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.
189    * 
190    * @param objects
191    *          objects to call <tt>close()</tt> on
192    */
193   public static void closeWhileHandlingException(Closeable... objects) throws IOException {
194     for (Closeable object : objects) {
195       try {
196         if (object != null) {
197           object.close();
198         }
199       } catch (Throwable t) {
200       }
201     }
202   }
203   
204   /**
205    * @see #closeWhileHandlingException(Closeable...)
206    */
207   public static void closeWhileHandlingException(Iterable<? extends Closeable> objects) throws IOException {
208     for (Closeable object : objects) {
209       try {
210         if (object != null) {
211           object.close();
212         }
213       } catch (Throwable t) {
214       }
215     }
216   }
217   
218   /** This reflected {@link Method} is {@code null} before Java 7 */
219   private static final Method SUPPRESS_METHOD;
220   static {
221     Method m;
222     try {
223       m = Throwable.class.getMethod("addSuppressed", Throwable.class);
224     } catch (Exception e) {
225       m = null;
226     }
227     SUPPRESS_METHOD = m;
228   }
229
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
233    */
234   private static final void addSuppressed(Throwable exception, Throwable suppressed) {
235     if (SUPPRESS_METHOD != null && exception != null && suppressed != null) {
236       try {
237         SUPPRESS_METHOD.invoke(exception, suppressed);
238       } catch (Exception e) {
239         // ignore any exceptions caused by invoking (e.g. security constraints)
240       }
241     }
242   }
243   
244   /**
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}. 
248    * <p>
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 
251    * reader.
252    * 
253    * @param stream the stream to wrap in a reader
254    * @param charSet the expected charset
255    * @return a wrapping reader
256    */
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));
262   }
263   
264   /**
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}. 
268    * <p>
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 
271    * reader.
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
275    */
276   public static Reader getDecodingReader(File file, Charset charSet) throws IOException {
277     FileInputStream stream = null;
278     boolean success = false;
279     try {
280       stream = new FileInputStream(file);
281       final Reader reader = getDecodingReader(stream, charSet);
282       success = true;
283       return reader;
284
285     } finally {
286       if (!success) {
287         IOUtils.close(stream);
288       }
289     }
290   }
291
292   /**
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}. 
296    * <p>
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 
299    * reader.
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
304    * 
305    */
306   public static Reader getDecodingReader(Class<?> clazz, String resource, Charset charSet) throws IOException {
307     InputStream stream = null;
308     boolean success = false;
309     try {
310       stream = clazz
311       .getResourceAsStream(resource);
312       final Reader reader = getDecodingReader(stream, charSet);
313       success = true;
314       return reader;
315     } finally {
316       if (!success) {
317         IOUtils.close(stream);
318       }
319     }
320   }
321
322
323 }