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