content: package org.apache.lucene.util;
  
  /**
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  import java.io.BufferedReader;
  import java.io.Closeable;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.io.Reader;
  import java.lang.reflect.Method;
  import java.nio.charset.Charset;
  import java.nio.charset.CharsetDecoder;
  import java.nio.charset.CodingErrorAction;
  
  /** This class emulates the new Java 7 "Try-With-Resources" statement.
   * Remove once Lucene is on Java 7.
   * @lucene.internal */
  public final class IOUtils {
    
    /**
     * UTF-8 charset string
     * @see Charset#forName(String)
     */
    public static final String UTF_8 = "UTF-8";
    
    /**
     * UTF-8 {@link Charset} instance to prevent repeated
     * {@link Charset#forName(String)} lookups
     */
    public static final Charset CHARSET_UTF_8 = Charset.forName("UTF-8");
    private IOUtils() {} // no instance
  
    /**
     * <p>Closes all given <tt>Closeable</tt>s, suppressing all thrown exceptions. Some of the <tt>Closeable</tt>s
     * may be null, they are ignored. After everything is closed, method either throws <tt>priorException</tt>,
     * if one is supplied, or the first of suppressed exceptions, or completes normally.</p>
     * <p>Sample usage:<br/>
     * <pre>
     * Closeable resource1 = null, resource2 = null, resource3 = null;
     * ExpectedException priorE = null;
     * try {
     *   resource1 = ...; resource2 = ...; resource3 = ...; // Acquisition may throw ExpectedException
     *   ..do..stuff.. // May throw ExpectedException
     * } catch (ExpectedException e) {
     *   priorE = e;
     * } finally {
     *   closeSafely(priorE, resource1, resource2, resource3);
     * }
     * </pre>
     * </p>
     * @param priorException  <tt>null</tt> or an exception that will be rethrown after method completion
     * @param objects         objects to call <tt>close()</tt> on
     */
    public static <E extends Exception> void closeWhileHandlingException(E priorException, Closeable... objects) throws E, IOException {
      Throwable th = null;
  
      for (Closeable object : objects) {
        try {
          if (object != null) {
            object.close();
          }
        } catch (Throwable t) {
          addSuppressed((priorException == null) ? th : priorException, t);
          if (th == null) {
            th = t;
          }
        }
      }
  
      if (priorException != null) {
        throw priorException;
      } else if (th != null) {
        if (th instanceof IOException) throw (IOException) th;
        if (th instanceof RuntimeException) throw (RuntimeException) th;
        if (th instanceof Error) throw (Error) th;
        throw new RuntimeException(th);
      }
    }
  
    /** @see #closeWhileHandlingException(Exception, Closeable...) */
    public static <E extends Exception> void closeWhileHandlingException(E priorException, Iterable<Closeable> objects) throws E, IOException {
      Throwable th = null;
  
      for (Closeable object : objects) {
        try {
          if (object != null) {
            object.close();
          }
        } catch (Throwable t) {
          addSuppressed((priorException == null) ? th : priorException, t);
          if (th == null) {
            th = t;
          }
        }
      }
  
      if (priorException != null) {
        throw priorException;
      } else if (th != null) {
        if (th instanceof IOException) throw (IOException) th;
        if (th instanceof RuntimeException) throw (RuntimeException) th;
        if (th instanceof Error) throw (Error) th;
        throw new RuntimeException(th);
      }
    }
  
    /**
     * Closes all given <tt>Closeable</tt>s.  Some of the
     * <tt>Closeable</tt>s may be null; they are
     * ignored.  After everything is closed, the method either
     * throws the first exception it hit while closing, or
     * completes normally if there were no exceptions.
     * 
     * @param objects
     *          objects to call <tt>close()</tt> on
     */
    public static void close(Closeable... objects) throws IOException {
      Throwable th = null;
  
      for (Closeable object : objects) {
        try {
          if (object != null) {
            object.close();
          }
        } catch (Throwable t) {
          addSuppressed(th, t);
          if (th == null) {
            th = t;
          }
        }
      }
  
      if (th != null) {
        if (th instanceof IOException) throw (IOException) th;
        if (th instanceof RuntimeException) throw (RuntimeException) th;
        if (th instanceof Error) throw (Error) th;
        throw new RuntimeException(th);
      }
    }
    
    /**
     * @see #close(Closeable...)
     */
    public static void close(Iterable<? extends Closeable> objects) throws IOException {
      Throwable th = null;
  
      for (Closeable object : objects) {
        try {
          if (object != null) {
            object.close();
          }
        } catch (Throwable t) {
          addSuppressed(th, t);
          if (th == null) {
            th = t;
          }
        }
      }
  
      if (th != null) {
        if (th instanceof IOException) throw (IOException) th;
        if (th instanceof RuntimeException) throw (RuntimeException) th;
        if (th instanceof Error) throw (Error) th;
        throw new RuntimeException(th);
      }
    }
  
    /**
     * Closes all given <tt>Closeable</tt>s, suppressing all thrown exceptions.
     * Some of the <tt>Closeable</tt>s may be null, they are ignored.
     * 
     * @param objects
     *          objects to call <tt>close()</tt> on
     */
    public static void closeWhileHandlingException(Closeable... objects) throws IOException {
      for (Closeable object : objects) {
        try {
          if (object != null) {
            object.close();
          }
        } catch (Throwable t) {
        }
      }
    }
    
    /**
     * @see #closeWhileHandlingException(Closeable...)
     */
    public static void closeWhileHandlingException(Iterable<? extends Closeable> objects) throws IOException {
      for (Closeable object : objects) {
        try {
          if (object != null) {
            object.close();
          }
        } catch (Throwable t) {
        }
      }
    }
    
    /** This reflected {@link Method} is {@code null} before Java 7 */
    private static final Method SUPPRESS_METHOD;
    static {
      Method m;
      try {
        m = Throwable.class.getMethod("addSuppressed", Throwable.class);
      } catch (Exception e) {
        m = null;
      }
      SUPPRESS_METHOD = m;
    }
  
    /** adds a Throwable to the list of suppressed Exceptions of the first Throwable (if Java 7 is detected)
     * @param exception this exception should get the suppressed one added
     * @param suppressed the suppressed exception
     */
    private static final void addSuppressed(Throwable exception, Throwable suppressed) {
      if (SUPPRESS_METHOD != null && exception != null && suppressed != null) {
        try {
          SUPPRESS_METHOD.invoke(exception, suppressed);
        } catch (Exception e) {
          // ignore any exceptions caused by invoking (e.g. security constraints)
        }
      }
    }
    
    /**
     * Wrapping the given {@link InputStream} in a reader using a {@link CharsetDecoder}.
     * Unlike Java's defaults this reader will throw an exception if your it detects 
     * the read charset doesn't match the expected {@link Charset}. 
     * <p>
     * Decoding readers are useful to load configuration files, stopword lists or synonym files
     * to detect character set problems. However, its not recommended to use as a common purpose 
     * reader.
     * 
     * @param stream the stream to wrap in a reader
     * @param charSet the expected charset
     * @return a wrapping reader
     */
    public static Reader getDecodingReader(InputStream stream, Charset charSet) {
      final CharsetDecoder charSetDecoder = charSet.newDecoder()
          .onMalformedInput(CodingErrorAction.REPORT)
          .onUnmappableCharacter(CodingErrorAction.REPORT);
      return new BufferedReader(new InputStreamReader(stream, charSetDecoder));
    }
    
    /**
     * Opens a Reader for the given {@link File} using a {@link CharsetDecoder}.
     * Unlike Java's defaults this reader will throw an exception if your it detects 
     * the read charset doesn't match the expected {@link Charset}. 
     * <p>
     * Decoding readers are useful to load configuration files, stopword lists or synonym files
     * to detect character set problems. However, its not recommended to use as a common purpose 
     * reader.
     * @param file the file to open a reader on
     * @param charSet the expected charset
     * @return a reader to read the given file
     */
    public static Reader getDecodingReader(File file, Charset charSet) throws IOException {
      FileInputStream stream = null;
      boolean success = false;
      try {
        stream = new FileInputStream(file);
        final Reader reader = getDecodingReader(stream, charSet);
        success = true;
        return reader;
  
      } finally {
        if (!success) {
          IOUtils.close(stream);
        }
      }
    }
  
    /**
     * Opens a Reader for the given resource using a {@link CharsetDecoder}.
     * Unlike Java's defaults this reader will throw an exception if your it detects 
     * the read charset doesn't match the expected {@link Charset}. 
     * <p>
     * Decoding readers are useful to load configuration files, stopword lists or synonym files
     * to detect character set problems. However, its not recommended to use as a common purpose 
     * reader.
     * @param clazz the class used to locate the resource
     * @param resource the resource name to load
     * @param charSet the expected charset
     * @return a reader to read the given file
     * 
     */
    public static Reader getDecodingReader(Class<?> clazz, String resource, Charset charSet) throws IOException {
      InputStream stream = null;
      boolean success = false;
      try {
        stream = clazz
        .getResourceAsStream(resource);
        final Reader reader = getDecodingReader(stream, charSet);
        success = true;
        return reader;
      } finally {
        if (!success) {
          IOUtils.close(stream);
        }
      }
    }
  
  
  }
  