You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@river.apache.org by pe...@apache.org on 2012/01/21 08:28:36 UTC

svn commit: r1234278 [13/29] - in /river/tck: ./ configs/ doc/ doc/api/ doc/api/com/ doc/api/com/sun/ doc/api/com/sun/jini/ doc/api/com/sun/jini/compat/ doc/api/com/sun/jini/compat/admin1/ doc/api/com/sun/jini/compat/admin2/ doc/api/com/sun/jini/compat...

Added: river/tck/src/com/sun/jini/compat/admin2/ServiceDestroyer.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/admin2/ServiceDestroyer.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/admin2/ServiceDestroyer.java (added)
+++ river/tck/src/com/sun/jini/compat/admin2/ServiceDestroyer.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,163 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.admin2;
+
+import net.jini.admin.Administrable;
+
+import com.sun.jini.admin.DestroyAdmin;
+import com.sun.jini.start.SharedActivatableServiceDescriptor;
+
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.UnknownObjectException;
+import java.rmi.activation.ActivationGroup;
+import java.rmi.RemoteException;
+
+/** 
+ * This class provides static methods that can be used to destroy a service.
+ */
+public class ServiceDestroyer {
+
+    public static final int DESTROY_SUCCESS = 0;
+    /* Failure return codes */
+    public static final int SERVICE_NOT_ADMINISTRABLE = -1;
+    public static final int SERVICE_NOT_DESTROY_ADMIN = -2;
+    public static final int DEACTIVATION_TIMEOUT      = -3;
+    public static final int PERSISTENT_STORE_EXISTS   = -4;
+
+    /**
+     * Administratively destroys the service referenced by the input
+     * parameter. The service input to this method must implement
+     * both <code>net.jini.admin.Administrable</code> and the
+     * <code>com.sun.jini.admin.DestroyAdmin</code> interfaces
+     * in order for this method to successfully destroy the service.
+     *
+     * @param service reference to the service to destroy
+     *
+     * @return <code>int</code> value that indicates either success or 
+     *         one of a number of possible reasons for failure to destroy
+     *         the service. Possible values are:
+     * <p><ul>
+     *   <li> ServiceDestroyer.DESTROY_SUCCESS
+     *   <li> ServiceDestroyer.SERVICE_NOT_ADMINISTRABLE - returned when
+     *        the service to destroy is not an instance of 
+     *        net.jini.admin.Administrable
+     *   <li> ServiceDestroyer.SERVICE_NOT_DESTROY_ADMIN - returned when
+     *        the service to destroy is not an instance of 
+     *        com.sun.jini.admin.DestroyAdmin
+     * </ul>
+     * 
+     * @throws java.rmi.RemoteException typically, this exception occurs when
+     *         there is a communication failure between the client and the
+     *         service's backend. When this exception does occur, the
+     *         service may or may not have been successfully destroyed.
+     */
+    public static int destroy(Object service) throws RemoteException {
+        /* First, test that the service implements both of the appropriate
+         * administration interfaces
+         */
+        DestroyAdmin destroyAdmin = null;
+        if( !(service instanceof Administrable) ) {
+            return SERVICE_NOT_ADMINISTRABLE;
+        }
+        Object admin = ((Administrable)service).getAdmin();
+        if( !(admin instanceof DestroyAdmin) ) {
+            return SERVICE_NOT_DESTROY_ADMIN;
+        }
+        destroyAdmin = (DestroyAdmin)admin;
+        destroyAdmin.destroy();
+        return DESTROY_SUCCESS;
+    }
+
+    /**
+     * Administratively destroys the service referenced by the
+     * <code>proxy</code> parameter, which is assumed to be running 
+     * under a shared VM environment. This method attempts to verify 
+     * that the desired service is indeed destroyed by verifying that
+     * the service's activation information/descriptor is no longer 
+     * registered with the activation system.
+     *
+     * @param created   the id of the activation group in which the service to
+     *                  destroy is registered, the activation ID of the 
+     *                  service to destroy, and the reference to the service 
+     *                  to destroy
+     * @param nSecsWait the number of seconds to wait for the service's 
+     *                  activation descriptor to be no longer registered with 
+     *                  the activation system
+     *
+     * @return <code>int</code> value that indicates either success or 
+     *         one of a number of possible reasons for failure to destroy
+     *         the service. Possible values are:
+     * <p><ul>
+     *   <li> ServiceDestroyer.DESTROY_SUCCESS
+     *   <li> ServiceDestroyer.SERVICE_NOT_ADMINISTRABLE - returned when
+     *        the service to destroy is not an instance of 
+     *        net.jini.admin.Administrable
+     *   <li> ServiceDestroyer.SERVICE_NOT_DESTROY_ADMIN - returned when
+     *        the service to destroy is not an instance of 
+     *        com.sun.jini.admin.DestroyAdmin
+     *   <li> ServiceDestroyer.DEACTIVATION_TIMEOUT - returned when the
+     *        service's activation descriptor is still registered with the
+     *        activation system after the number of seconds to wait have passed
+     *   <li> ServiceDestroyer.PERSISTENT_STORE_EXISTS - returned when the
+     *        directory in which the service stores its persistent state
+     *        still exists after the service has been successfully destroyed
+     * </ul>
+     * 
+     * @throws java.rmi.RemoteException typically, this exception occurs when
+     *         there is a communication failure between the client and the
+     *         service's backend. When this exception does occur, the
+     *         service may or may not have been successfully destroyed.
+     * @throws java.rmi.activation.ActivationException typically, this
+     *         exception occurs when problems arise while attempting to
+     *         interact with the activation system
+     */
+    public static int destroy(
+        SharedActivatableServiceDescriptor.Created created, int nSecsWait)
+	throws RemoteException, ActivationException
+    {
+	Object proxy = created.proxy;
+        int destroyCode = destroy(proxy);
+        if(destroyCode != DESTROY_SUCCESS) return destroyCode;
+        /* Verify the service has actually been destroyed by waiting until
+         * service's activation ID is no longer registered with the
+         * activation system.
+         *
+         * Since an exception will be thrown when an attempt is made to
+         * retrieve an activation descriptor for an ID which is not
+         * registered, this method makes repeated attempts to retrieve the
+         * activation descriptor until such an exception is thrown,
+         * or until the indicated number of seconds to wait has passed.
+         */
+        boolean deactivated = false;
+        for(int i = 0; i < nSecsWait; i++) {
+            try {
+                ActivationGroup.getSystem().getActivationDesc(created.aid);
+            } catch (UnknownObjectException e) {
+                deactivated = true;
+                break;
+            }
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) { }
+        }
+        if(!deactivated) return DEACTIVATION_TIMEOUT;
+        return DESTROY_SUCCESS;
+    }
+
+}
+

Propchange: river/tck/src/com/sun/jini/compat/admin2/ServiceDestroyer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/admin2/ServiceStarterAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/admin2/ServiceStarterAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/admin2/ServiceStarterAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/admin2/ServiceStarterAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,365 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+
+package com.sun.jini.compat.admin2;
+
+import java.rmi.RemoteException;
+import java.rmi.activation.ActivationException;
+import java.rmi.server.RMIClassLoader;
+import java.rmi.activation.ActivationGroupID;
+import java.io.IOException;
+import java.io.File;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import com.sun.jini.compat.harness.SysConfig;
+import com.sun.jini.compat.harness.Config;
+import com.sun.jini.compat.harness.BasicServiceAdmin;
+import com.sun.jini.compat.harness.BasicLookupAdmin;
+import com.sun.jini.compat.harness.TestUtility;
+
+import com.sun.jini.start.SharedGroup;
+import com.sun.jini.start.ServiceDescriptor;
+import com.sun.jini.start.NonActivatableServiceDescriptor;
+import com.sun.jini.start.SharedActivatableServiceDescriptor;
+import com.sun.jini.start.SharedActivationGroupDescriptor;
+import net.jini.core.lookup.ServiceRegistrar;
+import net.jini.core.lookup.ServiceItem;
+import net.jini.core.lookup.ServiceTemplate;
+import net.jini.core.lookup.ServiceID;
+import net.jini.config.Configuration;
+import net.jini.config.ConfigurationProvider;
+import net.jini.config.ConfigurationException;
+
+/**
+ * This class implements the BasicServiceAdmin and BasicLookupAdmin
+ * interfaces to automate the testing of any <b>activatable</b> program that can be 
+ * started by the ServiceStarter framework.  See the <code>start</code> method
+ * documentation for config file properties supported by this Admin.
+ */
+public class ServiceStarterAdmin implements BasicServiceAdmin, BasicLookupAdmin
+{
+
+    protected Config compatConfig;
+    protected SysConfig compatSysConfig;
+    protected PrintWriter log;
+
+    protected NonActivatableServiceDescriptor.Created nonActivatableCreated;
+    protected SharedActivatableServiceDescriptor.Created sharedCreated;
+    protected SharedActivatableServiceDescriptor.Created activatableCreated;
+    protected ActivationGroupID groupCreated;
+
+    protected Object proxy;
+
+    protected String groupLog;
+
+    /**
+     * Default constructor.
+     */
+    public ServiceStarterAdmin() {
+    }
+
+    /**
+     * Takes the Config object for this test run so that the implementation
+     * can get access to property files and other config information.
+     *
+     * @param conf the Config object for this test run
+     */
+    public void setConfig(Config config) {
+	compatConfig = config;
+	compatSysConfig = config.getSysConfig();
+        log = compatConfig.getLog();
+        if (log == null) {
+            log = new PrintWriter(System.out, true);
+        }
+    }
+
+    /**
+     * Returns the address of the host the program is running on by
+     * looking up the property com.sun.jini.compat.defaultAdmin.address.
+     * If that property is not specified the default is the host the
+     * LDJ Kit harness is running on.
+     *
+     * @return the address of the program
+     */
+    public InetAddress getAddress() throws RemoteException {
+        String addr = compatSysConfig.getStringConfigVal(
+            "com.sun.jini.compat.defaultAdmin.address", null);
+        try {
+            if(addr == null) {
+                return InetAddress.getLocalHost();
+            } else {
+                return InetAddress.getByName(addr);
+            }
+        } catch(UnknownHostException uhe) {
+            throw new RemoteException(addr + " is an unknown host", uhe);
+        }
+    }
+
+    /**
+     * Using the <code>ServiceStarter</code>, starts the program(s)
+     * specified in the service starter configuration file specified
+     * by the property <code>com.sun.jini.compat.admin2.starterConfig</code>.
+     * The following strings are passed to this configuration as overrides:
+     * <ul>
+     * <li><code>com.sun.jini.compat.admin2.jskHome</code>=
+     *     &lt;value of <code>com.sun.jini.compat.admin2.jskHome</code> system property&gt;
+     * <li><code>com.sun.jini.compat.admin2.javaHome</code>=
+     *     &lt;value of <code>com.sun.jini.compat.admin2.javaHome</code> system property&gt;
+     * <li><code>com.sun.jini.compat.admin2.groupLog</code>=
+     *     &lt;return value of <code>getGroupLog()</code> method call&gt;
+     * <li><code>com.sun.jini.compat.admin2.policyDir</code>=
+     *     &lt;value of the <code>com.sun.jini.compat.admin2.policyDir</code>
+     *     system property or, if <code>null</code>, the value of 
+     *     <code>com.sun.jini.compat.installDir</code> property + "/policy"&gt;
+     * <li><code>com.sun.jini.compat.admin2.persistenceDir</code>=
+     *     &lt;return value of <code>getPersistenceDir()</code> method call&gt;
+     * <li><code>com.sun.jini.compat.admin2.host</code>=
+     *     &lt;return value of <code>getAddress().getHostName()</code> method call&gt;
+     * </ul>
+     * See the example configuration files in the <code>configs</code> sub-directory
+     * of the LDJ Kit.  The <code>*-activatable.config</code> files 
+     * are used by this Admin to test services in the Jini starter kit.
+     */
+    public synchronized void start() throws RemoteException {
+	String starterConfig = compatSysConfig.getStringConfigVal(
+	    "com.sun.jini.compat.admin2.starterConfig", null);
+        if (compatConfig.getDebugLevel() == Config.ALL) {
+            log.println("Using " + starterConfig 
+                + " starter configuration file specified "
+                + "by the com.sun.jini.compat.admin2.starterConfig property");
+        }
+
+	String jskHome = compatSysConfig.getStringConfigVal(
+	    "com.sun.jini.compat.admin2.jskHome", null);
+	String javaHome = compatSysConfig.getStringConfigVal(
+	    "com.sun.jini.compat.admin2.javaHome", null);
+	String installDir = compatSysConfig.getStringConfigVal(
+	    "com.sun.jini.compat.installDir", null);
+	String policyDir = compatSysConfig.getStringConfigVal(
+	    "com.sun.jini.compat.admin2.policyDir", installDir + "/policy");
+
+        try {
+            Configuration config = ConfigurationProvider.getInstance(
+                new String[] { // config file followed by overrides
+                    starterConfig,
+                    "com.sun.jini.compat.admin2.jskHome=\"" + jskHome + "\"",
+                    "com.sun.jini.compat.admin2.javaHome=\"" + javaHome + "\"",
+                    "com.sun.jini.compat.admin2.groupLog=\"" 
+                        + getGroupLog() + "\"",
+                    "com.sun.jini.compat.admin2.policyDir=\"" + policyDir + "\"",
+                    "com.sun.jini.compat.admin2.persistenceDir=\"" 
+                        + getPersistenceDir() + "\"",
+                    "com.sun.jini.compat.admin2.host=\"" 
+                        + getAddress().getHostName() + "\""
+                },
+                this.getClass().getClassLoader());
+
+            ServiceDescriptor[] descs =  (ServiceDescriptor[])
+                config.getEntry("com.sun.jini.start", "serviceDescriptors",
+                    ServiceDescriptor[].class, null);
+
+            if (descs == null || descs.length == 0) {
+                log.println(starterConfig + " does not contain a "
+                    + "com.sun.jini.start.serviceDescriptors entry; "
+                    + "aborting");
+                System.exit(1);
+            }
+
+            // Non-activatable case: only 1 service descriptor must be present
+            if (descs.length == 1 &&
+                descs[0] instanceof NonActivatableServiceDescriptor) 
+            {
+                if (compatConfig.getDebugLevel() == Config.ALL) {
+                    log.println(descs[0].toString());
+                }
+                nonActivatableCreated = 
+                    (NonActivatableServiceDescriptor.Created) 
+                        descs[0].create(config);
+                proxy = nonActivatableCreated.proxy;
+
+            // Activatable case: only 3 service descriptors must be present
+            } else if (
+                descs.length == 3 &&
+                descs[0] instanceof SharedActivationGroupDescriptor &&
+                descs[1] instanceof SharedActivatableServiceDescriptor &&
+                descs[2] instanceof SharedActivatableServiceDescriptor)
+            {
+                if (compatConfig.getDebugLevel() == Config.ALL) {
+                    log.println("SharedActivationGroupDescriptor: " 
+                        + descs[0].toString());
+                }
+                groupCreated = (ActivationGroupID) descs[0].create(config);
+
+                if (compatConfig.getDebugLevel() == Config.ALL) {
+                    log.println("SharedActivatableServiceDescriptor:"
+                        + descs[1].toString());
+                }
+                sharedCreated = (SharedActivatableServiceDescriptor.Created)
+                    descs[1].create(config);
+
+                if (compatConfig.getDebugLevel() == Config.ALL) {
+                    log.println("SharedActivatableServiceDescriptor: "
+                        + descs[2].toString());
+                }
+                activatableCreated = 
+                    (SharedActivatableServiceDescriptor.Created)
+                        descs[2].create(config);
+
+                proxy = activatableCreated.proxy;
+
+            } else {
+                log.println(starterConfig + " contains wrong number "
+                        + "or type of ServiceDescriptors; aborting");
+                System.exit(1);
+            }
+
+        } catch (Exception e) {
+            if (compatConfig.getDebugLevel() >= Config.ERROR) {
+                log.println("Service creation exception: " + e);
+                e.printStackTrace();
+            }
+        }
+    }
+    
+    /**
+     * Stops the program.
+     *
+     * If the program is activatable and implements 
+     * <code>net.jini.admin.Administrable</code> and
+     * <code>com.sun.jini.admin.DestroyAdmin</code>
+     * then this method will make certain the program is 
+     * unregistered with the activation system before returning. 
+     */
+    public synchronized void stop() throws RemoteException {
+        int returnCode = ServiceDestroyer.DESTROY_SUCCESS;
+	try {
+
+            // stop non-activatable service (if non-null)
+	    if (nonActivatableCreated != null) {
+                returnCode = ServiceDestroyer.destroy(
+                    nonActivatableCreated.proxy);
+                nonActivatableCreated = null;
+                if (returnCode != ServiceDestroyer.DESTROY_SUCCESS) {
+                    if (compatConfig.getDebugLevel() >= Config.ERROR) {
+	                log.println("Warning: program may not have shutdown "
+                        + "cleanly; destroy code is: " + returnCode);
+                    }
+                }
+            }
+
+            // stop activatable service (if non-null)
+	    if (activatableCreated != null) {
+                returnCode = ServiceDestroyer.destroy(activatableCreated,30);
+                activatableCreated = null;
+            }
+
+            // stop shared group (if non-null)
+	    if (sharedCreated != null) {
+                ((SharedGroup)sharedCreated.proxy).destroyVM();
+                sharedCreated = null;
+                if (compatConfig.getDebugLevel() == Config.ALL) {
+	            log.println("Destroyed activation group VM");
+                }
+            }
+	} catch (ActivationException ae) {
+            if (compatConfig.getDebugLevel() >= Config.ERROR) {
+	        log.println("Warning: program may not have shutdown cleanly");
+	        ae.printStackTrace(log);
+            }
+	}
+
+        // delete group log if present
+        if (groupLog != null) {
+            File groupLogFile = new File(groupLog);
+            File[] contents = groupLogFile.listFiles();
+            if (contents != null) {
+                for (int i = 0; i< contents.length; i++) {
+                    contents[i].delete();
+                }
+            }
+            groupLogFile.delete();
+        }
+    }
+
+    /**
+     * Given a list of objects which are ServiceItems this method
+     * determines if any of them are the program we are testing.  It
+     * does this by comparing the <code>service</code> field of each
+     * <code>ServiceItem</code> to the program's proxy returned from
+     * the ServiceStarter framework when the program was started.
+     *
+     * @param services the array of ServiceItems that need to be picked from
+     *
+     * @return the ServiceItem for the program being tested or null if
+     *         none of the ServiceItems represent the program being tested
+     */
+    public synchronized ServiceItem pickService(ServiceItem[] services)
+	throws RemoteException
+    {
+	for (int i = 0; i < services.length; i++) {
+	    if (services[i].service.equals(proxy)) {
+		return services[i];
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * Returns a fully wild-carded template.
+     *
+     * @return the template
+     */ 
+    public ServiceTemplate getTemplate() throws RemoteException {
+	return new ServiceTemplate(null, null, null);
+    }
+
+    /**
+     * Returns the proxy for the lookup service being tested.
+     *
+     * @return lookup service proxy
+     */
+    public ServiceRegistrar getServiceRegistrar() throws RemoteException {
+        return (ServiceRegistrar) proxy;
+    }
+
+    /**
+     * Returns a randomized directory name within the
+     * <code>com.sun.jini.compat.scratchDir</code> that can be used
+     * as the group log directory.  The returned directory name
+     * is saved so that this Admin can remove it later.
+     */
+    public String getGroupLog() {
+        String scratchDir = compatSysConfig.getStringConfigVal(
+            "com.sun.jini.compat.scratchDir", null);
+        groupLog = scratchDir + "/" + TestUtility.randomString(8);
+        return groupLog;
+    }
+
+    /**
+     * Returns a randomized directory name within the
+     * <code>com.sun.jini.compat.scratchDir</code> that can be used
+     * as the program's persistence directory.
+     */
+    public String getPersistenceDir() {
+        String scratchDir = compatSysConfig.getStringConfigVal(
+            "com.sun.jini.compat.scratchDir", null);
+        return scratchDir + "/" + TestUtility.randomString(8);
+    }
+}

Propchange: river/tck/src/com/sun/jini/compat/admin2/ServiceStarterAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/admin2/package.html
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/admin2/package.html?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/admin2/package.html (added)
+++ river/tck/src/com/sun/jini/compat/admin2/package.html Sat Jan 21 07:28:27 2012
@@ -0,0 +1,22 @@
+<!--
+ ! 
+ ! Copyright 2005, Sun Microsystems, Inc.
+ ! Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">
+ ! Apache License, Version 2.0</a>.
+ ! 
+ !-->
+<BODY BGCOLOR="white">
+
+This package contains admin implementations for the services that ship
+with the Jini(TM) Technology Starter Kit, v2.0 and later.
+
+These classes are provided as examples of how to
+write your own service's admin.  Admins are used to automate the testing of a
+program using the Jini Technology Lookup, Discovery, and Join Compatibility Kit.
+
+
+@see <a href="../../../../../../writing-admin.html"><i>Implementing the LDJ Kit Admin Interface</i></a>
+@see <a href="../../../../../../running.html"><i>Running the Jini Technology Lookup, Discovery, and Join Compatibility Kit</i></a>
+
+</BODY>
+</HTML>

Propchange: river/tck/src/com/sun/jini/compat/admin2/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/constants/ThrowableConstants.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/constants/ThrowableConstants.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/constants/ThrowableConstants.java (added)
+++ river/tck/src/com/sun/jini/compat/constants/ThrowableConstants.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,133 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.constants;
+
+import java.io.ObjectStreamException;
+import java.rmi.RemoteException;
+import java.rmi.NoSuchObjectException;
+import java.rmi.MarshalException;
+import java.rmi.UnmarshalException;
+import java.rmi.ServerException;
+import java.rmi.ServerError;
+
+/**
+ * Various constants useful in processing exceptions
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ */
+public class ThrowableConstants {
+    /**
+     * Value returned by <code>retryable</code> to indicate that the
+     * passed <code>Throwable</code> does not provide any new
+     * information on the state of the object that threw it.
+     * @see #retryable
+     */
+    final static public int INDEFINITE = 0;
+
+    /**
+     * Value returned by <code>retryable</code> to indicate that the
+     * passed <code>Throwable</code> implies that retrying the
+     * operation that threw the <code>Throwable</code> with the same
+     * arguments and the same expected return value would not be
+     * fruitful.  
+     * @see #retryable
+     */
+    final static public int BAD_INVOCATION = 1;
+
+    /**
+     * Value returned by <code>retryable</code> to indicate that the
+     * passed <code>Throwable</code> implies that any further
+     * operations on the object that threw the <code>Throwable</code>
+     * would not be fruitful.  
+     * @see #retryable
+     */
+    final static public int BAD_OBJECT = 2;
+
+    /**
+     * Value returned by <code>retryable</code> to indicate that the
+     * passed <code>Throwable</code> was of a type that could not be
+     * classified.
+     * @see #retryable
+     */
+    final static public int UNCATEGORIZED = 3;
+
+    /**
+     * Attempt to classify the passed <code>Throwable</code> in terms of 
+     * what it implies about the probability of success of future operations
+     * on the object that threw the exception.
+     *
+     * @return <code>INDEFINITE</code>, <code>BAD_INVOCATION</code>,
+     * or <code>BAD_OBJECT</code> if the exception is a
+     * <code>RuntimeException</code>, <code>Error</code>, or
+     * <code>java.rmi.RemoteException</code> depending on the details of 
+     * the <code>Throwable</code>.  Otherwise return <code>UNCATEGORIZED</code>
+     * @throws NullPointerException if the passed <code>Throwable</code> is
+     * <code>null</code>
+     */
+    public static int retryable(Throwable t) {
+	if (t == null) 
+	    throw new NullPointerException("Must pass a non-null Throwable");
+
+	if (t instanceof RuntimeException)
+	    return BAD_OBJECT;
+
+	if (t instanceof Error) {
+	    if ((t instanceof OutOfMemoryError) ||
+		(t instanceof LinkageError))
+	    {
+		return INDEFINITE;
+	    }
+
+	    return BAD_OBJECT;
+	}
+
+	if (t instanceof RemoteException) {
+	    final RemoteException re = (RemoteException)t;
+
+	    if (re instanceof NoSuchObjectException) 
+		return BAD_OBJECT;
+
+	    final Throwable detail = re.detail;
+	    if (detail == null)
+		return INDEFINITE;
+	    	    
+	    if (re instanceof MarshalException || 
+		re instanceof UnmarshalException) 
+	    {
+		if (detail instanceof ObjectStreamException)
+		    return BAD_INVOCATION;
+
+		return INDEFINITE;
+	    }
+
+	    if (re instanceof ServerException) {
+		return retryable(detail);
+	    }
+
+	    if (re instanceof ServerError) {
+		return retryable(detail);
+	    }
+
+	    return INDEFINITE;
+	}
+	    
+	return UNCATEGORIZED;
+
+    }
+}

Propchange: river/tck/src/com/sun/jini/compat/constants/ThrowableConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/AbstractRunner.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/AbstractRunner.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/AbstractRunner.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/AbstractRunner.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,472 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+
+// java.util
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.StringTokenizer;
+
+// java.io
+import java.io.PrintWriter;
+
+// com.sun.jini
+import com.sun.jini.system.MultiCommandLine;
+import com.sun.jini.system.CommandLine.BadInvocationException;
+import com.sun.jini.system.CommandLine.HelpOnlyException;
+import com.sun.jini.compat.harness.BasicAdmin;
+
+/**
+ * This class is a base class for implementing harness (or "runner") classes
+ * for the LDJ Kit tests. This class defines methods, both concrete
+ * and abstract, that handle the functions involved with running a set
+ * of tests identified on the command line through either a list of individual
+ * test name or categories (or both); functions such as setting up the
+ * the top-level configuration of the test harness, identifying the tests
+ * to execute on the requested run, and actually initiating the tests
+ * to run.
+ */
+public abstract class AbstractRunner {
+
+    private static final int INVALID_ADMIN     = -3;
+    private static final int INVALID_CATEGORY  = -2;
+    private static final int INVALID_TEST      = -1;
+    private static final int VALID_TEST        = 0;
+    private static final int EXCLUDED_TEST     = 1;
+    private static final int EXCLUDED_CATEGORY = 2;
+
+    private List testNames;
+    private String[] arguments;
+    private List categories;
+    private boolean dups;
+    private int testTries = 0;
+    private PrintWriter log;
+
+    private List xCategories = new ArrayList(11); //excluded categories
+    private List xTestNames  = new ArrayList(11); //excluded tests
+
+    private final static int maxTestCount = 100;
+    private Config tConfig = null;
+
+    /**
+     * Constructs a new instance of this class. This constructor parses
+     * the command line, sets up the top-level configuration for the
+     * requested test run, and identifies the tests to run.
+     *
+     * @param args      <code>String</code> array containing the command line
+     *                  arguments
+     * @param log       an instance of <code>java.io.PrintWriter</code>
+     *                  through which all test output is written
+     */
+    public AbstractRunner(String[] args, PrintWriter log) {
+        this.log = log;
+        arguments = args;
+        MultiCommandLine mcl = new MultiCommandLine(arguments);
+        try {
+            String testString = mcl.getString("tests", null);
+            boolean gui = mcl.getBoolean("gui");
+            dups = !mcl.getBoolean("noduplicates");
+            String cats = mcl.getString("categories", null);
+            if (cats == null)
+                cats = mcl.getString("category", null);
+
+            String configFile = null;
+            try {
+                String[] ops = mcl.getOperands();
+                if (ops.length >= 1)
+                    configFile = ops[0];
+            } catch (HelpOnlyException hoe) {
+                usage();
+                System.exit(1);
+            }
+
+            tConfig = doConfig(configFile,log);
+
+            log.println();
+            log.println("---------------------------");
+            log.println("CONFIGURATION FILE:");
+            log.println();
+            log.println("   " + configFile);
+            log.println();
+
+            if (cats == null) {
+                SysConfig sys = tConfig.getSysConfig();
+                cats = sys.getStringConfigVal("com.sun.jini.compat.categories",
+                                              null);
+                if (cats == null) {
+                    log.println("ERROR: The category of the "
+                                + "of the product being tested must either "
+                                + "be specified on the command line by "
+                                + "-categories cat1,cat2,etc.. or "
+                                + "by the property "
+                                + "com.sun.jini.compat.categories");
+                    System.exit(1);
+                }
+            }
+
+            setupCategories(cats);
+            testNames = new ArrayList();
+
+            String xTestsString = mcl.getString("xtests", null);
+            setupXTests(xTestsString);
+            String xCats = mcl.getString("xcategories", null);
+            setupXCategories(xCats);
+
+            log.println("---------------------------");
+            log.println("SETTING UP THE TEST LIST:");
+            log.println();
+            // If there are no arguments assume the user wants all the tests.
+            if (testString == null) {
+                addAllTests();
+            } else {
+                addTests(testString);
+            }
+        } catch (BadInvocationException bie) {
+            usage();
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Returns the categories that were input for the current test run either
+     * on the command line, or in the configuration file.
+     *
+     * @return <code>String</code> array containing the categories that were
+     *         input for the current test run either on the command line, or
+     *         in the configuration file.
+     */
+    public String[] getRequestedCategories() {
+        return ((String[])categories.toArray(new String[categories.size()]));
+    }
+
+    /**
+     * Abstract method which allows sub-classes of this class to define
+     * the mechanism for retrieving the information contained in the top-level
+     * configuration property file identified by the <code>configFile</code>
+     * parameter, and for storing that information in the return value for
+     * access throughout the test run.
+     *
+     * @param configFile the name of the property file containing the
+     *                   top-level configuration information for all
+     *                   tests to be executed on the current run
+     * @param log        an instance of <code>java.io.PrintWriter</code>
+     *                   through which all test output is written
+     *
+     * @return the Config object that stores the retrieved information
+     */
+    protected abstract Config doConfig(String configFile, PrintWriter log);
+
+    /**
+     * Gives subclasses access to the Config object.
+     *
+     * @return the Config object
+     */
+    protected Config getConfig() {
+        return tConfig;
+    }
+
+    /**
+     * Abstract method which allows sub-classes of this class to define
+     * the action to take when all possible tests have been requested
+     * for the current test run.
+     *
+     * @throws com.sun.jini.system.CommandLine.BadInvocationException to
+     *         allow for the case where a particular harness will not
+     *         (or cannot) handle a request to run all possible tests
+     */
+    protected abstract void addAllTests() throws BadInvocationException;
+
+    /**
+     * Abstract method which allows sub-classes of this class to define
+     * the harness usage message that is printed to standard output.
+     */
+    protected abstract void usage();
+
+    private void setupCategories(String cats) {
+        categories = new ArrayList();
+        StringTokenizer st = new StringTokenizer(cats, ",");
+        while (st.hasMoreTokens()) {
+            categories.add(st.nextToken().toLowerCase());
+        }
+    }
+
+    private void setupXCategories(String xCats) {
+        if (xCats == null) {
+            return;
+        }
+        StringTokenizer st = new StringTokenizer(xCats, ",");
+        while (st.hasMoreTokens()) {
+            xCategories.add(st.nextToken().toLowerCase());
+        }
+    }
+
+    private void setupXTests(String xTests) {
+        if (xTests == null) {
+            return;
+        }
+        StringTokenizer st = new StringTokenizer(xTests, ",");
+        while (st.hasMoreTokens()) {
+            xTestNames.add(st.nextToken().toLowerCase());
+        }
+    }
+
+    private void addTests(String testList) {
+        // to make sure we are not in some kind of property loop
+        if (testTries > maxTestCount) {
+            return;
+        }
+
+        // if we haven't hit our limit and we count this as a try
+        testTries++;
+        String nextList = null;
+        SysConfig sysConfig = tConfig.getSysConfig();
+
+        // if it starts with "set:" it's a subset
+        if (testList.substring(0,4).toLowerCase().equals("set:")) {
+            StringTokenizer st = new StringTokenizer(testList, ",");
+            String subset = st.nextToken().substring(4);
+            nextList = System.getProperty(subset);
+            if (nextList == null) {
+                nextList =
+                    sysConfig.getStringConfigVal(subset, null);
+            }
+            if (nextList != null) {
+                addTests(nextList);
+                if (st.hasMoreTokens())
+                    addTests(testList.substring(subset.length() + 5));
+            }
+        } else {
+            StringTokenizer st = new StringTokenizer(testList, ",");
+            String className = st.nextToken();
+            // try to add the test to the list to execute
+            addTest(className);
+            if (st.hasMoreTokens()) {
+                nextList = testList.substring(className.length() + 1);
+                addTests(nextList);
+            }
+        }
+    }
+
+    private int validTest(Test test) {
+        try {
+            // Determine if the test been excluded by name
+            String testName = new String((test.getClass()).toString()).
+                substring("class ".length()).toLowerCase();
+            if (xTestNames.contains(testName))
+                return EXCLUDED_TEST;
+
+            String[] cats = test.getCategories();
+
+            // Determine if the test belongs to any excluded category
+            for (int i = 0; i < cats.length; i++) {
+                if (xCategories.contains(cats[i]))
+                    return EXCLUDED_CATEGORY;
+            }//end loop(i)
+
+            // Determine if test's categories are valid
+            boolean good = false;
+            for (int i = 0; i < cats.length; i++) {
+                if (categories.contains(cats[i])) {
+                    good = true;
+                    break;
+                }
+            }
+            if (!good) {
+                return INVALID_CATEGORY;
+            }
+
+            Class[] admins = test.getRequiredAdmins();
+            BasicAdmin ba = tConfig.getAdmin();
+            Class baClass = ba.getClass();
+            for (int i = 0; i < admins.length; i++) {
+                if (!admins[i].isAssignableFrom(baClass)) {
+                    return INVALID_ADMIN;
+                }
+            }
+            return VALID_TEST;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return INVALID_TEST;
+    }
+
+    /**
+     * Method called after each test to run a command in a separate process.
+     * As an example, this method is useful to execute a diagnostic
+     * command script to determine system resources after each test.
+     * <p>
+     * The command to run is specified by the property
+     * com.sun.jini.qa.runCommandAfterEachTest.  If this property is null or
+     * not specified, then no command is run.
+     * <p>
+     * The method returns once the command finishes.  Any exception thrown
+     * by trying to run the command is ignored.
+     */
+    private void runCommandAfterEachTest() {
+        try {
+            String command = getConfig().getSysConfig().getStringConfigVal(
+                "com.sun.jini.qa.runCommandAfterEachTest",null);
+            if (command != null) {
+                Process process = Runtime.getRuntime().exec(command);
+                process.waitFor();
+            }
+        } catch (Exception ignore) {}
+    }
+
+    /**
+     * Attempt to add the test implemented by className to the current
+     * set of tests.
+     */
+    protected void addTest(String className) {
+        Test test = null;
+        try {
+            Class c = Class.forName(className);
+            test = (Test)c.newInstance();
+        } catch (Exception e) {
+            log.println("   Skipping test: " + className);
+            log.println("      Reason: cannot find/call a public no "
+                + "argument constructor for " + className);
+            log.println("      Exception: " + e);
+            return;
+        }
+
+        int testState = validTest(test);
+        if (testState == VALID_TEST) {
+            if (!dups && testNames.contains(className)) {
+                    log.println("   Skipping test: " + className);
+                    log.println("      Reason: duplicate test");
+                    return;
+            }
+            log.println("   Adding test: " + className);
+            testNames.add(className);
+        } else if ((testState == EXCLUDED_TEST) ||
+                   (testState == EXCLUDED_CATEGORY) ) {
+            log.println("   Excluding test: " + className);
+        } else if (testState == INVALID_CATEGORY) {
+            log.println("   Skipping test: " + className);
+            log.println("      Reason: category mismatch");
+            log.print("      Categories selected for this run: ");
+            for (int j = 0; j < categories.size(); j++) {
+                log.print(categories.get(j) + " ");
+            }
+            log.println();
+            log.print("      Categories this test applies to: ");
+            String[] testCategories = test.getCategories();
+            for (int j = 0; j < testCategories.length; j++) {
+                log.print(testCategories[j] + " ");
+            }
+            log.println();
+        } else if (testState == INVALID_ADMIN) {
+            log.println("   Skipping test: " + className);
+            log.println("      Reason: required Admin mismatch");
+        } else { // testState == INVALID_TEST
+            log.println("   Skipping test: " + className);
+            log.println("      Reason: invalid test");
+        } //endif(validTest)
+    } //end addTest
+
+    /**
+     * This method batch runs all of the tests and displays their results.
+     *
+     * @return true if all started tests complete and pass; false if either
+     *         one or more of the started tests fail or does not complete
+     */
+    public boolean runTests() {
+        log.println("---------------------------");
+        log.println("STARTING TO RUN THE TESTS");
+        log.println();
+        log.println();
+        ArrayList testList = new ArrayList(testNames.size());
+        ArrayList statusList = new ArrayList(testNames.size());
+        int numPassed = 0;
+        int numFailed = 0;
+        for (int i = 0; i < testNames.size(); i++) {
+            String className = (String)testNames.get(i);
+            Test test = null;
+            try {
+                Class c = Class.forName(className);
+                test = (Test)c.newInstance();
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.println();
+                log.println("Error instantiating class: " + className);
+                continue;
+            } //end try
+            Status status = null;
+            try {
+                log.println("Running " + className + "...");
+                log.println("Time is " + new Date());
+                if (!tConfig.isOfficial()) {
+                    log.println("UNOFFICIAL TEST RUN");
+                }
+
+                test.setConfig(tConfig);
+                test.setup(arguments);
+                status = test.run(arguments);
+
+                if (status.getState()) {
+                    numPassed++;
+                } else {
+                    numFailed++;
+                }
+                testList.add(className);
+                statusList.add(status);
+            } catch (Throwable e) {
+                status = Status.failed(Status.ENV,
+                    "Exception caught by Runner: " + e);
+                if (tConfig.getDebugLevel() >= Config.ERROR) {
+                    e.printStackTrace(log);
+                }
+            } finally {
+                test.tearDown();
+                status.displayResults(log);
+                runCommandAfterEachTest();
+            } //end try
+            try {
+               Thread.sleep(10000); //wait 10 seconds between tests
+            } catch (InterruptedException ignore) {
+            }
+            log.println();
+            log.println("--------------------------");
+            log.println();
+            log.flush();
+        } //end loop
+        log.println("Summary --");
+        log.println();
+        for (int i = 0; i < testList.size(); i++) {
+            String testName = (String)testList.get(i);
+            Status testStatus = (Status)statusList.get(i);
+            log.println(testName);
+            testStatus.displayResults(log);
+            log.println("--------------------------");
+            log.flush();
+        }
+        log.println();
+        log.println("# of tests started   = " + testNames.size());
+        log.println("# of tests completed = " + testList.size());
+        log.println("# of tests passed    = " + numPassed);
+        log.println("# of tests failed    = " + numFailed);
+        log.println("--------------------------");
+        log.println();
+        log.flush();
+        return (numFailed == 0 && testNames.size() == testList.size());
+    } //end runTests
+
+}

Propchange: river/tck/src/com/sun/jini/compat/harness/AbstractRunner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/BasicAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/BasicAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/BasicAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/BasicAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,62 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+import java.rmi.RemoteException;
+import java.net.InetAddress;
+import com.sun.jini.compat.harness.Config;
+
+/**
+ * An interface for basic administration of any kind of program.  All
+ * Admin interfaces subclass from this one.  If someone wishes to automate
+ * the  testing of their program they need to implement this
+ * interface and one of it's subinterfaces depending on the program
+ * category.  The implementation must also have a no argument
+ * constructor or a constructor that takes a <code>String</code>
+ * as it's only argument.
+ */
+public interface BasicAdmin {
+    
+    /**
+     * Passes a config object to the admin so that implementations of the
+     * admin can get access to configuration information, such as
+     * config files.
+     * 
+     * @param conf the configuration object
+     */
+    void setConfig(Config conf);
+
+    /**
+     * Start the Jini(TM) technology features of the program.
+     */
+    void start() throws RemoteException;
+    
+    /**
+     * Gets the internet address of the host where the program is
+     * being run.
+     *
+     * @return the address
+     */
+    InetAddress getAddress() throws RemoteException;
+
+    /**
+     * Stop the Jini(TM) technology features of the program completely including
+     * removing the program from activation and resetting any
+     * persistence these features require.
+     */
+    void stop() throws RemoteException;
+}

Propchange: river/tck/src/com/sun/jini/compat/harness/BasicAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/BasicClientAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/BasicClientAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/BasicClientAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/BasicClientAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,34 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+import java.rmi.RemoteException;
+import java.net.InetAddress;
+
+/**
+ * An interface for the basic administration of a client.
+ * Developers wishing to automate the testing of their client need to
+ * implement this interface. A Jini(TM) technology client is an program 
+ * that goes through discovery to find a lookup service. Currently this
+ * is mostly a marker interface with the name of the category included.
+ * The <code>BasicClientAdmin</code> implementation class is expected 
+ * to have a constructor that either takes no arguments or takes 
+ * a <code>String</code> as an argument.
+ */
+public interface BasicClientAdmin extends BasicAdmin{
+    public final static String CATEGORY = "client";
+}

Propchange: river/tck/src/com/sun/jini/compat/harness/BasicClientAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/BasicLookupAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/BasicLookupAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/BasicLookupAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/BasicLookupAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,46 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+
+import java.rmi.RemoteException;
+import net.jini.core.lookup.ServiceRegistrar;
+
+/**
+ * An interface for basic administration of a lookup.  Developers
+ * wishing to automate the testing of their lookup should write
+ * a class that implements this interface and provides appropriate
+ * method implementations for the service it administers. The 
+ * <code>BasicLookupAdmin</code> implementation class is expected 
+ * to have a constructor that either takes no arguments or takes 
+ * a <code>String</code> as an argument.
+ */
+public interface BasicLookupAdmin extends BasicAdmin{
+    public final static String CATEGORY = "lookup";
+
+    /**
+     * Returns the ServiceRegistrar from an already started Lookup.
+     * If there are any problems getting the ServiceRegistrar it
+     * throws a RemoteException.
+     *
+     * @return a ServiceRegistrar for the lookup being tested.
+     */
+    public ServiceRegistrar getServiceRegistrar()
+	throws RemoteException;
+}
+	
+

Propchange: river/tck/src/com/sun/jini/compat/harness/BasicLookupAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/BasicServiceAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/BasicServiceAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/BasicServiceAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/BasicServiceAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,60 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+
+import java.net.InetAddress;
+
+import java.rmi.RemoteException;
+import net.jini.core.lookup.ServiceItem;
+import net.jini.core.lookup.ServiceTemplate;
+
+/**
+ * An interface for basic administration of a service.  Developers
+ * wishing to automate the testing of their service should write
+ * a class that implements this interface and provides appropriate
+ * method implementations for the service it administers. The 
+ * <code>BasicServiceAdmin</code> implementation class is expected 
+ * to have a constructor that either takes no arguments or takes 
+ * a <code>String</code> as an argument.
+ */
+public interface BasicServiceAdmin extends BasicAdmin{
+    public final static String CATEGORY = "service";
+
+    /**
+     * Given an array of service proxy objects, this method
+     * should return the service associated with this admin. If the
+     * associated service is not found in the <code>services</code>
+     * array, then this method should return <code>null</code>.
+     *
+     * @param services the array of <code>ServiceItem</code> objects   
+     *        from which to choose 
+     * @return the <code>ServiceItem</code> for the service being tested, 
+     * 	      or <code>null</code>
+     */
+    ServiceItem pickService(ServiceItem[] services) throws RemoteException;
+
+    /**
+     * Return a <code>ServiceTemplate</code> that can be used to identify 
+     * the service. This helps to filter out unnecessary notifications.
+     *
+     * @return the template that best matches the service being tested
+     */ 
+    ServiceTemplate getTemplate() throws RemoteException;
+}
+	
+

Propchange: river/tck/src/com/sun/jini/compat/harness/BasicServiceAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/Config.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/Config.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/Config.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/Config.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,273 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+
+import java.lang.reflect.Constructor;
+import java.io.PrintWriter;
+import java.net.URL;
+
+/**
+ * This class processes and holds the configuration information for 
+ * all the tests being run.  The <code>Runner</code> generates 
+ * a single Config and passes it to each test using the setConfig 
+ * method on <code>Test</code>.  This class provides the 
+ * <code>InstrumentedClassServer</code>, the <code>SysConfig</code> 
+ * and the <code>BasicAdmin</code> for the current run of the LDJ Kit.
+ * It also sets up the codebase and the security manager when it 
+ * is constructed.
+ */
+public class Config {
+    private String propFilename = null;
+    private SysConfig sysConfig = null;
+    private BasicAdmin ba = null;
+    private InstrumentedClassServer ics = null;
+    private PrintWriter log;
+    private boolean official = true;
+
+    // Default timeout for quietTime is 10 minutes
+    private static final int QUIETTIMEOUT = 1000*60*10;
+    // Default timeout for failureTime is 30 seconds
+    private static final int FAILURETIMEOUT = 30000;
+
+    private int currentQuietTime = 0;
+
+    /**
+     * Debug Level that prints no extra information.
+     */
+    public static final int NONE = 0;
+    
+    /**
+     * Debug Level that prints extra information when something
+     * unexpected happens.
+     */
+    public static final int ERROR = 1;
+    
+    /**
+     * Debug Level that prints extra information throughout the run.
+     */
+    public static final int ALL = 2;
+
+    /*
+     * The default class name for the implementation class of the
+     * service admin.
+     */
+    private static final String defaultAdminClass = 
+        "com.sun.jini.compat.harness.DefaultAdmin";
+
+    /*
+     * The class name for the basic service admin interface
+     */
+    private static final String adminInterface =
+        "com.sun.jini.compat.harness.BasicAdmin";
+
+    /**
+     * Constructor for the Config class.  It does all the
+     * precalculations necessary to provide configuration
+     * information.
+     *
+     * @param pfn         the path/filename of the config property file
+     * @param classServer a reference to a currently running
+     *                    <code>InstrumentedClassServer</code>
+     * @param log         an instance of <code>java.io.PrintWriter</code>
+     *                    through which all test output is written
+     */
+    public Config(String pfn, InstrumentedClassServer classServer,
+		  PrintWriter log)
+	throws Exception
+    {
+	this.log = log;
+	propFilename = new String(pfn);
+	sysConfig = new SysConfig(propFilename);
+	
+	System.setSecurityManager(new java.rmi.RMISecurityManager());
+	
+	ics = classServer;
+	System.setProperty("java.rmi.server.codebase",
+			   ics.getCodeURL().toString() + "compat-dl.jar");
+	setupAdmin();
+
+	currentQuietTime =
+	    sysConfig.getIntConfigVal("com.sun.jini.compat.unofficialQuietTime",
+				      QUIETTIMEOUT);
+	if(currentQuietTime < QUIETTIMEOUT)
+	    official = false;
+    }
+
+    /**
+     * Constructor for the Config class.  It does 
+     * precalculations necessary to provide configuration
+     * information but does not specify a class server
+     * nor does it set the Quiet Time needed by the LDJ Kit.
+     *
+     * @param pfn the path/filename of the config property file
+     * @param log an instance of <code>java.io.PrintWriter</code>
+     *            through which all test output is written
+     */
+    public Config(String pfn, PrintWriter log)  throws Exception {
+	this.log = log;
+	propFilename = new String(pfn);
+	sysConfig = new SysConfig(propFilename);
+	System.setSecurityManager(new java.rmi.RMISecurityManager());
+	setupAdmin();
+    }
+
+    private void setupAdmin() throws Exception {
+	String adminClassName = sysConfig.getStringConfigVal(
+                          "com.sun.jini.compat.adminClass",
+                          defaultAdminClass);
+	String adminArg = sysConfig.getStringConfigVal(
+                          "com.sun.jini.compat.adminArg", null);
+	    
+	try {
+	    Class adminClass = Class.forName(adminClassName);
+	    Class basicAdminInterface = Class.forName(adminInterface);
+	    if(!basicAdminInterface.isAssignableFrom(adminClass)) {
+		throw new Exception("Administration class "+
+			    "specified in the config file "+
+			    "must implement "+ adminInterface);
+	    }
+
+	    if(adminArg != null) {
+		Class[] constrArgClasses = { String.class };
+		Constructor[] all = adminClass.getConstructors();
+		Constructor stringConstr = 
+		    adminClass.getConstructor(constrArgClasses);
+		Object[] constrArgs = { adminArg };
+		ba =
+		    (BasicAdmin)stringConstr.newInstance(constrArgs);
+	    } else {
+		ba = (BasicAdmin)adminClass.newInstance();
+	    }
+	    ba.setConfig(this);
+	} catch(Exception e) {
+	    throw new Exception("Problems getting Administration "+
+				"object for the service: "+e);
+	}
+    }
+
+    /**
+     * Method returns the class server for this run of the LDJ Kit.
+     *
+     * @return the class server
+     */
+    public InstrumentedClassServer getClassServer() {
+	return ics;
+    }
+
+    /**
+     * Method returns the <code>SysConfig</code> for this run of the
+     * LDJ Kit.  It is used by tests to get access to the LDJ Kit property
+     * file.
+     *
+     * @return the <code>SysConfig</code>
+     */
+    public SysConfig getSysConfig() {
+	return sysConfig;
+    }
+
+    /**
+     * Method returns the admin for this run of the LDJ Kit.  Depending on
+     * the program being tested this method will return different
+     * subclasses of <code>BasicAdmin</code>.
+     *
+     * @return the admin
+     */
+    public BasicAdmin getAdmin() {
+	return ba;
+    }    
+    
+    /**
+     * Returns the Quiet Time value.  This is the value used for
+     * "negative" tests (when nothing should happen in a time interval). 
+     * If the property <code>com.sun.jini.compat.unofficialQuietTime</code>
+     * is set, then its value is used.  If this value is less than the
+     * official Quiet Time, then the run of the LDJ Kit is unofficial (used
+     * for testing/debugging purposes only).
+     *
+     * @return the Quite Time duration in milliseconds
+     */
+    public int getQuietTime() {
+	return currentQuietTime;
+    }
+    
+    /**
+     * Returns the Failure Time value from SysConfig.  This value
+     * is used to limit the time it takes for something to fail.
+     * It indicated the length of time you are willing to wait 
+     * before you accept that the action is not going to happen.
+     *
+     * @return the Failure Time duration in milliseconds
+     */
+    public int getFailureTime() {
+	if(sysConfig == null)
+	    throw new NullPointerException("SysConfig not initialized");
+	int to =
+	    sysConfig.getIntConfigVal("com.sun.jini.compat.failureTime",
+				      FAILURETIMEOUT);
+
+	return to;
+    }
+
+    /**
+     * Returns the log <code>PrintWriter</code> for this run of the LDJ Kit.
+     *
+     * @return the log <code>PrintWriter</code>
+     */
+    public PrintWriter getLog() {
+	return log;
+    }
+    
+    /**
+     * Returns the current debug level of the LDJ Kit.  Currently there
+     * are three debug levels:
+     * <p><ul>
+     *   <li>NONE:  no extra debug information is displayed
+     *   <li>ERROR: extra debug information is only displayed during
+     *              times when there are errors/problems
+     *   <li>ALL:   extra information is displayed throughout all parts of
+     *              the run
+     * </ul><p>
+     * The debug level is obtained from the property:
+     * <code>com.sun.jini.compat.debugLevel</code>
+     *
+     * @return the debug level
+     */
+    public int getDebugLevel() {
+	if(sysConfig == null)
+	    throw new NullPointerException("SysConfig not initialized");
+	String dl =
+	    sysConfig.getStringConfigVal("com.sun.jini.compat.debugLevel",
+				      "none").toLowerCase();
+	
+	if(dl.equals("error"))
+	    return ERROR;
+	else if(dl.equals("all"))
+	    return ALL;
+	else
+	    return NONE;
+    }
+    
+    /**
+     * Returns whether this is an official run or not.
+     *
+     * @return <code>true</code> if this is an official run
+     */
+    public boolean isOfficial() {
+	return official;
+    }
+}

Propchange: river/tck/src/com/sun/jini/compat/harness/Config.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/ConfigProperties.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/ConfigProperties.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/ConfigProperties.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/ConfigProperties.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,300 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+
+import java.io.File;
+import java.util.Properties;
+
+/** 
+ * When used in place of the class <code>java.util.Properties</code>, calls
+ * to this class' <code>getProperty</code> method will automatically perform
+ * pre-defined substitutions based on the following criteria:
+ *
+ * If test.name=aaaa.bbbb.cccc, then all occurrences of either $test.name
+ * or ${test.name} will be replaced with the value aaaa.bbbb.cccc
+ *
+ * Any value contained in single quotes is take literally. For example, if
+ * test.dollar='$', then the value of the property test.dollar is $.
+ *
+ * Substitutions are made within property values contained in double quotes,
+ * but no substitutions are made within property values contained in
+ * single quotes.
+ */
+public class ConfigProperties extends Properties {
+
+    /** 
+     * Constructor that creates an empty property list with no default
+     * values.
+     */
+    public ConfigProperties() {
+        super(null);
+    }//end constructor
+
+    /** 
+     * Constructor that creates an empty property list with the given default
+     * values.
+     *
+     * @param defaults <code>Properties</code> object containing the desired
+     *                 default values with which to construct this object.
+     */
+    public ConfigProperties(Properties defaults) {
+        super(defaults);
+    }//end constructor
+
+
+    /**
+     * Searches this property list for the property corresponding to the given
+     * <code>key</code> parameter. If the key is not found in this property
+     * list, the default property list and its defaults are then checked
+     * (recursively). This method returns <code>null</code> if the property is
+     * not found in any of the property lists checked. If the property is 
+     * found, then any pre-defined substitutions are made and the result is
+     * returned.
+     * 
+     * @param key <code>String</code> containing the property key whose 
+     *            corresponding value is to be retrieved and returned.
+     *
+     * @return <code>String</code> containing the property value corresponding
+     *         to the given <code>key</code> parameter, with all substitutions
+     *         made in the appropriate manner, or <code>null</code> if
+     *         property not found
+     */
+    public String getProperty(String key) {
+        try {
+            return resolve(lookup(key));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }//end getProperty
+  
+    /**
+     * Searches this property list for the property corresponding to the given
+     * <code>key</code> parameter. If the key is not found in this property
+     * list, the default property list and its defaults are then checked
+     * (recursively). If the property is not found in any of the property
+     * lists checked, the value in the <code>defaultValue</code> parameter,
+     * with all appropriate substitutions, is returned. If the property is 
+     * found, then any pre-defined substitutions are made and the result is
+     * returned.
+     * 
+     * @param key          <code>String</code> containing the property key
+     *                     whose corresponding value is to be retrieved and
+     *                     returned.
+     * @param defaultValue <code>String</code> containing the value to return
+     *                     if no property value can be found in any of the
+     *                     property lists. 
+     *
+     * @return <code>String</code> containing the property value corresponding
+     *         to the given <code>key</code> parameter, with all substitutions
+     *         made in the appropriate manner.
+     */
+    public String getProperty(String key, String defaultValue) {
+        try {
+            String val = getProperty(key); // val is already resolved
+            return ((val == null) ? resolve(defaultValue) : val);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }//end getProperty
+
+
+    /** 
+     * Resolves a value in the environment by splitting it into words and
+     * performing pre-defined substitutions on it. White-space separates
+     * words except inside quoted strings.
+     *
+     * `<code>$<em>name</em></code>' and `<code>${<em>name</em>}</code>' are 
+     * replaced by the result of calling `lookup(<em>name</em>)'. 
+     *
+     * `<code>$/</code>' is replaced by the platform-specific file separator;
+     * `<code>$:</code>' is replaced by the platform-specific path separator;
+     *
+     * `<code>$$</code>' is replaced by a single `$'.
+     *
+     * No substitutions are performed inside single-quoted strings;
+     * $ substitutions are performed in double-quoted strings.  
+     * 
+     * @arg s <code>String</code> containing the value to be resolved
+     *
+     * @return <code>String</code> containing the result after the 
+     *         appropriate substitution(s) are made
+     *
+     * @throws java.lang.Exception typically, this exception occurs when there
+     *         is a problem resolving the value of the input argument.
+     */
+    public String resolve(String s) throws Exception {
+        if (s == null)  return s;
+        StringBuffer current = new StringBuffer(64);
+        char term = 0; // 0   => top level
+                       // ' ' => inside word
+        char c = 0;
+        iLoop:
+        for (int i = 0;i < s.length(); i++) {
+            c = s.charAt(i);
+            switch (c) {
+                case '#':
+                    /* # at top level introduces comment to end of line and
+                     * terminates command (if found); otherwise, it goes into
+                     * the current word
+                     */
+                    if (term == 0 || term ==' ') {
+                        break iLoop;
+                    } else {
+                        current.append(c);
+                    }
+                    break;
+                
+                case '\'':
+                case '\"':
+                    /* string quotes at top level begin/end a matched pair;
+                     * otherwise they are part of it
+                     */
+                    if (term == 0 || term == ' ') {
+                        term = c;          // start matched pair
+                    } else if (term == c) {
+                        term = ' ';        // end matched pair
+                    } else {
+                        current.append(c); // put character in string
+                    }
+                    break;
+                case '$':
+                    /* dollar introduces a name to be substituted, provided
+                     * it does not appear in single quotes.
+                     *
+                     * Special values: $/ is File.separatorChar
+                     *                 $: is File.pathSeparatorChar
+                     *                 $$ is $
+                     */
+                    if (term != '\'') {
+                        StringBuffer buf = new StringBuffer();
+                        String name = null;
+                        try {
+                            c = s.charAt(++i);
+                            switch (c) {
+                                case '/':
+                                    current.append(File.separatorChar);
+                                    continue iLoop;
+                                case ':':
+                                    current.append(File.pathSeparatorChar);
+                                    continue iLoop;
+                                case '$':
+                                    current.append('$');
+                                    continue iLoop;
+                                case '{':
+                                    c = s.charAt(++i);
+                                    while (c != '}') {
+                                        buf.append(c);
+                                        c = s.charAt(++i);
+                                    }
+                                    name = lookup(buf.toString());
+                                    break;
+                                default:
+                                if (isNameChar(c)) {
+                                    while(    i < s.length()
+                                           && isNameChar(s.charAt(i)) )
+                                    {
+                                        buf.append(s.charAt(i++));
+                                    }//end loop
+                                    i--;
+                                } else {
+                                    throw new Exception
+                                           ("bad $ expression: `$" + c + "'");
+                                }
+                                name = lookup(buf.toString());
+                            }//end switch
+                            String val = resolve(name);
+                            /* only start a new word if there is something to
+                             * substitute
+                             */
+                            if (val != null) {
+                                if (term == 0)  term = ' ';
+                                current.append(val);
+                            }
+                        } catch (IndexOutOfBoundsException e) {
+                            //e.printStackTrace();
+                            throw new Exception("bad $ expression");
+                        }
+                    } else {
+                        current.append(c);
+                    }//endif
+                    break;
+                case ' ':
+                    /* space is skipped if not in a word; otherwise it goes
+                     * into the current word
+                     */
+                    if (term != 0) current.append(c);
+                    break;
+                case '\t':
+                    /* tab is skipped if not in a word; if in a word and term
+                     * is space, then terminate it; otherwise it goes into 
+                     * the current word
+                     */
+                    if (term != 0) {
+                        if (term == ' ') {
+                            term = 0;
+                        } else {
+                            current.append(c);
+                        }
+                    }
+                    break;
+                default:
+                    /* other characters start a word if needed, then go into
+                     * the word
+                     */
+                    if (term == 0)  term = ' ';
+                    current.append(c);
+                    break;
+                }//end switch
+        }//end loop(i)
+        /* the end has been reached; if a word has been started, finish it */
+        return current.toString();
+    }//end resolve
+
+    /* Returns the property value corresponding to the given <code>key</code>
+     * parameter without performing any substitution,
+     * 
+     * @param key <code>String</code> containing the property key whose 
+     *            corresponding value is to be retrieved and returned.
+     *
+     * @return <code>String</code> containing the property value corresponding
+     *         to the given <code>key</code> parameter.
+     */
+    private String lookup(String key) {
+        return super.getProperty(key);
+    }//end lookup
+
+    /* Determines if the given character is one of the characters associated
+     * with the dollar sign ($) substitution symbol.
+     * 
+     * @param c <code>char</code> containing the character to analyze.
+     *
+     * @return <code>true</code> if the given character is one of the
+     *         characters associated with the dollar sign ($) substitution 
+     *         symbol; <code>false</code> otherwise.
+     */
+    private static boolean isNameChar(char c) {
+        return (   Character.isUpperCase(c) 
+                || Character.isLowerCase(c) 
+                || Character.isDigit(c)
+                || (c == '_') 
+                || (c == '.') );
+    }//end isNameChar
+
+}//end class ConfigProperties

Propchange: river/tck/src/com/sun/jini/compat/harness/ConfigProperties.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/DefaultAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/DefaultAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/DefaultAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/DefaultAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,147 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+
+package com.sun.jini.compat.harness;
+import java.rmi.RemoteException;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+import com.sun.jini.compat.harness.Config;
+
+/**
+ * An implementation of the BasicAdmin interface.  This
+ * implementation is not program specific and it is not automated.  It
+ * asks the person running the tests to manually start and stop the
+ * program being tested.  Also it uses a property called:
+ * com.sun.jini.compat.defaultAdmin.address to specify the host the
+ * client is running on.  If the property is not specified the default
+ * is the host the LDJ Kit harness is running on.
+ */
+public class DefaultAdmin implements BasicAdmin {
+    private String userMessage = null;
+    private Config config = null;
+
+    /**
+     * A basic no-arg constructor.
+     */
+    public DefaultAdmin() {
+    }
+
+    /**
+     * A constructor that takes a message to
+     * be displayed with the various user input requests.
+     *
+     * @param message a message to be displayed with the user input
+     * requests.
+     */
+    public DefaultAdmin(String message) {
+	userMessage = new String(message);
+    }
+
+    /**
+     * See comments for <code>BasicAdmin</code>.
+     */
+    public void setConfig(Config conf) {
+	config = conf;
+    }
+
+    /**
+     * Returns the Config object for this run of the LDJ Kit.
+     *
+     * @return the Config object
+     */
+    protected Config getConfig() {
+	return config;
+    }
+
+    /**
+     * Wait for a character to be read in.
+     *
+     * @return the character read from <code>System.in</code> 
+     */
+    protected char waitForChar() {
+	InputStreamReader isr = new InputStreamReader(System.in);
+	int readChar = -1;
+
+	try {
+	    readChar = isr.read();
+	} catch(IOException ioe) {
+	    System.err.println("Problem reading keys.");
+	}
+	return (char)readChar;
+    }
+     
+    /**
+     * Prompt the user to start the program.
+     */
+    public synchronized void start() throws RemoteException {
+	System.out.println();
+	if(userMessage != null) {
+	    System.out.println(userMessage);
+	}
+	System.out.println("Start the program now.");
+	System.out.print("Press Enter when program started: ");
+	waitForChar();
+	System.out.println("Testing....");
+	System.out.println();
+    } 
+    
+    /**
+     * Returns the address of the host the program is running on by
+     * looking up the property com.sun.jini.compat.defaultAdmin.address.
+     * If that property is not specified the default is the host the
+     * LDJ Kit harness is running on.
+     *
+     * @return the address of the program
+     */
+    public InetAddress getAddress() throws RemoteException {
+	SysConfig sysConfig = config.getSysConfig();
+	
+	String addr = sysConfig.getStringConfigVal(
+			   "com.sun.jini.compat.defaultAdmin.address",
+			   null);
+	InetAddress ia = null;
+	try {
+	    if(addr == null) {
+		ia = InetAddress.getLocalHost();
+	    } else {
+		ia = InetAddress.getByName(addr);
+	    }
+	} catch(UnknownHostException uhe) {
+	    throw new RemoteException(addr + " is an unknown host", uhe);
+	}
+	
+	return ia;
+    }
+
+    /**
+     * Prompt the user to stop the program.
+     */
+    public synchronized void stop() throws RemoteException {
+	System.out.println();
+	if(userMessage != null) {
+	    System.out.println(userMessage);
+	}
+	System.out.println("Stop the program now.");
+	System.out.print("Press Enter when program stopped: ");
+	waitForChar();
+	System.out.println();
+    }
+}

Propchange: river/tck/src/com/sun/jini/compat/harness/DefaultAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: river/tck/src/com/sun/jini/compat/harness/DefaultClientAdmin.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/harness/DefaultClientAdmin.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/harness/DefaultClientAdmin.java (added)
+++ river/tck/src/com/sun/jini/compat/harness/DefaultClientAdmin.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,33 @@
+/*
+ * 
+ * Copyright 2005 Sun Microsystems, Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * 	http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ */
+package com.sun.jini.compat.harness;
+
+import java.rmi.RemoteException;
+
+/**
+ * This class extends DefaultAdmin which currently provides all of the
+ * necessary functionality for testing clients.
+ */
+public class DefaultClientAdmin extends DefaultAdmin
+   implements BasicClientAdmin
+{ 
+    public DefaultClientAdmin() {
+    }
+}
+	
+

Propchange: river/tck/src/com/sun/jini/compat/harness/DefaultClientAdmin.java
------------------------------------------------------------------------------
    svn:eol-style = native