FileDocCategorySizeDatePackage
DeploymentUtils.javaAPI DocGlassfish v2 API18331Thu Jul 19 11:29:38 BST 2007com.sun.enterprise.deployment.backend

DeploymentUtils.java

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. 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.html
 * or glassfish/bootstrap/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 glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [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.
 */

/*
 * @(#) DeploymentUtils.java
 *
 */
package com.sun.enterprise.deployment.backend;

import com.sun.enterprise.admin.server.core.AdminService;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.ServerHelper;
import com.sun.enterprise.config.serverbeans.Cluster;
import com.sun.enterprise.config.serverbeans.ClusterHelper;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.archivist.ArchivistFactory;
import com.sun.enterprise.deployment.archivist.AppClientArchivist;
import com.sun.enterprise.deployment.archivist.ApplicationArchivist;
import com.sun.enterprise.deployment.archivist.Archivist;
import com.sun.enterprise.deployment.archivist.ConnectorArchivist;
import com.sun.enterprise.deployment.archivist.EjbArchivist;
import com.sun.enterprise.deployment.archivist.WebArchivist;
import com.sun.enterprise.deployment.deploy.shared.FileArchive;
import com.sun.enterprise.deployment.RootDeploymentDescriptor;
import com.sun.enterprise.deployment.phasing.DeploymentServiceUtils;
import com.sun.enterprise.instance.AppclientModulesManager;
import com.sun.enterprise.instance.AppsManager;
import com.sun.enterprise.instance.BaseManager;
import com.sun.enterprise.instance.ConnectorModulesManager;
import com.sun.enterprise.instance.EjbModulesManager;
import com.sun.enterprise.instance.InstanceEnvironment;
import com.sun.enterprise.instance.WebModulesManager;
import com.sun.enterprise.loader.ClassLoaderUtils;
import com.sun.enterprise.loader.EJBClassLoader;
import com.sun.enterprise.server.Constants;
import com.sun.enterprise.util.io.FileUtils;

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

/** 
 * Utility methods for deployment backend. 
 *
 * @author Nazrul Islam
 * @since  JDK 1.4
 */
public final class DeploymentUtils {

    private DeploymentUtils()   { /* disallow instantiation */ }

    private static final Logger _logger = DeploymentLogger.get();

    /**
     * Sets the parent class loader for the given deployment request.
     *
     * @param    bootStrap    bootStrap (or parent) class loader 
     * @param    baseMgr      provides access to server configuration 
     * @param    req          deployment request
     *
     * @throws   ConfigException  if an error while reading the server.xml
     * @throws   IOException      if an i/o error
     */
    static void setParentClassLoader(ClassLoader bootStrap, BaseManager baseMgr,
            DeploymentRequest req) throws ConfigException, IOException {

        List allClassPaths = new ArrayList();
        
        // system class loader 
        List systemClasspath = baseMgr.getSystemCPathPrefixNSuffix();
        if (systemClasspath.size() > 0) {
            allClassPaths.addAll(systemClasspath);
        }

        // common class loader
        List commonClassPath = getCommonClasspath(baseMgr);
        if (commonClassPath.size() > 0) {
            allClassPaths.addAll(commonClassPath);
        }

        // shared class loader
        // Some explanation on the special handling below:
        // Per the platform specification, connector classes are to be availble
        // to all applications, i.e. a connector deployed to target foo should
        // be available to apps deployed on foo (and not target bar). In that
        // case, we will need to figure out all connector module deployed to 
        // the target on which the application is deployed.  Resolving the
        // classpath accordlingly. 
        String targetString = req.getResourceTargetList();
        List<String> targets = null;
        if (targetString != null) {
            // get the accurate list of targets from client
            targets = DeploymentServiceUtils.getTargetNamesFromTargetString(
                targetString); 
        } else {
            // get all the targets of this domain
            targets = new ArrayList<String>(); 
            ConfigContext configContext = AdminService.getAdminService(
                ).getAdminContext().getAdminConfigContext();

            Server[] servers = ServerHelper.getServersInDomain(configContext); 
            for (Server server: servers) {
                targets.add(server.getName());
            } 
            Cluster[] clusters = ClusterHelper.getClustersInDomain(
                configContext); 
            for (Cluster cluster: clusters) {
                targets.add(cluster.getName());
            } 
        }

        for (String target: targets) {
            List sharedClassPath = 
                baseMgr.getSharedClasspath(true, target);
            if (sharedClassPath.size() > 0) {
                allClassPaths.addAll(sharedClassPath);
            }
        }

        ClassLoader parentClassLoader = 
            getClassLoader(allClassPaths, bootStrap, null);

        // sets the parent class loader
        req.setParentClassLoader(parentClassLoader);

        // sets the class path for the class loader
        req.setParentClasspath(allClassPaths);
    }

    /**
     * Returns the class loader to be used for deployment. It contains all the 
     * urls for the given application.
     *
     * @param    classPaths   name of the application
     * @param    parent       parent class loader
     * @param    other        additional directory to be added to the class path
     *
     * @throws   exception  IOException  if an error while creating the 
     *                                   class loader
     */
    static EJBClassLoader getClassLoader(List paths, ClassLoader parent,
            File other) throws IOException {

        EJBClassLoader ejbCl  = null;

        if (parent != null) {
            ejbCl  = new EJBClassLoader(parent);
        } else {
            ejbCl  = new EJBClassLoader();
        }

        final int LIST_SZ = paths.size();
        for (int i=0; i<LIST_SZ; i++) {
            String path = (String) paths.get(i);
            ejbCl.appendURL(new File(path));
        }

        if (other != null) {
            ejbCl.appendURL(other);
        }

        return ejbCl;
    }

    /**
     * Returns the common class loader paths, if any, or an empty list.
     *
     * @param    mgr    manager obj that provides access to application config
     * @return   the common class path urls
     */
    static List getCommonClasspath(BaseManager mgr) throws IOException {

        InstanceEnvironment env  = mgr.getInstanceEnvironment();
        String dir               = env.getLibClassesPath();
        String jarDir            = env.getLibPath();

        return ClassLoaderUtils.getUrlList(new File[] {new File(dir)}, 
                                           new File[] {new File(jarDir)});
    }

	protected static String getSystemPropertyIgnoreCase(final String key)
	{
		Properties	p	= System.getProperties();
		Set			set = p.entrySet();

		for(Iterator it = set.iterator(); it.hasNext(); )
		{
			Map.Entry	me		= (Map.Entry)it.next();
			String		propKey = (String)me.getKey();
			
			if(key.compareToIgnoreCase(propKey) == 0)
				return (String)me.getValue();
		}
		
		return null;
	}

    /**
     * Returns the deployment descriptor object for the application.
     * Turn off the annotation processing during undeployment.  Note that 
     * this method is called *only* during the undeployment phase right now.
     *
     * @param    appDir       exploded application dir location
     *
     * @return   the deployment descriptor object for the application living in
	 * the given appdir
     *
     * @throws   IASDeploymentException if any of these other Exceptions are caught:
     * ConfigException  if unable to load the deployment descriptor
	 * AppConfigException  if an error if the while reading 
     *                               the deployment descriptor
     * IOException  if an i/o error
     */
    static Application getAppDescriptor(String appDir) throws IASDeploymentException
    {
        return getAppDescriptor(appDir, false);
	}

    /**
     * Returns the deployment descriptor object for the application.
     *
     * @param    appDir       exploded application dir location
     * @param    annotationProcessing whether to process annotation
     *
     * @return   the deployment descriptor object for the application living in
	 * the given appdir
     *
     * @throws   IASDeploymentException if any of these other Exceptions are caught:
     * ConfigException  if unable to load the deployment descriptor
	 * AppConfigException  if an error if the while reading 
     *                               the deployment descriptor
     * IOException  if an i/o error
     */
    static Application getAppDescriptor(String appDir, boolean annotationProcessing) 
            throws IASDeploymentException
    {
		try {
            FileArchive archive = new FileArchive();
            archive.open(appDir);

            ApplicationArchivist archivist = new ApplicationArchivist();
            archivist.setAnnotationProcessingRequested(annotationProcessing);
            archivist.setXMLValidation(false);

            return (Application) archivist.open(archive);
		} catch(Throwable t) {
			throw new IASDeploymentException(t);
		}
	}

    /**
     * Turn off the annotation processing during undeployment.  Note that 
     * this method is called *only* during the undeployment phase right now.
     */
    static Application getModuleDescriptor(String appDir) throws IASDeploymentException
    {
        return getModuleDescriptor(appDir, false);
    }

    static Application getModuleDescriptor(String appDir, boolean annotationProcessing) 
            throws IASDeploymentException
    {
        try {
            FileArchive archive = new FileArchive();
            archive.open(appDir);

            Archivist archivist =
                ArchivistFactory.getArchivistForArchive(archive);

            archivist.setAnnotationProcessingRequested(annotationProcessing);
            archivist.setXMLValidation(false);

            return (Application) ApplicationArchivist.openArchive(archivist, archive, true);
        } catch(Throwable t) {
            throw new IASDeploymentException(t);
        }
    }

    /**
     * This method returns a fully populated top level descriptor object.
     * It does so by first checking the cache in the instance manager.
     * If the descriptor object does not exist in cache, it then proceeds
     * to read off of the disk.  Note that reading from the disk is an
     * expensive operation.  So please use this method with caution.  In
     * addition, this method does not cache the read Descriptor object
     * in the instance manager so that query for Descriptors from cli and 
     * gui would not (and should not) meddle with the cache management for
     * descriptors.
     *
     *@param appId The module ID of the application
     *@param manager The instance manager for the module
     *@return The top level Descriptor object
     */
    public static RootDeploymentDescriptor getDescriptor(
            String appId, BaseManager manager) throws IASDeploymentException {
        Application application = manager.getRegisteredDescriptor(appId);
        if (application != null) {
            if (application.isVirtual()) {
                return application.getStandaloneBundleDescriptor();
            } else {
                return application;
            }
        }

        //Now, load from disk
        FileArchive in = new FileArchive();
        try {
            String appDir = manager.getLocation(appId);
            // if is system predeployed app, load from original app dir
            // else load from generated/xml dir
            // print a warning if generated/xml dir is not there
            // and load from original dir (upgrade scenario)
            if (manager.isSystemAdmin(appId)) {
                in.open(appDir);
            } else {
                String xmlDir = manager.getGeneratedXMLLocation(appId);
                if (FileUtils.safeIsDirectory(xmlDir)) {
                    in.open(xmlDir);
                } else {
                    // log a warning message in the server log
                    _logger.log(Level.WARNING, 
                        "enterprise.deployment.backend.no_generated_xmldir",
                        new Object[]{appId, xmlDir, appDir});
                    in.open(appDir);
                }
            }

            Archivist archivist = null;
            if (manager instanceof AppsManager) {
                archivist = new ApplicationArchivist();
            } else if (manager instanceof EjbModulesManager) {
                archivist = new EjbArchivist();
            } else if (manager instanceof WebModulesManager) {
                archivist = new WebArchivist();
            } else if (manager instanceof AppclientModulesManager) {
                archivist = new AppClientArchivist();
            } else if (manager instanceof ConnectorModulesManager) {
                archivist = new ConnectorArchivist();
            }

            archivist.setAnnotationProcessingRequested(false);
            archivist.setXMLValidation(false);
            Application desc = ApplicationArchivist.openArchive(
                                        appId, archivist, in, true);

            //note: we are not reading back the persistence information here
            //we could, if ever the tools need it.
            if (!desc.isVirtual()) {
                archivist.setHandleRuntimeInfo(false);
                ((ApplicationArchivist) 
                    archivist).readModulesDescriptors(desc, in);
                // now process runtime DDs
                archivist.setHandleRuntimeInfo(true);
                archivist.readRuntimeDeploymentDescriptor(in, desc);
            } else {
                return (BundleDescriptor)
                        desc.getBundleDescriptors().iterator().next();
            }
            return desc;
        } catch (Exception ex) {
            _logger.log(Level.SEVERE, 
                        "enterprise.deployment.backend.get_descriptor_failed",
                        new Object[]{appId});
            IASDeploymentException de = new IASDeploymentException(ex.getMessage());
            de.initCause(ex);
            throw de;
        } finally {
            try {
                in.close();
            } catch (Exception ex) {}
        }
    }

    /**
     * This method returns the relative file path of an embedded module to 
     * the application root.
     * For example, if the module is expanded/located at 
     * $domain_dir/applications/j2ee-apps/foo/fooEJB_jar,
     * this method will return fooEJB_jar
     *
     *@param appRootPath The path of the application root which
     *                   contains the module 
     *                   e.g. $domain_dir/applications/j2ee-apps/foo
     *@param moduleUri The module uri
     *                 e.g. fooEJB.jar
     *@return The relative file path of the module to the application root
     */
    public static String getRelativeEmbeddedModulePath(String appRootPath,
        String moduleUri) {
        moduleUri = FileUtils.makeLegalNoBlankFileName(moduleUri);
        if (FileUtils.safeIsDirectory(new File(appRootPath, moduleUri))) {
            return moduleUri;
        } else {
            return FileUtils.makeFriendlyFilename(moduleUri);
        }
    }

    /**
     * This method returns the file path of an embedded module. 
     * For example, if the module is expanded/located at 
     * $domain_dir/applications/j2ee-apps/foo/fooEJB_jar,
     * this method will return 
     * $domain_dir/applications/j2ee-apps/foo/fooEJB_jar
     *
     *@param appRootPath The path of the application root which
     *                   contains the module 
     *                   e.g. $domain_dir/applications/j2ee-apps/foo
     *@param moduleUri The module uri
     *                 e.g. fooEJB.jar
     *@return The file path of the module
     */
    public static String getEmbeddedModulePath(String appRootPath,
        String moduleUri) {
        return appRootPath + File.separator + getRelativeEmbeddedModulePath(appRootPath, moduleUri) ;
    }
}