com.liferay.portal.tools.deploy.BaseDeployer.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.portal.tools.deploy.BaseDeployer.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.portal.tools.deploy;

import com.liferay.petra.function.UnsafeConsumer;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.petra.xml.DocUtil;
import com.liferay.petra.xml.XMLUtil;
import com.liferay.portal.deploy.DeployUtil;
import com.liferay.portal.kernel.deploy.Deployer;
import com.liferay.portal.kernel.deploy.auto.AutoDeployException;
import com.liferay.portal.kernel.deploy.auto.AutoDeployer;
import com.liferay.portal.kernel.deploy.auto.context.AutoDeploymentContext;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.plugin.License;
import com.liferay.portal.kernel.plugin.PluginPackage;
import com.liferay.portal.kernel.servlet.PluginContextListener;
import com.liferay.portal.kernel.servlet.PortalClassLoaderServlet;
import com.liferay.portal.kernel.servlet.PortalDelegateServlet;
import com.liferay.portal.kernel.servlet.PortletServlet;
import com.liferay.portal.kernel.servlet.SecurePluginContextListener;
import com.liferay.portal.kernel.servlet.SecureServlet;
import com.liferay.portal.kernel.servlet.SerializableSessionAttributeListener;
import com.liferay.portal.kernel.servlet.filters.invoker.InvokerFilter;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.HashMapBuilder;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.PropertiesUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.ServerDetector;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.SystemProperties;
import com.liferay.portal.kernel.util.TextFormatter;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xml.Document;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
import com.liferay.portal.plugin.PluginPackageUtil;
import com.liferay.portal.tools.ToolDependencies;
import com.liferay.portal.tools.WebXMLBuilder;
import com.liferay.portal.tools.deploy.extension.DeploymentExtension;
import com.liferay.portal.util.ExtRegistry;
import com.liferay.portal.util.PrefsPropsUtil;
import com.liferay.portal.util.PropsUtil;
import com.liferay.portal.util.PropsValues;
import com.liferay.portal.webserver.DynamicResourceServlet;
import com.liferay.util.ant.CopyTask;
import com.liferay.util.ant.DeleteTask;
import com.liferay.util.ant.ExpandTask;
import com.liferay.util.ant.UpToDateTask;
import com.liferay.util.ant.WarTask;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.apache.oro.io.GlobFilenameFilter;

/**
 * @author Brian Wing Shun Chan
 * @author Sandeep Soni
 */
public class BaseDeployer implements AutoDeployer, Deployer {

    public static final String DEPLOY_TO_PREFIX = "DEPLOY_TO__";

    public static void main(String[] args) {
        ToolDependencies.wireDeployers();

        List<String> wars = new ArrayList<>();
        List<String> jars = new ArrayList<>();

        for (String arg : args) {
            String fileName = StringUtil.toLowerCase(arg);

            if (fileName.endsWith(".war")) {
                wars.add(arg);
            } else if (fileName.endsWith(".jar")) {
                jars.add(arg);
            }
        }

        try (BaseDeployer baseDeployer = new BaseDeployer(wars, jars)) {
        } catch (IOException ioe) {
            if (_log.isWarnEnabled()) {
                _log.warn(ioe, ioe);
            }
        }
    }

    public BaseDeployer() {
        ServiceLoader<DeploymentExtension> serviceLoader = ServiceLoader.load(DeploymentExtension.class,
                BaseDeployer.class.getClassLoader());

        for (DeploymentExtension deploymentExtension : serviceLoader) {
            _deploymentExtensions.add(deploymentExtension);
        }
    }

    public BaseDeployer(List<String> wars, List<String> jars) {
        this();

        baseDir = System.getProperty("deployer.base.dir");
        destDir = System.getProperty("deployer.dest.dir");
        appServerType = System.getProperty("deployer.app.server.type");
        auiTaglibDTD = System.getProperty("deployer.aui.taglib.dtd");
        portletTaglibDTD = System.getProperty("deployer.portlet.taglib.dtd");
        portletExtTaglibDTD = System.getProperty("deployer.portlet-ext.taglib.dtd");
        securityTaglibDTD = System.getProperty("deployer.security.taglib.dtd");
        themeTaglibDTD = System.getProperty("deployer.theme.taglib.dtd");
        uiTaglibDTD = System.getProperty("deployer.ui.taglib.dtd");
        utilTaglibDTD = System.getProperty("deployer.util.taglib.dtd");
        unpackWar = GetterUtil.getBoolean(System.getProperty("deployer.unpack.war"), true);
        filePattern = System.getProperty("deployer.file.pattern");
        jbossPrefix = GetterUtil.getString(System.getProperty("deployer.jboss.prefix"));
        tomcatLibDir = System.getProperty("deployer.tomcat.lib.dir");
        wildflyPrefix = GetterUtil.getString(System.getProperty("deployer.wildfly.prefix"));
        this.wars = wars;
        this.jars = jars;

        checkArguments();

        String context = System.getProperty("deployer.context");

        try {
            deploy(context);
        } catch (Exception e) {
            _log.error(e, e);
        }
    }

    @Override
    public void addExtJar(List<String> jars, String resource) throws Exception {
        Set<String> servletContextNames = ExtRegistry.getServletContextNames();

        for (String servletContextName : servletContextNames) {
            String extResource = "ext-" + servletContextName + resource.substring(3);

            String path = DeployUtil.getResourcePath(tempDirPaths, extResource);

            if (_log.isDebugEnabled()) {
                if (path == null) {
                    _log.debug("Resource " + extResource + " is not available");
                } else {
                    _log.debug(StringBundler.concat("Resource ", extResource, " is available at ", path));
                }
            }

            if (path != null) {
                jars.add(path);
            }
        }
    }

    @Override
    public void addRequiredJar(List<String> jars, String resource) throws Exception {

        String path = DeployUtil.getResourcePath(tempDirPaths, resource);

        if (path == null) {
            throw new RuntimeException("Resource " + resource + " does not exist");
        }

        if (_log.isDebugEnabled()) {
            _log.debug(StringBundler.concat("Resource ", resource, " is available at ", path));
        }

        jars.add(path);
    }

    @Override
    public int autoDeploy(AutoDeploymentContext autoDeploymentContext) throws AutoDeployException {

        List<String> wars = new ArrayList<>();

        File file = autoDeploymentContext.getFile();

        wars.add(file.getName());

        this.wars = wars;

        try {
            return deployFile(autoDeploymentContext);
        } catch (Exception e) {
            throw new AutoDeployException(e);
        }
    }

    @Override
    public void checkArguments() {
        if (Validator.isNull(baseDir)) {
            throw new IllegalArgumentException("The system property deployer.base.dir is not set");
        }

        if (Validator.isNull(destDir)) {
            throw new IllegalArgumentException("The system property deployer.dest.dir is not set");
        }

        if (Validator.isNull(appServerType)) {
            throw new IllegalArgumentException("The system property deployer.app.server.type is not set");
        }

        if (!ServerDetector.isSupported(appServerType)) {
            throw new IllegalArgumentException(appServerType + " is not a valid application server type");
        }

        if (appServerType.equals(ServerDetector.WEBSPHERE_ID)) {
            unpackWar = false;
        }

        if (Validator.isNotNull(jbossPrefix) && !Validator.isNumber(jbossPrefix)) {

            jbossPrefix = "1";
        }

        if (Validator.isNotNull(wildflyPrefix) && !Validator.isNumber(wildflyPrefix)) {

            wildflyPrefix = "1";
        }
    }

    @Override
    public AutoDeployer cloneAutoDeployer() throws AutoDeployException {
        try {
            Class<? extends BaseDeployer> clazz = getClass();

            BaseDeployer baseDeployer = (BaseDeployer) clazz.newInstance();

            baseDeployer.setAppServerType(appServerType);
            baseDeployer.setAuiTaglibDTD(auiTaglibDTD);
            baseDeployer.setBaseDir(baseDir);
            baseDeployer.setDestDir(destDir);
            baseDeployer.setFilePattern(filePattern);
            baseDeployer.setJars(jars);
            baseDeployer.setJbossPrefix(jbossPrefix);
            baseDeployer.setPortletExtTaglibDTD(portletExtTaglibDTD);
            baseDeployer.setPortletTaglibDTD(portletTaglibDTD);
            baseDeployer.setSecurityTaglibDTD(securityTaglibDTD);
            baseDeployer.setThemeTaglibDTD(themeTaglibDTD);
            baseDeployer.setTomcatLibDir(tomcatLibDir);
            baseDeployer.setUiTaglibDTD(uiTaglibDTD);
            baseDeployer.setUnpackWar(unpackWar);
            baseDeployer.setUtilTaglibDTD(utilTaglibDTD);
            baseDeployer.setWars(wars);
            baseDeployer.setWildflyPrefix(wildflyPrefix);

            return (AutoDeployer) baseDeployer;
        } catch (Exception e) {
            throw new AutoDeployException(e);
        }
    }

    @Override
    public void close() throws IOException {
        UnsafeConsumer.accept(tempDirPaths, DeployUtil::deletePath, IOException.class);
    }

    @Override
    public void copyDependencyXml(String fileName, String targetDir) throws Exception {

        copyDependencyXml(fileName, targetDir, null);
    }

    @Override
    public void copyDependencyXml(String fileName, String targetDir, Map<String, String> filterMap)
            throws Exception {

        copyDependencyXml(fileName, targetDir, filterMap, false);
    }

    @Override
    public void copyDependencyXml(String fileName, String targetDir, Map<String, String> filterMap,
            boolean overwrite) throws Exception {

        DeployUtil.copyDependencyXml(fileName, targetDir, fileName, filterMap, overwrite);
    }

    @Override
    public void copyJars(File srcFile, PluginPackage pluginPackage) throws Exception {

        for (String jarFullName : jars) {
            String jarName = jarFullName.substring(jarFullName.lastIndexOf("/") + 1);

            if (!FileUtil.exists(jarFullName)) {
                DeployUtil.getResourcePath(tempDirPaths, jarName);
            }

            FileUtil.copyFile(jarFullName, srcFile + "/WEB-INF/lib/" + jarName, false);
        }
    }

    public void copyPortalDependencies(File srcFile) throws Exception {
        Properties properties = getPluginPackageProperties(srcFile);

        if (properties == null) {
            return;
        }

        // jars

        String[] portalJars = StringUtil.split(
                properties.getProperty("portal-dependency-jars", properties.getProperty("portal.dependency.jars")));

        for (String portalJar : portalJars) {
            portalJar = portalJar.trim();

            portalJar = fixPortalDependencyJar(portalJar);

            if (_log.isDebugEnabled()) {
                _log.debug("Copy portal JAR " + portalJar);
            }

            try {
                String portalJarPath = PortalUtil.getPortalLibDir() + portalJar;

                FileUtil.copyFile(portalJarPath, srcFile + "/WEB-INF/lib/" + portalJar, true);
            } catch (Exception e) {
                _log.error("Unable to copy portal JAR " + portalJar, e);
            }
        }

        // tlds

        String[] portalTlds = StringUtil.split(
                properties.getProperty("portal-dependency-tlds", properties.getProperty("portal.dependency.tlds")));

        for (String portalTld : portalTlds) {
            portalTld = portalTld.trim();

            if (_log.isDebugEnabled()) {
                _log.debug("Copy portal TLD " + portalTld);
            }

            try {
                String portalTldPath = DeployUtil.getResourcePath(tempDirPaths, portalTld);

                FileUtil.copyFile(portalTldPath, srcFile + "/WEB-INF/tld/" + portalTld, true);
            } catch (Exception e) {
                _log.error("Unable to copy portal TLD " + portalTld, e);
            }
        }

        // commons-logging*.jar

        File pluginLibDir = new File(srcFile + "/WEB-INF/lib/");

        if (PropsValues.AUTO_DEPLOY_COPY_COMMONS_LOGGING) {
            String[] commonsLoggingJars = pluginLibDir.list(new GlobFilenameFilter("commons-logging*.jar"));

            if (ArrayUtil.isEmpty(commonsLoggingJars)) {
                String portalJarPath = PortalUtil.getPortalLibDir() + "commons-logging.jar";

                FileUtil.copyFile(portalJarPath, srcFile + "/WEB-INF/lib/commons-logging.jar", true);
            }
        }

        // log4j*.jar

        if (PropsValues.AUTO_DEPLOY_COPY_LOG4J) {
            String[] log4jJars = pluginLibDir.list(new GlobFilenameFilter("log4j*.jar"));

            if (ArrayUtil.isEmpty(log4jJars)) {
                String portalJarPath = PortalUtil.getPortalLibDir() + "log4j.jar";

                FileUtil.copyFile(portalJarPath, srcFile + "/WEB-INF/lib/log4j.jar", true);

                portalJarPath = PortalUtil.getPortalLibDir() + "log4j-extras.jar";

                FileUtil.copyFile(portalJarPath, srcFile + "/WEB-INF/lib/log4j-extras.jar", true);
            }
        }
    }

    @Override
    public void copyProperties(File srcFile, PluginPackage pluginPackage) throws Exception {

        if (PropsValues.AUTO_DEPLOY_COPY_COMMONS_LOGGING) {
            copyDependencyXml("logging.properties", srcFile + "/WEB-INF/classes");
        }

        if (PropsValues.AUTO_DEPLOY_COPY_LOG4J) {
            copyDependencyXml("log4j.properties", srcFile + "/WEB-INF/classes");
        }

        File servicePropertiesFile = new File(srcFile.getAbsolutePath() + "/WEB-INF/classes/service.properties");

        if (!servicePropertiesFile.exists()) {
            return;
        }

        File portletPropertiesFile = new File(srcFile.getAbsolutePath() + "/WEB-INF/classes/portlet.properties");

        if (portletPropertiesFile.exists()) {
            return;
        }

        String pluginPackageName = null;

        if (pluginPackage != null) {
            pluginPackageName = pluginPackage.getName();
        } else {
            pluginPackageName = srcFile.getName();
        }

        FileUtil.write(portletPropertiesFile, "plugin.package.name=" + pluginPackageName);
    }

    @Override
    public void copyTlds(File srcFile, PluginPackage pluginPackage) throws Exception {

        if (Validator.isNotNull(auiTaglibDTD)) {
            FileUtil.copyFile(auiTaglibDTD, srcFile + "/WEB-INF/tld/liferay-aui.tld", true);
        }

        if (Validator.isNotNull(portletTaglibDTD)) {
            FileUtil.copyFile(portletTaglibDTD, srcFile + "/WEB-INF/tld/liferay-portlet.tld", true);
            FileUtil.copyFile(DeployUtil.getResourcePath(tempDirPaths, "liferay-portlet_2_0.tld"),
                    srcFile + "/WEB-INF/tld/liferay-portlet_2_0.tld", true);
        }

        if (Validator.isNotNull(portletExtTaglibDTD)) {
            FileUtil.copyFile(portletExtTaglibDTD, srcFile + "/WEB-INF/tld/liferay-portlet-ext.tld", true);
        }

        if (Validator.isNotNull(securityTaglibDTD)) {
            FileUtil.copyFile(securityTaglibDTD, srcFile + "/WEB-INF/tld/liferay-security.tld", true);
        }

        if (Validator.isNotNull(themeTaglibDTD)) {
            FileUtil.copyFile(themeTaglibDTD, srcFile + "/WEB-INF/tld/liferay-theme.tld", true);
        }

        if (Validator.isNotNull(uiTaglibDTD)) {
            FileUtil.copyFile(uiTaglibDTD, srcFile + "/WEB-INF/tld/liferay-ui.tld", true);
        }

        if (Validator.isNotNull(utilTaglibDTD)) {
            FileUtil.copyFile(utilTaglibDTD, srcFile + "/WEB-INF/tld/liferay-util.tld", true);
        }
    }

    public void copyTomcatContextXml(File targetDir) throws Exception {
        if (!appServerType.equals(ServerDetector.TOMCAT_ID)) {
            return;
        }

        File targetFile = new File(targetDir, "META-INF/context.xml");

        if (targetFile.exists()) {
            return;
        }

        String contextPath = DeployUtil.getResourcePath(tempDirPaths, "context.xml");

        String content = FileUtil.read(contextPath);

        if (!PropsValues.AUTO_DEPLOY_UNPACK_WAR) {
            content = StringUtil.replace(content, "antiResourceLocking=\"true\"", StringPool.BLANK);
        }

        FileUtil.write(targetFile, content);
    }

    @Override
    public void copyXmls(File srcFile, String displayName, PluginPackage pluginPackage) throws Exception {

        if (appServerType.equals(ServerDetector.JBOSS_ID) || appServerType.equals(ServerDetector.WILDFLY_ID)) {

            File file = new File(PropsValues.LIFERAY_WEB_PORTAL_DIR);

            copyDependencyXml("jboss-all.xml", srcFile + "/WEB-INF",
                    Collections.singletonMap("root_war", file.getName()), true);

            copyDependencyXml("jboss-deployment-structure.xml", srcFile + "/WEB-INF");
        }

        for (DeploymentExtension deploymentExtension : _deploymentExtensions) {
            if (Objects.equals(appServerType, deploymentExtension.getServerId())) {

                deploymentExtension.copyXmls(this, srcFile);
            }
        }

        copyDependencyXml("web.xml", srcFile + "/WEB-INF");
    }

    public void deploy(String context) throws Exception {
        try {
            File baseDirFile = new File(baseDir);

            File[] files = baseDirFile.listFiles();

            if (files == null) {
                return;
            }

            files = FileUtil.sortFiles(files);

            for (File srcFile : files) {
                String fileName = StringUtil.toLowerCase(srcFile.getName());

                boolean deploy = false;

                if (fileName.endsWith(".war") || fileName.endsWith(".zip")) {
                    deploy = true;

                    if (!wars.isEmpty()) {
                        if (!wars.contains(srcFile.getName())) {
                            deploy = false;
                        }
                    } else if (Validator.isNotNull(filePattern)) {
                        if (!StringUtil.matchesIgnoreCase(fileName, filePattern)) {

                            deploy = false;
                        }
                    }
                }

                if (deploy) {
                    AutoDeploymentContext autoDeploymentContext = new AutoDeploymentContext();

                    autoDeploymentContext.setContext(context);
                    autoDeploymentContext.setFile(srcFile);

                    deployFile(autoDeploymentContext);
                }
            }
        } catch (Exception e) {
            _log.error(e, e);
        }
    }

    public void deployDirectory(File srcFile, File mergeDir, File deployDir, String displayName, boolean overwrite,
            PluginPackage pluginPackage) throws Exception {

        rewriteFiles(srcFile);

        mergeDirectory(mergeDir, srcFile);

        processPluginPackageProperties(srcFile, displayName, pluginPackage);

        copyJars(srcFile, pluginPackage);
        copyProperties(srcFile, pluginPackage);
        copyTlds(srcFile, pluginPackage);
        copyXmls(srcFile, displayName, pluginPackage);
        copyPortalDependencies(srcFile);

        File webXml = new File(srcFile + "/WEB-INF/web.xml");

        updateWebXml(webXml, srcFile, displayName, pluginPackage);

        File extLibGlobalDir = new File(srcFile.getAbsolutePath() + "/WEB-INF/ext-lib/global");

        if (extLibGlobalDir.exists()) {
            File globalLibDir = new File(PortalUtil.getGlobalLibDir());

            CopyTask.copyDirectory(extLibGlobalDir, globalLibDir, "*.jar", StringPool.BLANK, overwrite, true);
        }

        File extLibPortalDir = new File(srcFile.getAbsolutePath() + "/WEB-INF/ext-lib/portal");

        if (extLibPortalDir.exists()) {
            File portalLibDir = new File(PortalUtil.getPortalLibDir());

            CopyTask.copyDirectory(extLibPortalDir, portalLibDir, "*.jar", StringPool.BLANK, overwrite, true);
        }

        if ((deployDir == null) || baseDir.equals(destDir)) {
            return;
        }

        updateDeployDirectory(srcFile);

        String excludes = StringPool.BLANK;

        if (appServerType.equals(ServerDetector.JBOSS_ID) || appServerType.equals(ServerDetector.WILDFLY_ID)) {

            excludes += "**/WEB-INF/lib/log4j.jar,";
        } else if (appServerType.equals(ServerDetector.TOMCAT_ID)) {
            String[] libs = FileUtil.listFiles(tomcatLibDir);

            for (String lib : libs) {
                excludes += "**/WEB-INF/lib/" + lib + ",";
            }

            File contextXml = new File(srcFile + "/META-INF/context.xml");

            if (contextXml.exists()) {
                String content = FileUtil.read(contextXml);

                if (content.contains(_PORTAL_CLASS_LOADER)) {
                    excludes += "**/WEB-INF/lib/util-bridges.jar,";
                    excludes += "**/WEB-INF/lib/util-java.jar,";
                    excludes += "**/WEB-INF/lib/util-taglib.jar,";
                }
            }

            try {

                // LEP-2990

                Class.forName("javax.el.ELContext");

                excludes += "**/WEB-INF/lib/el-api.jar,";
            } catch (ClassNotFoundException cnfe) {
            }
        }

        // LPS-11268

        Properties properties = getPluginPackageProperties(srcFile);

        if (properties != null) {
            String deployExcludes = properties.getProperty("deploy-excludes");

            if (deployExcludes != null) {
                excludes += deployExcludes.trim();

                if (!excludes.endsWith(",")) {
                    excludes += ",";
                }
            }

            deployExcludes = properties.getProperty("deploy-excludes-" + appServerType);

            if (deployExcludes != null) {
                excludes += deployExcludes.trim();

                if (!excludes.endsWith(",")) {
                    excludes += ",";
                }
            }
        }

        if (_log.isDebugEnabled()) {
            _log.debug("Excludes " + excludes);
        }

        if (!unpackWar) {
            Path tempDirPath = Files.createTempDirectory(Paths.get(SystemProperties.get(SystemProperties.TMP_DIR)),
                    null);

            File tempDir = tempDirPath.toFile();

            excludes += "/WEB-INF/web.xml";

            File tempFile = new File(tempDir, displayName + ".war");

            WarTask.war(srcFile, tempFile, excludes, webXml);

            if (isJEEDeploymentEnabled()) {
                File tempWarDir = new File(tempDir.getParent(), deployDir.getName());

                if (tempWarDir.exists()) {
                    tempWarDir.delete();
                }

                if (!tempDir.renameTo(tempWarDir)) {
                    tempWarDir = tempDir;
                }

                DeploymentHandler deploymentHandler = getDeploymentHandler();

                deploymentHandler.deploy(tempWarDir, displayName);

                deploymentHandler.releaseDeploymentManager();

                DeleteTask.deleteDirectory(tempWarDir);
            } else {
                if (!tempFile.renameTo(deployDir)) {
                    WarTask.war(srcFile, deployDir, excludes, webXml);
                }

                if (tempDir.isDirectory()) {
                    DeleteTask.deleteDirectory(tempDir);
                } else {
                    tempDir.delete();
                }
            }
        } else {

            // The deployer might only copy files that have been modified.
            // However, the deployer always copies and overwrites web.xml after
            // the other files have been copied because application servers
            // usually detect that a WAR has been modified based on the web.xml
            // timestamp.

            excludes += "**/WEB-INF/web.xml";

            CopyTask.copyDirectory(srcFile, deployDir, StringPool.BLANK, excludes, overwrite, true);

            CopyTask.copyDirectory(srcFile, deployDir, "**/WEB-INF/web.xml", StringPool.BLANK, true, false);

            if (appServerType.equals(ServerDetector.TOMCAT_ID)) {

                // See org.apache.catalina.startup.HostConfig to see how Tomcat
                // checks to make sure that web.xml was modified 5 seconds after
                // WEB-INF

                File deployWebXml = new File(deployDir + "/WEB-INF/web.xml");

                deployWebXml.setLastModified(System.currentTimeMillis() + (Time.SECOND * 6));
            }
        }
    }

    public void deployDirectory(File srcFile, String displayName, boolean override, PluginPackage pluginPackage)
            throws Exception {

        deployDirectory(srcFile, null, null, displayName, override, pluginPackage);
    }

    public int deployFile(AutoDeploymentContext autoDeploymentContext) throws Exception {

        File srcFile = autoDeploymentContext.getFile();

        PluginPackage pluginPackage = autoDeploymentContext.getPluginPackage();

        if (pluginPackage == null) {
            pluginPackage = readPluginPackage(srcFile);

            autoDeploymentContext.setPluginPackage(pluginPackage);
        }

        if (_log.isInfoEnabled()) {
            _log.info("Deploying " + srcFile.getName());
        }

        String autoDeploymentContextAppServerType = autoDeploymentContext.getAppServerType();

        if (Validator.isNotNull(autoDeploymentContextAppServerType)) {
            appServerType = autoDeploymentContextAppServerType;
        }

        String specifiedContext = autoDeploymentContext.getContext();

        String displayName = specifiedContext;

        boolean overwrite = false;
        String preliminaryContext = specifiedContext;

        // The order of priority of the context is: 1.) the specified context,
        // 2.) if the file name starts with DEPLOY_TO_PREFIX, use the file name
        // after the prefix, or 3.) the recommended deployment context as
        // specified in liferay-plugin-package.properties, or 4.) the file name.

        String srcFileName = srcFile.getName();

        if (Validator.isNull(specifiedContext) && srcFileName.startsWith(DEPLOY_TO_PREFIX)) {

            displayName = srcFileName.substring(DEPLOY_TO_PREFIX.length(), srcFileName.length() - 4);

            overwrite = true;
            preliminaryContext = displayName;
        }

        if (preliminaryContext == null) {
            preliminaryContext = getDisplayName(srcFile);
        }

        if (pluginPackage != null) {
            if (!PluginPackageUtil.isCurrentVersionSupported(pluginPackage.getLiferayVersions())) {

                throw new AutoDeployException(srcFile.getName() + " does not support this version of Liferay");
            }

            if (displayName == null) {
                displayName = pluginPackage.getRecommendedDeploymentContext();
            }

            if (Validator.isNull(displayName)) {
                displayName = getDisplayName(srcFile);
            }

            pluginPackage.setContext(displayName);

            PluginPackageUtil.updateInstallingPluginPackage(preliminaryContext, pluginPackage);
        }

        String deployDir = null;

        if (Validator.isNotNull(displayName)) {
            deployDir = displayName + ".war";
        } else {
            deployDir = srcFile.getName();
            displayName = getDisplayName(srcFile);
        }

        if (appServerType.equals(ServerDetector.JBOSS_ID)) {
            deployDir = jbossPrefix + deployDir;
        } else if (appServerType.equals(ServerDetector.WILDFLY_ID)) {
            deployDir = GetterUtil.getString(wildflyPrefix) + deployDir;
        } else if (appServerType.equals(ServerDetector.TOMCAT_ID)
                || appServerType.equals(ServerDetector.WEBLOGIC_ID)) {

            if (unpackWar) {
                deployDir = deployDir.substring(0, deployDir.length() - 4);
            }
        }

        String destDir = this.destDir;

        if (autoDeploymentContext.getDestDir() != null) {
            destDir = autoDeploymentContext.getDestDir();
        }

        File deployDirFile = new File(destDir + "/" + deployDir);

        try {
            PluginPackage previousPluginPackage = readPluginPackage(deployDirFile);

            if ((pluginPackage != null) && (previousPluginPackage != null)) {
                String name = pluginPackage.getName();
                String previousVersion = previousPluginPackage.getVersion();
                String version = pluginPackage.getVersion();

                if (_log.isInfoEnabled()) {
                    _log.info(StringBundler.concat("Updating ", name, " from version ", previousVersion,
                            " to version ", version));
                }

                if (pluginPackage.isPreviousVersionThan(previousPluginPackage)) {

                    if (_log.isInfoEnabled()) {
                        _log.info(StringBundler.concat("Not updating ", name, " because version ", previousVersion,
                                " is newer than version ", version));
                    }

                    return AutoDeployer.CODE_SKIP_NEWER_VERSION;
                }

                overwrite = true;
            }

            File mergeDirFile = new File(srcFile.getParent() + "/merge/" + srcFile.getName());

            if (srcFile.isDirectory()) {
                deployDirectory(srcFile, mergeDirFile, deployDirFile, displayName, overwrite, pluginPackage);
            } else {
                boolean deployed = deployFile(srcFile, mergeDirFile, deployDirFile, displayName, overwrite,
                        pluginPackage);

                if (!deployed) {
                    String context = preliminaryContext;

                    if (pluginPackage != null) {
                        context = pluginPackage.getContext();
                    }

                    PluginPackageUtil.endPluginPackageInstallation(context);
                } else {
                    postDeploy(destDir, deployDir);
                }
            }

            return AutoDeployer.CODE_DEFAULT;
        } catch (Exception e) {
            if (pluginPackage != null) {
                PluginPackageUtil.endPluginPackageInstallation(pluginPackage.getContext());
            }

            throw e;
        }
    }

    public boolean deployFile(File srcFile, File mergeDir, File deployDir, String displayName, boolean overwrite,
            PluginPackage pluginPackage) throws Exception {

        boolean undeployOnRedeploy = false;

        try {
            undeployOnRedeploy = PrefsPropsUtil.getBoolean(PropsKeys.HOT_UNDEPLOY_ON_REDEPLOY,
                    PropsValues.HOT_UNDEPLOY_ON_REDEPLOY);
        } catch (Exception e) {

            // This will only happen when running the deploy tool in Ant in the
            // classical way where the WAR file is actually massaged and
            // packaged.

        }

        if (undeployOnRedeploy) {
            DeployUtil.undeploy(appServerType, deployDir);
        }

        if (!overwrite && UpToDateTask.isUpToDate(srcFile, deployDir)) {
            if (_log.isInfoEnabled()) {
                _log.info(deployDir + " is already up to date");
            }

            return false;
        }

        Path tempDirPath = Files.createTempDirectory(Paths.get(SystemProperties.get(SystemProperties.TMP_DIR)),
                null);

        File tempDir = tempDirPath.toFile();

        ExpandTask.expand(srcFile, tempDir);

        deployDirectory(tempDir, mergeDir, deployDir, displayName, overwrite, pluginPackage);

        DeleteTask.deleteDirectory(tempDir);

        return true;
    }

    public String fixPortalDependencyJar(String portalJar) {
        if (portalJar.equals("antlr.jar")) {
            portalJar = "antlr2.jar";
        }

        return portalJar;
    }

    public DeploymentHandler getDeploymentHandler() {
        String prefix = "auto.deploy." + ServerDetector.getServerId() + ".jee.";

        String dmId = PropsUtil.get(prefix + "dm.id");
        String dmUser = PropsUtil.get(prefix + "dm.user");
        String dmPassword = PropsUtil.get(prefix + "dm.passwd");
        String dfClassName = PropsUtil.get(prefix + "df.classname");

        return new DeploymentHandler(dmId, dmUser, dmPassword, dfClassName);
    }

    public String getDisplayName(File srcFile) {
        String displayName = srcFile.getName();

        if (StringUtil.endsWith(displayName, ".war") || StringUtil.endsWith(displayName, ".xml")) {

            displayName = displayName.substring(0, displayName.length() - 4);
        }

        if ((appServerType.equals(ServerDetector.JBOSS_ID) && Validator.isNotNull(jbossPrefix)
                && displayName.startsWith(jbossPrefix))
                || (appServerType.equals(ServerDetector.WILDFLY_ID) && Validator.isNotNull(wildflyPrefix)
                        && displayName.startsWith(wildflyPrefix))) {

            displayName = displayName.substring(1);
        }

        return displayName;
    }

    public String getDynamicResourceServletContent() {
        StringBundler sb = new StringBundler();

        sb.append("<servlet>");
        sb.append("<servlet-name>");
        sb.append("Dynamic Resource Servlet");
        sb.append("</servlet-name>");
        sb.append("<servlet-class>");
        sb.append(PortalClassLoaderServlet.class.getName());
        sb.append("</servlet-class>");
        sb.append("<init-param>");
        sb.append("<param-name>");
        sb.append("servlet-class");
        sb.append("</param-name>");
        sb.append("<param-value>");
        sb.append(DynamicResourceServlet.class.getName());
        sb.append("</param-value>");
        sb.append("</init-param>");
        sb.append("<load-on-startup>1</load-on-startup>");
        sb.append("</servlet>");

        for (String allowedPath : PropsValues.DYNAMIC_RESOURCE_SERVLET_ALLOWED_PATHS) {

            sb.append("<servlet-mapping>");
            sb.append("<servlet-name>");
            sb.append("Dynamic Resource Servlet");
            sb.append("</servlet-name>");
            sb.append("<url-pattern>");
            sb.append(allowedPath);

            if (!allowedPath.endsWith(StringPool.SLASH)) {
                sb.append(StringPool.SLASH);
            }

            sb.append(StringPool.STAR);
            sb.append("</url-pattern>");
            sb.append("</servlet-mapping>");
        }

        return sb.toString();
    }

    public String getExtraContent(double webXmlVersion, File srcFile, String displayName) throws Exception {

        if (displayName.startsWith(StringPool.FORWARD_SLASH)) {
            displayName = displayName.substring(1);
        }

        StringBundler sb = new StringBundler(70);

        sb.append("<display-name>");
        sb.append(displayName);
        sb.append("</display-name>");

        if (webXmlVersion < 2.4) {
            sb.append("<context-param>");
            sb.append("<param-name>liferay-invoker-enabled</param-name>");
            sb.append("<param-value>false</param-value>");
            sb.append("</context-param>");
        }

        if (PropsValues.SESSION_VERIFY_SERIALIZABLE_ATTRIBUTE) {
            sb.append("<listener>");
            sb.append("<listener-class>");
            sb.append(SerializableSessionAttributeListener.class.getName());
            sb.append("</listener-class>");
            sb.append("</listener>");
        }

        sb.append(getDynamicResourceServletContent());

        boolean hasTaglib = false;

        if (Validator.isNotNull(auiTaglibDTD) || Validator.isNotNull(portletTaglibDTD)
                || Validator.isNotNull(portletExtTaglibDTD) || Validator.isNotNull(securityTaglibDTD)
                || Validator.isNotNull(themeTaglibDTD) || Validator.isNotNull(uiTaglibDTD)
                || Validator.isNotNull(utilTaglibDTD)) {

            hasTaglib = true;
        }

        if (hasTaglib && (webXmlVersion > 2.3)) {
            sb.append("<jsp-config>");
        }

        if (Validator.isNotNull(auiTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>http://liferay.com/tld/aui</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-aui.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (Validator.isNotNull(portletTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>http://java.sun.com/portlet_2_0");
            sb.append("</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-portlet_2_0.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
            sb.append("<taglib>");
            sb.append("<taglib-uri>");
            sb.append("http://xmlns.jcp.org/portlet_3_0");
            sb.append("</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-portlet.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (Validator.isNotNull(portletExtTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>");
            sb.append("http://liferay.com/tld/portlet");
            sb.append("</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-portlet-ext.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (Validator.isNotNull(securityTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>");
            sb.append("http://liferay.com/tld/security");
            sb.append("</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-security.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (Validator.isNotNull(themeTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>http://liferay.com/tld/theme</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-theme.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (Validator.isNotNull(uiTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>http://liferay.com/tld/ui</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-ui.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (Validator.isNotNull(utilTaglibDTD)) {
            sb.append("<taglib>");
            sb.append("<taglib-uri>http://liferay.com/tld/util</taglib-uri>");
            sb.append("<taglib-location>");
            sb.append("/WEB-INF/tld/liferay-util.tld");
            sb.append("</taglib-location>");
            sb.append("</taglib>");
        }

        if (hasTaglib && (webXmlVersion > 2.3)) {
            sb.append("</jsp-config>");
        }

        return sb.toString();
    }

    public String getExtraFiltersContent(double webXmlVersion, File srcFile) throws Exception {

        return getSessionFiltersContent();
    }

    public String getIgnoreFiltersContent(File srcFile) throws Exception {
        boolean ignoreFiltersEnabled = true;

        Properties properties = getPluginPackageProperties(srcFile);

        if (properties != null) {
            ignoreFiltersEnabled = GetterUtil.getBoolean(properties.getProperty("ignore-filters-enabled"), true);
        }

        if (ignoreFiltersEnabled) {
            return FileUtil.read(DeployUtil.getResourcePath(tempDirPaths, "ignore-filters-web.xml"));
        }

        return StringPool.BLANK;
    }

    public String getInvokerFilterContent() {
        StringBundler sb = new StringBundler(5);

        sb.append(getInvokerFilterContent("ASYNC"));
        sb.append(getInvokerFilterContent("ERROR"));
        sb.append(getInvokerFilterContent("FORWARD"));
        sb.append(getInvokerFilterContent("INCLUDE"));
        sb.append(getInvokerFilterContent("REQUEST"));

        return sb.toString();
    }

    public String getInvokerFilterContent(String dispatcher) {
        StringBundler sb = new StringBundler(24);

        sb.append("<filter>");
        sb.append("<filter-name>Invoker Filter - ");
        sb.append(dispatcher);
        sb.append("</filter-name>");
        sb.append("<filter-class>");
        sb.append(InvokerFilter.class.getName());
        sb.append("</filter-class>");
        sb.append("<async-supported>true</async-supported>");
        sb.append("<init-param>");
        sb.append("<param-name>dispatcher</param-name>");
        sb.append("<param-value>");
        sb.append(dispatcher);
        sb.append("</param-value>");
        sb.append("</init-param>");
        sb.append("</filter>");

        sb.append("<filter-mapping>");
        sb.append("<filter-name>Invoker Filter - ");
        sb.append(dispatcher);
        sb.append("</filter-name>");
        sb.append("<url-pattern>/*</url-pattern>");
        sb.append("<dispatcher>");
        sb.append(dispatcher);
        sb.append("</dispatcher>");
        sb.append("</filter-mapping>");

        return sb.toString();
    }

    public String getPluginPackageLicensesXml(List<License> licenses) {
        if (licenses.isEmpty()) {
            return StringPool.BLANK;
        }

        StringBundler sb = new StringBundler(5 * licenses.size() + 2);

        for (int i = 0; i < licenses.size(); i++) {
            License license = licenses.get(i);

            if (i == 0) {
                sb.append("\r\n");
            }

            sb.append("\t\t<license osi-approved=\"");
            sb.append(license.isOsiApproved());
            sb.append("\">");
            sb.append(license.getName());
            sb.append("</license>\r\n");

            if ((i + 1) == licenses.size()) {
                sb.append("\t");
            }
        }

        return sb.toString();
    }

    public String getPluginPackageLiferayVersionsXml(List<String> liferayVersions) {

        if (liferayVersions.isEmpty()) {
            return StringPool.BLANK;
        }

        StringBundler sb = new StringBundler(liferayVersions.size() * 3 + 2);

        for (int i = 0; i < liferayVersions.size(); i++) {
            String liferayVersion = liferayVersions.get(i);

            if (i == 0) {
                sb.append("\r\n");
            }

            sb.append("\t\t<liferay-version>");
            sb.append(liferayVersion);
            sb.append("</liferay-version>\r\n");

            if ((i + 1) == liferayVersions.size()) {
                sb.append("\t");
            }
        }

        return sb.toString();
    }

    public Properties getPluginPackageProperties(File srcFile) throws Exception {

        File propertiesFile = new File(srcFile + "/WEB-INF/liferay-plugin-package.properties");

        if (!propertiesFile.exists()) {
            return null;
        }

        String propertiesString = FileUtil.read(propertiesFile);

        return PropertiesUtil.load(propertiesString);
    }

    public String getPluginPackageRequiredDeploymentContextsXml(List<String> requiredDeploymentContexts) {

        if (requiredDeploymentContexts.isEmpty()) {
            return StringPool.BLANK;
        }

        StringBundler sb = new StringBundler(requiredDeploymentContexts.size() * 3 + 2);

        for (int i = 0; i < requiredDeploymentContexts.size(); i++) {
            String requiredDeploymentContext = requiredDeploymentContexts.get(i);

            if (i == 0) {
                sb.append("\r\n");
            }

            sb.append("\t\t<required-deployment-context>");
            sb.append(requiredDeploymentContext);
            sb.append("</required-deployment-context>\r\n");

            if ((i + 1) == requiredDeploymentContexts.size()) {
                sb.append("\t");
            }
        }

        return sb.toString();
    }

    public String getPluginPackageTagsXml(List<String> tags) {
        if (tags.isEmpty()) {
            return StringPool.BLANK;
        }

        StringBundler sb = new StringBundler(tags.size() * 3 + 2);

        for (int i = 0; i < tags.size(); i++) {
            String tag = tags.get(i);

            if (i == 0) {
                sb.append("\r\n");
            }

            sb.append("\t\t<tag>");
            sb.append(tag);
            sb.append("</tag>\r\n");

            if ((i + 1) == tags.size()) {
                sb.append("\t");
            }
        }

        return sb.toString();
    }

    public Map<String, String> getPluginPackageXmlFilterMap(PluginPackage pluginPackage) {

        List<String> pluginTypes = pluginPackage.getTypes();

        String pluginType = pluginTypes.get(0);

        if (!pluginType.equals(getPluginType())) {
            return null;
        }

        return HashMapBuilder.put("author", wrapCDATA(pluginPackage.getAuthor()))
                .put("change_log", wrapCDATA(pluginPackage.getChangeLog()))
                .put("licenses", getPluginPackageLicensesXml(pluginPackage.getLicenses()))
                .put("liferay_versions", getPluginPackageLiferayVersionsXml(pluginPackage.getLiferayVersions()))
                .put("long_description", wrapCDATA(pluginPackage.getLongDescription()))
                .put("module_artifact_id", pluginPackage.getArtifactId())
                .put("module_group_id", pluginPackage.getGroupId())
                .put("module_version", pluginPackage.getVersion()).put("page_url", pluginPackage.getPageURL())
                .put("plugin_name", wrapCDATA(pluginPackage.getName())).put("plugin_type", pluginType)
                .put("plugin_type_name", TextFormatter.format(pluginType, TextFormatter.J))
                .put("recommended_deployment_context", pluginPackage.getRecommendedDeploymentContext())
                .put("required_deployment_contexts",
                        getPluginPackageRequiredDeploymentContextsXml(
                                pluginPackage.getRequiredDeploymentContexts()))
                .put("short_description", wrapCDATA(pluginPackage.getShortDescription()))
                .put("tags", getPluginPackageTagsXml(pluginPackage.getTags())).build();
    }

    public String getPluginType() {
        return null;
    }

    public String getServletContextIncludeFiltersContent(double webXmlVersion, File srcFile) throws Exception {

        if (webXmlVersion < 2.4) {
            return StringPool.BLANK;
        }

        Properties properties = getPluginPackageProperties(srcFile);

        if (properties == null) {
            return StringPool.BLANK;
        }

        if (!GetterUtil.getBoolean(properties.getProperty("servlet-context-include-filters-enabled"), true)) {

            return StringPool.BLANK;
        }

        return FileUtil.read(DeployUtil.getResourcePath(tempDirPaths, "servlet-context-include-filters-web.xml"));
    }

    public String getSessionFiltersContent() throws Exception {
        return FileUtil.read(DeployUtil.getResourcePath(tempDirPaths, "session-filters-web.xml"));
    }

    public String getSpeedFiltersContent(File srcFile) throws Exception {
        boolean speedFiltersEnabled = true;

        Properties properties = getPluginPackageProperties(srcFile);

        if (properties != null) {
            speedFiltersEnabled = GetterUtil.getBoolean(properties.getProperty("speed-filters-enabled"), true);
        }

        if (speedFiltersEnabled) {
            return FileUtil.read(DeployUtil.getResourcePath(tempDirPaths, "speed-filters-web.xml"));
        }

        return StringPool.BLANK;
    }

    public boolean isJEEDeploymentEnabled() {
        return GetterUtil.getBoolean(
                PropsUtil.get("auto.deploy." + ServerDetector.getServerId() + ".jee.deployment.enabled"));
    }

    public void mergeDirectory(File mergeDir, File targetDir) {
        if ((mergeDir == null) || !mergeDir.exists()) {
            return;
        }

        CopyTask.copyDirectory(mergeDir, targetDir, null, null, true, false);
    }

    public void postDeploy(String destDir, String deployDir) throws Exception {
        if (appServerType.equals(ServerDetector.JBOSS_ID)) {
            postDeployJBoss(destDir, deployDir);
        } else if (appServerType.equals(ServerDetector.WILDFLY_ID)) {
            postDeployWildfly(destDir, deployDir);
        }

        for (DeploymentExtension deploymentExtension : _deploymentExtensions) {
            if (Objects.equals(appServerType, deploymentExtension.getServerId())) {

                deploymentExtension.postDeploy(destDir, deployDir);
            }
        }
    }

    public void postDeployJBoss(String destDir, String deployDir) throws Exception {

        FileUtil.write(StringBundler.concat(destDir, "/", deployDir, ".dodeploy"), StringPool.BLANK);
    }

    public void postDeployWildfly(String destDir, String deployDir) throws Exception {

        FileUtil.write(StringBundler.concat(destDir, "/", deployDir, ".dodeploy"), StringPool.BLANK);
    }

    @Override
    public Map<String, String> processPluginPackageProperties(File srcFile, String displayName,
            PluginPackage pluginPackage) throws Exception {

        if (pluginPackage == null) {
            return null;
        }

        Properties properties = getPluginPackageProperties(srcFile);

        if ((properties == null) || properties.isEmpty()) {
            return null;
        }

        Map<String, String> filterMap = getPluginPackageXmlFilterMap(pluginPackage);

        if (filterMap == null) {
            return null;
        }

        copyDependencyXml("liferay-plugin-package.xml", srcFile + "/WEB-INF", filterMap, true);

        return filterMap;
    }

    /**
     * @see PluginPackageUtil#_readPluginPackageServletContext(
     *      javax.servlet.ServletContext)
     */
    @Override
    public PluginPackage readPluginPackage(File file) {
        if (!file.exists()) {
            return null;
        }

        InputStream is = null;
        ZipFile zipFile = null;

        try {
            boolean parseProps = false;

            if (file.isDirectory()) {
                String path = file.getPath();

                File pluginPackageXmlFile = new File(StringBundler.concat(file.getParent(), "/merge/",
                        file.getName(), "/WEB-INF/liferay-plugin-package.xml"));

                if (pluginPackageXmlFile.exists()) {
                    is = new FileInputStream(pluginPackageXmlFile);
                } else {
                    pluginPackageXmlFile = new File(path + "/WEB-INF/liferay-plugin-package.xml");

                    if (pluginPackageXmlFile.exists()) {
                        is = new FileInputStream(pluginPackageXmlFile);
                    }
                }

                File pluginPackagePropertiesFile = new File(StringBundler.concat(file.getParent(), "/merge/",
                        file.getName(), "/WEB-INF/liferay-plugin-package.properties"));

                if ((is == null) && pluginPackagePropertiesFile.exists()) {
                    is = new FileInputStream(pluginPackagePropertiesFile);

                    parseProps = true;
                } else {
                    pluginPackagePropertiesFile = new File(path + "/WEB-INF/liferay-plugin-package.properties");

                    if ((is == null) && pluginPackagePropertiesFile.exists()) {
                        is = new FileInputStream(pluginPackagePropertiesFile);

                        parseProps = true;
                    }
                }
            } else {
                zipFile = new ZipFile(file);

                File pluginPackageXmlFile = new File(StringBundler.concat(file.getParent(), "/merge/",
                        file.getName(), "/WEB-INF/liferay-plugin-package.xml"));

                if (pluginPackageXmlFile.exists()) {
                    is = new FileInputStream(pluginPackageXmlFile);
                } else {
                    ZipEntry zipEntry = zipFile.getEntry("WEB-INF/liferay-plugin-package.xml");

                    if (zipEntry != null) {
                        is = zipFile.getInputStream(zipEntry);
                    }
                }

                File pluginPackagePropertiesFile = new File(StringBundler.concat(file.getParent(), "/merge/",
                        file.getName(), "/WEB-INF/liferay-plugin-package.properties"));

                if ((is == null) && pluginPackagePropertiesFile.exists()) {
                    is = new FileInputStream(pluginPackagePropertiesFile);

                    parseProps = true;
                } else {
                    ZipEntry zipEntry = zipFile.getEntry("WEB-INF/liferay-plugin-package.properties");

                    if ((is == null) && (zipEntry != null)) {
                        is = zipFile.getInputStream(zipEntry);

                        parseProps = true;
                    }
                }
            }

            if (is == null) {
                if (_log.isInfoEnabled()) {
                    _log.info(StringBundler.concat(file.getPath(), " does not have a ",
                            "WEB-INF/liferay-plugin-package.xml or ", "WEB-INF/liferay-plugin-package.properties"));
                }

                return null;
            }

            if (parseProps) {
                String displayName = getDisplayName(file);

                String propertiesString = StringUtil.read(is);

                Properties properties = PropertiesUtil.load(propertiesString);

                return PluginPackageUtil.readPluginPackageProperties(displayName, properties);
            }

            String xml = StringUtil.read(is);

            xml = XMLUtil.fixProlog(xml);

            return PluginPackageUtil.readPluginPackageXml(xml);
        } catch (Exception e) {
            _log.error(file.getPath() + ": " + e.toString(), e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ioe) {
                }
            }

            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException ioe) {
                }
            }
        }

        return null;
    }

    public void rewriteFiles(File srcDir) throws Exception {
        String[] fileNames = FileUtil.listFiles(srcDir + "/WEB-INF/");

        for (String fileName : fileNames) {
            String shortFileName = GetterUtil.getString(FileUtil.getShortFileName(fileName));

            // LEP-6415

            if (StringUtil.equalsIgnoreCase(shortFileName, "mule-config.xml")) {
                continue;
            }

            String ext = GetterUtil.getString(FileUtil.getExtension(fileName));

            if (!StringUtil.equalsIgnoreCase(ext, "xml")) {
                continue;
            }

            // Make sure to rewrite any XML files to include external entities
            // into same file. See LEP-3142.

            File file = new File(srcDir + "/WEB-INF/" + fileName);

            try {
                Document doc = UnsecureSAXReaderUtil.read(file);

                String content = doc.formattedString(StringPool.TAB, true);

                FileUtil.write(file, content);
            } catch (Exception e) {
                if (_log.isWarnEnabled()) {
                    _log.warn(StringBundler.concat("Unable to format ", file, ": ", e.getMessage()));
                }
            }
        }
    }

    public String secureWebXml(String content, boolean hasCustomServletListener, boolean securityManagerEnabled)
            throws Exception {

        if (!hasCustomServletListener && !securityManagerEnabled) {
            return content;
        }

        Document document = UnsecureSAXReaderUtil.read(content);

        Element rootElement = document.getRootElement();

        List<String> listenerClasses = new ArrayList<>();

        List<Element> listenerElements = rootElement.elements("listener");

        for (Element listenerElement : listenerElements) {
            String listenerClass = GetterUtil.getString(listenerElement.elementText("listener-class"));

            if (listenerClass.equals(PluginContextListener.class.getName())
                    || listenerClass.equals(SecurePluginContextListener.class.getName())) {

                continue;
            }

            listenerClasses.add(listenerClass);

            listenerElement.detach();
        }

        Element contextParamElement = rootElement.addElement("context-param");

        DocUtil.add(contextParamElement, "param-name", "portalListenerClasses");
        DocUtil.add(contextParamElement, "param-value", StringUtil.merge(listenerClasses));

        if (!securityManagerEnabled) {
            return document.compactString();
        }

        List<Element> servletElements = rootElement.elements("servlet");

        for (Element servletElement : servletElements) {
            Element servletClassElement = servletElement.element("servlet-class");

            String servletClass = GetterUtil.getString(servletClassElement.getText());

            if (servletClass.equals(PortalClassLoaderServlet.class.getName())
                    || servletClass.equals(PortalDelegateServlet.class.getName())
                    || servletClass.equals(PortletServlet.class.getName())) {

                continue;
            }

            servletClassElement.setText(SecureServlet.class.getName());

            Element initParamElement = servletElement.addElement("init-param");

            DocUtil.add(initParamElement, "param-name", "servlet-class");
            DocUtil.add(initParamElement, "param-value", servletClass);
        }

        return document.compactString();
    }

    @Override
    public void setAppServerType(String appServerType) {
        this.appServerType = appServerType;
    }

    @Override
    public void setAuiTaglibDTD(String auiTaglibDTD) {
        this.auiTaglibDTD = auiTaglibDTD;
    }

    @Override
    public void setBaseDir(String baseDir) {
        this.baseDir = baseDir;
    }

    @Override
    public void setDestDir(String destDir) {
        this.destDir = destDir;
    }

    @Override
    public void setFilePattern(String filePattern) {
        this.filePattern = filePattern;
    }

    @Override
    public void setJars(List<String> jars) {
        this.jars = jars;
    }

    @Override
    public void setJbossPrefix(String jbossPrefix) {
        this.jbossPrefix = jbossPrefix;
    }

    @Override
    public void setPortletExtTaglibDTD(String portletExtTaglibDTD) {
        this.portletExtTaglibDTD = portletExtTaglibDTD;
    }

    @Override
    public void setPortletTaglibDTD(String portletTaglibDTD) {
        this.portletTaglibDTD = portletTaglibDTD;
    }

    @Override
    public void setSecurityTaglibDTD(String securityTaglibDTD) {
        this.securityTaglibDTD = securityTaglibDTD;
    }

    @Override
    public void setThemeTaglibDTD(String themeTaglibDTD) {
        this.themeTaglibDTD = themeTaglibDTD;
    }

    @Override
    public void setTomcatLibDir(String tomcatLibDir) {
        this.tomcatLibDir = tomcatLibDir;
    }

    @Override
    public void setUiTaglibDTD(String uiTaglibDTD) {
        this.uiTaglibDTD = uiTaglibDTD;
    }

    @Override
    public void setUnpackWar(boolean unpackWar) {
        this.unpackWar = unpackWar;
    }

    @Override
    public void setUtilTaglibDTD(String utilTaglibDTD) {
        this.utilTaglibDTD = utilTaglibDTD;
    }

    @Override
    public void setWars(List<String> wars) {
        this.wars = wars;
    }

    @Override
    public void setWildflyPrefix(String wildflyPrefix) {
        this.wildflyPrefix = wildflyPrefix;
    }

    public void updateDeployDirectory(File srcFile) throws Exception {
    }

    public String updateLiferayWebXml(double webXmlVersion, File srcFile, String webXmlContent) throws Exception {

        boolean liferayWebXmlEnabled = true;

        Properties properties = getPluginPackageProperties(srcFile);

        if (properties != null) {
            liferayWebXmlEnabled = GetterUtil.getBoolean(properties.getProperty("liferay-web-xml-enabled"), true);
        }

        webXmlContent = WebXMLBuilder.organizeWebXML(webXmlContent);

        int x = webXmlContent.indexOf("<filter>");
        int y = webXmlContent.lastIndexOf("</filter-mapping>");

        String webXmlFiltersContent = StringPool.BLANK;

        if ((x == -1) || (y == -1)) {
            x = webXmlContent.lastIndexOf("</display-name>") + 15;

            y = x;
        } else {
            if (liferayWebXmlEnabled && (webXmlVersion > 2.3)) {
                webXmlFiltersContent = webXmlContent.substring(x, y + 17);

                y = y + 17;
            } else {
                x = y + 17;
                y = y + 17;
            }
        }

        if (webXmlVersion < 2.4) {
            webXmlContent = webXmlContent.substring(0, x) + getExtraFiltersContent(webXmlVersion, srcFile)
                    + webXmlContent.substring(y);

            return webXmlContent;
        }

        String filtersContent = webXmlFiltersContent + getExtraFiltersContent(webXmlVersion, srcFile);

        String liferayWebXmlContent = FileUtil.read(DeployUtil.getResourcePath(tempDirPaths, "web.xml"));

        int z = liferayWebXmlContent.indexOf("</web-app>");

        liferayWebXmlContent = liferayWebXmlContent.substring(0, z) + filtersContent
                + liferayWebXmlContent.substring(z);

        liferayWebXmlContent = WebXMLBuilder.organizeWebXML(liferayWebXmlContent);

        FileUtil.write(srcFile + "/WEB-INF/liferay-web.xml", liferayWebXmlContent);

        webXmlContent = webXmlContent.substring(0, x) + getInvokerFilterContent() + webXmlContent.substring(y);

        return webXmlContent;
    }

    @Override
    public void updateWebXml(File webXml, File srcFile, String displayName, PluginPackage pluginPackage)
            throws Exception {

        // Check version

        String content = FileUtil.read(webXml);

        content = WebXMLBuilder.organizeWebXML(content);

        int x = content.indexOf("<display-name>");

        if (x != -1) {
            int y = content.indexOf("</display-name>", x);

            y = content.indexOf(">", y) + 1;

            content = content.substring(0, x) + content.substring(y);
        }

        Document document = UnsecureSAXReaderUtil.read(content);

        Element rootElement = document.getRootElement();

        double webXmlVersion = GetterUtil.getDouble(rootElement.attributeValue("version"), 2.3);

        if (webXmlVersion <= 2.3) {
            throw new AutoDeployException(webXml.getName() + " must be updated to the Servlet 2.4 specification");
        }

        // Plugin context listener

        StringBundler sb = new StringBundler(5);

        sb.append("<listener>");
        sb.append("<listener-class>");

        boolean hasCustomServletListener = false;

        List<Element> listenerElements = rootElement.elements("listener");

        for (Element listenerElement : listenerElements) {
            String listenerClass = GetterUtil.getString(listenerElement.elementText("listener-class"));

            if (listenerClass.equals(PluginContextListener.class.getName())
                    || listenerClass.equals(SerializableSessionAttributeListener.class.getName())
                    || listenerClass.equals(SecurePluginContextListener.class.getName())) {

                continue;
            }

            hasCustomServletListener = true;

            break;
        }

        boolean securityManagerEnabled = false;

        Properties properties = getPluginPackageProperties(srcFile);

        if (properties != null) {
            securityManagerEnabled = GetterUtil.getBoolean(properties.getProperty("security-manager-enabled"));
        }

        if (hasCustomServletListener || securityManagerEnabled) {
            sb.append(SecurePluginContextListener.class.getName());
        } else {
            sb.append(PluginContextListener.class.getName());
        }

        sb.append("</listener-class>");
        sb.append("</listener>");

        String pluginContextListenerContent = sb.toString();

        // Merge content

        String extraContent = getExtraContent(webXmlVersion, srcFile, displayName);

        int pos = content.indexOf("<listener>");

        if (pos == -1) {
            pos = content.indexOf("</web-app>");
        }

        String newContent = StringBundler.concat(content.substring(0, pos), pluginContextListenerContent,
                extraContent, content.substring(pos));

        // Update liferay-web.xml

        newContent = updateLiferayWebXml(webXmlVersion, srcFile, newContent);

        // Update web.xml

        newContent = secureWebXml(newContent, hasCustomServletListener, securityManagerEnabled);

        newContent = WebXMLBuilder.organizeWebXML(newContent);

        FileUtil.write(webXml, newContent, true);

        if (_log.isDebugEnabled()) {
            _log.debug(StringBundler.concat("Modifying Servlet ", webXmlVersion, " ", webXml));
        }
    }

    @Override
    public String wrapCDATA(String string) {
        return StringPool.CDATA_OPEN + string + StringPool.CDATA_CLOSE;
    }

    protected String appServerType;
    protected String auiTaglibDTD;
    protected String baseDir;
    protected String destDir;
    protected String filePattern;
    protected List<String> jars;
    protected String jbossPrefix;
    protected String portletExtTaglibDTD;
    protected String portletTaglibDTD;
    protected String securityTaglibDTD;
    protected final Set<Path> tempDirPaths = new HashSet<>();
    protected String themeTaglibDTD;
    protected String tomcatLibDir;
    protected String uiTaglibDTD;
    protected boolean unpackWar;
    protected String utilTaglibDTD;
    protected List<String> wars;
    protected String wildflyPrefix;

    private static final String _PORTAL_CLASS_LOADER = "com.liferay.support.tomcat.loader.PortalClassLoader";

    private static final Log _log = LogFactoryUtil.getLog(BaseDeployer.class);

    private final List<DeploymentExtension> _deploymentExtensions = new ArrayList<>();

}