package conformance.rmi; import test.*; import rmi.*; import java.net.*; /** Performs basic tests on the public interface of {@link rmi.Skeleton}.

The tests performed are:

*/ public class SkeletonTest extends Test { /** Test notice. */ public static final String notice = "checking skeleton public interface"; /** Socket address used for the creation of skeletons. */ private final InetSocketAddress address; /** Dummy object used for testing calls to Skeleton constructors. */ private final BadInterfaceImplementation dummy_server; /** Regular server object. */ private final TestServer server; /** The main skeleton used for testing. */ private final TestSkeleton skeleton; /** Indicates whether the skeleton has stopped. */ private boolean stopped; /** Creates a SkeletonTest object. */ public SkeletonTest() { address = new InetSocketAddress(7000); dummy_server = new BadInterfaceImplementation(); server = new TestServer(); skeleton = new TestSkeleton(); stopped = false; } /** Performs the test. */ @Override protected void perform() throws TestFailed { ensureClassRejected(); ensureNonRemoteInterfaceRejected(); ensureNullPointerExceptions(); ensureSkeletonRuns(); } /** Performs tests with a running skeleton.

This method starts the skeleton and then stops it. In between, it probes to see if the skeleton is accepting connections. */ private void ensureSkeletonRuns() throws TestFailed { if(probe()) throw new TestFailed("skeleton accepts connections before start"); try { skeleton.start(); } catch(RMIException e) { throw new TestFailed("unable to start skeleton", e); } if(!probe()) throw new TestFailed("skeleton refuses connections after start"); skeleton.stop(); synchronized(this) { while(!stopped) { try { wait(); } catch(InterruptedException e) { } } } if(probe()) throw new TestFailed("skeleton accepts connections after stop"); } /** Wakes ensureSkeletonRuns. */ private synchronized void wake() { stopped = true; notifyAll(); } /** Checks that it is possible to connect to the server. @return true if the connection can be established, and false if it cannot be. */ private boolean probe() { Socket socket = new Socket(); try { socket.connect(address); } catch(Exception e) { return false; } try { socket.close(); } catch(Exception e) { } return true; } /** Stops the skeleton server, if it is running, and attempts to wake the test main thread. */ @Override protected void clean() { skeleton.stop(); wake(); } /** Ensures that a Skeleton cannot be constructed from a class rather than an interface. @throws TestFailed If a Skeleton is constructed from a class, or if an unexpected exception occurs. */ private void ensureClassRejected() throws TestFailed { try { Skeleton bad_skeleton = new Skeleton(Object.class, dummy_server); throw new TestFailed("Skeleton(Class, T) constructor has " + "accepted a class"); } catch(TestFailed e) { throw e; } catch(Error e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T) constructor threw " + "an unexpected exception when given a " + "class", t); } try { Skeleton bad_skeleton = new Skeleton(Object.class, dummy_server, address); throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor has accepted a class"); } catch(TestFailed e) { throw e; } catch(Error e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor threw an unexpected exception " + "when given a class", t); } } /** Ensures that a Skeleton cannot be constructed from a non-remote interface. @throws TestFailed If a Skeleton is constructed from a non-remote interface, or if an unexpected exception occurs. */ private void ensureNonRemoteInterfaceRejected() throws TestFailed { try { Skeleton bad_skeleton = new Skeleton(BadInterface.class, dummy_server); throw new TestFailed("Skeleton(Class, T) constructor has " + "accepted a non-remote interface"); } catch(TestFailed e) { throw e; } catch(Error e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T) constructor threw " + "an unexpected exception when given a " + "non-remote interface", t); } try { Skeleton bad_skeleton = new Skeleton(BadInterface.class, dummy_server, address); throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor has accepted a non-remote " + "interface"); } catch(TestFailed e) { throw e; } catch(Error e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor threw an unexpected exception " + "when given a non-remote interface", t); } } /** Ensures that Skeleton constructors throw NullPointerException when given null for the class or server parameters. @throws TestFailed If null is given as a parameter but the correct exception is not thrown. */ private void ensureNullPointerExceptions() throws TestFailed { // Make sure that null for the first argument is rejected. try { Skeleton bad_skeleton = new Skeleton(null, server); throw new TestFailed("Skeleton(Class, T) constructor " + "accepted null for first argument"); } catch(TestFailed e) { throw e; } catch(NullPointerException e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T) constructor threw " + "an unexpected exception when given null " + "for first argument", t); } try { Skeleton bad_skeleton = new Skeleton(null, server, address); throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor accepted null for first " + "argument"); } catch(TestFailed e) { throw e; } catch(NullPointerException e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor threw an unexpected exception " + "when given null for first argument", t); } // Make sure that null for the second argument is rejected. try { Skeleton bad_skeleton = new Skeleton(TestInterface.class, null); throw new TestFailed("Skeleton(Class, T) constructor " + "accepted null for second argument"); } catch(TestFailed e) { throw e; } catch(NullPointerException e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T) constructor threw " + "an unexpected exception when given null " + "for second argument", t); } try { Skeleton bad_skeleton = new Skeleton(TestInterface.class, null, address); throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor accepted null for second " + "argument"); } catch(TestFailed e) { throw e; } catch(NullPointerException e) { } catch(Throwable t) { throw new TestFailed("Skeleton(Class, T, InetSocketAddress) " + "constructor threw an unexpected exception " + "when given null for second argument", t); } } /** Derivative of Skeleton which notifies the test when it stops.

Service thread errors are ignored because, in this test, their source is generally the probe method. */ private class TestSkeleton extends Skeleton { /** Creates a TestSkeleton */ TestSkeleton() { super(TestInterface.class, server, address); } /** Wakes the testing main thread. */ @Override protected void stopped(Throwable cause) { wake(); } /** Handles an error in the listening thread. */ @Override protected boolean listen_error(Exception e) { failure(new TestFailed("error in skeleton listening thread", e)); return false; } } /** Dummy implementation of BadInterface. */ private class BadInterfaceImplementation implements BadInterface { /** Returns its argument. */ @Override public Object method(int argument) { return argument; } } }