/*
Copyright (c) 2007 Health Market Science, Inc.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA
You can contact Health Market Science at info@healthmarketscience.com
or at the following address:
Health Market Science
2700 Horizon Drive
Suite 200
King of Prussia, PA 19406
*/
package com.healthmarketscience.rmiio;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import com.healthmarketscience.rmiio.exporter.RemoteStreamExporter;
/**
* Base class for implementing the server side of a RemoteIterator. This
* object manages RemoteInputStreamServer which connects the client and the
* server. Implementations of this class must provide an InputStream which is
* the source of the data going over the wire. Note, users of this class
* should ensure that the close() method is called one way or another, or
* shutdown of the process may be delayed.
*
* @author James Ahlborn
*/
public class RemoteIteratorServer<DataType> implements Closeable
{
/** InputStream which is used by the RemoteInputStreamServer to read the
objects. */
protected final InputStream _localIStream;
/** handle to the remote pipe linking this class to the client */
private final RemoteInputStreamServer _remoteIStream;
public RemoteIteratorServer(InputStream localIStream)
throws IOException
{
this(localIStream, true, RemoteInputStreamServer.DUMMY_MONITOR);
}
public RemoteIteratorServer(InputStream localIStream, boolean useCompression)
throws IOException
{
this(localIStream, useCompression, RemoteInputStreamServer.DUMMY_MONITOR);
}
public RemoteIteratorServer(
InputStream localIStream,
boolean useCompression,
RemoteStreamMonitor<RemoteInputStreamServer> monitor)
throws IOException
{
this(localIStream, useCompression, monitor,
RemoteInputStreamServer.DEFAULT_CHUNK_SIZE);
}
public RemoteIteratorServer(
InputStream localIStream,
boolean useCompression,
RemoteStreamMonitor<RemoteInputStreamServer> monitor,
int chunkSize)
throws IOException
{
_localIStream = localIStream;
if(useCompression) {
_remoteIStream = new GZIPRemoteInputStream(_localIStream, monitor,
chunkSize) {
private static final long serialVersionUID = 0L;
@Override
protected void closeImpl(boolean readSuccess)
throws IOException {
// hook into any remote/Unreferenced close calls
try {
super.closeImpl(readSuccess);
} finally {
RemoteIteratorServer.this.closeImpl(readSuccess);
}
}
};
} else {
_remoteIStream = new SimpleRemoteInputStream(_localIStream, monitor,
chunkSize) {
private static final long serialVersionUID = 0L;
@Override
protected void closeImpl(boolean readSuccess)
throws IOException {
// hook into any remote/Unreferenced close calls
try {
super.closeImpl(readSuccess);
} finally {
RemoteIteratorServer.this.closeImpl(readSuccess);
}
}
};
}
}
/**
* Package-protected: gets handle to the RemoteInputStream which the
* RemoteInputStreamClient should use. Does the export of the object, so
* should only be called <b>once</b> by the client.
* @param exporter the exporter which will handle exporting the underlying
* RemoteInputStream on the appropriate RPC framework
*/
RemoteInputStream getRemoteInputStream(RemoteStreamExporter exporter)
throws IOException
{
return((exporter == null) ? _remoteIStream.export() :
exporter.export(_remoteIStream));
}
/**
* @return <code>true</code> iff this iterator server has been closed (one
* way or another), <code>false</code> otherwise.
*/
public final boolean isClosed() {
return _remoteIStream.isClosed();
}
/**
* Forces this iterator server to close (if not already closed), will
* <b>break</b> any outstanding client interactions. Should be called one
* way or another on the server object (may be left to the underlying stream
* <code>unreferenced</code> method if the server object must live beyond
* the creation method call).
*/
public final void close() {
// note, this will eventually call our closeImpl method below due to the
// override on creation. this method is final because we do not want to
// add additional behavior here which might not get invoked on remote
// close (whereas closeImpl will get invoked on remote close).
_remoteIStream.close();
}
/**
* Aborts the current transfer without closing this RemoteIteratorServer.
* This method is thread safe. This will usually shutdown a currently
* working transfer faster than just closing the RemoteIteratorServer
* directly (because this will cause the client to get an IOException
* instead of a RemoteException, which may cause retries, etc.). This
* RemoteIteratorServer should still be closed as normal.
*/
public void abort()
throws IOException
{
_remoteIStream.abort();
}
/**
* Cleans up any local resources after the underlying stream server is
* closed. Since this method is called by the close() method on the
* underlying remote stream, <i>it will be invoked on a successful remote
* close</i>.
*
* @param readSuccess <code>true</code> iff all data was successfully
* transferred, <code>false</code> otherwise
*/
protected void closeImpl(boolean readSuccess)
throws IOException
{
// base class does nothing
}
}