blob: d4dd95ca5570fef6b655c30d7883ca95e95b3e48 [file] [log] [blame]
/*******************************************************************************
* 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.
*******************************************************************************/
package org.ofbiz.base.util;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Serializable;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.ofbiz.base.container.ClassLoaderContainer;
import org.ofbiz.base.conversion.Converter;
import org.ofbiz.base.conversion.Converters;
import org.ofbiz.base.json.JSON;
import org.ofbiz.base.json.JSONWriter;
public final class UtilIO {
public static final Charset UTF8 = Charset.forName("UTF-8");
public static final String module = UtilIO.class.getName();
/** Copy an InputStream to an OutputStream, optionally closing either
* the input or the output.
*
* @param in the InputStream to copy from
* @param closeIn whether to close the input when the copy is done
* @param out the OutputStream to copy to
* @param closeOut whether to close the output when the copy is done
* @throws IOException if an error occurs
*/
public static void copy(InputStream in, boolean closeIn, OutputStream out, boolean closeOut) throws IOException {
try {
try {
IOUtils.copy(in, out);
} finally {
if (closeIn) IOUtils.closeQuietly(in);
}
} finally {
if (closeOut) IOUtils.closeQuietly(out);
}
}
/** Copy a Reader to a Writer, optionally closing either the input or
* the output.
*
* @param reader the Reader to copy from
* @param closeIn whether to close the input when the copy is done
* @param writer the Writer to copy to
* @param closeOut whether to close the output when the copy is done
* @throws IOException if an error occurs
*/
public static void copy(Reader reader, boolean closeIn, Writer writer, boolean closeOut) throws IOException {
try {
try {
IOUtils.copy(reader, writer);
} finally {
if (closeIn) IOUtils.closeQuietly(reader);
}
} finally {
if (closeOut) IOUtils.closeQuietly(writer);
}
}
/** Copy a Reader to an Appendable, optionally closing the input.
*
* @param reader the Reader to copy from
* @param closeIn whether to close the input when the copy is done
* @param out the Appendable to copy to
* @throws IOException if an error occurs
*/
public static void copy(Reader reader, boolean closeIn, Appendable out) throws IOException {
try {
CharBuffer buffer = CharBuffer.allocate(4096);
while (reader.read(buffer) > 0) {
buffer.flip();
buffer.rewind();
out.append(buffer);
}
} finally {
if (closeIn) IOUtils.closeQuietly(reader);
}
}
/** Convert a byte array to a string; consistently uses \n line endings
* in java. This uses a default {@link Charset UTF-8} charset.
*
* @param bytes the array of bytes to convert
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(byte[] bytes) throws IOException {
return readString(bytes, 0, bytes.length, UTF8);
}
/** Convert a byte array to a string; consistently uses \n line endings
* in java. The conversion is limited to the specified offset/length
* pair, and uses a default {@link Charset UTF-8} charset.
*
* @param bytes the array of bytes to convert
* @param offset the start of the conversion
* @param length how many bytes to convert
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(byte[] bytes, int offset, int length) throws IOException {
return readString(bytes, offset, length, UTF8);
}
/** Convert a byte array to a string; consistently uses \n line endings
* in java. The conversion is limited to the specified offset/length
* pair, and uses the requested charset to decode the bytes.
*
* @param bytes the array of bytes to convert
* @param charset the charset to use to convert the raw bytes
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(byte[] bytes, String charset) throws IOException {
return readString(bytes, 0, bytes.length, Charset.forName(charset));
}
/** Convert a byte array to a string; consistently uses \n line
* endings in java. The conversion is limited to the specified
* offset/length pair, and uses the requested charset to decode the
* bytes.
*
* @param bytes the array of bytes to convert
* @param offset the start of the conversion
* @param length how many bytes to convert
* @param charset the charset to use to convert the raw bytes
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(byte[] bytes, int offset, int length, String charset) throws IOException {
return readString(bytes, 0, bytes.length, Charset.forName(charset));
}
/** Convert a byte array to a string, consistently uses \n line
* endings in java. The specified {@link Charset charset} is used
* to decode the bytes.
* @param bytes the array of bytes to convert
* @param charset the charset to use to convert the raw bytes
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(byte[] bytes, Charset charset) throws IOException {
return readString(bytes, 0, bytes.length, charset);
}
/** Convert a byte array to a string, consistently uses \n line
* endings in java. The conversion is limited to the specified
* offset/length pair, and uses the requested {@link Charset
* charset} to decode the bytes.
*
* @param bytes the array of bytes to convert
* @param offset the start of the conversion
* @param length how many bytes to convert
* @param charset the charset to use to convert the raw bytes
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(byte[] bytes, int offset, int length, Charset charset) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(length);
buf.put(bytes, offset, length);
buf.flip();
return filterLineEndings(new StringBuilder(charset.decode(buf).toString())).toString();
}
/** Convert an {@link InputStream} to a string; consistently uses \n line endings
* in java. This uses a default {@link Charset UTF-8} charset.
*
* @param stream the stream of bytes to convert
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(InputStream stream) throws IOException {
return readString(stream, UTF8);
}
/** Convert an {@link InputStream} to a string; consistently uses \n line endings
* in java. This uses a default {@link Charset UTF-8} charset.
*
* @param stream the stream of bytes to convert
* @param charset the charset to use to convert the raw bytes
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(InputStream stream, String charset) throws IOException {
return readString(stream, Charset.forName(charset));
}
/** Convert an {@link InputStream} to a string; consistently uses \n line endings
* in java. This uses a default {@link Charset UTF-8} charset.
*
* @param stream the stream of bytes to convert
* @param charset the charset to use to convert the raw bytes
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(InputStream stream, Charset charset) throws IOException {
return readString(new InputStreamReader(new BufferedInputStream(stream), charset));
}
/** Convert an {@link Reader} to a string; consistently uses \n line endings
* in java.
*
* @param reader the stream of characters convert
* @return the converted string, with platform line endings converted
* to \n
*/
public static final String readString(Reader reader) throws IOException {
try {
StringBuilder sb = new StringBuilder();
char[] buf = new char[4096];
int r;
while ((r = reader.read(buf, 0, 4096)) > 0) {
sb.append(buf, 0, r);
}
return filterLineEndings(sb).toString();
} finally {
try {
reader.close();
} catch (IOException e) {
Debug.logError(e, "Error closing after reading text: " + e.toString(), module);
}
}
}
private static StringBuilder filterLineEndings(StringBuilder sb) {
String nl = System.getProperty("line.separator");
if (!nl.equals("\n")) {
int r = 0;
while (r < sb.length()) {
int i = sb.indexOf(nl, r);
if (i == -1) {
break;
}
sb.replace(i, i + nl.length(), "\n");
r = i + 1;
}
}
return sb;
}
/** Convert a \n string to a platform encoding. This uses a default
* {@link Charset UTF-8} charset.
*
* @param file where to write the converted bytes to
* @param value the value to write
*/
public static void writeString(File file, String value) throws IOException {
writeString(new FileOutputStream(file), UTF8, value);
}
/** Convert a \n string to a platform encoding. This uses a default
* {@link Charset UTF-8} charset.
*
* @param out where to write the converted bytes to
* @param value the value to write
*/
public static void writeString(OutputStream out, String value) throws IOException {
writeString(out, UTF8, value);
}
/** Convert a \n string to a platform encoding. This uses the
* specified charset to extract the raw bytes.
*
* @param out where to write the converted bytes to
* @param charset the charset to use to convert the raw bytes
* @param value the value to write
*/
public static void writeString(OutputStream out, String charset, String value) throws IOException {
writeString(out, Charset.forName(charset), value);
}
/** Convert a \n string to a platform encoding. This uses the
* specified charset to extract the raw bytes.
*
* @param out where to write the converted bytes to
* @param charset the charset to use to convert the raw bytes
* @param value the value to write
*/
public static void writeString(OutputStream out, Charset charset, String value) throws IOException {
Writer writer = new OutputStreamWriter(out, charset);
String nl = System.getProperty("line.separator");
int r = 0;
while (r < value.length()) {
int i = value.indexOf("\n", r);
if (i == -1) {
break;
}
writer.write(value.substring(r, i));
writer.write(nl);
r = i + 1;
}
writer.write(value.substring(r));
writer.close();
}
public static Object readObject(File file) throws ClassNotFoundException, IOException {
return readObject(new FileInputStream(file), false);
}
public static Object readObject(File file, boolean allowJsonResolve) throws ClassNotFoundException, IOException {
return readObject(new FileInputStream(file), allowJsonResolve);
}
public static Object readObject(InputStream in) throws ClassNotFoundException, IOException {
return readObject(in, false);
}
public static Object readObject(InputStream in, boolean allowJsonResolve) throws ClassNotFoundException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IOUtils.copy(in, baos);
in.close();
byte[] bytes = baos.toByteArray();
try {
char[] buffer = StringUtils.chomp(readString(bytes)).toCharArray();
return parseObject(buffer, 0, buffer.length, allowJsonResolve);
} catch (Exception e) {
}
ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(bytes));
Serializable value = (Serializable) oin.readObject();
oin.close();
return value;
}
public static Object readObject(char[] buffer) throws ClassNotFoundException, IOException {
return parseObject(buffer, 0, buffer.length, false);
}
public static Object readObject(char[] buffer, int offset, int length) throws ClassNotFoundException, IOException {
return parseObject(buffer, offset, length, false);
}
private static <S, T> T convertObject(Class<S> sourceClass, S value, Class<T> targetClass) throws Exception {
Converter<S, T> converter = Converters.getConverter(sourceClass, targetClass);
return converter.convert(targetClass, value);
}
private static Object parseObject(char[] buffer, int offset, int length, boolean allowJsonResolve) throws ClassNotFoundException, IOException {
try {
int i;
for (i = offset; i < length && buffer[i] != ':'; i++);
if (i > offset && i < length) {
String className = new String(buffer, offset, i);
Class<?> type = Class.forName(className, true, ClassLoaderContainer.getClassLoader());
if (buffer[length - 1] == '\n') {
length--;
}
return convertObject(String.class, new String(buffer, i + 1, length - i - 1), type);
}
} catch (Exception e) {
}
try {
return new JSON(new StringReader(new String(buffer, offset, length))).allowResolve(allowJsonResolve).JSONValue();
} catch (Error e) {
} catch (Exception e) {
}
throw new IOException("Can't read (" + new String(buffer, offset, length) + ")");
}
public static void writeObject(File file, Object value) throws IOException {
writeObject(new FileOutputStream(file), value, false);
}
public static void writeObject(File file, Object value, boolean allowJsonResolve) throws IOException {
writeObject(new FileOutputStream(file), value, allowJsonResolve);
}
public static void writeObject(OutputStream out, Object value) throws IOException {
writeObject(out, value, false);
}
public static void writeObject(OutputStream out, Object value, boolean allowJsonResolve) throws IOException {
try {
PrintWriter writer = new PrintWriter(new OutputStreamWriter(out, UTF8));
if (encodeObject(writer, value, allowJsonResolve)) {
writer.println();
writer.close();
return;
}
} catch (Exception e) {
}
ObjectOutputStream oout = new ObjectOutputStream(out);
oout.writeObject(value);
oout.close();
out.close();
}
private static <T> boolean encodeObject(Writer writer, T value, boolean allowJsonResolve) throws Exception {
Converter<T, String> converter = UtilGenerics.cast(Converters.getConverter(value.getClass(), String.class));
if (converter != null) {
Class<?> clz = converter.getSourceClass();
String str = converter.convert(value);
if (clz != null) {
writer.write(clz.getName());
} else {
writer.write(value.getClass().getName());
}
writer.write(':');
writer.write(str);
return true;
} else {
StringWriter sw = new StringWriter();
IndentingWriter indenting = new IndentingWriter(writer, true, false);
JSONWriter jsonWriter;
if (allowJsonResolve) {
jsonWriter = new JSONWriter(indenting, JSONWriter.ResolvingFallbackHandler);
} else {
jsonWriter = new JSONWriter(indenting);
}
jsonWriter.write(value);
writer.write(sw.toString());
return true;
}
}
public static void writeObject(StringBuilder sb, Object value) throws IOException {
writeObject(sb, value, false);
}
public static void writeObject(StringBuilder sb, Object value, boolean allowJsonResolve) throws IOException {
try {
StringWriter writer = new StringWriter();
if (encodeObject(writer, value, allowJsonResolve)) {
sb.append(writer.toString());
return;
}
} catch (Exception e) {} //Empty catch because writeObject() calls encodeObject(), which *always* returns true, unless an error occurs.
throw new IOException("Can't write (" + value + ")");
}
}