Package com.sun.ejb.codegen

Source Code of com.sun.ejb.codegen.StaticRmiStubGenerator

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.ejb.codegen;

import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.api.deployment.DeploymentContext;
import org.glassfish.deployment.common.ClientArtifactsManager;
import org.glassfish.ejb.spi.CMPDeployer;
import org.glassfish.hk2.api.ServiceLocator;

import com.sun.enterprise.util.i18n.StringManager;
import com.sun.logging.LogDomains;

import com.sun.enterprise.config.serverbeans.JavaConfig;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.util.TypeUtil;
import com.sun.enterprise.util.OS;
import org.glassfish.api.admin.ServerEnvironment;

/**
* This class is used to generate the RMI-IIOP version of a
* remote business interface.
*/

public class StaticRmiStubGenerator {

    private static final StringManager localStrings = StringManager.getManager(StaticRmiStubGenerator.class);

     private static final Logger _logger =
                LogDomains.getLogger(StaticRmiStubGenerator.class, LogDomains.EJB_LOGGER);

     private static final String ORG_OMG_STUB_PREFIX  = "org.omg.stub.";

     private final String toolsJarPath;

     private List<String> rmicOptionsList;

    /**
     * This class is only instantiated internally.
     */
    public StaticRmiStubGenerator(ServiceLocator services) {
        // Find java path and tools.jar

        //Try this jre's parent
        String jreHome = System.getProperty("java.home");
        File jdkDir = null;
        if(jreHome != null) {
            // on the mac the java.home does not point to the jre
            // subdirectory.
            if (OS.isDarwin()) {
                jdkDir = new File(jreHome);
            } else {
                jdkDir = (new File(jreHome)).getParentFile();       //jdk_dir/jre/..
            }

            jdkDir = getValidDirectory(jdkDir);
        }

        if(jdkDir == null) {
            // Check for "JAVA_HOME" -- which is set via Server.xml during initialization
            // of the Server that is calling us.

            String jh = System.getProperty("JAVA_HOME");
            if(jh != null) {
                jdkDir = getValidDirectory(new File(jh))// e.g. c:/ias7/jdk
            }
        }

/** XXX ???
        if(jdkDir == null) {
            //Somehow, JAVA_HOME is not set. Try the "well-known" location...
            if(installRoot != null) {
                jdkDir = getValidDirectory(new File(installRoot + "/jdk"));

            }
        }
** XXX **/

        if(jdkDir == null) {
            _logger.warning("Cannot identify JDK location.");
            toolsJarPath = null;
        } else {
            File toolsJar = new File(jdkDir + "/lib/tools.jar" );
            if (toolsJar != null && toolsJar.exists()) {
                toolsJarPath = toolsJar.getPath();
            } else {
                toolsJarPath = null;
            }
        }

        JavaConfig jc = services.getService(JavaConfig.class,
                ServerEnvironment.DEFAULT_INSTANCE_NAME);
        String rmicOptions = jc.getRmicOptions();

        rmicOptionsList = new ArrayList<String>();
        StringTokenizer st = new StringTokenizer(rmicOptions, " ");
        while (st.hasMoreTokens()) {
            String op = (String) st.nextToken();
            rmicOptionsList.add(op);
            _logger.log(Level.INFO, "Detected Rmic option: " + op);
        }
    }

    /**
     * Generates and compiles the necessary impl classes, stubs and skels.
     *
     * <pre>
     *
     * This method makes the following assumptions:
     *    - the deployment descriptor xmls are registered with Config
     *    - the class paths are registered with Config
     *
     * @@@
     * In case of re-deployment, the following steps should happen before:
     *    - rename the src dir from previous deployment (ex. /app/pet-old)
     *    - rename the stubs dir from previous deployment (ex. /stub/pet-old)
     *    - explode the ear file (ex. /app/petstore)
     *    - register the deployment descriptor xml with config
     *    - register the class path with config
     *
     * After successful completion of this method, the old src and sutbs
     * directories may be deleted.
     *
     * </pre>
     *
     * @param    deploymentCtx
     *
     * @return   array of the client stubs files as zip items or empty array
     *
     */
    public void ejbc(DeploymentContext deploymentCtx) throws Exception {

        // stubs dir for the current deployment
        File stubsDir = deploymentCtx.getScratchDir("ejb");
        String explodedDir = deploymentCtx.getSource().getURI().getSchemeSpecificPart();

        // deployment descriptor object representation
        EjbBundleDescriptor ejbBundle  = deploymentCtx.getModuleMetaData(EjbBundleDescriptor.class);

        long startTime = now();

        // class path to be used for this application during javac & rmic
        String classPath =  deploymentCtx.getTransientAppMetaData(CMPDeployer.MODULE_CLASSPATH, String.class);

        // getClassPath(ejbcCtx.getClasspathUrls(), stubsDir);

        // Warning: A class loader is passed in while constructing the
        //          application object
        final ClassLoader jcl = ejbBundle.getClassLoader();

        // stubs dir is used as repository for code generator
        final String gnrtrTMP = stubsDir.getCanonicalPath();

        // ---- EJB DEPLOYMENT DESCRIPTORS -------------------------------

        // The main use-case we want to support is the one where existing
        // stand-alone java clients that access ejbs hosted in our appserver
        // directly through CosNaming need the generated stubs.  We don't want to
        // force them to run rmic themselves so it's better for them
        // just to tell us during the deployment of an ejb client app
        // or ejb app that we should run rmic and put the stubs in the
        // client.jar.  Turning on the deployment-time rmic flag ONLY
        // controls the generation of rmic stubs.  Dynamic stubs will be used
        // in the server, in the Application Client container, and in
        // stand-alone clients that instantiate our naming provider. 

        progress(localStrings.getStringWithDefault
                 ("generator.processing_beans", "Processing beans..."));


        // ---- END OF EJB DEPLOYMENT DESCRIPTORS --------------------------

        // ---- RMIC ALL STUB CLASSES --------------------------------------

        Set<String> allStubClasses = new HashSet<String>();

        // stubs classes for ejbs within this app that need rmic
        Set<String> ejbStubClasses = getStubClasses(jcl, ejbBundle);
        allStubClasses.addAll(ejbStubClasses);

        // Compile and RMIC all Stubs
        rmic(classPath, allStubClasses, stubsDir, gnrtrTMP, explodedDir);

        _logger.log(Level.INFO,  "[RMIC] RMIC execution time: " + (now() - startTime) + " msec");

        // ---- END OF RMIC ALL STUB CLASSES -------------------------------

        // Create list of all server files and client files
        List<String> allClientFiles = new ArrayList<String>();

        // assemble the client files
        addGeneratedFiles(allStubClasses, allClientFiles, stubsDir);

        ClientArtifactsManager cArtifactsManager =  ClientArtifactsManager.get(deploymentCtx);
        for (String file : allClientFiles) {
            cArtifactsManager.add(stubsDir, new File(file));
        }

        _logger.log(Level.INFO, "ejbc.end", deploymentCtx.getModuleMetaData(Application.class).getRegistrationName());
        _logger.log(Level.INFO,  "[RMIC] Total time: " + (now() - startTime) + " msec");

    }

    /**
     * Compile all the generated .java files, run rmic on them.
     *
     * @param    classPath         class path for javac & rmic
     * @param    stubClasses  additional classes to be compilled with
     *                             the other files
     * @param    destDir           destination directory for javac & rmic
     * @param    repository        repository for code generator
     * @param    explodedDir  exploded directory for .class files
     *
     * @exception    GeneratorException  if an error during code generation
     * @exception    IOException         if an i/o error
     */
    private void rmic(String classPath, Set<String> stubClasses, File destDir,
                                String repository, String explodedDir)
        throws GeneratorException, IOException
    {

        if( stubClasses.size() == 0 ) {
            _logger.log(Level.INFO,  "[RMIC] No code generation required");
            return;
        }

        if( toolsJarPath == null && !OS.isDarwin()) {
            _logger.log(Level.INFO,  "[RMIC] tools.jar location was not found");
            return;
        }

        progress(localStrings.getStringWithDefault(
                                         "generator.compiling_rmi_iiop",
                                         "Compiling RMI-IIOP code."));

        List<String> cmds = new ArrayList<String>();
        cmds.addAll(rmicOptionsList);
        cmds.add("-classpath");

        StringBuilder sb = new StringBuilder().append(System.getProperty("java.class.path"));
        if (toolsJarPath != null) {
             sb.append(File.pathSeparator).append(toolsJarPath);
        }
        sb.append(File.pathSeparator).append(explodedDir)
          .append(File.pathSeparator).append(repository)
          .append(File.pathSeparator).append(classPath);

        cmds.add(sb.toString());
        cmds.add("-d");
        cmds.add(destDir.toString());
        cmds.addAll(stubClasses);

        _logger.info("[RMIC] options: " + cmds);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        sun.rmi.rmic.Main compiler = new sun.rmi.rmic.Main(baos, "rmic");
        boolean success = compiler.compile(cmds.toArray(new String[cmds.size()]));
        //success = true;  // it ALWAYS returns an "error" if -Xnocompile is used!!

        String output = baos.toString();
        if (!success) {
             _logger.warning("[RMIC] Errors: " + output);
            throw new GeneratorException(
                    localStrings.getString("generator.rmic_compilation_failed_see_log"));
        }
    }

    /**
     * Assembles the name of the client jar files into the given vector.
     *
     * @param    stubClasses  classes that required rmic
     * @param    allClientFiles    List that contains all client jar files
     * @param    stubsDir          current stubsnskells dir for the app
     */
    private void addGeneratedFiles(Set<String> stubClasses,
                                   List<String> allClientFiles, File stubsDir)
    {
        for (String stubClass : stubClasses) {
            String stubFile = stubsDir.toString() + File.separator +
                                getStubName(stubClass).replace('.',
                                File.separatorChar) + ".class";
            allClientFiles.add(stubFile);
        }

        _logger.log(Level.INFO,
                    "[RMIC] Generated client files: " + allClientFiles);
    }

     
    private String getStubName(String fullName) {

        String className = fullName;
        String packageName = "";

        int lastDot = fullName.lastIndexOf('.');
        if (lastDot != -1) {
            className   = fullName.substring(lastDot+1, fullName.length());
            packageName = fullName.substring(0, lastDot+1);
        }

        String stubName = packageName + "_" + className + "_Stub";

      if(isSpecialPackage(fullName))
            stubName = ORG_OMG_STUB_PREFIX + stubName;

        return stubName;
    }

    private boolean isSpecialPackage(String name)
    {
      // these package names are magic.  RMIC puts any home/remote stubs
      // into a different directory in these cases.
      // 4845896  bnevins, April 2003

      // this is really an error.  But we have enough errors. Let's be forgiving
      // and not allow a NPE out of here...
      if(name == null)
        return false;

      // Licensee bug 4959550
      // if(name.startsWith("com.sun.") || name.startsWith("javax."))
      if(name.startsWith("javax.")) {
        return true;
        }

      return false;
    }

    private Set getRemoteSuperInterfaces(ClassLoader jcl,
                                         String homeRemoteIntf)
        throws ClassNotFoundException {

        // all super interfaces of home or remote that need to be
        // processed for stubs.
        Set allSuperInterfaces =
            TypeUtil.getSuperInterfaces(jcl, homeRemoteIntf,"java.rmi.Remote");

        Set remoteSuperInterfaces = new HashSet();

        Iterator iter = allSuperInterfaces.iterator();
        while (iter.hasNext()) {
            String intfName = (String) iter.next();
            Class  intfClass = jcl.loadClass(intfName);
            if ( java.rmi.Remote.class.isAssignableFrom(intfClass) &&
                 !(intfName.equals("javax.ejb.EJBHome")) &&
                 !(intfName.equals("javax.ejb.EJBObject")) ) {
                remoteSuperInterfaces.add(intfName);
            }
        }

        return remoteSuperInterfaces;
    }


    private Set<String> getStubClasses(ClassLoader jcl,
                              EjbBundleDescriptor ejbBundle)
            throws IOException, ClassNotFoundException
    {

        Set<String> stubClasses     = new HashSet<String>();

        for (Iterator iter = ejbBundle.getEjbs().iterator(); iter.hasNext();)
        {

            EjbDescriptor desc = (EjbDescriptor) iter.next();
            if( desc.isRemoteInterfacesSupported() ) {

                String home   = desc.getHomeClassName();
                String remote = desc.getRemoteClassName();

                stubClasses.add(home);
                Set homeSuperIntfs = getRemoteSuperInterfaces(jcl, home);
                stubClasses.addAll(homeSuperIntfs);


                stubClasses.add(remote);
                Set remoteSuperIntfs = getRemoteSuperInterfaces(jcl, remote);
                stubClasses.addAll(remoteSuperIntfs);

            }

        }

        return stubClasses;
    }

    /**
     * Helper method - returns the class path as string with path separator.
     *
     * @param    paths      array of class paths
     * @param    other      additional directory to be added to the class path
     *
     * @return   class path for the given application
     */
    private String getClassPath(String[] paths, File other) {

        StringBuilder sb  = new StringBuilder();

        for (int i=0; i<paths.length; i++) {
            sb.append(paths[i]+File.pathSeparator);
        }

        if (other != null) {
            sb.append(other.toString());
        }

        return sb.toString();
    }



    private long now()
    {
        return System.currentTimeMillis();
    }

    private void progress(String message) {
            try {
                _logger.log(Level.INFO, message);
            } catch(Throwable t) {
                _logger.log(Level.FINER,"Cannot set status message",t);
            }
    }


    private File getValidDirectory(File f) {
        try {
            if(f != null && f.isDirectory()) {
                return f.getCanonicalFile();
            }
        } catch (IOException e) {
            _logger.log(Level.INFO, e.getMessage(), e);
        }
        return null;
    }

}
TOP

Related Classes of com.sun.ejb.codegen.StaticRmiStubGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.