/**
* 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.io.OutputStream;
import com.asakusafw.windgate.core.WindGateLogger;
import com.asakusafw.windgate.core.resource.DrainDriver;
import com.asakusafw.windgate.core.resource.SourceDriver;
import com.asakusafw.windgate.core.vocabulary.DataModelStreamSupport;
import com.asakusafw.windgate.core.vocabulary.DataModelStreamSupport.DataModelWriter;
/**
* An implementation of {@link SourceDriver} using binary {@link InputStream}.
* @param <T> type of data model objects
* @since 0.2.4
*/
public class StreamDrainDriver<T> implements DrainDriver<T> {
static final WindGateLogger WGLOG = new WindGateStreamLogger(StreamDrainDriver.class);
private final String resourceName;
private final String processName;
private final OutputStreamProvider streamProvider;
private final DataModelStreamSupport<? super T> streamSupport;
private final long eachStreamSize;
private String currentPath;
private CountingOutputStream currentStream;
private DataModelWriter<? super T> currentWriter;
private long bytesCount;
private boolean closed;
/**
* Creates a new instance.
* @param resourceName original resource name
* @param processName current process name
* @param streamProvider provides target {@link OutputStream}
* @param streamSupport converts data model objects into binary data
* @throws IllegalArgumentException if some parameters were {@code null}
*/
public StreamDrainDriver(
String resourceName,
String processName,
OutputStreamProvider streamProvider,
DataModelStreamSupport<? super T> streamSupport) {
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$
}
this.resourceName = resourceName;
this.processName = processName;
this.streamProvider = streamProvider;
this.streamSupport = streamSupport;
if (streamProvider.getDesiredStreamSize() > 0) {
eachStreamSize = streamProvider.getDesiredStreamSize();
} else {
eachStreamSize = Long.MAX_VALUE;
}
}
@Override
public void prepare() throws IOException {
prepareNextStream();
}
@Override
public void put(T object) throws IOException {
if (currentWriter == null || currentStream.getCount() >= eachStreamSize) {
if (currentWriter != null) {
closeCurrentStream();
}
prepareNextStream();
}
currentWriter.write(object);
}
private void prepareNextStream() throws IOException {
streamProvider.next();
currentPath = streamProvider.getCurrentPath();
WGLOG.info("I04001",
resourceName,
processName,
currentPath);
try {
currentStream = streamProvider.openStream();
currentWriter = streamSupport.createWriter(currentPath, currentStream);
} catch (IOException e) {
WGLOG.error(e, "E04001",
resourceName,
processName,
currentPath);
throw e;
}
}
private void closeCurrentStream() throws IOException {
currentWriter.flush();
WGLOG.info("I04002",
resourceName,
processName,
currentPath,
currentStream.getCount());
bytesCount += currentStream.getCount();
try {
currentStream.close();
} catch (IOException e) {
WGLOG.error(e, "E04002",
resourceName,
processName,
currentPath);
throw e;
}
currentPath = null;
currentStream = null;
currentWriter = null;
}
@Override
public void close() throws IOException {
if (closed) {
return;
}
if (currentWriter != null) {
closeCurrentStream();
}
closed = true;
}
}