org.jahia.services.templates.TemplatePackageDeployer.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.services.templates.TemplatePackageDeployer.java

Source

/**
 * ==========================================================================================
 * =                   JAHIA'S DUAL LICENSING - IMPORTANT INFORMATION                       =
 * ==========================================================================================
 *
 *                                 http://www.jahia.com
 *
 *     Copyright (C) 2002-2017 Jahia Solutions Group SA. All rights reserved.
 *
 *     THIS FILE IS AVAILABLE UNDER TWO DIFFERENT LICENSES:
 *     1/GPL OR 2/JSEL
 *
 *     1/ GPL
 *     ==================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE GPL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program 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 General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 *
 *     2/ JSEL - Commercial and Supported Versions of the program
 *     ===================================================================================
 *
 *     IF YOU DECIDE TO CHOOSE THE JSEL LICENSE, YOU MUST COMPLY WITH THE FOLLOWING TERMS:
 *
 *     Alternatively, commercial and supported versions of the program - also known as
 *     Enterprise Distributions - must be used in accordance with the terms and conditions
 *     contained in a separate written agreement between you and Jahia Solutions Group SA.
 *
 *     If you are unsure which license is appropriate for your use,
 *     please contact the sales department at sales@jahia.com.
 */
package org.jahia.services.templates;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.jackrabbit.core.security.JahiaAccessManager;
import org.jahia.api.Constants;
import org.jahia.data.templates.JahiaTemplatesPackage;
import org.jahia.osgi.BundleUtils;
import org.jahia.osgi.FrameworkService;
import org.jahia.services.content.*;
import org.jahia.services.importexport.DocumentViewImportHandler;
import org.jahia.services.importexport.ImportExportBaseService;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;

import javax.jcr.ImportUUIDBehavior;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * Template package deployer service.
 *
 * @author Sergiy Shyrkov
 * @author Thomas Draier
 */
public class TemplatePackageDeployer {

    private static Logger logger = LoggerFactory.getLogger(TemplatePackageDeployer.class);

    protected JahiaTemplateManagerService service;

    private TemplatePackageRegistry templatePackageRegistry;
    private ComponentRegistry componentRegistry;

    private ImportExportBaseService importExportService;

    public void setComponentRegistry(ComponentRegistry componentRegistry) {
        this.componentRegistry = componentRegistry;
    }

    public void setImportExportService(ImportExportBaseService importExportService) {
        this.importExportService = importExportService;
    }

    public void setService(JahiaTemplateManagerService service) {
        this.service = service;
    }

    public void setTemplatePackageRegistry(TemplatePackageRegistry tmplPackageRegistry) {
        templatePackageRegistry = tmplPackageRegistry;
    }

    public void initializeModuleContent(JahiaTemplatesPackage aPackage, JCRSessionWrapper session)
            throws RepositoryException {
        resetModuleNodes(aPackage, session);

        logger.info("Starting import for the module package '" + aPackage.getName() + "' including: "
                + aPackage.getInitialImports());
        for (String imp : aPackage.getInitialImports()) {
            String targetPath = "/" + StringUtils
                    .substringAfter(StringUtils.substringBeforeLast(imp, "."), "import-").replace('-', '/');
            Resource importFile = aPackage.getResource(imp);
            logger.info("... importing " + importFile + " into " + targetPath);
            session.getPathMapping().put("/templateSets/", "/modules/");
            session.getPathMapping().put("/modules/" + aPackage.getId() + "/",
                    "/modules/" + aPackage.getId() + "/" + aPackage.getVersion() + "/");

            try {
                if (imp.toLowerCase().endsWith(".xml")) {
                    InputStream is = null;
                    try {
                        is = new BufferedInputStream(importFile.getInputStream());
                        session.importXML(targetPath, is, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW,
                                DocumentViewImportHandler.ROOT_BEHAVIOUR_IGNORE);
                    } finally {
                        IOUtils.closeQuietly(is);
                    }
                } else if (imp.toLowerCase().contains("/importsite")) {
                    importExportService.importSiteZip(importFile, session);
                } else {
                    //                    importExportService.importZip(targetPath, importFile, DocumentViewImportHandler.ROOT_BEHAVIOUR_IGNORE, session);
                    importExportService.importZip(targetPath, importFile,
                            DocumentViewImportHandler.ROOT_BEHAVIOUR_IGNORE, session,
                            new HashSet<String>(Arrays.asList("permissions.xml", "roles.xml")), false);
                    if (targetPath.equals("/")) {
                        List<String> fileList = new ArrayList<String>();
                        Map<String, Long> sizes = new HashMap<String, Long>();
                        importExportService.getFileList(importFile, sizes, fileList);
                        if (sizes.containsKey("permissions.xml")) {
                            Set<String> s = new HashSet<String>(sizes.keySet());
                            s.remove("permissions.xml");
                            if (!session.itemExists("/modules/" + aPackage.getIdWithVersion() + "/permissions")) {
                                session.getNode("/modules/" + aPackage.getIdWithVersion()).addNode("permissions",
                                        "jnt:permission");
                            }
                            importExportService.importZip("/modules/" + aPackage.getIdWithVersion(), importFile,
                                    DocumentViewImportHandler.ROOT_BEHAVIOUR_IGNORE, session, s, false);
                        }
                        if (sizes.containsKey("roles.xml")) {
                            Set<String> s = new HashSet<String>(sizes.keySet());
                            s.remove("roles.xml");
                            session.getPathMapping().put("/permissions",
                                    "/modules/" + aPackage.getIdWithVersion() + "/permissions");
                            importExportService.importZip("/", importFile,
                                    DocumentViewImportHandler.ROOT_BEHAVIOUR_IGNORE, session, s, false);
                            session.getPathMapping().remove("/permissions");
                        }
                    }
                }
            } catch (IOException e) {
                throw new RepositoryException(e);
            }

            File realImportFile = null;
            try {
                realImportFile = importFile.getFile();
            } catch (IOException ioe) {
                realImportFile = null;
            }
            if (realImportFile != null) {
                realImportFile.delete();
            }
            session.save(JCRObservationManager.IMPORT);
        }
        cloneModuleInLive(aPackage);
        logger.info("... finished initial import for module package '" + aPackage.getName() + "'.");

        componentRegistry.registerComponents(aPackage, session);

        session.save();
    }

    private synchronized void cloneModuleInLive(final JahiaTemplatesPackage pack) throws RepositoryException {
        JCRTemplate.getInstance().doExecuteWithSystemSessionAsUser(null, "live", null, new JCRCallback<Object>() {
            public Object doInJCR(JCRSessionWrapper session) throws RepositoryException {
                try {
                    JCRObservationManager.setEventListenersAvailableDuringPublishOnly(true);
                    if (!session.itemExists("/modules")) {
                        JahiaAccessManager
                                .setDeniedPaths(Arrays.asList("/modules/" + pack.getIdWithVersion() + "/sources"));
                        session.getWorkspace().clone("default", "/modules", "/modules", true);
                    } else if (!session.itemExists("/modules/" + pack.getId())) {
                        JahiaAccessManager
                                .setDeniedPaths(Arrays.asList("/modules/" + pack.getIdWithVersion() + "/sources"));
                        session.getWorkspace().clone("default", "/modules/" + pack.getId(),
                                "/modules/" + pack.getId(), true);
                    } else {
                        if (session.itemExists("/modules/" + pack.getIdWithVersion())) {
                            session.getNode("/modules/" + pack.getIdWithVersion()).remove();
                            session.save();
                        }
                        JahiaAccessManager
                                .setDeniedPaths(Arrays.asList("/modules/" + pack.getIdWithVersion() + "/sources"));
                        session.getWorkspace().clone("default", "/modules/" + pack.getIdWithVersion(),
                                "/modules/" + pack.getIdWithVersion(), true);
                    }
                } finally {
                    JCRObservationManager.setEventListenersAvailableDuringPublishOnly(false);
                    JahiaAccessManager.setDeniedPaths(null);
                }
                return null;
            }
        });
    }

    private void resetModuleNodes(JahiaTemplatesPackage pkg, JCRSessionWrapper session) throws RepositoryException {
        clearModuleNodes(pkg, session);
        if (initModuleNode(session, pkg, true)) {
            resetModuleAttributes(session, pkg);
        }
        session.save();
    }

    public void clearModuleNodes(JahiaTemplatesPackage pkg, JCRSessionWrapper session) throws RepositoryException {
        String modulePath = "/modules/" + pkg.getId() + "/" + pkg.getVersion();
        if (session.nodeExists(modulePath)) {
            JCRNodeWrapper moduleNode = session.getNode(modulePath);
            NodeIterator nodeIterator = moduleNode.getNodes();
            while (nodeIterator.hasNext()) {
                JCRNodeWrapper next = (JCRNodeWrapper) nodeIterator.next();
                if (!next.isNodeType("jnt:versionInfo") && !next.isNodeType("jnt:moduleVersionFolder")) {
                    next.remove();
                }
            }
            session.save();
        }
    }

    private boolean initModuleNode(JCRSessionWrapper session, JahiaTemplatesPackage pack,
            boolean updateDeploymentDate) throws RepositoryException {
        boolean modified = false;
        if (!session.nodeExists("/modules")) {
            session.getRootNode().addNode("modules", "jnt:modules");
            modified = true;
        }
        JCRNodeWrapper modules = session.getNode("/modules");
        JCRNodeWrapper m;
        if (!modules.hasNode(pack.getId())) {
            modified = true;
            m = modules.addNode(pack.getId(), "jnt:module");
        } else {
            m = modules.getNode(pack.getId());
        }

        if (!m.hasNode(pack.getVersion().toString())) {
            modified = true;
            m = m.addNode(pack.getVersion().toString(), "jnt:moduleVersion");
        } else {
            m = m.getNode(pack.getVersion().toString());
        }

        JCRNodeWrapper v;
        if (!m.hasNode("j:versionInfo")) {
            v = m.addNode("j:versionInfo", "jnt:versionInfo");
            modified = true;
        } else {
            v = m.getNode("j:versionInfo");
        }
        if (!v.hasProperty("j:version")) {
            v.setProperty("j:version", pack.getVersion().toString());
            modified = true;
        }
        if (pack.getSourcesFolder() != null) {
            v.setProperty("j:sourcesFolder", pack.getSourcesFolder().getPath());
        }
        if (pack.getScmURI() != null && !Constants.SCM_DUMMY_URI.equals(pack.getScmURI())) {
            try {
                v.setProperty("j:scmURI", pack.getScmURI());
                if (pack.getScmTag() != null) {
                    v.setProperty("j:scmTag", pack.getScmTag());
                }
            } catch (Exception e) {
                logger.error("Cannot get SCM url");
            }
        }
        if (updateDeploymentDate) {
            v.setProperty("j:deployementDate", new GregorianCalendar());
            modified = true;
        }

        if (!m.hasNode("portlets")) {
            modified = true;
            m.addNode("portlets", "jnt:portletFolder");
        }
        if (!m.hasNode("files")) {
            modified = true;
            m.addNode("files", "jnt:folder");
        }
        if (!m.hasNode("contents")) {
            modified = true;
            m.addNode("contents", "jnt:contentFolder");
        }
        if (!m.hasNode("templates")) {
            modified = true;
            JCRNodeWrapper tpls = m.addNode("templates", "jnt:templatesFolder");
            if (JahiaTemplateManagerService.MODULE_TYPE_MODULE.equals(pack.getModuleType())) {
                tpls.setProperty("j:rootTemplatePath", "/base");
            }
            tpls.addNode("files", "jnt:folder");
            tpls.addNode("contents", "jnt:contentFolder");
        }

        return modified;
    }

    private void resetModuleAttributes(JCRSessionWrapper session, JahiaTemplatesPackage pack)
            throws RepositoryException {
        JCRNodeWrapper modules = session.getNode("/modules");
        JCRNodeWrapper m = modules.getNode(pack.getIdWithVersion());

        m.setProperty("j:title", pack.getName());
        if (pack.getModuleType() != null) {
            m.setProperty("j:moduleType", pack.getModuleType());
        }
        m.setProperty("j:modulePriority", pack.getModulePriority());
        List<Value> l = new ArrayList<Value>();
        for (String d : pack.getDepends()) {
            String v = templatePackageRegistry.getModuleId(d);
            if (v != null) {
                l.add(session.getValueFactory().createValue(v));
            } else {
                logger.warn("Cannot find dependency {} for package '{}'", d, pack.getName());
            }
        }
        Value[] values = new Value[pack.getDepends().size()];
        m.setProperty("j:dependencies", l.toArray(values));

        if (pack.getModuleType() == null) {
            String moduleType = guessModuleType(session, pack);
            pack.setModuleType(moduleType);
        }

        if (!m.hasNode("templates")) {
            m.addNode("templates", "jnt:templatesFolder");
        }
        if (!m.hasNode("permissions")) {
            m.addNode("permissions", "jnt:permission");
        }
        JCRNodeWrapper perms = m.getNode("permissions");
        if (!perms.hasNode("components")) {
            perms.addNode("components", "jnt:permission");
        }
        if (!perms.hasNode("templates")) {
            perms.addNode("templates", "jnt:permission");
        }

        JCRNodeWrapper tpls = m.getNode("templates");
        if (!tpls.hasProperty("j:rootTemplatePath")
                && JahiaTemplateManagerService.MODULE_TYPE_MODULE.equals(pack.getModuleType())) {
            tpls.setProperty("j:rootTemplatePath", "/base");
        }

        if (pack.getResourceBundleName() != null) {
            List<String> langs = new ArrayList<String>();
            Resource[] resources = pack.getResources("resources");
            for (Resource resource : resources) {
                try {
                    String key = resource.getURI().getPath().substring(1).replace("/", ".");
                    if (key.startsWith(pack.getResourceBundleName())) {
                        String langCode = StringUtils.substringBetween(key, pack.getResourceBundleName() + "_",
                                ".properties");
                        if (langCode != null) {
                            langs.add(langCode);
                        }
                    }
                } catch (IOException e) {
                    logger.error("Cannot get resources", e);
                }
            }
            JCRNodeWrapper moduleNode = m.getParent();
            if (moduleNode.hasProperty("j:languages")) {
                Value[] oldValues = m.getParent().getProperty("j:languages").getValues();
                for (Value value : oldValues) {
                    if (!langs.contains(value.getString())) {
                        langs.add(value.getString());
                    }
                }
            }
            moduleNode.setProperty("j:languages", langs.toArray(new String[langs.size()]));
        }
    }

    private String guessModuleType(JCRSessionWrapper session, JahiaTemplatesPackage pack)
            throws RepositoryException {
        String moduleType = JahiaTemplateManagerService.MODULE_TYPE_MODULE;
        if (session.itemExists("/modules/" + pack.getIdWithVersion() + "/j:moduleType")) {
            moduleType = session.getNode("/modules/" + pack.getIdWithVersion()).getProperty("j:moduleType")
                    .getValue().getString();
        } else {
            String[] fileNames = new File(pack.getFilePath()).list();
            if (fileNames != null) {
                List<String> files = new ArrayList<String>(Arrays.asList(fileNames));
                files.removeAll(Arrays.asList("META-INF", "WEB-INF", "resources"));
                if (files.isEmpty()) {
                    moduleType = JahiaTemplateManagerService.MODULE_TYPE_SYSTEM;
                }
            }
        }
        return moduleType;
    }

    public JahiaTemplatesPackage deployModule(File jarFile, JCRSessionWrapper session) throws RepositoryException {
        try {
            String location = jarFile.toURI().toString();
            Bundle bundle = FrameworkService.getBundleContext().installBundle(location);
            bundle.update();
            bundle.start();
            String moduleId = BundleUtils.getModuleId(bundle);
            String version = BundleUtils.getModuleVersion(bundle);
            return service.getTemplatePackageRegistry().lookupByIdAndVersion(moduleId, new ModuleVersion(version));
        } catch (BundleException e) {
            logger.error("Cannot deploy module", e);
        }

        return null;
    }

    public void undeployModule(String id, String version) throws RepositoryException {
        Bundle[] bundles = FrameworkService.getBundleContext().getBundles();
        for (Bundle bundle : bundles) {
            String moduleId = BundleUtils.getModuleId(bundle);
            String moduleVersion = BundleUtils.getModuleVersion(bundle);
            if (moduleId.equals(id) && moduleVersion.equals(version)) {
                try {
                    bundle.uninstall();
                    return;
                } catch (BundleException e) {
                    logger.error("Cannot undeploy module", e);
                }
            }
        }
    }

}