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 [19/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/start/ClassLoaderUtil.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/start/ClassLoaderUtil.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/start/ClassLoaderUtil.java (added)
+++ river/tck/src/com/sun/jini/compat/start/ClassLoaderUtil.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,631 @@
+/*
+ * 
+ * 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.start;
+
+import java.io.File;
+
+import java.lang.reflect.Method;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationID;
+
+import java.security.SecureClassLoader;
+
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/** 
+ * This class provides utilities that can be useful when creating and
+ * manipulating class loaders.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ */
+public class ClassLoaderUtil {
+
+    /** Flags used by the static utility methods of this class that are
+     *  involved with class loaders. For more information, refer to the
+     *  documentation for the methods in which these flags are used.
+     */
+    public static final int PARENT_DEFAULT       = 0;
+    public static final int PARENT_EXTENSION     = (PARENT_DEFAULT-1);
+    public static final int PARENT_SYSTEM_PARENT = (PARENT_DEFAULT-2);
+
+    /** Special class loader that causes the RMI sub-system to annotate
+     *  classes loaded with this class loader with the given codebase
+     *  rather than with the usual search path urls. A class loader such
+     *  as this helps facilitate the separation of classpath and codebase.
+     *  <p>
+     *  To help understand the utility of this class, recall the following
+     *  characteristics of the RMI sub-system with respect to class loaders: 
+     * <p>
+     *   <ul>
+     *     <li>  when the RMI sub-system marshals an object, it invokes
+     *           the <code>getURLs</code> method on the class loader
+     *           associated with the object being marshalled, retrieving
+     *           the urls making up that class loader's search path. It
+     *           then uses those urls to annotate the serialization stream.
+     *     <li>  when the RMI sub-system loads a class, it creates a new
+     *           instance of <code>URLClassLoader</code> that has a search
+     *           path equal to the urls contained in the codebase annotation
+     *           of the class being loaded; and which has as its parent
+     *           class loader, the current context class loader. Note that
+     *           the RMI sub-system only creates a new class loader if it has
+     *           not already created a class loader with a search path that
+     *           allows it to load the desired class (recall that RMI caches
+     *           the class loaders it creates, and so it certainly may
+     *           have already created a class loader with the "appropriate"
+     *           search path).
+     *  </ul>
+     * <p>
+     * Since the RMI sub-system operates as described above, this class 
+     * can be used to cause RMI, when marshalling classes whose class loader
+     * is an instance of this class, to annotate those classes with a
+     * codebase that is different than the search path of the class loader.
+     * Thus, when the marshalled class is un-marshalled, a new class loader
+     * will be created with that annotated codebase as search path.
+     */
+    static class CodebaseClassLoader extends URLClassLoader {
+        private URL[] codebase;
+        /** Constructs an instance of this class having the given parent.
+         *
+         * @param searchPath <code>URL</code> array in which each element
+         *                   corresponds to a component of the search path
+         *                   for the new class loader; that is, the array
+         *                   elements are the locations from which the new
+         *                   class loader will load requested classes.
+         * @param parent     the class loader to set as the parent of the
+         *                   new <code>ClassLoader</code> instance
+         * @param codebase   <code>URL</code> array in which each element
+         *                   corresponds to a codebase location with which
+         *                   the RMI sub-system will annotate classes.
+         */
+        CodebaseClassLoader(URL[] searchPath,
+                            ClassLoader parent,
+                            URL[] codebase)
+        {
+            super(searchPath,parent);
+            this.codebase = codebase;
+        }//end constructor
+
+        /** Constructs an instance of this class with default parent
+         * (typically the system class loader).
+         *
+         * @param searchPath <code>URL</code> array in which each element
+         *                   corresponds to a component of the search path
+         *                   for the new class loader; that is, the array
+         *                   elements are the locations from which the new
+         *                   class loader will load requested classes.
+         * @param codebase   <code>URL</code> array in which each element
+         *                   corresponds to a codebase location with which
+         *                   the RMI sub-system will annotate classes.
+         */
+        CodebaseClassLoader(URL[] searchPath, URL[] codebase) {
+            super(searchPath);
+            this.codebase = codebase;
+        }//end constructor
+
+        /* Override getURLs so that RMI will use the codebase to annotate 
+         * the classes loaded with this class loader, rather than the urls
+         */
+        public URL[] getURLs() {
+            return codebase;
+        }
+    }//end class CodebaseClassLoader
+
+    /**
+     * Method that creates a <code>URLClassLoader</code> that will be
+     * configured to load requested classes from the locations indicated
+     * by the <code>searchPath</code> parameter; and which will, when
+     * the RMI sub-system marshals classes that are loaded through the
+     * object returned by this method, cause the resulting serialization
+     * stream to be annotated with the contents of the <code>codebase</code>
+     * parameter.
+     * <p>
+     * The structure of the delegation tree in which the returned class loader
+     * will reside depends on the value of the <code>nParentsToSkip</code>
+     * parameter. That parameter provides control over the structure (that
+     * is, the ancestral relationships) of the delegation tree. For
+     * details on the possible values of this parameter, and the resulting
+     * delegation tree structure that results, refer to the method
+     * <code>getURLClassLoader</code> in this class.
+     *
+     * @param searchPath     <code>String</code> containing the location(s)
+     *                       from which the new class loader will load
+     *                       requested classes. This parameter represents
+     *                       a classpath; that is, path/filenames separated
+     *                       by path separators.
+     * @param codebase       <code>String</code> containing the url(s)
+     *                       with which the RMI sub-system will annotate
+     *                       classes. This parameter represents a codebase;
+     *                       that is, a set of urls separated by spaces.
+     * @param nParentsToSkip <code>int</code> value indicating the structure
+     *                       of the delegation tree with which to create the
+     *                       desired class loader. This parameter takes one
+     *                       of the following values: 
+     *                       <ul> <li> StartUtil.PARENT_DEFAULT 
+     *                            <li> StartUtil.PARENT_EXTENSION 
+     *                            <li> StartUtil.PARENT_SYSTEM_PARENT 
+     *                            <li> any positive integer value </ul>
+     *
+     * @see com.sun.jini.compat.start.ClassLoaderUtil#getURLClassLoader
+     */
+    public static URLClassLoader getCodebaseClassLoader(String searchPath,
+                                                        String codebase,
+                                                        int    nParentsToSkip)
+                                                  throws MalformedURLException
+    {
+        URL[] searchPathURLs = getClasspathURLs(searchPath);
+        URL[] codebaseURLs   = getCodebaseURLs(codebase);
+        ArrayList loaderList = null;
+        switch(nParentsToSkip) {
+            case PARENT_DEFAULT:
+                return (new CodebaseClassLoader(searchPathURLs,codebaseURLs));
+            case PARENT_EXTENSION: //explicitly use the extension cl as parent
+                loaderList = getCurClassLoaderTree();
+                int n = loaderList.size()-2;// index where extension should be
+                ClassLoader extClassLoader = (ClassLoader)(loaderList.get(n));
+                return ( new CodebaseClassLoader(searchPathURLs,
+                                                 extClassLoader,
+                                                 codebaseURLs) );
+            case PARENT_SYSTEM_PARENT: //use parent of system cl as parent
+                ClassLoader sysCL = ClassLoader.getSystemClassLoader();
+                ClassLoader sysParentCL = sysCL.getParent();
+                return ( new CodebaseClassLoader(searchPathURLs,
+                                                 sysParentCL,
+                                                 codebaseURLs) );
+            default: //skip the requested number of parents in the tree
+                loaderList = getCurClassLoaderTree();
+                for(int i=0;i<nParentsToSkip;i++) {
+                    loaderList.remove(0);
+                }
+                ClassLoader parentClassLoader = (ClassLoader)loaderList.get(0);
+                return ( new CodebaseClassLoader(searchPathURLs,
+                                                 parentClassLoader,
+                                                 codebaseURLs) );
+        }//end case
+    }//end getCodebaseClassLoader
+
+    /**
+     * Method that creates a <code>URLClassLoader</code> that will be 
+     * configured to load requested classes from the locations indicated
+     * by the <code>searchPath</code> parameter (which may be a classpath
+     * or a codebase, as indicated by the <code>isClasspath</code>parameter);
+     * and which will have a delegation tree whose structure is determined
+     * by the <code>nParentsToSkip</code> parameter.
+     * <p>
+     * How this method treats the <code>searchPath</code> parameter is
+     * determined by the <code>isClasspath</code>parameter. If that parameter
+     * is <code>true</code>, this method will create the desired class loader
+     * using file urls. If the value of parameter is <code>false</code>,
+     * this method will construct the class loader using default urls.
+     * <p>
+     * The structure of the delegation tree in which the returned class loader
+     * will reside depends on the value of the <code>nParentsToSkip</code>
+     * parameter. That parameter provides control over the structure (that is,
+     * the ancestral relationships) of the delegation tree. The possible
+     * values, and the resulting delegation tree structure that results,
+     * are as follows:
+     * <p>
+     *   <ul>
+     *     <li> StartUtil.PARENT_DEFAULT - creates a class loader with 
+     *          delegation tree with the default structure; that is, the
+     *          parent of the new class loader will be the current 
+     *          "system class loader" (often referred to as the "application
+     *          class loader". The resulting delegation tree will be of the
+     *          form:
+     *      'bootCL--extensionCL--parentCL0-- ... --parentCLn--systemCL--newCL'
+     *     <li> StartUtil.PARENT_EXTENSION - creates a class loader with 
+     *          delegation tree of the form:
+     *                   'bootCL--extensionCL--newCL';
+     *          that is, there are no other class loaders between the
+     *          "extension class loader" and the class loader created by
+     *          this method.
+     *     <li> StartUtil.PARENT_SYSTEM_PARENT - creates a class loader whose
+     *          parent class loader is the parent loader of the current
+     *          system class loader. Thus, the new class loader will belong
+     *          to a tree of the form:
+     *          'bootCL--extensionCL--parentCL0-- ... --parentCLn--newCL',
+     *          where the "system class loader" has effectively been 
+     *          "skipped" in the tree. Typically, the system class loader
+     *          is the default delegation parent of any new ClassLoader
+     *          instances. Thus, the system class loader typically resides
+     *          in a delegation tree of the form: 
+     *          'bootCL--extensionCL--parentCL0-- ... --parentCLn--systemCL'
+     *          Thus, the 'systemCL' component of the tree is "skipped" when
+     *          the nParentsToSkip parameter is equal to PARENT_SYSTEM_PARENT.
+     *     <li> Any positive value - creates a class loader with delegation
+     *          tree of the form: 
+     *          'bootCL--extensionCL--parentCL0-- ... --parentCLi--newCL',
+     *          where the current tree is "walked", skipping the desired
+     *          number of parent class loaders in the current tree; where
+     *          the current tree is of the form: 
+     *   'bootCL--extensionCL--parentCL0-...-parentCLi-...-parentCLn--systemCL'
+     *  </ul>
+     * <p>
+     * @param searchPath     <code>String</code> containing the location(s)
+     *                       from which the new class loader will load
+     *                       requested classes. This parameter represents
+     *                       either a classpath (path/filenames separated by
+     *                       path separators), or a codebase (urls separated
+     *                       by spaces).
+     * @param isClasspath    <code>boolean</code> value indicating how this
+     *                       method should treat the <code>searchPath</code>
+     *                       parameter: as a classpath or a codebase.
+     * @param nParentsToSkip <code>int</code> value indicating the structure
+     *                       of the delegation tree with which to create the
+     *                       desired class loader. This parameter takes one
+     *                       of the following values: 
+     *                       <ul> <li> StartUtil.PARENT_DEFAULT 
+     *                            <li> StartUtil.PARENT_EXTENSION 
+     *                            <li> StartUtil.PARENT_SYSTEM_PARENT 
+     *                            <li> any positive integer value </ul>
+     *
+     * @return an instance of <code>URLClassLoader</code> with characteristics
+     *         as indicated by the values of the input parameters of this
+     *         method.
+     *                       
+     * @throws java.net.MalformedURLException 
+     */
+    public static URLClassLoader getURLClassLoader(String  searchPath,
+                                                   boolean isClasspath,
+                                                   int     nParentsToSkip)
+                                                  throws MalformedURLException
+    {
+        URL[] urls = ( (isClasspath) ?  getClasspathURLs(searchPath)
+                                      : getCodebaseURLs(searchPath)  );
+        ArrayList loaderList = null;
+        switch(nParentsToSkip) {
+            case PARENT_DEFAULT:
+                return ( new URLClassLoader(urls) );
+            case PARENT_EXTENSION: //explicitly use the extension cl as parent
+                loaderList = getCurClassLoaderTree();
+                int n = loaderList.size()-2;// index where extension should be
+                ClassLoader extClassLoader = (ClassLoader)(loaderList.get(n));
+                return ( new URLClassLoader(urls,extClassLoader) );
+            case PARENT_SYSTEM_PARENT: //use parent of system cl as parent
+                /* Retrieve the default delegation parent for new ClassLoader
+                 * instances (typically, this is the class loader that was
+                 * used to start the application). 
+                 */
+                ClassLoader sysClassLoader
+                                        = ClassLoader.getSystemClassLoader();
+                /* Retrieve the parent of the class loader just retrieved */
+                ClassLoader sysParentClassLoader = sysClassLoader.getParent();
+                /* Return a new class loader in which the default delegation
+                 * parent is removed (or "skipped") in the tree in favor of the
+                 * default parent's own parent loader.
+                 */
+                return ( new URLClassLoader(urls,sysParentClassLoader) );
+            default: //skip the requested number of parents in the tree
+                loaderList = getCurClassLoaderTree();
+                for(int i=0;i<nParentsToSkip;i++) {
+                    loaderList.remove(0);
+                }
+                ClassLoader parentClassLoader = (ClassLoader)loaderList.get(0);
+                return ( new URLClassLoader(urls,parentClassLoader) );
+        }//end case
+
+    }//end getURLClassLoader
+
+    /**
+     * Method that creates a <code>URLClassLoader</code> that will be 
+     * configured to load requested classes from the locations indicated
+     * by the <code>searchPath</code> parameter (which may be a classpath
+     * or a codebase, as indicated by the <code>isClasspath</code>parameter);
+     * and which will have a default delegation tree.
+     *
+     * @param searchPath     <code>String</code> containing the location(s)
+     *                       from which the new class loader will load
+     *                       requested classes. This parameter represents
+     *                       either a classpath (path/filenames separated by
+     *                       path separators), or a codebase (urls separated
+     *                       by spaces).
+     * @param isClasspath    <code>boolean</code> value indicating how this
+     *                       method should treat the <code>searchPath</code>
+     *                       parameter: as a classpath or a codebase.
+     *
+     * @return an instance of <code>URLClassLoader</code> with characteristics
+     *         as indicated by the values of the input parameters of this
+     *         method.
+     *                       
+     * @throws java.net.MalformedURLException 
+     */
+    public static URLClassLoader getURLClassLoader(String  searchPath,
+                                                   boolean isClasspath)
+                                                  throws MalformedURLException
+    {
+        return getURLClassLoader(searchPath,isClasspath,PARENT_DEFAULT);
+    }//end getURLClassLoader
+
+    /**
+     * Method that creates a <code>URLClassLoader</code> that will be 
+     * configured to load requested classes from the locations indicated
+     * by the <code>searchPath</code> parameter (which is assumed to be
+     * a codebase); and which will have a default delegation tree.
+     *
+     * @param searchPath     <code>String</code> containing the location(s)
+     *                       from which the new class loader will load
+     *                       requested classes. This parameter represents
+     *                       is assumed to be a codebase (urls separated
+     *                       by spaces).
+     *
+     * @return an instance of <code>URLClassLoader</code> with characteristics
+     *         as indicated by the values of the input parameters of this
+     *         method.
+     *                       
+     * @throws java.net.MalformedURLException 
+     */
+    public static URLClassLoader getURLClassLoader(String searchPath)
+                                                  throws MalformedURLException
+    {
+        return getURLClassLoader(searchPath,false,PARENT_DEFAULT);
+    }//end getURLClassLoader
+
+
+    /**
+     * Utility method that converts the components of a <code>String</code>
+     * representing a classpath into file urls; returning an array in which
+     * each element of the array is an instance of <code>URL</code>.
+     *
+     * @param classpath <code>String</code> containing components separated
+     *                  by path separators that represent the components
+     *                  making up a classpath
+     *
+     * @return an array containing instances of <code>URL</code> in which
+     *         each element of the array corresponds to one of the components
+     *         in the <code>classpath</code> parameter
+     *                       
+     * @throws java.net.MalformedURLException 
+     */
+    public static URL[] getClasspathURLs(String classpath)
+                                                 throws MalformedURLException
+    {
+        StringTokenizer st = new StringTokenizer(classpath,File.pathSeparator);
+        URL[] urls = new URL[st.countTokens()];
+        for (int i=0; st.hasMoreTokens(); i++) {
+            urls[i] = new File(st.nextToken()).toURL();
+        }
+        return urls;
+    }//end getClasspathURLs
+
+    /**
+     * Utility method that constructs from the given array of <code>URL</code>
+     * instances, a single space-separated <code>String</code>. The 
+     * <code>String</code> returned by this method can be used for things
+     * such as the  <code>location</code> argument when constructing an
+     * instance of <code>ActivationDesc</code>.
+     *
+     * @param urls <code>URL</code> array containing containing the elements
+     *             from which the return value will be constructed
+     *
+     * @return a single space-separated <code>String</code>. The 
+     *         <code>String</code> returned by this method can be used
+     *         for things such as the  <code>location</code> argument
+     *         when constructing an instance of <code>ActivationDesc</code>
+     */
+    public static String URLsToString(URL[] urls) {
+        if ( (urls == null) || (urls.length == 0) ) return new String("");
+        StringBuffer buffer = new StringBuffer(urls[0].toString());
+        for(int i=1;i<urls.length;i++) {
+            buffer.append(" "+urls[i].toString());
+        }
+        return  buffer.toString();
+    }//end URLsToString
+
+    /**
+     * Utility method that converts the components of a <code>String</code>
+     * representing a codebase into standard urls; returning an array in which
+     * each element of the array is an instance of <code>URL</code>.
+     *
+     * @param codebase  <code>String</code> containing components separated
+     *                  by spaces in which each component is in url format
+     *                  (http, ftp, etc)
+     *
+     * @return an array containing instances of <code>URL</code> in which
+     *         each element of the array corresponds to one of the components
+     *         in the <code>codebase</code> parameter
+     *                       
+     * @throws java.net.MalformedURLException 
+     */
+    public static URL[] getCodebaseURLs(String codebase)
+                                                 throws MalformedURLException
+    {
+        StringTokenizer st = new StringTokenizer(codebase);
+        URL[] urls = new URL[st.countTokens()];
+        for (int i=0; st.hasMoreTokens(); i++) {
+            urls[i] = new URL(st.nextToken());
+        }
+        return urls;
+    }//end getCodebaseURLs
+
+    /**
+     * Utility method that retrieves the components making up the class loader
+     * delegation tree for the current context class loader and returns each
+     * in an <code>ArrayList</code>.
+     *
+     * @return an <code>ArrayList</code> instance in which each element of the
+     *         list is one of the components making up the current delegation
+     *         tree.
+     */
+    public static ArrayList getCurClassLoaderTree() {
+        Thread curThread = Thread.currentThread();
+        ClassLoader curClassLoader = curThread.getContextClassLoader();
+        return getClassLoaderTree(curClassLoader);
+    }//end getCurClassLoaderTree
+
+    /**
+     * Utility method that retrieves the components making up the class loader
+     * delegation tree for the given <code>classloader</code>parameter and
+     * returns each in an <code>ArrayList</code>.
+     *
+     * @param classloader <code>ClassLoader</code> instance whose delegation
+     *                    tree is to be retrieved and returned
+     *
+     * @return an <code>ArrayList</code> instance in which each element of the
+     *         list is one of the components making up the delegation tree
+     *         of the given class loader.
+     */
+    public static ArrayList getClassLoaderTree(ClassLoader classloader) {
+        ArrayList loaderList = new ArrayList();
+        ClassLoader curClassLoader = classloader;
+        loaderList.add(curClassLoader);
+        ClassLoader parentClassLoader = curClassLoader.getParent();
+        loaderList.add(parentClassLoader);
+        while(parentClassLoader != null) {
+            parentClassLoader = parentClassLoader.getParent();
+            loaderList.add(parentClassLoader);
+        }//end loop
+        return loaderList;
+    }//end getClassLoaderTree
+
+    /**
+     * Utility method that displays the class loader delegation tree for
+     * the current context class loader. For each class loader in the tree,
+     * this method displays the locations from which that class loader
+     * will retrieve and load requested classes.
+     * <p>
+     * This method can be useful when debugging problems related to the
+     * receipt of exceptions such as <code>ClassNotFoundException</code>.
+     */
+    public static void displayCurClassLoaderTree() {
+        Thread curThread = Thread.currentThread();
+        ClassLoader curClassLoader = curThread.getContextClassLoader();
+        displayClassLoaderTree(curClassLoader);
+    }//end displayCurClassLoaderTree
+
+    /**
+     * Utility method that displays the class loader delegation tree for
+     * the given class loader. For each class loader in the tree, this
+     * method displays the locations from which that class loader will
+     * retrieve and load requested classes.
+     * <p>
+     * This method can be useful when debugging problems related to the
+     * receipt of exceptions such as <code>ClassNotFoundException</code>.
+     *
+     * @param classloader <code>ClassLoader</code> instance whose delegation
+     *                    tree is to be displayed
+     */
+    public static void displayClassLoaderTree(ClassLoader classloader) {
+        ArrayList loaderList = getClassLoaderTree(classloader);
+        System.out.println("");
+        System.out.println
+                         ("ClassLoader Tree has "+loaderList.size()+" levels");
+        System.out.println("  cl0 -- boot ClassLoader");
+        System.out.println("   |");
+        System.out.println("  cl1 -- extension ClassLoader");
+        for(int i=((loaderList.size()-2)-1),k=2;i>=0;i--,k++) {
+            System.out.println("   |");
+            ClassLoader curClassLoader = (ClassLoader)loaderList.get(i);
+            System.out.print("  cl"+k+" -- ClassLoader "
+                                   +curClassLoader+": ");
+            if(curClassLoader instanceof URLClassLoader) {
+                URL[] urls = ((URLClassLoader)(curClassLoader)).getURLs();
+                if(urls != null) {
+                    System.out.print(urls[0]);
+                    for(int j=1;j<urls.length;j++){
+                        System.out.print(", "+urls[j]);
+                    }
+                } else {//urls == null
+                    System.out.print("null search path");
+                }//endif
+            } else {
+                if(curClassLoader instanceof SecureClassLoader) {
+                    System.out.print("is instance of SecureClassLoader");
+                } else {
+                    System.out.print("is unknown ClassLoader type");
+                }
+            }//endif
+            System.out.println("");
+        }//end loop
+            System.out.println("");
+    }//end displayClassLoaderTree
+    
+    /**
+     * Custom class loader that only loads <code>ActivateClass</code> through
+     * the provided set of <code>URL</code>s. This class loader is used in 
+     * conjunction
+     * with <code>ActivateClass</code> to insert a user defined (non-null) 
+     * class loader onto the execution stack through which no other classes 
+     * (for example, stub classes) can be loaded. This setup provides the 
+     * desired "unmarshalling environment" for any calls made through the
+     * "loaded" 
+     * <code>ActivateClass</code>. That is, the last user defined class loader
+     * on the call stack is used to load any return values. If the classes 
+     * cannot be found through that class loader, then the context class loader
+     * is used (which is what we need in this case).
+     */
+    private static class ActivateClassLoader extends URLClassLoader {
+        ActivateClassLoader(URL[] urls, ClassLoader parent) { 
+	    super(urls, parent); 
+	}
+	
+        protected Class findClass(String name) throws ClassNotFoundException {
+            if (ActivateClass.class.getName().equals(name)) {
+                return super.findClass(name);
+            } else {
+                throw new ClassNotFoundException(name);
+            }
+        }
+    } // end ActivateClassLoader
+
+    /**
+     * Utility class used to delegate call to <code>ActivationID.activate</code>. 
+     * This class is intended to be loaded via an <code>ActivateClassLoader</code>
+     * instance in order to provide the proper unmarshalling environment
+     * needed by <code>ActivateWrapper.register()</code> and 
+     * <code>ServiceStarter.doCreate()</code>. 
+     */
+    public static class ActivateClass {
+        public static Remote activate(ActivationID id)
+            throws ActivationException, RemoteException
+        {
+            return id.activate(false);
+        }
+    } // end ActivateClass
+
+    /**
+     * Utility method that returns the <code>ActivateClass.activate</code>
+     * method that was loaded through an <code>ActivateClassLoader</code>.
+     * The class loader assumes that the necessary classes can be found
+     * through the system's class path.
+     */
+    public static Method getActivateMethod() 
+        throws ClassNotFoundException, NoSuchMethodException {
+        try {
+            ClassLoader cl = new ActivateClassLoader(
+                getClasspathURLs(System.getProperty("java.class.path")), null);
+	    Class c = Class.forName(ActivateClass.class.getName(), false, cl);
+            Method m = c.getDeclaredMethod(
+                "activate",
+                new Class[] { ActivationID.class });
+            return m;
+        } catch (MalformedURLException mue) {
+	    throw new ClassNotFoundException(
+	        "Could not determine classpath", mue);
+	}	        
+    }
+    
+ 
+}//end class ClassLoaderUtil

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

Added: river/tck/src/com/sun/jini/compat/start/CreateSharedGroup.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/start/CreateSharedGroup.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/start/CreateSharedGroup.java (added)
+++ river/tck/src/com/sun/jini/compat/start/CreateSharedGroup.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,145 @@
+/*
+ * 
+ * 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.start;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.rmi.activation.ActivationException;
+import java.rmi.activation.ActivationGroup;
+import java.rmi.activation.ActivationGroupID;
+import java.rmi.activation.ActivationGroupDesc;
+import java.rmi.activation.ActivationGroupDesc.CommandEnvironment;
+import java.rmi.MarshalledObject;
+import java.rmi.Remote;
+import java.security.AccessController;
+import java.util.Properties;
+
+import com.sun.jini.debug.Debug;
+
+/**
+ * This class contains the public methods and command-line interface for
+ * creating an instance of a shared activation group.
+ * This class employs the utility class 
+ * <code>com.sun.jini.compat.start.ServiceStarter</code> to create the 
+ * activation group and start a <code>SharedGroup</code> instance in that
+ * activation group. 
+ * That utility class requires that this class define a
+ * <code>public static create</code> method (and an optional 
+ * <code>public static createSharedGroup</code> method) that performs all 
+ * functions that are specific to the desired service. This method is invoked
+ * by the utility class.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ * @see com.sun.jini.compat.start.ServiceStarter
+ *
+ * @since 1.2 
+ */
+public class CreateSharedGroup {
+    /**
+     * Utility for outputting debug messages.
+     */
+    private static final Debug debug = 
+	(Debug)AccessController.doPrivileged(
+	    Debug.getDebugAction(GroupConstants.DEBUG_PROP));
+
+    /**
+     * Print writer for group creation related messages.
+     */
+    private static final PrintWriter dbgCreate = debug.getWriter("create");
+
+    /** 
+     * The fully qualified name of <code>this</code> class, which will be
+     * passed to the <code>ServiceStarter</code> utility class.
+     */
+    private static String starterClass = CreateSharedGroup.class.getName();
+
+    /** 
+     * The fully qualified name of the class that defines the
+     * implementation of the service to be started.
+     */
+    private static String implClass = SharedGroupImpl.class.getName();
+
+    /** 
+     * The name used to identify the particular resource bundle from which
+     * usage and error message information may be retrieved for display
+     * (helpful with internationalization).
+     */
+    private static String resourcename = GroupConstants.resourceName;
+
+    /**
+     * Command-line interface for creating a shared activation group.
+     *
+     * @param args <code>String</code> array containing the command 
+     *             line arguments
+     *
+     * @see com.sun.jini.compat.start.ServiceStarter
+     */
+    public static void main(String[] args) {
+        if (dbgCreate != null) {
+            dbgCreate.println("CreateSharedGroup::main");
+        }
+        Object proxy =
+            ServiceStarter.createSharedGroup(args, starterClass, 
+                                             implClass, resourcename);
+        if (dbgCreate != null) { 
+            dbgCreate.println("CreateSharedGroup::main:proxy-> " + proxy );
+        }
+
+    }//end main
+
+    /**
+     * This method defines how the shared activation group is started.
+     * This method will be invoked through reflection by the utility
+     * class <code>com.sun.jini.compat.start.ServiceStarter</code>. This method
+     * performs all functions that require knowledge of, or access to,
+     * the service-specific information; information that the utility
+     * class cannot easily obtain or exploit while attempting to start
+     * the desired service.
+     * <p>
+     * This method returns a proxy that provides client-side access to
+     * the shared activation group.
+     *
+     * @param  serverStub a <code>Remote</code> reference to the shared 
+     *         group instance
+     * 
+     * @return a proxy object that implements the <code>SharedGroup</code>
+     *         interface and provides client-side access to the
+     *         actual service implementation.
+     * 
+     * @see com.sun.jini.compat.start.ServiceStarter
+     */
+    public static SharedGroup create(Remote serverStub) {
+        if (dbgCreate != null) { 
+            dbgCreate.println("CreateSharedGroup::create(" + serverStub + ")");
+        }
+        // Create client-side proxy for backend service
+	return new SharedGroupProxy((SharedGroupBackEnd)serverStub);
+    }//end create
+
+    /*
+     * If the ServiceStarter framework's default logic for creating an 
+     * an activation group isn't appropriate, you can
+     * override it by defining the following method.
+     *
+     * public static ActivationGroupID createSharedGroup(
+     *     final Properties properties, 
+     *     final String serverJVM, 
+     *     final String[] options) { }
+     */
+}//end class CreateSharedGroup

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

Added: river/tck/src/com/sun/jini/compat/start/DestroySharedGroup.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/start/DestroySharedGroup.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/start/DestroySharedGroup.java (added)
+++ river/tck/src/com/sun/jini/compat/start/DestroySharedGroup.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,82 @@
+/*
+ * 
+ * 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.start;
+
+import java.io.PrintWriter;
+import java.security.AccessController;
+
+import com.sun.jini.debug.Debug;
+
+/**
+ * This class contains the command-line interface for
+ * destroying an instance of a shared activation group.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ * @see com.sun.jini.compat.start.ServiceStarter
+ * @see com.sun.jini.compat.start.StartUtil
+ *
+ * @since 1.2 
+ */
+public class DestroySharedGroup {
+    /**
+     * Utility for outputting debug messages.
+     */
+    private static final Debug debug =
+	(Debug)AccessController.doPrivileged(
+	    Debug.getDebugAction(GroupConstants.DEBUG_PROP));
+
+    /**
+     * Print writer for destruction related messages.
+     */
+    private static final PrintWriter dbgDestroy = debug.getWriter("destroy");
+
+    /** 
+     * The name used to identify the particular resource bundle from which
+     * usage and error message information may be retrieved for display
+     * (helpful with internationalization)
+     */
+    private static final String resourceName = GroupConstants.resourceName;
+    
+    /**
+     * Command-line interface for destroying a shared activation group.
+     *
+     * @param args <code>String</code> array containing the command 
+     *             line arguments
+     *
+     * @see com.sun.jini.compat.start.ServiceStarter
+     * @see com.sun.jini.compat.start.StartUtil
+     */
+    public static void main(String[] args) { 
+        StartUtil util = new StartUtil(resourceName);
+        if (args.length != 1) 
+            util.print("destroyGroup.usage", null);
+        try {
+            if (dbgDestroy != null) {
+                dbgDestroy.println("DestroySharedGroup::main: destroying -> "
+                    + args[0]);
+            }
+            ServiceStarter.destroySharedGroup(args[0], resourceName);
+	} catch (Exception e) {
+	    e.printStackTrace(System.err);
+	}
+
+    }
+}
+
+

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

Added: river/tck/src/com/sun/jini/compat/start/GroupConstants.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/start/GroupConstants.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/start/GroupConstants.java (added)
+++ river/tck/src/com/sun/jini/compat/start/GroupConstants.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.start;
+
+/**
+ * Interface that maintains shared activation constant values
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ */
+public interface GroupConstants {
+    /** 
+     * The name used to identify the particular resource bundle from which
+     * usage and error message information may be retrieved for display
+     * (helpful with internationalization)
+     */
+    public static final String resourceName = "service";
+
+    /** 
+     * The filename that contains the "cookie" for the activation
+     * group managing a particular log directory.
+     */
+    public static final String GROUP_COOKIE_FILE = "cookie";
+
+    /**
+     * Property string for enabling the debugging facility.
+     */
+    public static final String DEBUG_PROP = "com.sun.jini.compat.start.sharedvm.debug";
+}
+
+

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

Propchange: river/tck/src/com/sun/jini/compat/start/GroupConstants.java
------------------------------------------------------------------------------
    svn:executable = *

Added: river/tck/src/com/sun/jini/compat/start/HTTPDStatus.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/start/HTTPDStatus.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/start/HTTPDStatus.java (added)
+++ river/tck/src/com/sun/jini/compat/start/HTTPDStatus.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,654 @@
+/*
+ * 
+ * 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.start;
+
+import com.sun.jini.compat.start.StartUtil;
+
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.net.URL;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InterruptedIOException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+
+/**
+ * Class which can be used to determines if an HTTP server daemon is
+ *  currently up, running, and has access to a desired JAR file.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ */
+public class HTTPDStatus {
+
+    public  static final  int DOWN          = 0;
+    public  static final  int UP            = 1;
+    public  static final  int UP_BUT_NO_JAR = 2;
+
+    private static String defProtocol = "no_protocol";
+    private static String defHost     = getLocalHost();
+    private static int    defPort     = 80;
+    private static String defJarFile  = "no_jar_file";
+    private static int    timeout     = 1*1000; // wait 1 second for data
+
+    /**
+     * Command line interface executing a determination of whether or not
+     * an HTTP server daemon is up, running, and has access to a desired
+     * JAR file. This method parses the command line, determines if the
+     * appropriate valid arguments have been input, and then invokes a
+     * method which determines the status of the HTTP server referenced
+     * by the input arguments.
+     *
+     * @param args <code>String</code> array containing the command line
+     *             arguments
+     */
+    public static void main(String[] argv) {
+        String host    = defHost;
+        int    port    = defPort;
+        String jarFile = defJarFile;
+        if(argv.length > 3) {
+            System.err.println("Usage: HTTPDStatus <hostname> <port> "
+                               +"<jarFilename>");
+            return;
+        }//endif
+        // assume the first integer is the port
+        int portIndx = -1;
+        for(int i=0;i<argv.length;i++) {
+            try {
+                int tmpPort = Integer.parseInt(argv[i]);
+                port = tmpPort;
+                portIndx = i;
+                break;
+            } catch(NumberFormatException e) { }
+        }//endloop
+        // assume the first String ending in ".jar" is the JAR file to download
+        int jarIndx = -1;
+        for(int i=0;i<argv.length;i++) {
+            if(argv[i].endsWith(".jar")) {
+                jarFile = argv[i];
+                jarIndx = i;
+                break;
+            }
+        }//endloop
+        // assume the first argument that is not a port or JAR file is a host
+        for(int i=0;i<argv.length;i++) {
+            if( (portIndx == i) || (jarIndx == i) ) continue;
+            host = argv[i];
+            break;
+        }//endloop
+	int status = httpdStatus(host,port,jarFile);
+        System.out.println(status);
+    }//end main
+
+    /**
+     * This method determines the current status of the HTTP server(s)
+     * satisfying the configuration reflected in the  <code>codebase</code>
+     * parameter.
+     * <p>
+     * This method uses the host name and port number referenced in the
+     * <code>codebase</code> parameter to poll for the existence of a running
+     * HTTP server with access to the JAR file also referenced in the
+     * <code>codebase</code> parameter.
+     *
+     * @param codebase <code>String</code> containing the codebase to poll
+     *                 for the existence of a running HTTP server with
+     *                 access to the JAR file referenced in this parameter
+     * 
+     * @return <code>int</code> value equal to one of the public constants
+     *         defined in this class (DOWN,UP,UP_BUT_NO_JAR) that indicates
+     *         the current status of the HTTP server satisfying the
+     *         configuration reflected in the  <code>codebase</code> parameter
+     */
+    public static int httpdStatus(String codebase) {
+        /* Step through each codebase in the string, validating each */
+        String codebaseHost    = defHost;
+        int    codebasePort    = defPort;
+        String codebaseJarFile = defJarFile;
+        StringTokenizer st = new StringTokenizer(codebase," \"");
+        for (int i = 0; st.hasMoreTokens(); i++) {
+            String url = st.nextToken();
+            try {
+                URL codebaseUrl = new URL(url);
+                codebaseHost = codebaseUrl.getHost();
+                int tmpPort  = codebaseUrl.getPort();
+                if(tmpPort != -1) codebasePort = tmpPort;
+                codebaseJarFile = getURLFile(codebaseUrl);
+            } catch(MalformedURLException e) {
+                try {
+                    codebaseHost = InetAddress.getLocalHost().getHostName();
+                } catch(UnknownHostException e1) { }
+            }
+            int status = httpdStatus(codebaseHost,
+                                     codebasePort,
+                                     codebaseJarFile);
+            if(status != UP) return status;
+        }//endloop
+        return UP;
+    }//end httpdStatus
+
+    /**
+     * Like the version of this method that takes only a <code>codebase</code>
+     * parameter and returns a status value, this method also determines the
+     * current status of the HTTP server(s) satisfying the configuration
+     * reflected in the <code>codebase</code> parameter. But rather than
+     * returning a status value, this method will test each component of the
+     * <code>codebase</code> parameter and display a warning message if
+     * it is determined that a potential problem exists.
+     *
+     * @param codebase  <code>String</code> containing the codebase to poll
+     *                  for the existence of a running HTTP server with
+     *                  access to the JAR file referenced in this parameter
+     * @param startUtil an instance of the <code>StartUtil</code> class,
+     *                  configured with the appropriate resource bundle
+     *                  information, which is used as the mechanism through
+     *                  which warning message(s) will be displayed
+     */
+    public static void httpdStatus(String codebase,StartUtil startUtil) {
+        /* Step through each codebase in the string, validating each */
+        String codebaseHost    = defHost;
+        int    codebasePort    = defPort;
+        String codebaseJarFile = defJarFile;
+        StringTokenizer st = new StringTokenizer(codebase," \"");
+        for (int i = 0; st.hasMoreTokens(); i++) {
+            String curProtocol = defProtocol;
+            String url = st.nextToken();
+            try {
+                URL codebaseUrl = new URL(url);
+                curProtocol = codebaseUrl.getProtocol();
+                codebaseHost = codebaseUrl.getHost();
+                int tmpPort  = codebaseUrl.getPort();
+                if(tmpPort != -1) codebasePort = tmpPort;
+                codebaseJarFile = getURLFile(codebaseUrl);
+            } catch(MalformedURLException e) {
+                try {
+                    codebaseHost = InetAddress.getLocalHost().getHostName();
+                } catch(UnknownHostException e1) { }
+            }
+            String urlStr = "("+url+")";
+            if( ("http").equals(curProtocol) || ("ftp").equals(curProtocol) ) {
+                int status = httpdStatus(codebaseHost,
+                                         codebasePort,
+                                         codebaseJarFile);
+                if (status == HTTPDStatus.DOWN) {
+                    startUtil.print("httpserver.down", urlStr);
+                } else if(status == HTTPDStatus.UP_BUT_NO_JAR) {
+	            startUtil.print("httpserver.nojar", urlStr);
+                }//endif
+            } else {
+                if(("file").equals(curProtocol)) {
+                    startUtil.print("fileurl.warning", urlStr);
+                } else {
+                    startUtil.print("nonstandardurl.warning", urlStr);
+                }
+            }
+        }//endloop
+    }//end httpdStatus
+
+    /**
+     * This method determines the current status of the HTTP server
+     * satisfying the configuration reflected in the <code>host</code>,
+     * <code>port</code>, and <code>jarFile</code> parameters.
+     * This method uses the <code>host</code> and <code>port</code>
+     * parameters to poll for the existence of a running HTTP server
+     * with access to the JAR file referenced in the <code>jarFile</code>
+     * parameter.
+     *
+     * @param host    <code>String</code> containing the name of the host on
+     *                which to poll for the desired HTTP server
+     * @param port    <code>int</code> value representing the port number of
+     *                the host on which to poll for the desired HTTP server
+     * @param jarFile <code>String</code> containing the full path and file
+     *                name of a JAR file. If this method determines that an
+     *                HTTP server is running on the indicated <code>host</code>
+     *                and is listening on the indicated <code>port</code>
+     *                number, then a determination will be made as to whether
+     *                that HTTP server can access (can serve) the JAR file
+     *                referenced by the contents of this parameter.
+     * 
+     * @return <code>int</code> value equal to one of the public constants
+     *         defined in this class (DOWN,UP,UP_BUT_NO_JAR) that indicates
+     *         the current status of the HTTP server satisfying the
+     *         configuration reflected in the  <code>codebase</code> parameter
+     */
+    public static int httpdStatus(String host, int port, String jarFile) {
+        Socket s = openSocket(host,port);
+        if(s != null) {
+            writeGetToSocket(s,jarFile);
+            String[] headerArray = getHeader(s);
+            boolean httpdOK = replyOK(headerArray);
+            drainSocket(s);
+            closeSocket(s);
+            if(httpdOK) {
+                return UP;
+            } else { // could connect, but couldn't retrieve JAR file
+                return UP_BUT_NO_JAR;
+            }
+        } else { // couldn't even connect ==> down
+            return DOWN;
+        }
+    }//end httpdStatus
+
+    /**
+     * This method is an alternate implementation of the 3-arg version of
+     * the <code>httpdStatus</code> method of this class. This method is
+     * much simpler and more general than its alternate form. This method
+     * is presented as the alternate form of <code>httpdStatus</code>
+     * because, unfortunately, when the HTTP server is running on Windows,
+     * it causes the error 'socket write error <code=10053>'; which is
+     * annoying, but seems to be harmless. Also, this method only determines
+     * if the HTTP server is up or down; it doesn't determine the status
+     * of the server's ability to access the JAR file.
+     *
+     * @param host    <code>String</code> containing the name of the host on
+     *                which to poll for the desired HTTP server
+     * @param port    <code>int</code> value representing the port number of
+     *                the host on which to poll for the desired HTTP server
+     * @param jarFile <code>String</code> containing the full path and file
+     *                name of a JAR file. If this method determines that an
+     *                HTTP server is running on the indicated <code>host</code,
+     *                and is listening on the indicated <code>port</code>
+     *                number, then a determination will be made as to whether
+     *                that HTTP server can access (can serve) the JAR file
+     *                referenced by the contents of this parameter.
+     * 
+     * @return <code>int</code> value equal to one of the public constants
+     *         defined in this class (DOWN or UP) that indicates the
+     *         current status of the HTTP server satisfying the configuration
+     *         reflected in the <code>codebase</code> parameter
+     */
+    public static int httpdStatusAlt(String host, int port, String jarFile) {
+        try {
+            URL serverURL = new URL("http",host,port,"/"+jarFile);
+            Object content = serverURL.getContent();
+            if(content != null) {
+                return UP;
+            } else {
+                return DOWN;
+            }
+        } catch(Exception e) {
+            return DOWN;
+        }
+    }//end httpdStatusAlt
+
+    /**
+     * Returns the name of the host on which this method is being executed.
+     * If that name cannot be obtained, the <code>String</code> "localhost"
+     * will be returned.
+     * 
+     * @return <code>String</code> containing the name of the host on which
+     *         this method is currently executing; or "localhost" if the
+     *         actual name of the host cannot be obtained.
+     */
+    private static String getLocalHost() {
+        String host = "localhost";
+        try {
+            host = InetAddress.getLocalHost().getHostName();
+        } catch(UnknownHostException e) {
+            System.err.println("\nOn hostname retrieval -- "+e.toString());
+            e.printStackTrace();
+        }
+        return host;
+    }//end getLocalHost
+
+    /**
+     * Constructs and returns a stream socket to the destination corresponding
+     * to the <code>host</code> and <code>port</code> parameters.
+     * 
+     * @param host    <code>String</code> containing the non-<code>null</code>
+     *                name of the destination's host
+     * @param port    <code>int</code> value (0 <= port <= 65535) containing
+     *                the destination's port number
+     *
+     * @return <code>Socket</code> instance referencing a stream socket to the
+     *         destination corresponding to the <code>host</code> and 
+     *         <code>port</code> parameters
+     */
+    private static Socket openSocket(String host, int port) {
+        Socket s = null;
+        try {
+            s = new Socket(host,port);
+        } catch(Exception e) { }
+        return s;
+    }//end openSocket
+
+    /**
+     * Retrieves the file name of the given <code>URL</code> and if that 
+     * file name is prepended with a file separator, strips off the file
+     * separator.
+     * 
+     * @param url <code>URL</code> instance whose file name is to be returned.
+     * 
+     * @return <code>String</code> containing the name of the file
+     *         corresponding to the given <code>URL</code>.
+     */
+    private static String getURLFile(URL url) {
+        String urlFile = url.getFile();
+        if(urlFile.startsWith("/")) {
+            return urlFile.substring(1);
+        }
+        return urlFile;
+    }//end getURLFile
+
+    /**
+     * Writes a retrieval request (an HTTP "GET" request) to the given socket
+     * for the data reflected in the <code>request</code> parameter.
+     * 
+     * @param s       the <code>Socket</code> on which to write the request
+     * @param request <code>String</code> referencing the data to request
+     */
+    private static void writeGetToSocket(Socket s, String request) {
+        if( (s == null) || (request == null) ) return;
+        try {
+            DataOutputStream out = new DataOutputStream(s.getOutputStream());
+            out.writeBytes("GET /"+request+" HTTP/1.0\r\n\r\n");
+            out.flush();
+        } catch (Exception e) {
+            System.err.println("\nOn socket write -- "+e.toString());
+            e.printStackTrace();
+        }
+    }//end writeGetToSocket
+
+    /**
+     * Reads from the given socket, the header data sent by an HTTP server
+     * as a result of a "GET" request; and returns that header data in 
+     * a <code>String</code> array.
+     * 
+     * @param s the <code>Socket</code> from which to retrieve the header data
+     *
+     * @return <code>String</code> array that contains the header data 
+     *         retrieved from the given socket
+     */
+    private static String[] getHeader(Socket s) {
+        if(s == null) return new String[0];
+        String headerStr = null;
+        try {
+            InputStream cReader  = s.getInputStream();
+            StringBuffer buffer  = new StringBuffer();
+            while(true) {
+                int ch = cReader.read();
+                if(ch < 0) {
+                    break;
+                } else {
+                    buffer.append((char)ch);
+                    int len = buffer.length();
+                    if(len > 3) {
+                        /* Test for end of header */
+                        if(    (buffer.charAt(len-4) == '\r')
+                            && (buffer.charAt(len-3) == '\n') 
+                            && (buffer.charAt(len-2) == '\r') 
+                            && (buffer.charAt(len-1) == '\n') )
+                        {
+                            headerStr = buffer.toString();
+                            break; 
+                        }
+                    }//endif(len > 3)
+                }//endif(ch<0)
+            }//end while
+        } catch (InterruptedIOException e) {
+        } catch (IOException e) {
+            System.err.println("\nWhile getting header -- "+e.toString());
+            e.printStackTrace();
+        }//end try
+        if(headerStr == null) return new String[0];
+        ArrayList headerList = new ArrayList();
+        StringTokenizer st = new StringTokenizer(headerStr,"\r\n");
+        while(st.hasMoreTokens()) {
+            headerList.add(st.nextToken());
+        }//endloop
+        return ((String[])(headerList).toArray(new String[headerList.size()]));
+    }//end getHeader
+
+    /**
+     * Examines the status field of the given header data, and returns
+     * <code>true</code> if the contents of that field indicate that the
+     * request that generated the header is valid and acceptable to the
+     * server; and <code>false</code> otherwise.
+     * 
+     * @param header <code>String</code> containing the header data to examine
+     *
+     * @return <code>true</code> if the contents of given data indicate that
+     *         the request that generated the header is valid and acceptable
+     *         to the server; and <code>false</code> otherwise
+     */
+    private static boolean replyOK(String[] header) {
+        boolean responseOK = false;
+        if((header == null) || (header.length == 0)) return responseOK;
+        /* According to RFC's 1945 and 2616, the response to the request
+         * must be of the following form:
+         *
+         *   HTTP/version [space] StatusCode [space] ReasonPhrase CRLF
+         *
+         * If the status code is of the form 2xx, then the interpretation of
+         * the response is that the action was successfully received,
+         * understood, and accepted. Thus, below the header is parsed to
+         * determine if the response is from the HTTP protocol, and if
+         * the status code is of the form 2xx.
+         */
+        if( header[0].startsWith("HTTP/") ) {
+            int indx = header[0].indexOf(' '); //index of first space
+            if((indx != -1) && (header[0].substring(indx)).startsWith(" 2")) {
+                responseOK = true;
+            }
+        }
+        return responseOK;
+    }//end readHeader
+
+    /**
+     * Examines the "Content-Length:" field of the given header data, and
+     * returns the number of bytes on the socket to which the given header
+     * refers.
+     * 
+     * @param header <code>String</code> containing the header data to examine
+     *
+     * @return <code>int</code> value that indicates the number of bytes on
+     *         the socket to which the given header refers
+     */
+    private static int getNBytesToRead(String[] header) {
+        int nBytes = -1; // number of bytes in body as indicated in header
+        if((header == null) || (header.length < 2)) return nBytes;
+        if(header[1].startsWith("Content-Length:")){
+            StringTokenizer st = new StringTokenizer(header[1]);
+            while(st.hasMoreTokens()) {
+                String token = st.nextToken();
+                try {
+                    nBytes = Integer.parseInt(token);
+                } catch(NumberFormatException e) { }
+            }
+        }
+        return nBytes;
+    }//end getNBytesToRead
+
+    /**
+     * Reads and discards all data currently on the given socket.
+     * 
+     * @param s the <code>Socket</code> from which to read data
+     */
+    private static void drainSocket(Socket s) {
+        if(s == null) return;
+        try {
+            InputStream cReader = s.getInputStream();
+            for(int ch = cReader.read(); ch >= 0; ch = cReader.read()) { }
+        } catch (InterruptedIOException e) {
+        } catch (IOException e) {
+            System.err.println("\nWhile draining the socket -- "+e.toString());
+            e.printStackTrace();
+        }
+    }//end drainSocket
+
+    /**
+     * Reads and discards the next <code>nBytes</code> of data on the given
+     * socket.
+     * 
+     * @param s      the <code>Socket</code> from which to read data
+     * @param nBytes the specific number of bytes to read and discard
+     */
+    private static void drainSocket(Socket s, int nBytes) {
+        if( (s == null) || (nBytes <= 0) ) return;
+        try {
+            InputStream cReader = s.getInputStream();
+            int ch;
+            int nBytesRead = 0;
+            for(int i=0;i<nBytes;i++) {
+                try {
+                    ch = cReader.read();
+                    if(ch == -1) {
+                        break;
+                    } else {
+                        nBytesRead++;
+                    }
+                } catch (InterruptedIOException e) {
+                    System.err.println("\nSocket read time out: "+nBytesRead
+                                       +" bytes read before timeout occurred");
+                }
+            }//end loop
+        } catch (IOException e) {
+            System.err.println("\nWhile draining the socket -- "+e.toString());
+            e.printStackTrace();
+        }
+    }//end drainSocket
+
+    /**
+     * Changes the time-out period of the given socket to the given value
+     * in milliseconds.
+     * 
+     * @param s         the <code>Socket</code> whose time-out period is to be
+     *                  changed
+     * @param timeoutMs the new value of the given socket's time-out period
+     *                  in milliseconds
+     */
+    private static void setSocketTimeout(Socket s, int timeoutMs) {
+        if(s == null) return;
+        int t = (timeoutMs < 0 ? 0 : timeoutMs);
+        try {
+            s.setSoTimeout(t);
+        } catch(IOException e) {
+            System.err.println("\nOn setting socket timeout -- "+e.toString());
+            e.printStackTrace();
+        }
+    }//end setSocketTimeout
+
+    /**
+     * Changes the linger-on-close time-out period of the given socket to the
+     * given value in milliseconds.
+     * 
+     * @param s         the <code>Socket</code> whose linger-on-close time-out
+     *                  period is to be changed
+     * @param timeoutMs a non-negative number specifying the maximum number of
+     *                  milliseconds that <code>close</code> will block until
+     *                  the given socket is forcibly closed. If this value is
+     *                  zero, <code>close</code> will return immediately.
+     */
+    private static void setSocketLingerOn(Socket s, int timeoutMs) {
+        if(s == null) return;
+        int t = (timeoutMs < 0 ? 0 : timeoutMs);
+        try {
+            s.setSoLinger(true,t);
+        } catch(IOException e) {
+            System.err.println("\nOn setting socket linger on -- "
+                               +e.toString());
+            e.printStackTrace();
+        }
+    }//end setSocketLingerOn
+
+    /**
+     * Disables the linger-on-close option of the given socket.
+     * 
+     * @param s the <code>Socket</code> whose linger-on-close option is to
+     *          be disabled
+     */
+    private static void setSocketLingerOff(Socket s) {
+        if(s == null) return;
+        try {
+            s.setSoLinger(false,0);
+        } catch(IOException e) {
+            System.err.println("\nOn setting socket linger on -- "
+                               +e.toString());
+            e.printStackTrace();
+        }
+    }//end setSocketLingerOff
+
+    /**
+     * Closes the given socket.
+     * 
+     * @param s the <code>Socket</code> to close
+     */
+    private static void closeSocket(Socket s) {
+        if(s == null) return;
+        try {
+            s.close();
+        } catch(IOException e) {
+            System.err.println("\nOn closing socket -- "+e.toString());
+            e.printStackTrace();
+        }
+    }//end closeSocket
+
+    /**
+     * Prints to standard err, configuration information of the given socket.
+     * 
+     * @param s the <code>Socket</code> whose information will be displayed
+     */
+    private static void displaySocketInfo(Socket s) {
+        if(s == null) return;
+        System.out.println("Socket Information -- ");
+        System.out.println("  Destination:    "
+                             +"host/address - "+s.getInetAddress()
+                             +", port - "+
+                             +s.getPort());
+        System.out.println("  Source:         "
+                             +"host/address - "+s.getLocalAddress()
+                             +", port - "+
+                             +s.getLocalPort());
+        try {
+            System.out.println("  Socket Timeout: "+s.getSoTimeout());
+            int linger = s.getSoLinger();
+            if(linger < 0) {
+                System.out.println("  Socket Linger:  disabled");
+            } else {
+                System.out.println("  Socket Linger:  "+linger);
+            }
+            boolean usingNagle = s.getTcpNoDelay();
+            if(usingNagle == true) {
+                System.out.println("  Socket is using Nagle's algorithm");
+            } else {
+                System.out.println("  Socket is NOT using Nagle's algorithm");
+            }
+        } catch(SocketException e) { }
+        System.out.println("\n");
+    }//end displaySocketInfo
+
+    /**
+     * Simple utility method used to impose a delay, blocking processing for
+     * the requested number of milliseconds.
+     * 
+     * @param t the number of milliseconds to delay processing
+     */
+    private static void delay(int t) {
+        if(t <= 0) return;
+        try {Thread.sleep(t);} catch (InterruptedException e) { }
+    }//end delay
+
+}//end class HTTPDStatus

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

Added: river/tck/src/com/sun/jini/compat/start/ParsedArgs.java
URL: http://svn.apache.org/viewvc/river/tck/src/com/sun/jini/compat/start/ParsedArgs.java?rev=1234278&view=auto
==============================================================================
--- river/tck/src/com/sun/jini/compat/start/ParsedArgs.java (added)
+++ river/tck/src/com/sun/jini/compat/start/ParsedArgs.java Sat Jan 21 07:28:27 2012
@@ -0,0 +1,171 @@
+/*
+ * 
+ * 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.start;
+
+import net.jini.core.discovery.LookupLocator;
+import java.util.Properties;
+
+/**
+ * This class serves as a data structure (with associated data accessor
+ * methods), which can be used to store and return the values of the arguments
+ * extracted from the command line when starting a client or service.
+ *
+ * @author Sun Microsystems, Inc.
+ *
+ */
+public class ParsedArgs {
+    /** The RMI codebase with which to annotate all remote classes that are
+     * downloaded from the server side of the entity associated with the
+     * arguments represented in this class.
+     */
+    private String codebase;
+    /** The security policy file for the entity associated with the arguments
+     *  represented in this class.
+     */
+    private String policyFile;
+    /** The directory in which the state of the entity associated with the
+     *  arguments represented in this class will be recorded for persistence.
+     */
+    private String logDir;
+    /** If the entity associated with the arguments represented in this class
+     *  is a lookup service, this field contains the names of the groups
+     *  to which that lookup service is to be a member; otherwise, this
+     *  field contains the names of the groups whose members are the lookup
+     *  services the entity should discover and join
+     */
+    private String[] groups;
+    /** If the entity associated with the arguments represented in this class
+     *  is a lookup service, this field typically will have no effect on
+     *  the state of that lookup service; otherwise, this field contains
+     *  references to the specific lookup services the entity should
+     *  discover and join
+     */
+    private LookupLocator[] locators;
+
+    /** Specifies which VM implementation should be used for the backend
+     *  server of the entity, associated with the arguments of this class,
+     *  that will be started as an activatable service. When not
+     *  <code>null</code>, the value of this field is an absolute path
+     *  to an executable and that accepts all the standard VM command-line
+     *  options (for example, -D, -classpath, and so on), and directly or
+     *  indirectly start a VM. The value contained in this field is useful
+     *  for testing such entities on alternate VM implementations. 
+     */
+    private String javaProgram;
+    /** Specifies the system properties with which to start the entity,
+     *  associated with the arguments of this class, that will be started
+     *  as an activatable service.
+     */
+    private Properties properties;
+    /** Specifies the command options (for example -cp <classpath>) to
+     *  use when starting the entity, associated with the arguments of
+     *  this class, as an activatable service.
+     */
+    private String[] options;
+    /** Specifies the shared activation group pathname to use
+     *  when starting a shared, activatable service instance.
+     */
+    private String sharedvmLog;
+    /* Constructs an instance of this data structure with the appropriate
+     * values extracted from the command line of the client or service being
+     * started. This constructor leaves <code>sharedvmLog</code> as 
+     * <code>null</code>.
+     */
+    public ParsedArgs(String          codebase,
+                      String          policyFile,
+                      String          logDir,
+                      String[]        groups,
+                      LookupLocator[] locators,
+                      String          javaProgram,
+                      Properties      properties,
+                      String[]        options)
+    {
+        this.codebase    = codebase;
+        this.policyFile  = policyFile;
+        this.logDir      = logDir;
+        this.groups      = groups;
+        this.locators    = locators;
+        this.javaProgram = javaProgram;
+        this.properties  = properties;
+        this.options     = options;
+    }//end constructor
+
+    /* Constructs an instance of this data structure with the appropriate
+     * values extracted from the command line of the client or service being
+     * started.
+     */
+    public ParsedArgs(String          codebase,
+                      String          policyFile,
+                      String          logDir,
+                      String[]        groups,
+                      LookupLocator[] locators,
+                      String          javaProgram,
+                      Properties      properties,
+                      String[]        options,
+		      String          sharedvmLog)
+    {
+        this(codebase, policyFile, logDir, groups, locators,
+             javaProgram, properties, options);
+        this.sharedvmLog = sharedvmLog;
+    }
+
+    /** Returns the <code>codebase</code> field of this class */
+    public String getCodebase() {
+        return codebase;
+    }
+
+    /** Returns the <code>policyFile</code> field of this class */
+    public String getPolicyFile() {
+        return policyFile;
+    }
+
+    /** Returns the <code>logDir</code> field of this class */
+    public String getLogDir() {
+        return logDir;
+    }
+
+    /** Returns the <code>groups</code> field of this class */
+    public String[] getGroups() {
+        return groups;
+    }
+
+    /** Returns the <code>locators</code> field of this class */
+    public LookupLocator[] getLocators() {
+        return locators;
+    }
+
+    /** Returns the <code>javaProgram</code> field of this class */
+    public String getJavaProgram() {
+        return javaProgram;
+    }
+
+    /** Returns the <code>properties</code> field of this class */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /** Returns the <code>options</code> field of this class */
+    public String[] getOptions() {
+        return options;
+    }
+
+    /** Returns the <code>sharedvmLog</code> field of this class */
+    public String getSharedVMLog() {
+        return sharedvmLog;
+    }
+}//end class ParsedArgs

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