All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.derquinse.common.io.MemoryByteSourceLoader Maven / Gradle / Ivy

Go to download

Module containing support classes depending on Java SE 6, Guava 11 and Joda-Time 2.0

There is a newer version: 1.0.37
Show newest version
/*
 * Copyright (C) the original author or authors.
 *
 * 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 net.derquinse.common.io;

import static com.google.common.base.Preconditions.checkNotNull;
import static net.derquinse.common.io.InternalPreconditions.checkChunkSize;
import static net.derquinse.common.io.InternalPreconditions.checkMaxSize;
import static net.derquinse.common.io.InternalPreconditions.checkSize;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.concurrent.ThreadSafe;

import com.google.common.base.Objects;
import com.google.common.io.ByteSource;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closer;
import com.google.common.io.Files;
import com.google.common.primitives.Ints;

/**
 * Memory byte source loader.
 * @author Andres Rodriguez
 */
@ThreadSafe
public final class MemoryByteSourceLoader {
	/** Default loader. */
	private static final MemoryByteSourceLoader DEFAULT = new MemoryByteSourceLoader(false, Integer.MAX_VALUE, 8192,
			false, null);
	/** Whether to use direct memory. */
	private final boolean direct;
	/** Maximum size. */
	private final int maxSize;
	/** Chunk size. */
	private final int chunkSize;
	/** Whether to merge after loading. */
	private final boolean merge;
	/** Transformer to use. */
	private final BytesTransformer transformer;

	/** Gets the default loader. */
	public static MemoryByteSourceLoader get() {
		return DEFAULT;
	}

	/** Constructor. */
	private MemoryByteSourceLoader(boolean direct, int maxSize, int chunkSize, boolean merge, BytesTransformer transformer) {
		this.direct = direct;
		this.maxSize = maxSize;
		this.chunkSize = chunkSize;
		this.merge = merge;
		this.transformer = transformer;
	}

	/** Returns whether the loader uses direct memory. */
	public boolean isDirect() {
		return direct;
	}

	/** Returns the maximum size. */
	public int getMaxSize() {
		return maxSize;
	}

	/** Returns the chunk size. */
	public int getChunkSize() {
		return chunkSize;
	}

	/** Returns whether the loader merges after loading. */
	public boolean isMerge() {
		return merge;
	}

	/** Returns the transformer used. */
	public BytesTransformer getTransformer() {
		return transformer;
	}

	/**
	 * Returns a loader with the same configuration and the use of direct memory specified by the
	 * argument.
	 * @param direct True to use direct memory, false to use heap.
	 */
	public MemoryByteSourceLoader direct(boolean direct) {
		if (direct == this.direct) {
			return this;
		}
		return new MemoryByteSourceLoader(direct, maxSize, chunkSize, merge, transformer);
	}

	/**
	 * Returns a loader with the same configuration and the maximum allowed size specified by the
	 * argument.
	 */
	public MemoryByteSourceLoader maxSize(int maxSize) {
		checkMaxSize(maxSize);
		if (maxSize == this.maxSize) {
			return this;
		}
		return new MemoryByteSourceLoader(direct, maxSize, chunkSize, merge, transformer);
	}

	/**
	 * Returns a loader with the same configuration and the chunk size specified by the argument.
	 */
	public MemoryByteSourceLoader chunkSize(int chunkSize) {
		checkChunkSize(chunkSize);
		if (chunkSize == this.chunkSize) {
			return this;
		}
		return new MemoryByteSourceLoader(direct, maxSize, chunkSize, merge, transformer);
	}

	/**
	 * Returns a loader with the same configuration and that merges the source after loading according
	 * to the provided argument.
	 * @param merge Whether to merge after loading.
	 */
	public MemoryByteSourceLoader merge(boolean merge) {
		if (merge == this.merge) {
			return this;
		}
		return new MemoryByteSourceLoader(direct, maxSize, chunkSize, merge, transformer);
	}

	/**
	 * Returns a loader with the same configuration and the transformer specified by the argument.
	 */
	public MemoryByteSourceLoader transformer(ByteStreamTransformer transformer) {
		BytesTransformer v = transformer == null ? null : BytesTransformer.of(transformer);
		if (Objects.equal(this.transformer, v)) {
			return this;
		}
		return new MemoryByteSourceLoader(direct, maxSize, chunkSize, merge, v);
	}

	private MemoryByteSource merged(MemoryByteSource source) {
		if (merge) {
			return source.merge();
		}
		return source;
	}

	/** Opens a new memory output stream. */
	public MemoryOutputStream openStream() {
		if (direct) {
			return DirectByteSource.openStream(this);
		}
		return HeapByteSource.openStream(this);
	}

	/**
	 * Loads the contents of the input stream into a memory byte source.
	 * @param is Input stream. It is not closed.
	 * @return The loaded data in a byte source.
	 */
	public MemoryByteSource load(InputStream is) throws IOException {
		checkNotNull(is, "The input stream to load must be provided");
		final MemoryOutputStream os = openStream();
		if (transformer != null) {
			transformer.transform(is, os);
		} else {
			ByteStreams.copy(is, os);
		}
		return os.toByteSource();
	}

	/** Performs a copy of the provided source. */
	MemoryByteSource copy(MemoryByteSource source) {
		try {
			return load(source.openStream());
		} catch (IOException e) {
			throw new IllegalStateException(e); // should not happen
		}
	}

	/**
	 * Transform an existing memory byte source.
	 */
	private MemoryByteSource transform(MemoryByteSource source) {
		checkSize(Ints.saturatedCast(source.size()), maxSize);
		final MemoryByteSource transformed;
		if (direct) {
			transformed = source.toDirect(chunkSize);
		} else {
			transformed = source.toHeap(chunkSize);
		}
		return merged(transformed);
	}

	/**
	 * Loads the contents of an existing source into a memory byte source.
	 * @return The loaded data in a byte source.
	 */
	public MemoryByteSource load(ByteSource source) throws IOException {
		checkNotNull(source, "The byte source to load must be provided");
		if (transformer == null && source instanceof MemoryByteSource) {
			return transform((MemoryByteSource) source);
		}
		Closer closer = Closer.create();
		try {
			InputStream is = closer.register(source.openStream());
			return load(is);
		} catch (Throwable t) {
			throw closer.rethrow(t);
		} finally {
			closer.close();
		}
	}

	/**
	 * Loads the contents of an existing file into a memory byte source.
	 * @return The loaded data in a byte source.
	 */
	public MemoryByteSource load(File file) throws IOException {
		checkNotNull(file, "The file to load must be provided");
		return load(Files.asByteSource(file));
	}

	@Override
	public int hashCode() {
		return Objects.hashCode(direct, maxSize, chunkSize, merge, transformer);
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof MemoryByteSourceLoader) {
			MemoryByteSourceLoader s = (MemoryByteSourceLoader) obj;
			return direct == s.direct && merge == s.merge && maxSize == s.maxSize && chunkSize == s.chunkSize
					&& transformer.equals(s.transformer);
		}
		return false;
	}

	/** Creates a new sink based on this loader. */
	public MemoryByteSink newSink() {
		return new MemoryByteSink(this);
	}

	@Override
	public String toString() {
		return Objects.toStringHelper(this).omitNullValues().add("direct", direct).add("maxSize", maxSize)
				.add("chunkSize", chunkSize).add("merge", merge).add("transformer", transformer).toString();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy