/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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 com.asakusafw.windgate.stream;
import java.io.IOException;
import java.io.InputStream;
import java.text.MessageFormat;
import com.asakusafw.windgate.core.WindGateLogger;
import com.asakusafw.windgate.core.resource.SourceDriver;
import com.asakusafw.windgate.core.vocabulary.DataModelStreamSupport;
import com.asakusafw.windgate.core.vocabulary.DataModelStreamSupport.DataModelReader;
/**
* An implementation of {@link SourceDriver} using binary {@link InputStream}.
* @param <T> type of data model objects
* @since 0.2.4
*/
public class StreamSourceDriver<T> implements SourceDriver<T> {
static final WindGateLogger WGLOG = new WindGateStreamLogger(StreamSourceDriver.class);
private final String resourceName;
private final String processName;
private final InputStreamProvider streamProvider;
private final DataModelStreamSupport<? super T> streamSupport;
private final T buffer;
private String currentPath;
private CountingInputStream currentStream;
private DataModelReader<? super T> currentReader;
private boolean sawNext;
private long bytesCount;
private boolean closed;
/**
* Creates a new instance.
* @param resourceName original resource name
* @param processName current process name
* @param streamProvider provides source {@link InputStream}
* @param streamSupport converts {@link InputStream} as data model objects
* @param buffer data model object for buffer
* @throws IllegalArgumentException if some parameters were {@code null}
*/
public StreamSourceDriver(
String resourceName,
String processName,
InputStreamProvider streamProvider,
DataModelStreamSupport<? super T> streamSupport,
T buffer) {
if (resourceName == null) {
throw new IllegalArgumentException("resourceName must not be null"); //$NON-NLS-1$
}
if (processName == null) {
throw new IllegalArgumentException("processName must not be null"); //$NON-NLS-1$
}
if (streamProvider == null) {
throw new IllegalArgumentException("streamProvider must not be null"); //$NON-NLS-1$
}
if (streamSupport == null) {
throw new IllegalArgumentException("streamSupport must not be null"); //$NON-NLS-1$
}
if (buffer == null) {
throw new IllegalArgumentException("buffer must not be null"); //$NON-NLS-1$
}
this.resourceName = resourceName;
this.processName = processName;
this.streamProvider = streamProvider;
this.streamSupport = streamSupport;
this.buffer = buffer;
}
@Override
public void prepare() throws IOException {
sawNext = false;
}
@Override
public boolean next() throws IOException {
while (true) {
if (currentReader == null) {
if (prepareNextStream() == false) {
sawNext = false;
break;
}
}
if (currentReader.readTo(buffer)) {
sawNext = true;
break;
} else {
closeCurrentStream();
}
}
return sawNext;
}
private boolean prepareNextStream() throws IOException {
if (streamProvider.next() == false) {
return false;
}
currentPath = streamProvider.getCurrentPath();
WGLOG.info("I03001",
resourceName,
processName,
currentPath);
try {
currentStream = streamProvider.openStream();
currentReader = streamSupport.createReader(currentPath, currentStream);
} catch (IOException e) {
WGLOG.error(e, "E03001",
resourceName,
processName,
currentPath);
throw e;
}
return true;
}
private void closeCurrentStream() {
WGLOG.info("I03002",
resourceName,
processName,
currentPath,
currentStream.getCount());
bytesCount += currentStream.getCount();
try {
currentStream.close();
} catch (IOException e) {
WGLOG.warn(e, "W03001",
resourceName,
processName,
currentPath);
}
currentPath = null;
currentStream = null;
currentReader = null;
}
@Override
public T get() throws IOException {
if (sawNext == false) {
throw new IllegalStateException(MessageFormat.format(
"next object is not yet prepared (resource={0}, process={1})",
resourceName,
processName));
}
return buffer;
}
@Override
public void close() throws IOException {
if (closed) {
return;
}
if (currentStream != null) {
closeCurrentStream();
}
sawNext = false;
closed = true;
}
}