JMU
Loading Java Classes from a Remote Machine
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Recall
A Brute Force Approach to Loading Remote Classes
A Brute Force Approach (cont.)
javaexamples/classloader/HTTPClassRetriever.java
        import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;

/**
 * An object that is responsible for retrieving classes from an
 * HTTP server and writing them to a local file
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class HTTPClassRetriever
{
    private String      uri;

    public static final String EXT = ".class";


    /**
     * Explicit Value Constructor
     * 
     * @param uri   The host and path to load from
     */
    public HTTPClassRetriever(String uri)
    {
        this.uri = uri;
    }

    /**
     * Retrieve the class using HTTP
     *
     * @param name  The name of the class (without the extension)
     * @param       The bytes that comprise the class
     */
    public void retrieveClass(String name) throws IOException
    {
        byte[]             bytes;
        FileOutputStream   out;

        bytes = requestBytes(name);
        out = new FileOutputStream(name+EXT);
        out.write(bytes);
    }

    /**
     * Request the bytes in the class using an HTTP GET request
     *
     * @param name  The name of the class (without the extension)
     * @param       The bytes that comprise the class
     */
    private byte[] requestBytes(String name) throws IOException
    {
       byte[]         bytes;
       InputStream    in;
       URL            u;

       u = new URL(uri + name + EXT);
        
       in    = u.openStream();
       bytes = new byte[in.available()];

       in.read(bytes);

       return bytes;
    }
}
        
A Brute Force Approach (cont.)
javaexamples/classloader/HTTPApplicationLauncher.java
        import java.lang.reflect.*;

/**
 * Retrieve a class containing an application 
 * (i.e., a class with a void main(String[] args))
 * from an HTTP server, save it locally, and execute it.
 * Example:
 *
 * java HTTPApplicationLauncher https://w3.cs.jmu.edu/bernstdh/web/common/lectures/javaexamples/classloader/ Example
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class HTTPApplicationLauncher
{
    /**
     * The entry point of this application
     *
     * @param args   The command-line arguments (URL, class)
     */
    public static void main(String[] args) throws Exception
    {
        
        Class                   appClass;
        Class[]                 parameters;
        HTTPClassRetriever      retriever;
        int                     realArgsLength;
        Method                  mainMethod;
        Object[]                oargs;
        String[]                realArgs;


        // Construct an HTTPClassRetriever that retrieves from
        // the host and path in args[0]
        retriever = new HTTPClassRetriever(args[0]);


        // Retrieve and save the class in args[1]
        retriever.retrieveClass(args[1]);

        // Get the Class
        appClass = Class.forName(args[1]);

        // We need the signature of the main method which includes
        // the class of the argument.  The easiest way to do
        // this is to use reflection and get the class of args
        parameters = new Class[1];
        parameters[0] = args.getClass();


        // Get the main method
        mainMethod = appClass.getDeclaredMethod("main", parameters);


        // Copy the remaining command line arguments
        realArgsLength = Math.max(args.length - 2, 0);
        realArgs = new String[realArgsLength];
        if (realArgsLength > 0) 
            System.arraycopy(args, 2, realArgs, 0, realArgsLength);
        oargs = new Object[]{realArgs}; // Initialize with realArgs


        // Invoke main
        //    Note: First argument is null because it's static
        mainMethod.invoke(null, oargs);
    }

}
        
A Remote Class Loader
A Remote Class Loader (cont.)
javaexamples/classloader/HTTPClassLoader.java
        import java.io.InputStream;
import java.io.IOException;
import java.net.URL;

/**
 * An object that is responsible for loading classes from an
 * HTTP server.
 *
 * @version 1.0
 * @author  Prof. David Bernstein, James Madison University
 */
public class HTTPClassLoader extends ClassLoader 
{

    private String      uri;

    public static final String EXT = ".class";


    /**
     * Explicit Value Constructor
     * 
     * @param uri   The host and path to load from
     */
    public HTTPClassLoader(String uri)
    {
       this.uri = uri;
    }

    /**
     * Finds the class with the specified name
     *
     * @param name    The name of the class (without extension)
     * @return        The resulting Class object
     */
    protected Class findClass(String name) throws ClassNotFoundException
    {
       byte[]         bytes;
       Class          c;

       bytes = null;
       try 
       {
          bytes = requestBytes(name);
          c = defineClass(name, bytes, 0, bytes.length);
          if (c == null) throw new ClassNotFoundException(name);
       } 
       catch (IOException ioe) 
       {
          throw new ClassNotFoundException(name);
       }

       return c;
    }

    /**
     * Request the bytes in the class using an HTTP GET request
     *
     * @param name  The name of the class (without the extension)
     * @param       The bytes that comprise the class
     */
    private byte[] requestBytes(String name) throws IOException
    {
       byte[]         bytes;
       InputStream    in;
       URL            u;


       u = new URL(uri + name + EXT);
        
       in    = u.openStream();
       bytes = new byte[in.available()];

       in.read(bytes);
        
       return bytes;
    }
}
        
A Remote Class Loader (cont.)
javaexamples/classloader/HTTPApplicationLoader.java
        import java.lang.reflect.*;

/**
 * Load an application (i.e., a class with a void main(String[] args))
 * from an HTTP server and execute it.
 *
 * Example:
 *
 * java HTTPApplicationLoader https://w3.cs.jmu.edu/bernstdh/web/common/lectures/javaexamples/classloader/ OtherExample Fred
 *
 * @version 1.0
 * @author  Computer Science Department, James Madison University
 */
public class HTTPApplicationLoader
{
    /**
     * The entry point of this application
     *
     * @param args   The command-line arguments (URL, class)
     */
    public static void main(String[] args) throws Exception
    {
        
        Class                   appClass;
        Class[]                 parameters;
        HTTPClassLoader         classLoader;
        int                     realArgsLength;
        Method                  mainMethod;
        Object[]                oargs;
        String[]                realArgs;


        // Construct an HTTPClassLoader that retrieves from
        // the host and path in args[0]
        classLoader = new HTTPClassLoader(args[0]);
        //setContextClassLoader(classLoader);

        // Load the class in args[1]
        //   Note: To get an instance use appClass.newInstance()
        appClass = classLoader.loadClass(args[1]);


        // We need the signature of the main method which includes
        // the class of the argument.  The easiest way to do
        // this is to use reflection and get the class of args
        parameters = new Class[1];
        parameters[0] = args.getClass();


        // Get the main method
        mainMethod = appClass.getDeclaredMethod("main", parameters);


        // Copy the remaining command line arguments
        realArgsLength = Math.max(args.length - 2, 0);
        realArgs = new String[realArgsLength];
        if (realArgsLength > 0) 
            System.arraycopy(args, 2, realArgs, 0, realArgsLength);
        oargs = new Object[]{realArgs}; // Initialize with realArgs


        // Invoke main
        //    Note: First argument is null because it's static
        mainMethod.invoke(null, oargs);
    }

}