Package org.jdesktop.wonderland.webserver

Source Code of org.jdesktop.wonderland.webserver.WebDeployer$DeployRecord

/**
* Open Wonderland
*
* Copyright (c) 2010 - 2011, Open Wonderland Foundation, All Rights Reserved
*
* Redistributions in source code form must reproduce the above
* copyright and this condition.
*
* The contents of this file are subject to the GNU General Public
* License, Version 2 (the "License"); you may not use this file
* except in compliance with the License. A copy of the License is
* available at http://www.opensource.org/licenses/gpl-license.php.
*
* The Open Wonderland Foundation designates this particular file as
* subject to the "Classpath" exception as provided by the Open Wonderland
* Foundation in the License file that accompanied this code.
*/

/**
* Project Wonderland
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc., All Rights Reserved
*
* Redistributions in source code form must reproduce the above
* copyright and this condition.
*
* The contents of this file are subject to the GNU General Public
* License, Version 2 (the "License"); you may not use this file
* except in compliance with the License. A copy of the License is
* available at http://www.opensource.org/licenses/gpl-license.php.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied
* this code.
*/
package org.jdesktop.wonderland.webserver;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.jar.JarInputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.embedded.LifecycleException;
import org.jdesktop.wonderland.modules.Module;
import org.jdesktop.wonderland.modules.ModulePart;
import org.jdesktop.wonderland.modules.spi.ModuleDeployerSPI;
import org.jdesktop.wonderland.utils.FileListUtil;
import org.jdesktop.wonderland.utils.RunUtil;

/**
* Deploy web modules to the app server
* @author jkaplan
*/
public class WebDeployer implements ModuleDeployerSPI {
    private static final Logger logger =
            Logger.getLogger(WebDeployer.class.getName());
   
    private static final String DEPLOY_DIR = "webdeploy";
    private static final String CHECKSUM_FILE = "webchecksums.list";

    /** list of deployed wars to avoid duplicate deploys */
    private static final List<DeployRecord> deployed =
            new ArrayList<DeployRecord>();

    /** property for disabling the deployer */
    static final String WEBDEPLOY_PARTNAME_PROP = "web.deployer.part";
    private static final String WEBDEPLOY_PARTNAME_DEFAULT = "web";

    private static String partName = System.getProperty(WEBDEPLOY_PARTNAME_PROP,
                                                        WEBDEPLOY_PARTNAME_DEFAULT);

    /**
     * Get the name of this deployer
     * @return the deployer
     */
    public String getName() {
        return "Web";
    }

    /**
     * This deployer supports the web part of modules
     * @return the types
     */
    public String[] getTypes() {
        return new String[] { partName };
    }

    /**
     * Web modules are always deployable if the server is running
     */
    public boolean isDeployable(String type, Module module, ModulePart part) {
        return RunAppServer.getAppServer().isDeployable();
    }

    /**
     * Web modules are always undeployable
     */
    public boolean isUndeployable(String arg0, Module arg1, ModulePart arg2) {
        return true;
    }
   
    /**
     * Deploy a web app
     * @param type the type of app
     * @param module the module to deploy wars from
     * @param part the web module part
     */
    public void deploy(String type, Module module, ModulePart part) {
        for (File war : getWebApps(part.getFile(), getFileSuffixes())) {
            try {
                deployFile(module.getName(), war);
            } catch (IOException ioe) {
                logger.log(Level.WARNING, "Unable to deploy " + war, ioe);
            }
        }
    }

    protected void deployFile(String moduleName, File war)
            throws IOException
    {
        File deployDir = new File(RunUtil.getRunDir(), DEPLOY_DIR);
        deployDir.mkdir();
       
        // generate a checksum for the file
        String checksum = FileListUtil.generateChecksum(new FileInputStream(war));
       
        // create a record for this file
        DeployRecord record = new DeployRecord(moduleName, war.getName(),
                                               checksum);

        // find out if we already have a record for this application
        DeployRecord existing = null;
        synchronized (deployed) {
            int idx = deployed.indexOf(record);
            if (idx != -1) {
                existing = deployed.get(idx);
            }
        }

        // if we do have a record, see if the checksums match
        if (existing != null && existing.checksumMatches(checksum)) {
            // this version is already deployed.
            return;
        } else if (existing != null) {
            // a different version of the same module is already deployed --
            // undeploy it.
            logger.warning("Duplicate deploy " + record + ", undeploying");
            undeploy(existing);
        }

        // read the checksums in the deploy directory
        File checksumFile = getChecksumFile(deployDir);
        Map<String, String> checksums = FileListUtil.readChecksums(checksumFile);

        // see if we already have written this version to disk
        String checksumKey = moduleName + "-" + war.getName();
        File extractDir = new File(deployDir, checksumKey);

        // see if the checksum matches.  If it doesn't match, get rid of what
        // is there and overwrite it with the new directory
        String fileChecksum = checksums.get(checksumKey);
        if (fileChecksum == null || !fileChecksum.equals(checksum)) {
            // make sure the directory doesn't already exist.  If it does, remove it
            if (extractDir.exists()) {
                logger.warning("Directory " + extractDir + " already exists");
                RunUtil.deleteDir(extractDir);
            }

            // extract the war file
            doExtract(war, extractDir);
        }

        // update our record with the directory
        record.setFile(extractDir);

        // do the actual deploy
        doDeploy(record);

        // record that the app is installed
        synchronized (deployed) {
            deployed.add(record);
        }

        // update the checksums, and write them out
        checksums.put(checksumKey, checksum);
        FileListUtil.writeChecksums(checksums, checksumFile);
    }

    protected void doExtract(File war, File extractDir) throws IOException {
        // extract the war into the directory
        JarInputStream jin = new JarInputStream(new FileInputStream(war));
        try {
            RunUtil.extractZip(jin, extractDir);
        } finally {
            jin.close();
        }
    }

    protected void doDeploy(DeployRecord record) throws IOException {
        // create a context root for this app.  The context root is
        // <module-name>/<war-name>, where <war-name> is the name of
        // the .war file with ".war" taken off.
        String contextRoot = record.getModuleName() + "/" +
                             record.getWarName();
        if (contextRoot.endsWith(".war")) {
            contextRoot = contextRoot.substring(0,
                                        contextRoot.length() - ".war".length());
        }

        DeployCommandParameters dcp = new DeployCommandParameters(record.getFile());
        dcp.contextroot = contextRoot;

        // finally, deploy the application to the web server
        try {
            String name = RunAppServer.getAppServer().deploy(record.getFile(),
                                                             dcp);
            record.setAppName(name);
        } catch (LifecycleException ee) {
            throw new IOException(ee);
        }
    }

    /**
     * Undeploy a web app
     * @param type the type of app
     * @param module the module to undeploy wars from
     * @param part the web module part
     */
    public void undeploy(String type, Module module, ModulePart part) {
        for (File war : getWebApps(part.getFile(), getFileSuffixes())) {
            DeployRecord record = new DeployRecord(module.getName(), war.getName());
            undeploy(record);
        }
    }
   
    /**
     * Undeploy a war file from the given module
     * @param record the module to undeploy
     */
    protected void undeploy(DeployRecord record) {
        // remove the record of this deployment
        DeployRecord remove = null;
        synchronized (deployed) {
            int deployIdx = deployed.indexOf(record);
            if (deployIdx != -1) {
                remove = deployed.get(deployIdx);
                deployed.remove(deployIdx);
            }
        }

        // make sure we found a record
        if (remove == null) {
            logger.fine("Not found on undeploy " + record);
            return;
        }

        // do the actual undeploy
        doUndeploy(remove);

        // remove the files associated with this record
        if (remove.getFile() != null) {
            RunUtil.deleteDir(remove.getFile());
        }

        // read the checksums in the deploy directory
        try {
            File deployDir = new File(RunUtil.getRunDir(), DEPLOY_DIR);
            File checksumFile = getChecksumFile(deployDir);
            Map<String, String> checksums = FileListUtil.readChecksums(checksumFile);

            // remove this checksum and write out the update
            String checksumKey = record.getModuleName() + "-" + record.getWarName();
            if (checksums.remove(checksumKey) != null) {
                FileListUtil.writeChecksums(checksums, checksumFile);
            }
        } catch (IOException ioe) {
            logger.log(Level.WARNING, "Error updating checksums for " + record,
                       ioe);
        }
    }

    protected void doUndeploy(DeployRecord remove) {
        // undeploy the app
        if (remove.getAppName() != null) {
            RunAppServer.getAppServer().getDeployer().undeploy(remove.getAppName(), null);
        }
    }

    /**
     * Get the file suffix
     * @return the file suffix
     */
    protected String[] getFileSuffixes() {
        return new String[] { ".war", ".ear", ".rar" };
    }

    /**
     * Get the list of .wars in a directory
     * @param dir the directory to search
     * @param suffixes the file suffixes to search for
     * @return a list of .war files in the directory, or an empty list
     * if there are no .wars in the directory
     */
    protected File[] getWebApps(File dir, final String[] suffixes) {
        File[] wars = dir.listFiles(new FileFilter() {
            public boolean accept(File pathname) {
                if (pathname.isDirectory()) {
                    return false;
            }        

                for (String suffix : suffixes) {
                    if (pathname.getName().endsWith(suffix)) {
                        return true;
                    }
                }

                return false;
            }        
        });
       
        if (wars == null) {
            return new File[0];
        }
       
        return wars;
    }

    protected File getChecksumFile(File deployDir) {
        return new File(deployDir, CHECKSUM_FILE);
    }
   
    protected class DeployRecord {
        private String moduleName;
        private String warName;
        private String checksum;

        // the file or on disk
        private File file;

        // the deployed app
        private String appName;

        public DeployRecord(String moduleName, String warName) {
            this (moduleName, warName, null);
        }

        public DeployRecord(String moduleName, String warName, String checksum)
        {
            this.moduleName = moduleName;
            this.warName = warName;
            this.checksum = checksum;
        }

        public String getModuleName() {
            return moduleName;
        }

        public String getWarName() {
            return warName;
        }

        public String getChecksum() {
            return checksum;
        }

        public void setChecksum(String checksum) {
            this.checksum = checksum;
        }

        public boolean checksumMatches(String checksum) {
            return this.checksum.equals(checksum);
        }

        public File getFile() {
            return file;
        }

        public void setFile(File file) {
            this.file = file;
        }

        public String getAppName() {
            return appName;
        }

        public void setAppName(String appName) {
            this.appName = appName;
        }


        // records are equal if they refer to the same module and war.
        // to check the checksum, manually compare the two
        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final DeployRecord other = (DeployRecord) obj;
            if (this.moduleName != other.moduleName &&
                    (this.moduleName == null ||
                    !this.moduleName.equals(other.moduleName)))
            {
                return false;
            }
            if (this.warName != other.warName &&
                    (this.warName == null ||
                    !this.warName.equals(other.warName)))
            {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 53 * hash + (this.moduleName != null ? this.moduleName.hashCode() : 0);
            hash = 53 * hash + (this.warName != null ? this.warName.hashCode() : 0);
            return hash;
        }
       
        @Override
        public String toString() {
            return "[ module: " + moduleName + ", war: " + warName +
                   "  app: " + appName + " ]";
        }
    }
}
TOP

Related Classes of org.jdesktop.wonderland.webserver.WebDeployer$DeployRecord

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.