/*
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.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import com.healthmarketscience.rmiio.util.PipeBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
/**
* Note, setting the system property {@code rmiio.fastTest} to {@code false}
* when running the maven test suite will run more exhaustive tests (although
* they take a while).
*
* @author James Ahlborn
*/
public class RemoteStreamServerTest extends BaseRemoteStreamTest {
private static final Logger LOG = LoggerFactory.getLogger(RemoteStreamServerTest.class);
static final String TEST_FILE = "./src/test/data/file_transfer.data";
static final int FILE_SIZE = 277672;
private static final int PARTIAL_SIZE = 3000;
private static boolean _deleteOnExit = true;
public void testTransfer() throws Exception
{
File testFile = new File(TEST_FILE);
LOG.debug("data file: " + testFile.getAbsolutePath());
List<List<File>> tempFiles = mainTest(new String[]{TEST_FILE,
Boolean.FALSE.toString(),
Boolean.FALSE.toString(),
Boolean.FALSE.toString(),
((Boolean)isFastTest()).toString()},
_clientExceptions,
_monitors);
checkClientExceptions(0);
checkFiles(testFile, tempFiles);
if(isFastTest()) {
checkMonitors(1, true);
} else {
checkMonitors(20, true);
}
}
public void testEmptyTransfer() throws Exception
{
File emptyFile = File.createTempFile("src", ".dat");
if(_deleteOnExit) {
emptyFile.deleteOnExit();
}
LOG.debug("empty data file: " + emptyFile.getAbsolutePath());
List<List<File>> tempFiles = mainTest(new String[]{emptyFile.getAbsolutePath()},
_clientExceptions, _monitors);
checkClientExceptions(0);
checkFiles(emptyFile, tempFiles);
checkMonitors(20, true);
}
public void testAbortedTransfer() throws Exception
{
File testFile = new File(TEST_FILE);
LOG.debug("data file: " + testFile.getAbsolutePath());
List<List<File>> tempFiles = mainTest(new String[]{TEST_FILE,
Boolean.TRUE.toString()},
_clientExceptions, _monitors);
// each client should have thrown an IOException
checkClientExceptions(8);
checkFiles(testFile, tempFiles);
checkMonitors(8, false);
}
public void testDoubleClose() throws Exception
{
DummyIOStream iostream = new DummyIOStream();
InputStream istream = RemoteInputStreamClient.wrap(iostream);
assertEquals(0, iostream._numCloses);
istream.close();
assertEquals(1, iostream._numCloses);
istream.close();
assertEquals(1, iostream._numCloses);
iostream = new DummyIOStream();
OutputStream ostream = RemoteOutputStreamClient.wrap(iostream);
assertEquals(0, iostream._numCloses);
ostream.close();
assertEquals(1, iostream._numCloses);
ostream.close();
assertEquals(1, iostream._numCloses);
}
public void testReverseTransfer() throws Exception
{
File testFile = new File(TEST_FILE);
LOG.debug("data file: " + testFile.getAbsolutePath());
List<List<File>> tempFiles = mainTest(new String[]{TEST_FILE,
Boolean.FALSE.toString(),
Boolean.TRUE.toString(),
Boolean.FALSE.toString(),
((Boolean)isFastTest()).toString()},
_clientExceptions,
_monitors);
checkClientExceptions(0);
checkFiles(testFile, tempFiles);
if(isFastTest()) {
checkMonitors(1, true);
} else {
checkMonitors(20, true);
}
}
public void testSkip() throws Exception
{
File testFile = new File(TEST_FILE);
LOG.debug("data file: " + testFile.getAbsolutePath());
List<List<File>> tempFiles = mainTest(new String[]{TEST_FILE,
Boolean.FALSE.toString(),
Boolean.FALSE.toString(),
Boolean.TRUE.toString()},
_clientExceptions, _monitors);
// each client should have thrown an IOException
checkClientExceptions(0);
checkFiles(testFile, tempFiles);
checkMonitors(4, true);
}
public void testReserialize() throws Exception
{
SerializableInputStream istream =
new SerializableInputStream(new FileInputStream(TEST_FILE));
Field inField = istream.getClass().getDeclaredField("_remoteIn");
inField.setAccessible(true);
assertTrue(inField.get(istream) instanceof GZIPRemoteInputStream);
SerializableInputStream istreamRem = simulateRemote(istream);
Object istreamRemIn = inField.get(istreamRem);
assertFalse(istreamRemIn instanceof GZIPRemoteInputStream);
istreamRem = simulateRemote(istream);
Object istreamRemInAlt = inField.get(istreamRem);
assertFalse(istreamRemInAlt instanceof GZIPRemoteInputStream);
assertNotSame(istreamRemIn, istreamRemInAlt);
assertEquals(istreamRemIn, istreamRemInAlt);
istreamRem = simulateRemote(istreamRem);
istreamRemInAlt = inField.get(istreamRem);
assertFalse(istreamRemInAlt instanceof GZIPRemoteInputStream);
assertNotSame(istreamRemIn, istreamRemInAlt);
assertEquals(istreamRemIn, istreamRemInAlt);
istream.close();
}
private void checkFiles(File srcFile, List<List<File>> tempFiles)
throws IOException
{
// compare all complete generated files to original
for(File tempFile : tempFiles.get(0)) {
assertTrue(compare(srcFile, tempFile, false) == 0);
}
// compare all partial generated files to original
for(File tempFile : tempFiles.get(1)) {
assertTrue(compare(srcFile, tempFile, true) == 0);
}
}
private static File getTempFile(String prefix, List<List<File>> tempFiles,
boolean doPartial,
boolean doAbort,
boolean doSkip)
throws IOException
{
File tempFile = File.createTempFile(prefix, ".out");
if(_deleteOnExit) {
tempFile.deleteOnExit();
}
if(tempFiles != null) {
if((!doPartial) && (!doAbort) && (!doSkip)) {
tempFiles.get(0).add(tempFile);
} else {
tempFiles.get(1).add(tempFile);
}
}
return tempFile;
}
public static int compare(File file1, File file2, boolean file2IsPartial)
throws IOException
{
LOG.debug("Comparing " + file1 + " and " + file2);
if(!file1.canRead() || !file2.canRead()) {
return (file1.canRead() ? 1 :
(file2.canRead() ? -1 : 0));
}
InputStream fileIStream1 =
new BufferedInputStream(new FileInputStream(file1));
InputStream fileIStream2 =
new BufferedInputStream(new FileInputStream(file2));
int b1;
int b2;
do {
b1 = fileIStream1.read();
b2 = fileIStream2.read();
} while((b1 == b2) && (b1 != -1) && (b2 != -1));
if(file2IsPartial && (b2 == -1)) {
// file2 is a partial file and all existing bytes match, we're all good
return 0;
}
return((b1 < b2) ? -1 :
((b1 > b2) ? 1 : 0));
}
private static RemoteInputStream createInputFileStream(
String fileName,
boolean unreliable,
boolean useCompression,
boolean doAbort,
List<Closeable> localServers,
List<AccumulateRemoteStreamMonitor<?>> monitors)
throws IOException
{
RemoteInputStream istream = null;
RemoteStreamServer<?, RemoteInputStream> server = null;
AccumulateRemoteStreamMonitor<RemoteInputStreamServer> monitor =
new AccumulateRemoteStreamMonitor<RemoteInputStreamServer>(doAbort);
if(monitors != null) {
monitors.add(monitor);
}
if(!unreliable) {
if(useCompression) {
istream =
simulateRemote(
(server =
(new GZIPRemoteInputStream(
new BufferedInputStream(new FileInputStream(fileName)),
monitor)))
.export());
} else {
// test writeReplace by *not* exporting explicitly here
istream =
simulateRemote((RemoteInputStream)
(server =
(new SimpleRemoteInputStream(
new BufferedInputStream(new FileInputStream(fileName)),
monitor))));
}
} else {
if(useCompression) {
istream =
simulateRemote(
(server =
(new UnreliableRemoteInputStreamServer(
(new GZIPRemoteInputStream(
new BufferedInputStream(new FileInputStream(fileName)),
monitor)))))
.export());
} else {
istream =
simulateRemote(
(server =
(new UnreliableRemoteInputStreamServer(
(new SimpleRemoteInputStream(
new BufferedInputStream(new FileInputStream(fileName)),
monitor)))))
.export());
}
}
if(localServers != null) {
localServers.add(server);
}
return istream;
}
private static RemoteOutputStream createOutputFileStream(
String callerName,
List<List<File>> tempFiles,
boolean unreliable,
boolean useCompression,
boolean doPartial,
boolean doAbort,
List<Closeable> localServers,
List<AccumulateRemoteStreamMonitor<?>> monitors)
throws IOException
{
// create temp file
File tempFile = getTempFile(callerName, tempFiles, doPartial, doAbort,
false);
RemoteOutputStream ostream = null;
RemoteStreamServer<?, RemoteOutputStream> server = null;
AccumulateRemoteStreamMonitor<RemoteOutputStreamServer> monitor =
new AccumulateRemoteStreamMonitor<RemoteOutputStreamServer>(doAbort);
if(monitors != null) {
monitors.add(monitor);
}
if(!unreliable) {
if(useCompression) {
// test writeReplace by *not* exporting explicitly here
ostream =
simulateRemote((RemoteOutputStream)
(server =
(new GZIPRemoteOutputStream(
new BufferedOutputStream(new FileOutputStream(tempFile)),
monitor))));
} else {
ostream =
simulateRemote(
(server =
(new SimpleRemoteOutputStream(
new BufferedOutputStream(new FileOutputStream(tempFile)),
monitor)))
.export());
}
} else {
if(useCompression) {
ostream =
simulateRemote(
(server =
(new UnreliableRemoteOutputStreamServer(
(new GZIPRemoteOutputStream(
new BufferedOutputStream(new FileOutputStream(tempFile)),
monitor)))))
.export());
} else {
ostream =
simulateRemote(
(server =
(new UnreliableRemoteOutputStreamServer(
(new SimpleRemoteOutputStream(
new BufferedOutputStream(new FileOutputStream(tempFile)),
monitor)))))
.export());
}
}
if(localServers != null) {
localServers.add(server);
}
return ostream;
}
private static void consumeInputStream(
String callerName,
InputStream in,
List<List<File>> tempFiles,
boolean doPartial,
boolean doAbort,
boolean doSkip)
throws IOException
{
// create temp file
File tempFile = getTempFile("client", tempFiles, doPartial, doAbort,
doSkip);
OutputStream out =
new BufferedOutputStream(new FileOutputStream(tempFile));
try {
copy(in, out, doPartial, doSkip);
} finally {
if(out != null) {
try {
out.close();
} catch(IOException ignored) {}
}
}
LOG.debug("Wrote file stream");
}
private static void generateOutputStream(
String inFileName,
OutputStream out,
boolean doPartial)
throws IOException
{
InputStream in =
new BufferedInputStream(new FileInputStream(inFileName));
try {
copy(in, out, doPartial, false);
} finally {
if(in != null) {
try {
in.close();
} catch(IOException ignored) {
}
}
}
LOG.debug("Sent file stream");
}
public static void copy(InputStream in, OutputStream out,
boolean doPartial, boolean doSkip)
throws IOException
{
final int BUF_SIZE = 1024;
byte[] tmp = new byte[BUF_SIZE];
int initAvail = in.available();
int skipAt = 0;
if(doSkip) {
skipAt = (FILE_SIZE % BUF_SIZE) - 1;
}
int numRead = 0;
int totRead = 0;
int iteration = 0;
while((numRead = cycleRead(in, tmp, iteration)) != -1) {
cycleWrite(out, tmp, numRead, iteration);
totRead += numRead;
if(doPartial && (totRead >= PARTIAL_SIZE)) {
// just return
return;
}
if(doSkip && (totRead >= skipAt)) {
long toSkip = FILE_SIZE - totRead;
long skipped = in.skip(toSkip);
if(skipped != toSkip) {
throw new IOException("skipped wrong?");
}
}
++iteration;
}
if(totRead > 0) {
if(initAvail < 0) {
throw new IOException("no bytes?");
}
}
out.flush();
if(in.available() != 0) {
throw new IOException("more bytes?");
}
}
private static boolean isFastTest()
{
// default to "true" if unspecified
return !Boolean.FALSE.toString().equals(
System.getProperty("rmiio.fastTest"));
}
@SuppressWarnings("unchecked")
public static List<List<File>> mainTest(
String[] args,
final List<Throwable> clientExceptions,
final List<AccumulateRemoteStreamMonitor<?>> monitors)
throws Exception
{
final String testFile = args[0];
final boolean doAbort = ((args.length > 1) ?
Boolean.parseBoolean(args[1]) :
false);
final boolean reverse = ((args.length > 2) ?
Boolean.parseBoolean(args[2]) :
false);
final boolean doSkip = ((args.length > 3) ?
Boolean.parseBoolean(args[3]) :
false);
final boolean doFastTests = ((args.length > 4) ?
Boolean.parseBoolean(args[4]) :
false);
final List<List<File>> tempFiles =
Arrays.asList(
Collections.synchronizedList(new LinkedList<File>()),
Collections.synchronizedList(new LinkedList<File>()));
FileServer server = new FileServer(testFile, tempFiles, monitors);
final RemoteFileServer stub = (RemoteFileServer)
simulateRemote(UnicastRemoteObject.exportObject(server, 0));
LOG.debug("Server ready");
LOG.debug("Sleeping 3000 ms...");
Thread.sleep(3000);
LOG.debug("Running 'reliable' tests");
Thread clientThread = new Thread(new Runnable()
{
public void run() {
clientExceptions.addAll(
FileClient.main(stub, testFile, tempFiles, doAbort, reverse,
doSkip, false, doFastTests, monitors));
}
});
clientThread.start();
clientThread.join();
if(!doFastTests) {
server.setUnreliable(true);
LOG.debug("Running 'unreliable' tests");
clientThread = new Thread(new Runnable()
{
public void run() {
clientExceptions.addAll(
FileClient.main(stub, testFile, tempFiles, doAbort, reverse,
doSkip, true, doFastTests, monitors));
}
});
clientThread.start();
clientThread.join();
}
LOG.debug("Unexporting server");
UnicastRemoteObject.unexportObject(server, true);
return tempFiles;
}
/**
* Returns the result of serializing and deserializing the given, exported
* RemoteStub.
* <p>
* Note, i'm leaving the paragraph below because i believe it is related to
* the problem, however, adding the serialization cycle did <b>not</b> solve
* the hard ref problem (hence that code is still in place).
* <p>
* Evidently, something special happens to a RemoteStub when it is
* serialized. There were previously issues during testing where
* RemoteStubs were throwing NoSuchObjectException on the first remote call.
* In these cases, the server objects were being garbage collected before
* ever being used. Eventually, I realized that this was because the
* RemoteStubs were not being serialized in the test code (because both the
* client and server are in the same VM). There was initially a hack in the
* RemoteStreamServer to get around this problem by temporarily maintaining
* a hard reference to the server object until the client makes the first
* successful call (which could cause leaks if the client dies before making
* the first call). After determining that the issue was due to
* serialization, I was able to make the problem disappear by forcing a
* serialize/deserialize cycle on the RemoteStub in the test code before
* handing it to the client thread.
*
* @param obj RMI stub to force into "remote" mode
*/
@SuppressWarnings("unchecked")
public static <T> T simulateRemote(T obj)
throws IOException
{
PipeBuffer.InputStreamAdapter istream =
new PipeBuffer.InputStreamAdapter();
PipeBuffer.OutputStreamAdapter ostream =
new PipeBuffer.OutputStreamAdapter();
istream.connect(ostream);
ObjectOutputStream objOstream = new ObjectOutputStream(ostream);
objOstream.writeObject(obj);
objOstream.close();
ObjectInputStream objIstream = new ObjectInputStream(istream);
try {
obj = (T)objIstream.readObject();
} catch(ClassNotFoundException e) {
throw (IOException)((new IOException()).initCause(e));
}
objIstream.close();
return obj;
}
public static void main(String[] args) throws Exception
{
int argc = 0;
String appType = null;
if(args.length > argc) {
appType = args[argc++];
}
// create sub-argument list
int subArgsLength = ((args.length > argc) ? (args.length - argc) : 0);
String[] subArgs = new String[subArgsLength];
if(subArgsLength > 0) {
System.arraycopy(args, argc, subArgs, 0, subArgsLength);
}
List<AccumulateRemoteStreamMonitor<?>> monitors = new ArrayList<AccumulateRemoteStreamMonitor<?>>();
List<Throwable> clientExceptions = new ArrayList<Throwable>();
if(appType.equals("-server")) {
FileServer.main(subArgs);
} else if(appType.equals("-client")) {
FileClient.main(subArgs);
} else if(appType.equals("-test")) {
mainTest(subArgs, clientExceptions, null);
} else {
LOG.debug("First argument must be '-server' or 'client'");
System.exit(1);
}
if(!clientExceptions.isEmpty()) {
LOG.debug("Client exceptions: " + clientExceptions);
}
}
public interface RemoteFileServer extends Remote {
public RemoteInputStream getInputFileStream(boolean useCompression,
boolean doAbort)
throws IOException;
public RemoteOutputStream getOutputFileStream(boolean useCompression,
boolean doPartial,
boolean doAbort)
throws IOException;
public SerializableInputStream getSerialInputFileStream(
boolean useCompression,
boolean doAbort)
throws IOException;
public SerializableOutputStream getSerialOutputFileStream(
boolean useCompression,
boolean doPartial,
boolean doAbort)
throws IOException;
public void useInputStream(
RemoteInputStream istream,
boolean doPartial,
boolean doAbort)
throws IOException;
public void useOutputStream(RemoteOutputStream ostream,
boolean doPartial)
throws IOException;
}
public static class FileServer
implements RemoteFileServer
{
private String _name;
private boolean _unreliable;
private List<List<File>> _tempFiles;
private List<AccumulateRemoteStreamMonitor<?>> _monitors;
public FileServer(String name, List<List<File>> tempFiles,
List<AccumulateRemoteStreamMonitor<?>> monitors) {
_name = name;
_tempFiles = tempFiles;
_monitors = monitors;
}
public void setUnreliable(boolean unreliable) {
_unreliable = unreliable;
}
public RemoteInputStream getInputFileStream(boolean useCompression,
boolean doAbort)
throws IOException
{
return createInputFileStream(_name, _unreliable, useCompression,
doAbort, null, _monitors);
}
public RemoteOutputStream getOutputFileStream(boolean useCompression,
boolean doPartial,
boolean doAbort)
throws IOException
{
return createOutputFileStream("server", _tempFiles, _unreliable,
useCompression, doPartial, doAbort,
null, _monitors);
}
public SerializableInputStream getSerialInputFileStream(
boolean useCompression,
boolean doAbort)
throws IOException
{
return new SerializableInputStream(getInputFileStream(useCompression,
doAbort));
}
public SerializableOutputStream getSerialOutputFileStream(
boolean useCompression,
boolean doPartial,
boolean doAbort)
throws IOException
{
return new SerializableOutputStream(getOutputFileStream(useCompression,
doPartial,
doAbort));
}
public void useInputStream(RemoteInputStream istream,
boolean doPartial,
boolean doAbort)
throws IOException
{
InputStream in = null;
try {
in = RemoteInputStreamClient.wrap(istream);
consumeInputStream("client", in, _tempFiles, doPartial, doAbort,
false);
} finally {
if(in != null) {
try {
in.close();
} catch(IOException ignored) {
LOG.debug("In close failed" + ignored);
}
}
}
}
public void useOutputStream(RemoteOutputStream ostream,
boolean doPartial)
throws IOException
{
OutputStream out = null;
try {
out = RemoteOutputStreamClient.wrap(ostream);
generateOutputStream(_name, out, doPartial);
} finally {
if(out != null) {
try {
out.close();
} catch(IOException ignored) {
LOG.debug("Out close failed" + ignored);
}
}
}
}
public static void main(String args[])
{
try {
FileServer server = new FileServer(args[0], null, null);
server.setUnreliable(true);
RemoteFileServer stub = (RemoteFileServer)
simulateRemote(UnicastRemoteObject.exportObject(server, 0));
// bind to registry
Registry registry = LocateRegistry.getRegistry();
registry.bind("RemoteFileServer", stub);
LOG.debug("Server ready");
} catch(Exception e) {
LOG.debug("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
public static class FileClient
{
private FileClient() {
}
private static void getFile(RemoteFileServer stub,
boolean useCompression,
List<List<File>> tempFiles,
boolean doPartial,
boolean doAbort,
boolean doSkip,
boolean useSerial)
throws Exception
{
InputStream in = null;
try {
LOG.debug("Getting in file stream");
if(!useSerial) {
in = RemoteInputStreamClient.wrap(
stub.getInputFileStream(useCompression, doAbort));
} else {
in = stub.getSerialInputFileStream(useCompression, doAbort);
}
consumeInputStream("client", in, tempFiles, doPartial, doAbort,
doSkip);
} finally {
if(in != null) {
try {
in.close();
} catch(IOException ignored) {
LOG.debug("In close failed" + ignored);
}
}
}
}
private static void getFileReverse(
RemoteFileServer stub,
boolean unreliable,
boolean useCompression,
List<List<File>> tempFiles,
boolean doPartial,
boolean doAbort,
boolean useSerial,
List<AccumulateRemoteStreamMonitor<?>> monitors)
throws Exception
{
List<Closeable> localServer = new ArrayList<Closeable>(1);
try {
stub.useOutputStream(createOutputFileStream("client", tempFiles,
unreliable, useCompression,
doPartial, doAbort,
localServer, monitors),
doPartial);
} finally {
for(Closeable server : localServer) {
server.close();
}
}
LOG.debug("Wrote file stream");
}
private static void sendFile(RemoteFileServer stub,
String inFileName,
boolean useCompression,
boolean doPartial,
boolean doAbort,
boolean useSerial)
throws Exception
{
OutputStream out = null;
try {
LOG.debug("Getting out file stream");
if(!useSerial) {
out = RemoteOutputStreamClient.wrap(
stub.getOutputFileStream(useCompression, doPartial,
doAbort));
} else {
out = stub.getSerialOutputFileStream(useCompression, doPartial,
doAbort);
}
generateOutputStream(inFileName, out, doPartial);
} finally {
if(out != null) {
try {
out.close();
} catch(IOException ignored) {
LOG.debug("Out close failed" + ignored);
}
}
}
}
private static void sendFileReverse(
RemoteFileServer stub,
String inFileName,
boolean unreliable,
boolean useCompression,
boolean doPartial,
boolean doAbort,
boolean useSerial,
List<AccumulateRemoteStreamMonitor<?>> monitors)
throws Exception
{
List<Closeable> localServer = new ArrayList<Closeable>(1);
try {
stub.useInputStream(createInputFileStream(inFileName,
unreliable, useCompression,
doAbort,
localServer, monitors),
doPartial, doAbort);
} finally {
for(Closeable server : localServer) {
server.close();
}
}
LOG.debug("Sent file stream");
}
public static List<Throwable> main(
RemoteFileServer stub,
String sendFileName,
List<List<File>> tempFiles,
boolean doAbort,
boolean reverse,
boolean doSkip,
boolean unreliable,
boolean doFastTests,
List<AccumulateRemoteStreamMonitor<?>> monitors)
{
List<Throwable> exceptions = new ArrayList<Throwable>();
// try uncompressed get (possibly aborted/skipped)
try {
if(!reverse) {
getFile(stub, false, tempFiles, false, doAbort, doSkip, false);
} else {
getFileReverse(stub, unreliable, false, tempFiles, false, doAbort,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
if(doFastTests) {
return exceptions;
}
// try compressed get (possibly aborted/skipped)
try {
if(!reverse) {
getFile(stub, true, tempFiles, false, doAbort, doSkip, false);
} else {
getFileReverse(stub, unreliable, true, tempFiles, false, doAbort,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
if(!doAbort && !doSkip) {
// try partial uncompressed get
try {
if(!reverse) {
getFile(stub, false, tempFiles, true, false, false, false);
} else {
getFileReverse(stub, unreliable, false, tempFiles, true, false,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
// try partial compressed get
try {
if(!reverse) {
getFile(stub, true, tempFiles, true, false, false, false);
} else {
getFileReverse(stub, unreliable, true, tempFiles, true, false,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
// try compressed get using serializable stream
try {
if(!reverse) {
getFile(stub, true, tempFiles, false, false, false, true);
} else {
getFileReverse(stub, unreliable, true, tempFiles, false, false,
true, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
}
if(!doSkip) {
// try uncompressed send (possibly aborted)
try {
if(!reverse) {
sendFile(stub, sendFileName, false, false, doAbort, false);
} else {
sendFileReverse(stub, sendFileName, unreliable, false, false,
doAbort, false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
// try compressed send (possibly aborted)
try {
if(!reverse) {
sendFile(stub, sendFileName, true, false, doAbort, false);
} else {
sendFileReverse(stub, sendFileName, unreliable, true, false, doAbort,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
if(!doAbort) {
// try partial uncompressed send
try {
if(!reverse) {
sendFile(stub, sendFileName, false, true, false, false);
} else {
sendFileReverse(stub, sendFileName, unreliable, false, true, false,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
// try partial compressed send
try {
if(!reverse) {
sendFile(stub, sendFileName, true, true, false, false);
} else {
sendFileReverse(stub, sendFileName, unreliable, true, true, false,
false, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
// try compressed send using serializable stream
try {
if(!reverse) {
sendFile(stub, sendFileName, true, false, false, true);
} else {
sendFileReverse(stub, sendFileName, unreliable, true, false, false,
true, monitors);
}
} catch(Throwable t) {
exceptions.add(t);
}
}
}
return exceptions;
}
public static void main(String args[])
{
String sendFileName = args[0];
String host = (args.length < 2) ? null : args[1];
try {
Registry registry = LocateRegistry.getRegistry(host);
RemoteFileServer stub = (RemoteFileServer)
registry.lookup("RemoteFileServer");
main(stub, sendFileName, null, false, false, false, false, false,
null);
} catch (Exception e) {
LOG.debug("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
private static class UnreliableRemoteInputStreamServer
extends RemoteStreamServer<RemoteInputStreamServer, RemoteInputStream>
implements RemoteInputStream
{
private static final long serialVersionUID = 0L;
private int _lastExPre = 1;
private int _lastExPost = 1;
private RemoteInputStreamServer _in;
public UnreliableRemoteInputStreamServer(
RemoteInputStreamServer in)
{
super(RemoteInputStreamServer.DUMMY_MONITOR);
_in = in;
}
private void beUnreliable(boolean pre)
throws RemoteException
{
if(pre) {
if(((_lastExPre++) % 9) == 0) {
throw new RemoteException("TESTING(PRE)");
}
} else {
if(((_lastExPost++) % 3) == 0) {
throw new RemoteException("TESTING(POST)");
}
}
}
public boolean usingGZIPCompression()
throws IOException
{
beUnreliable(true);
try {
return _in.usingGZIPCompression();
} finally {
beUnreliable(false);
}
}
public int available()
throws IOException
{
beUnreliable(true);
try {
return _in.available();
} finally {
beUnreliable(false);
}
}
public void close(boolean readSuccess)
throws IOException
{
beUnreliable(true);
try {
_monitor.closed(_in, true);
_in.close(readSuccess);
} finally {
beUnreliable(false);
}
}
public byte[] readPacket(int packetId)
throws IOException
{
beUnreliable(true);
try {
_monitor.bytesMoved(_in, 0, false);
return _in.readPacket(packetId);
} finally {
beUnreliable(false);
}
}
public long skip(long n, int skipId)
throws IOException
{
beUnreliable(true);
try {
_monitor.bytesSkipped(_in, 0, false);
return _in.skip(n, skipId);
} finally {
beUnreliable(false);
}
}
@Override
protected RemoteInputStreamServer getAsSub()
{ return _in.getAsSub(); }
@Override
public Class<RemoteInputStream> getRemoteClass() {
return RemoteInputStream.class;
}
@Override
protected Object getLock() { return _in.getLock(); }
@Override
protected void closeImpl(boolean writeSuccess)
throws IOException
{ _in.closeImpl(writeSuccess); }
}
private static class UnreliableRemoteOutputStreamServer
extends RemoteStreamServer<RemoteOutputStreamServer, RemoteOutputStream>
implements RemoteOutputStream
{
private static final long serialVersionUID = 0L;
private int _lastExPre = 1;
private int _lastExPost = 1;
private RemoteOutputStreamServer _out;
public UnreliableRemoteOutputStreamServer(
RemoteOutputStreamServer out)
{
super(RemoteOutputStreamServer.DUMMY_MONITOR);
_out = out;
}
private void beUnreliable(boolean pre)
throws RemoteException
{
if(pre) {
if(((_lastExPre++) % 9) == 0) {
throw new RemoteException("TESTING(PRE)");
}
} else {
if(((_lastExPost++) % 3) == 0) {
throw new RemoteException("TESTING(POST)");
}
}
}
public boolean usingGZIPCompression()
throws IOException
{
beUnreliable(true);
try {
return _out.usingGZIPCompression();
} finally {
beUnreliable(false);
}
}
public void close(boolean writeSuccess)
throws IOException
{
beUnreliable(true);
try {
_monitor.closed(_out, true);
_out.close(writeSuccess);
} finally {
beUnreliable(false);
}
}
public void flush()
throws IOException
{
beUnreliable(true);
try {
_out.flush();
} finally {
beUnreliable(false);
}
}
public void writePacket(byte[] packet, int packetId)
throws IOException
{
beUnreliable(true);
try {
_monitor.bytesMoved(_out, 0, false);
_out.writePacket(packet, packetId);
} finally {
beUnreliable(false);
}
}
@Override
protected RemoteOutputStreamServer getAsSub()
{ return _out.getAsSub(); }
@Override
public Class<RemoteOutputStream> getRemoteClass() {
return RemoteOutputStream.class;
}
@Override
protected Object getLock() { return _out.getLock(); }
@Override
protected void closeImpl(boolean writeSuccess)
throws IOException
{ _out.closeImpl(writeSuccess); }
}
private static class DummyIOStream
implements RemoteOutputStream, RemoteInputStream
{
private int _numCloses;
public boolean usingGZIPCompression()
throws RemoteException
{
return false;
}
public void close(boolean transferSuccess)
throws IOException, RemoteException
{
++_numCloses;
}
public void flush()
throws IOException, RemoteException
{
}
public void writePacket(byte[] packet, int packetId)
throws IOException, RemoteException
{
}
public int available()
throws IOException, RemoteException
{
return 0;
}
public byte[] readPacket(int packetId)
throws IOException, RemoteException
{
return null;
}
public long skip(long n, int skipId)
throws IOException, RemoteException
{
return 0;
}
}
}