public static void main(String args[]) {
    /*
     * The following line is required with the JDK 1.2 VM so that the
     * VM can exit gracefully when this test completes.  Otherwise, the
     * conservative garbage collector will find a handle to the server
     * object on the native stack and not clear the weak reference to
     * it in the RMI runtime's object table.
     */
    Object dummy1 = new Object();
    RMID rmid = null;

    System.err.println("\nRegression test for bug/rfe 4109103\n");

    try {

      // Set security manager according to the
      // testlibrary.
      TestLibrary.suggestSecurityManager(TestParams.defaultSecurityManager);

      // start an rmid.
      RMID.removeLog();
      rmid = RMID.createRMID(rmidOut, rmidErr, false);
      rmid.start();

      /* Cause activation groups to have a security policy that will
       * allow security managers to be downloaded and installed
       */
      Properties p = new Properties();
      // this test must always set policies/managers in its
      // activation groups
      p.put("java.security.policy", TestParams.defaultGroupPolicy);
      p.put("java.security.manager", TestParams.defaultSecurityManager);

      /* new desc - we will reuse in order to get multiple vms.*/
      System.err.println("Create activation group in this VM");
      ActivationGroupDesc groupDesc = new ActivationGroupDesc(p, null);
      ActivationSystem system = ActivationGroup.getSystem();
      ActivationGroupID groupID = system.registerGroup(groupDesc);
      ActivationGroup.createGroup(groupID, groupDesc, 0);

      ActivationDesc desc = new ActivationDesc("CheckAnnotations", null, null);
      myRMI = (MyRMI) Activatable.register(desc);

      /* The test-
       * Loop a bunch of times to force activator to
       * spawn VMs (groups)
       */
      for (int i = 0; i < 3; i++) {

        // object activated in annotation check via method call
        if (!checkAnnotations(i - 1)) {
          TestLibrary.bomb("Test failed: output improperly annotated.");
        }

        /*
         * Clean up object too.
         */
        System.err.println("Deactivate object via method call");
        myRMI.shutdown();
      }
      System.err.println("\nsuccess: CheckAnnotations test passed ");

    } catch (Exception e) {
      TestLibrary.bomb("\nfailure: unexpected exception ", e);
    } finally {
      try {
        Thread.sleep(4000);
      } catch (InterruptedException e) {
      }

      myRMI = null;
      System.err.println("rmid shut down");
      ActivationLibrary.rmidCleanup(rmid);
    }
  }
  /** check to make sure that the output from a spawned vm is formatted/annotated properly. */
  public static boolean checkAnnotations(int iteration) throws IOException {
    try {
      Thread.sleep(5000);
    } catch (Exception e) {
      System.err.println(e.getMessage());
    }

    /**
     * cause the spawned vm to generate output that will be checked for proper annotation. printOut
     * is actually being called on an activated implementation.
     */
    myRMI.printOut("out" + iteration);
    myRMI.printErr("err" + iteration);
    myRMI.printOut("out" + iteration);
    myRMI.printErr("err" + iteration);

    /* we have to wait for output to filter down
     * from children so we can read it before we
     * kill rmid.
     */

    String outString = null;
    String errString = null;

    for (int i = 0; i < 5; i++) {
      // have to give output from rmid time to trickle down to
      // this process
      try {
        Thread.sleep(4000);
      } catch (InterruptedException e) {
      }

      outString = rmidOut.toString();
      errString = rmidErr.toString();

      if ((!outString.equals("")) && (!errString.equals(""))) {
        System.err.println("obtained annotations");
        break;
      }
      System.err.println("rmid output not yet received, retrying...");
    }

    rmidOut.reset();
    rmidErr.reset();

    // only test when we are annotating..., first run does not annotate
    if (iteration >= 0) {
      System.err.println("Checking annotations...");
      System.err.println(outString);
      System.err.println(errString);

      StringTokenizer stOut = new StringTokenizer(outString, ":");
      StringTokenizer stErr = new StringTokenizer(errString, ":");

      String execErr = null;
      String execOut = null;
      String destOut = null;
      String destErr = null;
      String outTmp = null;
      String errTmp = null;

      while (stOut.hasMoreTokens()) {
        execOut = outTmp;
        outTmp = destOut;
        destOut = stOut.nextToken();
      }
      while (stErr.hasMoreTokens()) {
        execErr = errTmp;
        errTmp = destErr;
        destErr = stErr.nextToken();
      }

      if ((execErr == null) || (errTmp == null) || (destErr == null)) {
        return false;
      }
      if ((execOut == null) || (outTmp == null) || (destOut == null)) {
        return false;
      }

      // just make sure that last two strings are what we expect.
      if (execOut.equals("ExecGroup-" + iteration)
          && (new String(destOut.substring(0, 4)).equals("out" + iteration))
          && (execErr.equals("ExecGroup-" + iteration))
          && (new String(destErr.substring(0, 4)).equals("err" + iteration))) {
        return true;
      } else {
        return false;
      }
    }
    return true;
  }