/* Licensed 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.
 */

package org.camunda.commons.utils;

import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * @author Sebastian Menski
 */
public class IoUtil {

  private static final IoUtilLogger LOG = UtilsLogger.IO_UTIL_LOGGER;
  public static final Charset ENCODING_CHARSET = Charset.forName("UTF-8");

  /**
   * Returns the input stream as {@link String}.
   *
   * @param inputStream the input stream
   */
  public static String inputStreamAsString(InputStream inputStream) {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    try {
      byte[] buffer = new byte[16 * 1024];
      int read;
      while((read = inputStream.read(buffer)) > 0) {
        os.write(buffer, 0, read);
      }
      return os.toString("utf-8");
    } catch (IOException e) {
      throw LOG.unableToReadInputStream(e);
    }
    finally {
      closeSilently(inputStream);
    }
  }

  /**
   * Returns the {@link String} as {@link InputStream}.
   *
   * @param string the {@link String} to convert
   * @return the {@link InputStream} containing the {@link String}
   */
  public static InputStream stringAsInputStream(String string) {
    return new ByteArrayInputStream(string.getBytes(ENCODING_CHARSET));
  }

  /**
   * Close a closable ignoring any IO exception.
   *
   * @param closeable the closable to close
   */
  public static void closeSilently(Closeable closeable) {
    try {
      if (closeable != null) {
        closeable.close();
      }
    } catch (IOException e) {
      // ignore
    }
  }

  /**
   * Returns the content of a file with specified filename
   *
   * @param filename name of the file to load
   * @return Content of the file as {@link String}
   */
  public static String fileAsString(String filename) {
    File classpathFile = getClasspathFile(filename);
    return fileAsString(classpathFile);
  }

  /**
   * Returns the content of a {@link File}.
   *
   * @param file the file to load
   * @return Content of the file as {@link String}
   */
  public static String fileAsString(File file) {
    try {
      return inputStreamAsString(new FileInputStream(file));
    } catch(FileNotFoundException e) {
      throw LOG.fileNotFoundException(file.getAbsolutePath(), e);
    }
  }

  /**
   * Returns the input stream of a file with specified filename
   *
   * @param filename the name of a {@link File} to load
   * @return the file content as input stream
   * @throws IoUtilException if the file cannot be loaded
   */
  public static InputStream fileAsStream(String filename) {
    File classpathFile = getClasspathFile(filename);
    return fileAsStream(classpathFile);
  }

  /**
   * Returns the input stream of a file.
   *
   * @param file the {@link File} to load
   * @return the file content as input stream
   * @throws IoUtilException if the file cannot be loaded
   */
  public static InputStream fileAsStream(File file) {
    try {
      return new BufferedInputStream(new FileInputStream(file));
    } catch(FileNotFoundException e) {
      throw LOG.fileNotFoundException(file.getAbsolutePath(), e);
    }
  }

  /**
   * Returns the {@link File} for a filename.
   *
   * @param filename the filename to load
   * @return the file object
   */
  public static File getClasspathFile(String filename) {
    if(filename == null) {
      throw LOG.nullParameter("filename");
    }

    return getClasspathFile(filename, IoUtil.class.getClassLoader());
  }

  /**
   * Returns the {@link File} for a filename.
   *
   * @param filename the filename to load
   * @param classLoader the classLoader to load file with
   * @return the file object
   * @throws IoUtilException if the file cannot be loaded
   */
  public static File getClasspathFile(String filename, ClassLoader classLoader) {
    if(filename == null) {
      throw LOG.nullParameter("filename");
    }

    URL fileUrl = classLoader.getResource(filename);

    if(fileUrl == null) {
      throw LOG.fileNotFoundException(filename);
    }

    try {
      return new File(fileUrl.toURI());
    } catch(URISyntaxException e) {
      throw LOG.fileNotFoundException(filename, e);
    }
  }
}

@@ -3977,37 +3977,12 @@
 me, 
-IoUtil.class.getClassLoader()
+null
 );%0A 
@@ -4141,16 +4141,78 @@
 ile with
+, if null falls back to TCCL and then this class's classloader
 %0A   * @r
@@ -4478,42 +4478,505 @@
 l = 
-classLoader.getResource(filename);
+null;%0A%0A    if (classLoader != null) %7B%0A      fileUrl = classLoader.getResource(filename);%0A    %7D%0A    if (fileUrl == null) %7B%0A      // Try the current Thread context classloader%0A      classLoader = Thread.currentThread().getContextClassLoader();%0A      fileUrl = classLoader.getResource(filename);%0A%0A      if (fileUrl == null) %7B%0A        // Finally, try the classloader for this class%0A        classLoader = IoUtil.class.getClassLoader();%0A        fileUrl = classLoader.getResource(filename);%0A      %7D%0A    %7D
 %0A%0A  

add classloader fallback solution