Hi All,

First I must admit I didn't follow this thread completely, second I have
no time to see whether I'm getting totally of topic :-) but what I do
know is I build a long time ago a build tool capable of delivering end
products based on our companies naming conventions. Part of that build
tool was automatic RMI stub/skeleton end EJB generation (for WebLogic
only).

In the future I would like to migrate to ant but currently I have no
time for that. However I thought lets drop in my knowledge of automatic
RMI generation. As far as I know it is conform the RMI specs and also
takes EJB's into account (by skipping them). I attach it over here.

In short it takes a file with paths to java files. The program assumes
correlating classes can be found through its classloader, the classes
will be checked to see if they are RMI objects, if so they are written
to a files and can be used as input for the RMI compiler. However I
think the isRMIObject method is the one to have a look at. This one is
dependent on the javax.ejb extension for it checks whether the object is
an EJB.

Regards,
-- 
Mark Brouwer
Virgil B.V.
/*
 * %Z%%M%    %R%, %E%
 *
 * Copyright (c) Virgil B.V., All rights reserved.
 */

package nl.virgil.app.tool.java;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Modifier;
import java.rmi.Remote;

import javax.ejb.EJBHome;
import javax.ejb.EJBObject;

import nl.virgil.lib.util.log.LogManager;
import nl.virgil.lib.util.log.Log;

/**
 * Scan a file with java objects for pure instances of RMI objects, the paths of
 * these objects are written to file.
 *
 * <h3>Purpose and Responsibilities</h3>
 *
 * The RemoteObjectFinder looks for java objects that are remote objetcs and
 * writes them to files. It skip remote objects that are not pure RMI object,
 * for example EJB objects. The output can be used for the RMI compiler
 * (<code>rmic</code>) for generating the stubs and skeletons. This class is
 * the executing point for the finder and takes three arguments:
 * <pre>
 *    Description: look for remote objects by scanning a file with paths to java
 *                 files. All matched classes are written to a file. The file
 *                 can be used as input for an RMI compiler.
 *
 *    Usage: java nl.virgil.lib.tools.RemoteObjectFinder <source> <input>
 *                                                       <output>
 *
 *    Required parameters:
 *
 *      source     path to the root of the Java files, comparable with the
 *                 directories you put in a classpath. The paths in the file
 *                 have to be absolute
 *
 *      input      path to file containing the all the java files to be
 *                 scanned for remote objects
 *
 *      output     path to file with the paths of the java objects being an
 *                 RMI object
 *
 * </pre>
 * The RMIObjectFinder introspects all the java objects in the file by
 * reflection. Classes implementing the [EMAIL PROTECTED] java.rmi.Remote
 * <code>java.rmi.Remote</code>} interface are written to file.
 *
 * @author   Mark Brouwer
 * @version  %R% : %L% - %B% - %S%, %E%
 */

public final class RemoteObjectFinder {

        /**
         * Create RemoteObjectFinder instance responsible for scanning remote
         * objects from a list of java classes.
         */
        private RemoteObjectFinder() {
                // nothing to do
        }

        /**
         * Entry point of RemoteObjectFinder tool, will start all processing.
         *
         * @param args arguments for the command, the first argument has to be
         *              the source root of the java classes. The second 
argument has to
         *              the file containing all the java files to be scanned 
for RMI
         *              objects
         */
        public static void main(String[] args) {

                // show usage if no three arguments have been given
                if (args.length != 3) {
                        
LogManager.getLog().write(RemoteObjectFinder.getUsage());

                        System.exit(1);
                }

                // create instance of RMI object finder
                RemoteObjectFinder rmifinder = new RemoteObjectFinder();

                // start processing
                rmifinder.start(args[0], args[1], args[2]);
        }

        /**
         * Start scanning for objects implementing the 
<code>java.rmi.Remote</code>
         * interface and that are pure RMI objects.
         * <p>
         * All matched pure RMI objects are written to file for further 
processing
         * by an RMI compiler, for example. Remote objects like EJB objects are 
not
         * considered as pure RMI objects.
         *
         * @param aSourcepath path to the root of the Java files, comparable 
with
         *              the directories you put in a classpath
         * @param anInputfile path to file containing the all the java files to 
be
         *              scanned for RMI objects
         * @param anOutputfile path to file with the paths of the java objetcs
         *              being an RMI object
         */
        public void start(String aSourcepath, String anInputfile,
                                          String anOutputfile) {

                // create the input and output file and scan all java files
                try {
                        FileInputStream in = new FileInputStream(anInputfile);
                        infile = new BufferedReader(new InputStreamReader(in));
                        FileOutputStream out = new 
FileOutputStream(anOutputfile);
                        outfile = new PrintWriter(new 
BufferedOutputStream(out));

                        String fullClass;

                        // read all java files from the input
                        while ((fullClass = infile.readLine()) != null) {
                                // convert file name to qualified class name
                                String className = 
getFullClassName(aSourcepath, fullClass);

                                // if a qualified class name has been found, 
scan it for being
                                // a remote object
                                if (className != null) {

                                        // check if the class is an RMI object, 
if so write it
                                        // to the output stream
                                        if (isRMIObject(className)) {
                                                outfile.println(className);
                                        }
                                }
                                else {
                                        LogManager.getLog().write("Wrong java 
filepath: "
                                                                                
          + fullClass);
                                }
                        }

                        // close open files
                        infile.close();
                        outfile.close();
                }
                catch (IOException e) {
                        // log exception and exit program
                        LogManager.getLog().write(null, e);
                        outfile.close();
                        System.exit(1);
                }
        }

        /**
         * Create usage message for showing the correct way of calling this
         * command.
         *
         * @return usage message for command
         */
        private static String getUsage() {

                // get line separator for this platform
                String sep = System.getProperty("line.separator");

                // buffer holding usage message, initial size set to 1024 bytes
                StringBuffer usage = new StringBuffer(1024);

                // append usage messages
                usage.append("   Description: look for remote objects by 
scanning a file with paths to java");
                usage.append(sep);
                usage.append("                files. All matched classes are 
written to a file. The file");
                usage.append(sep);
                usage.append("                can be used as input for an RMI 
compiler.");
                usage.append(sep);
                usage.append(sep);
                usage.append("    Usage: java 
nl.virgil.lib.tools.RemoteObjectFinder <source> <input>");
                usage.append(sep);
                usage.append("                                                  
     <output>");
                usage.append(sep);
                usage.append(sep);
                usage.append("    Required parameters:");
                usage.append(sep);
                usage.append(sep);
                usage.append("      source     path to the root of the Java 
files, comparable with the");
                usage.append(sep);
                usage.append("                 directories you put in a 
classpath. The paths in the file");
                usage.append(sep);
                usage.append("                 have to be absolute");
                usage.append(sep);
                usage.append(sep);
                usage.append("      input      path to file containing the all 
the java files to be");
                usage.append(sep);
                usage.append("                 scanned for remote objects");
                usage.append(sep);
                usage.append(sep);
                usage.append("      output     path to file with the paths of 
the java objects being an");
                usage.append(sep);
                usage.append("                 RMI object");
                usage.append(sep);

                return usage.toString();
        }

        /**
         * Get the full qualified class name of an java object, based on the
         * filepath of that object.
         *
         * @param aSourcepath path to the root of the Java files, comparable 
with
         *              the directories you put in a classpath. An empyt string 
means
         *              there is no source path and the files are relative
         * @param aJavaFile path name of the java file to be converted to full
         *              qualified class name
         *
         * @return full qualified class name or <code>null</code> if the source
         *              path (if specified) differs from the start of the file 
path
         */
        private String getFullClassName(String aSourcepath, String aJavaFile) {

                // full qualified class name based on java filename
                String className = null;

                // remove sourcepath for filenames if a sourcepath is given
                if (aSourcepath.length() > 0) {
                        // if the java filepath doesn't start with the source 
path return
                        // null
                        if (aJavaFile.startsWith(aSourcepath) == false) {
                                return null;
                        }

                        className = aJavaFile.substring(aSourcepath.length() + 
1);
                }

                // remove '.java' extension from filepath and change 
fileseparator to
                // package separator
                className = className.substring(0, className.length()
                                                                                
- ".java".length());
                className = className.replace(filesep.charAt(0), '.');

                return className;
        }

        /**
         * Check whether the given full qualified class is a remote object that 
is
         * not an EJB object.
         * <p>
         * An object is called to be a remote object when a class implements
         * the [EMAIL PROTECTED] java.rmi.Remote <code>java.rmi.Remote</code>} 
interface.
         *
         * @param aClassName full qualified class name to be checked
         */
        private boolean isRMIObject(String aClassName) {

                // get actual class for given name
                try {
                        Class object = Class.forName(aClassName, false,
                                                                                
 this.getClass().getClassLoader());

                        // return false in case the class is just an interface

                        if (object.isInterface()) {
                                return false;
                        }

                        // return false in case the class is abstract
                        if (Modifier.isAbstract(object.getModifiers())) {
                                return false;
                        }

                        // check whether the object is an remote object but no 
EJB
                        // object. An object is considered to be an EJB object 
in
                        // case it implements the EJBHome and EJBObject 
interface
                        if (EJBHome.class.isAssignableFrom(object)
                                || EJBObject.class.isAssignableFrom(object)) {

                                return false;
                        }
                        else {
                                // check whether the object directly implements 
a Remote
                                // interface that extends the java.rmi.Remote 
interface

                                Class[] interfaces = object.getInterfaces();
                                for (int index = 0 ; index < interfaces.length 
; index++) {
                                        if 
(Remote.class.isAssignableFrom(interfaces[index])) {
                                                return true;
                                        }
                                }
                        }
                }
                catch (ClassNotFoundException e) {
                        LogManager.getLog().write("Can't check class for remote 
object: ",
                                                                          e);
                }

                return false;
        }

        /** file separator for current OS */
        private String filesep = System.getProperty("file.separator");

        /** input stream for reading java classes to be scanned for RMI objects 
*/
        private BufferedReader infile;

        /** output stream to write RMI objects to */
        private PrintWriter outfile;
}

Reply via email to