blob: 0e55f34eee3316a52a6c2ade51bfedc03c948aad [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.apache.chemistry.opencmis.commons.impl;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
public final class IOUtils {
/** UTF-8 character set name. */
public static final String UTF8 = "UTF-8";
/** ISO-8859-1 character set name. */
public static final String ISO_8859_1 = "ISO-8859-1";
private IOUtils() {
}
/**
* Returns UTF-8 bytes of the given string or throws a
* {@link CmisRuntimeException} if the charset 'UTF-8' is not available.
*
* @param s
* the input string
*
* @return the UTF-8 bytes
*/
public static byte[] toUTF8Bytes(String s) {
if (s == null) {
return null;
}
try {
return s.getBytes(UTF8);
} catch (UnsupportedEncodingException e) {
throw new CmisRuntimeException("Unsupported encoding 'UTF-8'!", e);
}
}
/**
* Converts a UTF-8 encoded byte array into a string or throws a
* {@link CmisRuntimeException} if the charset 'UTF-8' is not available.
*
* @param bytes
* the byte array
* @return the string
*/
public static String toUTF8String(byte[] bytes) {
if (bytes == null) {
return null;
}
try {
return new String(bytes, UTF8);
} catch (UnsupportedEncodingException e) {
throw new CmisRuntimeException("Unsupported encoding 'UTF-8'!", e);
}
}
/**
* URL encodes the given string or throws a {@link CmisRuntimeException} if
* the charset 'UTF-8' is not available.
*
* @param s
* the string to encode
*
* @return the encoded
*/
public static String encodeURL(String s) {
if (s == null) {
return null;
}
try {
return URLEncoder.encode(s, UTF8);
} catch (UnsupportedEncodingException e) {
throw new CmisRuntimeException("Unsupported encoding 'UTF-8'!", e);
}
}
/**
* URL decodes the given string or throws a {@link CmisRuntimeException} if
* the charset 'UTF-8' is not available.
*
* @param s
* the string to decode
*
* @return the decoded string
*/
public static String decodeURL(String s) {
if (s == null) {
return null;
}
try {
return URLDecoder.decode(s, UTF8);
} catch (UnsupportedEncodingException e) {
throw new CmisRuntimeException("Unsupported encoding 'UTF-8'!", e);
}
}
/**
* Checks if a stream has more bytes. If the provided stream is not
* markable, it wrappes a {@link BufferedInputStream} around the stream and
* returns it.
*
* @param stream
* the stream
* @param bufferSize
* the size of the buffer in bytes if a
* {@link BufferedInputStream} has to be created
* @return {@code null} if the stream doesn't have more bytes, the provided
* stream if the provided stream is markable and has more bytes, or
* a {@link BufferedInputStream} if the provided stream is not
* markable and has more bytes
*
* @throws IOException
*/
public static InputStream checkForBytes(InputStream stream, int bufferSize) throws IOException {
if (stream == null) {
return null;
}
InputStream checkStream = stream;
if (!stream.markSupported()) {
checkStream = new BufferedInputStream(stream, bufferSize);
}
if (checkForBytes(checkStream)) {
return checkStream;
}
return null;
}
/**
* Checks if a stream has more bytes.
*
* @param stream
* a markable stream
* @return {@code true} if the stream has more bytes, {@code false}
* otherwise
*/
public static boolean checkForBytes(InputStream stream) throws IOException {
if (stream == null) {
return false;
}
if (!stream.markSupported()) {
throw new IllegalArgumentException("Stream must support marks!");
}
stream.mark(2);
if (stream.read() != -1) {
stream.reset();
return true;
}
return false;
}
/**
* Closes a stream and ignores any exceptions.
*
* @param closeable
* the {@link Closeable} object
*/
@SuppressWarnings("PMD.EmptyCatchBlock")
public static void closeQuietly(final Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (final IOException ioe) {
// ignore
}
}
/**
* Closes the stream of a {@link ContentStream} object and ignores any
* exceptions.
*
* @param contentStream
* the content stream
*/
public static void closeQuietly(final ContentStream contentStream) {
if (contentStream != null) {
closeQuietly(contentStream.getStream());
}
}
/**
* Consumes and closes the provided stream.
*
* @param stream
* the stream
*/
@SuppressWarnings({ "PMD.EmptyCatchBlock", "PMD.EmptyWhileStmt" })
public static void consumeAndClose(final InputStream stream) {
if (stream == null) {
return;
}
try {
final byte[] buffer = new byte[64 * 1024];
while (stream.read(buffer) > -1) {
// just consume
}
} catch (IOException e) {
// ignore
} finally {
IOUtils.closeQuietly(stream);
}
}
/**
* Consumes and closes the provided reader.
*
* @param reader
* the reader
*/
@SuppressWarnings({ "PMD.EmptyCatchBlock", "PMD.EmptyWhileStmt" })
public static void consumeAndClose(final Reader reader) {
if (reader == null) {
return;
}
try {
final char[] buffer = new char[64 * 1024];
while (reader.read(buffer) > -1) {
// just consume
}
} catch (IOException e) {
// ignore
} finally {
IOUtils.closeQuietly(reader);
}
}
/**
* Copies all bytes of an input stream to an output stream.
*
* Neither the input stream nor the output stream will the closed after the
* copy.
*
* @param in
* the input stream, must not be {@code null}
* @param out
* the output stream, must not be {@code null}
*/
public static void copy(InputStream in, OutputStream out) throws IOException {
copy(in, out, 64 * 1024);
}
/**
* Copies all bytes of an input stream to an output stream.
*
* Neither the input stream nor the output stream will the closed after the
* copy.
*
* @param in
* the input stream, must not be {@code null}
* @param out
* the output stream, must not be {@code null}
* @param bufferSize
* the size of the internal buffer, must be positive
*/
public static void copy(InputStream in, OutputStream out, int bufferSize) throws IOException {
assert in != null;
assert out != null;
assert bufferSize > 0;
int b;
byte[] buffer = new byte[bufferSize];
while ((b = in.read(buffer)) > -1) {
out.write(buffer, 0, b);
}
}
/**
* Reads lines from an UTF-8 encoded stream and closes the stream.
*
* @param stream
* the stream
* @param handler
* a handler the processes each line.
*/
public static void readLinesFromStream(InputStream stream, LineHandler handler) throws IOException {
if (stream == null) {
return;
}
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(stream, UTF8));
String line;
while ((line = reader.readLine()) != null) {
if (!handler.handle(line)) {
break;
}
}
} finally {
closeQuietly(reader);
}
}
/**
* Reads the first line from a stream and closes the stream.
*
* @param stream
* the input stream
*/
public static String readFirstLine(InputStream stream) throws IOException {
final StringBuilder result = new StringBuilder();
readLinesFromStream(stream, new LineHandler() {
public boolean handle(String line) {
result.append(line);
return false;
}
});
return result.toString();
}
/**
* Reads all lines from a stream and closes the stream.
*
* @param stream
* the input stream
*/
public static String readAllLines(InputStream stream) throws IOException {
final StringBuilder result = new StringBuilder();
readLinesFromStream(stream, new LineHandler() {
public boolean handle(String line) {
result.append(line);
result.append('\n');
return true;
}
});
return result.toString();
}
/**
* Reads all lines from a stream, removes the header, and closes the stream.
*
* @param stream
* the input stream
*/
public static String readAllLinesAndRemoveHeader(InputStream stream) throws IOException {
final StringBuilder result = new StringBuilder();
readLinesFromStream(stream, new SkipHeaderLineHandler() {
public boolean handle(String line) {
if (!isHeaderLine(line)) {
result.append(line);
result.append('\n');
}
return true;
}
});
return result.toString();
}
/**
* Reads all lines from a stream, ignores all comments, and closes the
* stream.
*
* @param stream
* the input stream
*/
public static String readAllLinesAndIgnoreComments(InputStream stream) throws IOException {
final StringBuilder result = new StringBuilder();
readLinesFromStream(stream, new IgnoreCommentsLineHandler() {
public boolean handle(String line) {
if (!isComment(line)) {
result.append(line);
result.append('\n');
}
return true;
}
});
return result.toString();
}
/**
* Reads all lines from a stream, ignores all comments, and closes the
* stream.
*
* @param stream
* the input stream
*/
public static List<String> readAllLinesAsList(InputStream stream) throws IOException {
final List<String> result = new ArrayList<String>();
readLinesFromStream(stream, new IgnoreCommentsLineHandler() {
public boolean handle(String line) {
if (!isComment(line)) {
result.add(line);
}
return true;
}
});
return result;
}
/**
* Reads all lines from a stream, ignores all comments, and closes the
* stream.
*
* @param stream
* the input stream
*/
public static Map<String, String> readAllLinesAsMap(InputStream stream) throws IOException {
final Map<String, String> result = new HashMap<String, String>();
readLinesFromStream(stream, new IgnoreCommentsLineHandler() {
public boolean handle(String line) {
if (!isComment(line)) {
int x = line.indexOf('=');
if (x < 0) {
result.put(line.trim(), "");
} else {
result.put(line.substring(0, x).trim(), line.substring(x + 1).trim());
}
}
return true;
}
});
return result;
}
public interface LineHandler {
/**
* Handles a line.
*
* @param line
* the line to handle
*
* @return <code>true</code> if the next line should be processed,
* <code>false</code> if the processing should stop.
*/
boolean handle(String line);
}
public abstract static class SkipHeaderLineHandler implements LineHandler {
private boolean header = true;
public boolean isHeaderLine(String line) {
if (!header) {
return false;
}
String trim = line.trim();
if (trim.length() == 0) {
header = false;
return true;
}
char c = trim.charAt(0);
return (c == '/') || (c == '*') || (c == '#');
}
}
public abstract static class IgnoreCommentsLineHandler implements LineHandler {
public boolean isComment(String line) {
String trim = line.trim();
if (trim.length() == 0) {
return true;
}
return trim.charAt(0) == '#';
}
}
}