/*
* Copyright 2004-2012 the Seasar Foundation and the Others.
*
* 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.seasar.mayaa.impl.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
import java.net.URLConnection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.seasar.mayaa.impl.CONST_IMPL;
/**
* @author Koji Suga (Gluegent, Inc.)
*/
public class IOUtil {
private static final Log LOG = LogFactory.getLog(IOUtil.class);
private static boolean _useURLCache = false;
static {
// 一応環境変数で設定できるように。基本的に有効にしない。
String env = System.getProperty("org.seasar.mayaa.useURLCache");
if (env != null && env.equalsIgnoreCase("true")) {
_useURLCache = true;
}
}
private IOUtil() {
// no instantiation.
}
/**
* InputStreamをcloseする。
* 例外が発生した場合はログにINFOレベルで出力する。
*
* @param stream closeするInputStream
*/
public static void close(InputStream stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException ignore) {
LOG.info(ignore.getMessage(), ignore);
}
}
}
/**
* Readerをcloseする。
* 例外が発生した場合はログにINFOレベルで出力する。
*
* @param reader closeするReader
*/
public static void close(Reader reader) {
if (reader != null) {
try {
reader.close();
} catch (IOException ignore) {
LOG.info(ignore.getMessage(), ignore);
}
}
}
/**
* OutputStreamをcloseする。
* 例外が発生した場合はログにINFOレベルで出力する。
*
* @param stream closeするOutputStream
*/
public static void close(OutputStream stream) {
if (stream != null) {
try {
stream.close();
} catch (IOException ignore) {
LOG.info(ignore.getMessage(), ignore);
}
}
}
/**
* InputStreamから指定文字エンコーディングでStringを読み出して返す。
* 読み出したあとはInputStreamをcloseする。
*
* @param is 読み出すInputStream
* @param encoding 文字エンコーディング
* @return InputStreamの内容
* @throws RuntimeException 内部で発生した例外をラップしたもの
*/
public static String readStream(InputStream is, String encoding) {
try {
Reader reader = new InputStreamReader(is, encoding);
try {
StringBuffer sb = new StringBuffer();
char[] buffer = new char[1024];
int readSize = -1;
while ((readSize = reader.read(buffer)) > 0) {
sb.append(buffer, 0, readSize);
}
return sb.toString();
} finally {
is.close();
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
/**
* OutputStreamへ指定文字エンコーディングでStringを書き出す。
* 書き出したあとはOutputStreamをcloseする。
*
* @param os 書き出すInputStream
* @param value 出力する内容
* @param encoding 文字エンコーディング
* @throws RuntimeException 内部で発生した例外をラップしたもの
*/
public static void writeStream(OutputStream os, String value, String encoding) {
try {
Writer writer = new OutputStreamWriter(os, encoding);
try {
writer.write(value);
writer.flush();
} finally {
os.close();
}
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
/**
* URLからInputStreamを取得する。
* 標準だとURLのキャッシュを使わない。
* キャッシュを使わない場合、jarファイルをホールドしない代わりに
* パフォーマンスに問題が出る場合がある。
* urlがnullの場合はnullを返す。
*
* URLのキャッシュを使うようにするには、システムプロパティに
* "org.seasar.mayaa.useURLCache=true" を設定すること。
*
* @param url 読み込むURL
* @return InputStream
*/
public static InputStream openStream(URL url) {
if (url == null) {
return null;
}
try {
URLConnection connection = url.openConnection();
// キャッシュを使うとjarファイルを掴んでしまう
// TODO useURLCacheをエンジン設定できるようにする
connection.setUseCaches(_useURLCache);
return connection.getInputStream();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* URLがファイルプロトコルかどうか判定する。
* urlがnullまたは不正な場合はfalseを返す。
*
* @param url 対象のURL
* @return ファイルプロトコルならtrue
*/
public static File getFile(URL url) {
if (url != null) {
if ("file".equalsIgnoreCase(url.getProtocol())) {
return new File(url.toString().substring(5));
}
}
return null;
}
/**
* URLから最終更新時刻を取得する。
* fileにのみ対応。それ以外は{@link CONST_IMPL.NULL_DATE_MILLIS}を返す。
*
* @param url 読み込むURL
* @return InputStream
*/
public static long getLastModified(URL url) {
File file = getFile(url);
if (file != null) {
return file.lastModified();
}
// TODO ServletContext#getResource で file ではなく jndi の URL が来た場合の対応
return CONST_IMPL.NULL_DATE_MILLIS;
}
/**
* カレントスレッドのContextClassLoaderを使ってリソースを読み込むInputStreamを返す。
* リソースが見つからない場合、あるいは権限がない場合はnullを返す。
* リソースのパスはクラスパスをルートとする絶対パス。
*
* @param name リソースの名前
* @return InputStream
*/
public static URL getResource(String name) {
return getResource(name, Thread.currentThread().getContextClassLoader());
}
/**
* カレントスレッドのContextClassLoaderを使ってリソースを読み込むInputStreamを返す。
* リソースが見つからない場合、あるいは権限がない場合はnullを返す。
* リソースのパスはクラスパスをルートとする絶対パス。
*
* @param name リソースの名前
* @return InputStream
*/
public static InputStream getResourceAsStream(String name) {
return getResourceAsStream(name, Thread.currentThread().getContextClassLoader());
}
/**
* クラスのあるパッケージを起点としてパスを解決する。
* java.lang.Class#resolveName(String)
*
* @param neighbor 基準とするクラス
* @param name リソースの名前
* @return 解決したパス
*/
protected static String resolveName(Class neighbor, String name) {
if (name == null) {
return name;
}
if (name.startsWith("/") == false) {
Class c = neighbor;
while (c.isArray()) {
c = c.getComponentType();
}
String baseName = c.getName();
int index = baseName.lastIndexOf('.');
if (index != -1) {
name = baseName.substring(0, index).replace('.', '/') + '/' + name;
}
} else {
name = name.substring(1);
}
return name;
}
/**
* neighborのClassLoaderを使ってリソースのURLを返す。
* リソースが見つからない場合、あるいは権限がない場合はnullを返す。
* リソースのパスはクラスパスをルートとする絶対パス。
* neighborがnullの場合はカレントスレッドのContextClassLoaderを使う。
*
* @param name リソースの名前
* @param neighbor リソースを探すための起点とするクラス
* @return InputStream
*/
public static URL getResource(String name, Class neighbor) {
if (neighbor == null) {
return getResource(name);
}
return getResource(resolveName(neighbor, name), neighbor.getClassLoader());
}
/**
* neighborのClassLoaderを使ってリソースを読み込むInputStreamを返す。
* リソースが見つからない場合、あるいは権限がない場合はnullを返す。
* リソースのパスはneighborのパッケージを起点とする相対パス。
* neighborがnullの場合はカレントスレッドのContextClassLoaderを使う。
*
* @param name リソースの名前
* @param neighbor リソースを探すための起点とするクラス
* @return InputStream
*/
public static InputStream getResourceAsStream(String name, Class neighbor) {
return openStream(getResource(name, neighbor));
}
/**
* 指定したClassLoaderを使ってリソースのURLを返す。
* リソースが見つからない場合、あるいは権限がない場合はnullを返す。
* リソースのパスはクラスパスをルートとする絶対パス。
* loaderがnullの場合はnullを返す。
*
* @param name リソースの名前
* @param loader リソースを読み込むためのクラスローダー
* @return InputStream
*/
public static URL getResource(String name, ClassLoader loader) {
if (loader == null) {
return null;
}
return loader.getResource(name);
}
/**
* 指定したClassLoaderを使ってリソースを読み込むInputStreamを返す。
* リソースが見つからない場合、あるいは権限がない場合はnullを返す。
* リソースのパスはクラスパスをルートとする絶対パス。
* loaderがnullの場合はnullを返す。
*
* @param name リソースの名前
* @param loader リソースを読み込むためのクラスローダー
* @return InputStream
*/
public static InputStream getResourceAsStream(String name, ClassLoader loader) {
return openStream(getResource(name, loader));
}
}