Jeff,

I agree that the test was not robust in the face of exceptions
in the isIdentical method.  I have attached an updated version
of the test client which is more robust.  However, it is a
little optimistic to say that PowerTier would have passed 99% of
the tests, without running the tests.  Please run the updated
test client and provide the results.

Also, how are other vendors doing on the tests?  We have not
yet heard about:

        BEA's WebLogic Enterprise
        BEA's WebLogic Server running over IIOP
        IBM's WebSphere
        Oracle's Application Server
        SUN/AOL/Netscape's iPlanet
        Sybase's EA Server

At this point, I would have to be pessimistic and assume that
a lack of results would indicate a lack of compliance.  A number
of vendors were very quick to respond that their products passed
the tests (and, again, congrats).  How about the silent ones?

-jkw

Jeff Mischkinsky wrote:
>
> Hi Jonathon,
>     We did some investigation into why you got the results you did, which
> needless to say, was a great puzzlement. It turns out that we discovered a
> problem with the implementation of EJBObject.isIdentical() for stateless
> session beans that was making it look as if the some of the tests were
> failing.
>
> So a more accurate characterization is that PowerTier 6 passes 99.36% since
> it only fails one test (the EJBObject.isIdentical() for stateless session
> beans). This defect has been fixed and a subsequent release will be issued
> soon that passes 100% of the tests.
>
> Thanks for taking the time to gather and collect this information.
>
> cheers,
>     jeff
>
> >Date:    Fri, 14 Apr 2000 11:49:45 -0700
> >From:    "Jonathan K. Weedon" <[EMAIL PROTECTED]>
> >Subject: Re: Why smoke signals matter
> >MIME-Version: 1.0
> >Content-Type: text/plain; charset=us-ascii
> >Content-Transfer-Encoding: 7bit
> >
> >Jon,
> >
> >Great results!
> >
> >To summarize, we now have:
> >
> >Bluestone Software EJB 1.1 Server:              100%  tests passed
> >Unify eWave Engine 1.1b:                        100%  tests passed
> >Sun's Reference Implementation:                 100%  tests passed
> >Inprise Application Server version 4.0:         100%  tests passed
> >BEA's WebLogic Server version 4.51:             99.3% tests passed
> >BEA's WebLogic Server version 5.0.0b2 (T3):     99.3% tests passed
> >Persistence's PowerTier 5.12:                   70.5% tests passed
> >IONA's iPortal:                                 58.3% tests passed
> >
> >How about some of those other products out there?  Is anybody
> >acutally using them?  If you are squeamish about posting negative
> >results, feel free to send them directly to me, and I can post
> >them after removing your name and/or your company name.
> >
> >-jkw
>
> Jeff Mischkinsky                   email: [EMAIL PROTECTED]
> Senior Software Architect
> Persistence Software, Inc.         voice: +1(650)372-3604
> 1720 S. Amphlett Blvd.             fax:   +1(650)341-8432
> San Mateo, CA 04402                web:   http://www.persistence.com
>
> ===========================================================================
> To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
> of the message "signoff EJB-INTEREST".  For general help, send email to
> [EMAIL PROTECTED] and include in the body of the message "help".
// RmiTestClient.java

import java.io.*;
import java.rmi.*;
import java.util.*;
import javax.ejb.*;
import javax.naming.*;
import javax.rmi.*;

public class RmiTestClient {

  final static boolean debug = System.getProperty("debug") != null;

  static RmiTest rmiTest;

  static int testsRun    = 0;
  static int testsPassed = 0;
  static int testsFailed = 0;
  static int testsTotal  = 156;

  private interface Verifier {
    void verify(Object arg, Object result) throws Exception;
  }

  public static void main(String[] args) throws Exception {

    // get a JNDI context...
    // you may have to modify this code if the given server
    // does not support JNDI 1.2, which should allow the
    // naming context to be created using the initial context's
    // default constructor...
    Context context = new InitialContext();

    RmiTestHome rmiTestHome = (RmiTestHome)
      PortableRemoteObject.narrow(context.lookup("rmiTest"), RmiTestHome.class);

    rmiTest = rmiTestHome.create();

    int beforeTestsFailed = testsFailed;
    try { // testing int
      // we pass various values for int, and make sure the server sends
      // back the same value.  If an AppServer can't do this, it is
      // likely misinstalled or misconfigured.
      assert(rmiTest.test_int(0) == 0);
      assert(rmiTest.test_int(1) == 1);
      assert(rmiTest.test_int(-1) == -1);
      assert(rmiTest.test_int(Integer.MIN_VALUE) == Integer.MIN_VALUE);
      assert(rmiTest.test_int(Integer.MAX_VALUE) == Integer.MAX_VALUE);
    }
    catch(Throwable e) {
      error(e);
    }
    message("int ", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing int[]
      // construct an array of ints, and send over various values.
      // then check that what gets sent back has the same set of
      // values
      int[] before = { 0, 1, -1, Integer.MIN_VALUE, Integer.MAX_VALUE };
      int[] after = rmiTest.test_ints(before);
      assert(before.length == after.length);
      for(int i = 0; i < before.length; i++) {
        assert(before[i] == after[i]);
      }
      // see if the null array is supported, as required by RMI
      assert(rmiTest.test_ints(null) == null);
    }
    catch(Throwable e) {
      error(e);
    }
    message("int[]", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing String
      // see if just a string is supported
      assert(rmiTest.test_String("Hello").equals("Hello"));
      // see if the null string is supported
      assert(rmiTest.test_String(null) == null);
      // see if Unicode strings are supported
      assert(rmiTest.test_String("\u4e2d\u56fd").equals("\u4e2d\u56fd"));
    }
    catch(Throwable e) {
      error(e);
    }
    message("String", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing String[]
      {
        // see if we can send an array of strings, including the
        // null string
        String[] before = { "Hello", "World", null };
        String[] after = rmiTest.test_Strings(before);
        assert(before.length == after.length);
        for(int i = 0; i < before.length; i++) {
          // make sure each value is either pointer equivalent
          // or value equivalent.  Either will do.
          assert(before[i] == after[i] || before[i].equals(after[i]));
        }
      }
      {
        // if we send multiple instances of the same string in an
        // array,  then when we get it back, the parameters should
        // still be pointer equal
        String s = "Hello";
        String[] before = { s, s };
        String[] after = rmiTest.test_Strings(before);
        assert(before.length == after.length);
        // object identity should be preserved in RMI
        assert(after[0] == after[1]);
      }
    }
    catch(Throwable e) {
      error(e);
    }
    message("String[]", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing remote object references
      // here we check that if we pass a reference to a remote object
      // it isIdentical to its original value
      Verifier verifier = new Verifier() {
        public void verify(Object arg, Object result) throws Exception {
          {
            EJBObject a = (EJBObject) PortableRemoteObject.narrow(arg, 
EJBObject.class);
            EJBObject b = (EJBObject) PortableRemoteObject.narrow(result, 
EJBObject.class);
            // make sure the objects are identical...
            assert(compare(a, b));
          }
          {
            RmiTest a = (RmiTest) PortableRemoteObject.narrow(arg, RmiTest.class);
            RmiTest b = (RmiTest) PortableRemoteObject.narrow(result, RmiTest.class);
            // make sure the objects are identical...
            assert(compare(a, b));
          }
        }
      };
      test(rmiTest, verifier);
    }
    catch(Throwable e) {
      error(e);
    }
    message("EJBObject", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing home object references
      // for home references, we can only check that after passing the
      // reference to the server and back, that it still points to the
      // same home class.  There is no equality test for home references.
      Verifier verifier = new Verifier() {
        public void verify(Object arg, Object result) throws Exception {
          {
            EJBHome home = (EJBHome) PortableRemoteObject.narrow(result, 
EJBHome.class);
            
assert(home.getEJBMetaData().getHomeInterfaceClass().equals(RmiTestHome.class));
          }
          {
            RmiTestHome home = (RmiTestHome) PortableRemoteObject.narrow(result, 
RmiTestHome.class);
            
assert(home.getEJBMetaData().getHomeInterfaceClass().equals(RmiTestHome.class));
          }
        }
      };
      test(rmiTestHome, verifier);
    }
    catch(Throwable e) {
      error(e);
    }
    message("EJBHome", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing Vector
      // this is the most complex test: basically, we construct
      // a Vector, and put all sorts of stuff into it.  Then we
      // check that the Vector passed back from the server still
      // contais the same stuff, with all the correct semantics
      // as required by RMI
      Verifier verifier = new Verifier() {
        public void verify(Object arg, Object result) throws Exception {
          Vector vector = (Vector) result;
          assert(vector.size() == 8);
          assert(vector.elementAt(0).equals("Hello"));
          assert(vector.elementAt(0) == vector.elementAt(1));
          assert(vector.elementAt(2).equals(new Integer(1)));
          assert(vector.elementAt(3).equals(new Date(1234)));
          RmiTest tmpRmiTest = (RmiTest)
            PortableRemoteObject.narrow(vector.elementAt(4), RmiTest.class);
          assert(compare(tmpRmiTest, rmiTest));
          RmiTestHome tmpRmiTestHome = (RmiTestHome)
            PortableRemoteObject.narrow(vector.elementAt(5), RmiTestHome.class);
          
assert(tmpRmiTestHome.getEJBMetaData().getHomeInterfaceClass().equals(RmiTestHome.class));
          Hashtable hashtable = (Hashtable) vector.elementAt(6);
          assert(hashtable.keys().nextElement() == vector.elementAt(0));
          assert(hashtable.elements().nextElement() == vector.elementAt(0));
          Object[] array = (Object[]) vector.elementAt(7);
          for(int i = 0; i < array.length; i++) {
            assert(array[i] == vector.elementAt(i));
          }
        }
      };
      Vector vector = new Vector();
      // add an item twice
      String s = "Hello";
      vector.add(s);
      vector.add(s);
      // add a couple different items
      vector.add(new Integer(1));
      vector.add(new Date(1234));
      // add some object references
      vector.add(rmiTest);
      vector.add(rmiTestHome);
      // add a hashtable containing the above string
      Hashtable hashtable = new Hashtable();
      hashtable.put(s, s);
      vector.add(hashtable);
      // finally, add an array containing the already added stuff...
      Object[] array = new Object[vector.size()];
      for(int i = 0; i < array.length; i++) {
        array[i] = vector.elementAt(i);
      }
      vector.add(array);
      test(vector, verifier);
    }
    catch(Throwable e) {
      error(e);
    }
    message("Vector(1)", beforeTestsFailed);

    beforeTestsFailed = testsFailed;
    try { // testing tree of Vectors
      // this test checks that deeply nested complex data retains
      // its validity, when send over the wire.
      Verifier verifier = new Verifier() {
        public void verify(Object arg, Object result) throws Exception {
          Vector vector = (Vector) result;
          for(int i = 0; i < 10; i++) {
            // each parent node should have two identical vectors
            assert(vector.size() == 2);
            assert(vector.elementAt(0) == vector.elementAt(1));
            vector = (Vector) vector.elementAt(0);
          }
          // the last child node should be empty
          assert(vector.size() == 0);
        }
      };
      Vector child = new Vector();
      for(int i = 0; i < 10; i++) {
        Vector parent = new Vector();
        parent.addElement(child);
        parent.addElement(child);
        child = parent;
      }
      test(child, verifier);
    }
    catch(Throwable e) {
      error(e);
    }
    message("Vector(2)", beforeTestsFailed);

    rmiTest.remove();

    System.out.println();
    { // print out the results
      String[] title = {
        "    Ran",
        "Skipped",
        " Passed",
        " Failed",
      };
      int[] value = {
        testsRun,
        testsTotal - testsRun,
        testsPassed,
        testsFailed,
      };
      for(int i = 0; i < title.length; i++) {
        String pad = value[i] < 10 ? "  " : value[i] < 100 ? " " : "";
        System.out.println(title[i] + " " + pad + value[i] + "/" + testsTotal + " 
tests:  " +
                           (1000 * value[i] / testsTotal) / 10f + "%");
      }
    }
  }

  private static void message(String type, int beforeTestsFailed) {
    String outcome = beforeTestsFailed == testsFailed ? "PASSED" : "** FAILED **";
    System.out.println("Support for " + type + "\t" + outcome);
  }

  private static void assert(boolean assertion) {
    if(assertion == true) {
      testsRun++;
      testsPassed++;
    }
    else {
      error(new Error("Test Failed"));
    }
  }

  private static void error(Throwable t) {
    testsRun++;
    testsFailed++;
    if(debug) {
      t.printStackTrace(System.err);
    }
  }

  private static boolean compare(javax.ejb.EJBObject lhs, javax.ejb.EJBObject rhs) {
    try {
      return lhs.isIdentical(rhs);
    }
    catch(Throwable t) {
      if(debug) {
        t.printStackTrace(System.err);
      }
      return false;
    }
  }

  private static void test(Object arg, Verifier verifier) throws Exception {
    try { // test Object
      Object result = rmiTest.test_Object(arg);
      verifier.verify(result, arg);
    }
    catch(Throwable e) {
      error(e);
    }

    try { // test Object[]
      Object[] args = { arg };
      Object[] result = rmiTest.test_Objects(args);
      assert(args.length == result.length);
      verifier.verify(result[0], args[0]);
    }
    catch(Throwable e) {
      error(e);
    }

    if(Vector.class.isAssignableFrom(arg.getClass())) {
      try {
        Vector result = rmiTest.test_Vector((Vector) arg);
        verifier.verify(result, arg);
      }
      catch(Throwable e) {
        error(e);
      }
    }

    if(Remote.class.isAssignableFrom(arg.getClass())) {
      try {
        Remote result = rmiTest.test_Remote((Remote) arg);
        verifier.verify(result, arg);
      }
      catch(Throwable e) {
        error(e);
      }
    }

    if(EJBObject.class.isAssignableFrom(arg.getClass())) {
      try {
        EJBObject result = rmiTest.test_EJBObject((EJBObject) arg);
        verifier.verify(result, arg);
      }
      catch(Throwable e) {
        error(e);
      }
    }

    if(EJBHome.class.isAssignableFrom(arg.getClass())) {
      try {
        EJBHome result = rmiTest.test_EJBHome((EJBHome) arg);
        verifier.verify(result, arg);
      }
      catch(Throwable e) {
        error(e);
      }
    }

    if(RmiTest.class.isAssignableFrom(arg.getClass())) {
      try {
        RmiTest result = rmiTest.test_RmiTest((RmiTest) arg);
        verifier.verify(result, arg);
      }
      catch(Throwable e) {
        error(e);
      }
    }

    if(RmiTestHome.class.isAssignableFrom(arg.getClass())) {
      try {
        RmiTestHome result = rmiTest.test_RmiTestHome((RmiTestHome) arg);
        verifier.verify(result, arg);
      }
      catch(Throwable e) {
        error(e);
      }
    }
  }

}

Reply via email to