/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.dqp.internal.process;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.teiid.common.buffer.FileStore.FileStoreOutputStream;
import org.teiid.common.buffer.FileStoreInputStreamFactory;
import org.teiid.core.types.InputStreamFactory;
/**
* An {@link InputStream} wrapper that saves the input on read and provides a {@link InputStreamFactory}.
*/
public final class SaveOnReadInputStream extends FilterInputStream {
class SwitchingInputStream extends FilterInputStream {
protected SwitchingInputStream() {
super(SaveOnReadInputStream.this);
}
public void setIn(InputStream is) {
this.in = is;
}
}
private SwitchingInputStream sis = new SwitchingInputStream();
private final FileStoreInputStreamFactory fsisf;
private FileStoreOutputStream fsos;
private boolean saved;
private boolean read;
private boolean returned;
InputStreamFactory inputStreamFactory = new InputStreamFactory() {
@Override
public InputStream getInputStream() throws IOException {
if (!saved) {
if (!returned) {
returned = true;
return sis;
}
//save the rest of the stream
SaveOnReadInputStream.this.fsos.flush();
long start = SaveOnReadInputStream.this.fsisf.getLength();
SaveOnReadInputStream.this.close(); //force the pending read
InputStream is = SaveOnReadInputStream.this.fsisf.getInputStream(start, -1);
sis.setIn(is);
}
return fsisf.getInputStream();
}
@Override
public StorageMode getStorageMode() {
if (!saved) {
try {
getInputStream().close();
} catch (IOException e) {
return StorageMode.OTHER;
}
}
return fsisf.getStorageMode();
}
};
public SaveOnReadInputStream(InputStream in,
FileStoreInputStreamFactory fsisf) {
super(in);
this.fsisf = fsisf;
fsos = fsisf.getOuputStream();
}
@Override
public int read() throws IOException {
read = true;
int i = super.read();
read = false;
if (i > 0) {
fsos.write(i);
} else {
saved = true;
}
return i;
}
@Override
public int read(byte[] b, int off, int len)
throws IOException {
read = true;
int bytes = super.read(b, off, len);
read = false;
if (bytes > 0) {
fsos.write(b, off, bytes);
} else if (bytes == -1) {
saved = true;
}
return bytes;
}
@Override
public void close() throws IOException {
try {
if (!saved && !read) {
byte[] bytes = new byte[1<<13];
while (!saved) {
read(bytes, 0, bytes.length);
}
}
fsos.close();
} finally {
if (!saved) {
fsisf.free();
saved = true;
}
super.close();
}
}
public InputStreamFactory getInputStreamFactory() {
return inputStreamFactory;
}
}