Java tutorial
/** * ========================================================================================== * = 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 java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.jcr.NodeIterator; import javax.jcr.PathNotFoundException; import javax.jcr.Property; import javax.jcr.PropertyIterator; import javax.jcr.PropertyType; import javax.jcr.RepositoryException; import javax.jcr.Value; import javax.jcr.nodetype.NodeType; import javax.jcr.nodetype.NodeTypeIterator; import javax.jcr.query.Query; import javax.jcr.query.QueryManager; import org.apache.commons.lang.StringUtils; import org.jahia.api.Constants; import org.jahia.data.templates.JahiaTemplatesPackage; import org.jahia.services.content.JCRCallback; import org.jahia.services.content.JCRContentUtils; import org.jahia.services.content.JCRNodeWrapper; import org.jahia.services.content.JCRPropertyWrapper; import org.jahia.services.content.JCRSessionWrapper; import org.jahia.services.content.JCRTemplate; import org.jahia.services.content.decorator.JCRSiteNode; import org.jahia.services.content.nodetypes.ExtendedNodeType; import org.jahia.services.content.nodetypes.NodeTypeRegistry; import org.jahia.services.importexport.ReferencesHelper; import org.jahia.services.sites.JahiaSitesService; import org.jahia.services.sites.SitesSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; /** * Module installation helper. * * @author Sergiy Shyrkov */ public class ModuleInstallationHelper implements ApplicationEventPublisherAware { private static Logger logger = LoggerFactory.getLogger(ModuleInstallationHelper.class); private ApplicationEventPublisher applicationEventPublisher; private JahiaSitesService siteService; private TemplatePackageRegistry templatePackageRegistry; private boolean addDependencyValue(JCRNodeWrapper originalNode, JCRNodeWrapper destinationNode, String propertyName) throws RepositoryException { String valueToBeAdded = originalNode.getName(); String newStringValue = valueToBeAdded; if (destinationNode.hasProperty(propertyName)) { JCRPropertyWrapper installedModules = destinationNode.getProperty(propertyName); Value[] values = installedModules.getValues(); List<String> stringValues = new LinkedList<>(); for (Value value : values) { String strVal = value.getString(); stringValues.add(strVal); if (strVal.equals(valueToBeAdded)) { return true; } } stringValues.add(valueToBeAdded); destinationNode.setProperty(propertyName, stringValues.toArray(new String[] {})); } else { destinationNode.setProperty(propertyName, new String[] { newStringValue }); } return false; } public void autoInstallModulesToSites(JahiaTemplatesPackage module, JCRSessionWrapper session) throws RepositoryException { Set<String> autoInstalled = new HashSet<String>(); if (StringUtils.isNotBlank(module.getAutoDeployOnSite())) { if ("system".equals(module.getAutoDeployOnSite()) || "systemsite".equals(module.getAutoDeployOnSite())) { if (session.nodeExists("/sites/systemsite")) { installModule(module, "/sites/systemsite", session); autoInstalled.add("systemsite"); } } else if ("all".equals(module.getAutoDeployOnSite())) { if (session.nodeExists("/sites/systemsite")) { installModuleOnAllSites(module, session, null); return; } } } List<JCRNodeWrapper> sites = new ArrayList<JCRNodeWrapper>(); NodeIterator ni = session.getNode("/sites").getNodes(); while (ni.hasNext()) { JCRNodeWrapper next = (JCRNodeWrapper) ni.next(); if (autoInstalled.contains(next.getName())) { continue; } if (next.hasProperty(SitesSettings.INSTALLED_MODULES)) { Value[] v = next.getProperty(SitesSettings.INSTALLED_MODULES).getValues(); for (Value value : v) { if (value.getString().equals(module.getId())) { sites.add(next); } } } } if (!sites.isEmpty()) { installModuleOnAllSites(module, session, sites); } } public void installModule(final JahiaTemplatesPackage module, final String sitePath, final JCRSessionWrapper session) throws RepositoryException { installModules(Collections.singletonList(module), sitePath, session); } public void installModule(final String moduleId, final String sitePath, String username) throws RepositoryException { JCRTemplate.getInstance().doExecuteWithSystemSession(username, new JCRCallback<Object>() { public Object doInJCR(JCRSessionWrapper session) throws RepositoryException { installModules(Collections.singletonList(templatePackageRegistry.lookupById(moduleId)), sitePath, session); session.save(); return null; } }); } public void installModule(final String moduleId, final String version, final String sitePath, String username) throws RepositoryException { JCRTemplate.getInstance().doExecuteWithSystemSession(username, new JCRCallback<Object>() { public Object doInJCR(JCRSessionWrapper session) throws RepositoryException { installModules( Collections.singletonList( templatePackageRegistry.lookupByIdAndVersion(moduleId, new ModuleVersion(version))), sitePath, session); session.save(); return null; } }); } public void installModuleOnAllSites(JahiaTemplatesPackage module, JCRSessionWrapper sessionWrapper, List<JCRNodeWrapper> sites) throws RepositoryException { if (sites == null) { sites = new ArrayList<JCRNodeWrapper>(); NodeIterator ni = sessionWrapper.getNode("/sites").getNodes(); while (ni.hasNext()) { JCRNodeWrapper next = (JCRNodeWrapper) ni.next(); if (!next.isNodeType("jnt:virtualsite")) { continue; } sites.add(next); } } JCRNodeWrapper tpl = sessionWrapper.getNode("/modules/" + module.getIdWithVersion()); for (JCRNodeWrapper site : sites) { if (!site.isNodeType("jnt:virtualsite")) { continue; } if (tpl.hasProperty("j:moduleType") && JahiaTemplateManagerService.MODULE_TYPE_TEMPLATES_SET .equals(tpl.getProperty("j:moduleType").getString())) { if (tpl.getName().equals(site.getResolveSite().getTemplateFolder())) { installModule(module, site.getPath(), sessionWrapper); } } else { installModule(module, site.getPath(), sessionWrapper); } } } public void installModules(final List<JahiaTemplatesPackage> modules, final String sitePath, final JCRSessionWrapper session) throws RepositoryException { if (!sitePath.startsWith("/sites/")) { return; } final JCRSiteNode siteNode = (JCRSiteNode) session.getNode(sitePath); HashMap<String, List<String>> references = new HashMap<String, List<String>>(); for (JahiaTemplatesPackage module : modules) { logger.info("Installing " + module.getName() + " on " + sitePath); JCRNodeWrapper moduleNode = null; try { moduleNode = session.getNode("/modules/" + module.getId()); String moduleName = moduleNode.getName(); if (moduleNode.isNodeType("jnt:module")) { moduleNode = moduleNode.getNode(module.getVersion().toString()); } synchro(moduleNode, siteNode, session, moduleName, references); ReferencesHelper.resolveCrossReferences(session, references); addDependencyValue(moduleNode.getParent(), siteNode, SitesSettings.INSTALLED_MODULES); logger.info("Done installing " + module.getName() + " on " + sitePath); } catch (PathNotFoundException e) { logger.warn("Cannot find module for path {}. Skipping deployment to site {}.", module, sitePath); return; } } applicationEventPublisher.publishEvent(new JahiaTemplateManagerService.ModuleDeployedOnSiteEvent(sitePath, ModuleInstallationHelper.class.getName())); } private void keepReference(JCRNodeWrapper destinationNode, Map<String, List<String>> references, Property property, String value) throws RepositoryException { if (!references.containsKey(value)) { references.put(value, new ArrayList<String>()); } references.get(value).add(destinationNode.getIdentifier() + "/" + property.getName()); } public void purgeModuleContent(final List<String> modules, final String sitePath, final JCRSessionWrapper session) throws RepositoryException { QueryManager manager = session.getWorkspace().getQueryManager(); for (String module : modules) { NodeTypeIterator nti = NodeTypeRegistry.getInstance().getNodeTypes(module); while (nti.hasNext()) { ExtendedNodeType next = (ExtendedNodeType) nti.next(); Query q = manager.createQuery("select * from ['" + next.getName() + "'] as c where isdescendantnode(c,'" + JCRContentUtils.sqlEncode(sitePath) + "')", Query.JCR_SQL2); try { NodeIterator ni = q.execute().getNodes(); while (ni.hasNext()) { JCRNodeWrapper nodeWrapper = (JCRNodeWrapper) ni.nextNode(); nodeWrapper.remove(); } } catch (RepositoryException e) { logger.error("Cannot remove node", e); } } } } public boolean checkExistingContent(final String module) throws RepositoryException { final JCRCallback<Boolean> callback = new JCRCallback<Boolean>() { public Boolean doInJCR(JCRSessionWrapper session) throws RepositoryException { QueryManager manager = session.getWorkspace().getQueryManager(); NodeTypeIterator nti = NodeTypeRegistry.getInstance().getNodeTypes(module); while (nti.hasNext()) { ExtendedNodeType next = (ExtendedNodeType) nti.next(); Query q = manager.createQuery("select * from ['" + next.getName() + "']", Query.JCR_SQL2); if (q.execute().getRows().hasNext()) { return true; } } return false; } }; return JCRTemplate.getInstance().doExecuteWithSystemSession(callback) || JCRTemplate.getInstance().doExecuteWithSystemSessionAsUser(null, "live", null, callback); } public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { this.applicationEventPublisher = applicationEventPublisher; } public void setSiteService(JahiaSitesService siteService) { this.siteService = siteService; } public void setTemplatePackageRegistry(TemplatePackageRegistry registry) { templatePackageRegistry = registry; } public void synchro(JCRNodeWrapper source, JCRNodeWrapper destinationNode, JCRSessionWrapper session, String moduleName, Map<String, List<String>> references) throws RepositoryException { if (source.isNodeType("jnt:moduleVersion")) { session.getUuidMapping().put(source.getIdentifier(), destinationNode.getIdentifier()); NodeIterator ni = source.getNodes(); while (ni.hasNext()) { JCRNodeWrapper child = (JCRNodeWrapper) ni.next(); if (child.isNodeType("jnt:versionInfo") || child.isNodeType("jnt:moduleVersionFolder") || child.isNodeType("jnt:externalProviderExtension") || child.isNodeType("jnt:templatesFolder") || child.isNodeType("jnt:componentFolder") || child.isNodeType("jnt:permission")) { continue; } JCRNodeWrapper node; boolean newNode = false; String childName = child.getName(); if (destinationNode.hasNode(childName)) { node = destinationNode.getNode(childName); } else { session.checkout(destinationNode); String primaryNodeTypeName = child.getPrimaryNodeTypeName(); node = destinationNode.addNode(childName, primaryNodeTypeName); newNode = true; } templatesSynchro(child, node, session, references, newNode, true); } } } public void templatesSynchro(final JCRNodeWrapper source, final JCRNodeWrapper destinationNode, JCRSessionWrapper session, Map<String, List<String>> references, boolean doUpdate, boolean doChildren) throws RepositoryException { if ("j:acl".equals(destinationNode.getName())) { return; } if (logger.isDebugEnabled()) { logger.debug("Synchronizing node : " + destinationNode.getPath() + ", update=" + doUpdate + "/children=" + doChildren); } session.checkout(destinationNode); final Map<String, String> uuidMapping = session.getUuidMapping(); ExtendedNodeType[] mixin = source.getMixinNodeTypes(); List<ExtendedNodeType> destMixin = Arrays.asList(destinationNode.getMixinNodeTypes()); for (ExtendedNodeType aMixin : mixin) { if (!destMixin.contains(aMixin)) { destinationNode.addMixin(aMixin.getName()); } } uuidMapping.put(source.getIdentifier(), destinationNode.getIdentifier()); List<String> names = new ArrayList<String>(); if (doUpdate) { if (source.hasProperty(Constants.JCR_LANGUAGE) && (!destinationNode.hasProperty(Constants.JCR_LANGUAGE) || (!destinationNode.getProperty(Constants.JCR_LANGUAGE).getString() .equals(source.getProperty(Constants.JCR_LANGUAGE).getString())))) { destinationNode.setProperty(Constants.JCR_LANGUAGE, source.getProperty(Constants.JCR_LANGUAGE).getString()); } PropertyIterator props = source.getProperties(); while (props.hasNext()) { Property property = props.nextProperty(); names.add(property.getName()); try { if (!property.getDefinition().isProtected() && !Constants.forbiddenPropertiesToCopy.contains(property.getName())) { if (property.getType() == PropertyType.REFERENCE || property.getType() == PropertyType.WEAKREFERENCE) { if (property.getDefinition().isMultiple() && (property.isMultiple())) { if (!destinationNode.hasProperty(property.getName()) || !Arrays.equals( destinationNode.getProperty(property.getName()).getValues(), property.getValues())) { destinationNode.setProperty(property.getName(), new Value[0]); Value[] values = property.getValues(); for (Value value : values) { keepReference(destinationNode, references, property, value.getString()); } } } else { if (!destinationNode.hasProperty(property.getName()) || !destinationNode .getProperty(property.getName()).getValue().equals(property.getValue())) { keepReference(destinationNode, references, property, property.getValue().getString()); } } } else if (property.getDefinition().isMultiple() && (property.isMultiple())) { if (!destinationNode.hasProperty(property.getName()) || !Arrays.equals(destinationNode.getProperty(property.getName()).getValues(), property.getValues())) { destinationNode.setProperty(property.getName(), property.getValues()); } } else if (!destinationNode.hasProperty(property.getName()) || !destinationNode .getProperty(property.getName()).getValue().equals(property.getValue())) { destinationNode.setProperty(property.getName(), property.getValue()); } } } catch (Exception e) { logger.warn("Unable to copy property '" + property.getName() + "'. Skipping.", e); } } PropertyIterator pi = destinationNode.getProperties(); while (pi.hasNext()) { JCRPropertyWrapper oldChild = (JCRPropertyWrapper) pi.next(); if (!oldChild.getDefinition().isProtected()) { if (!names.contains(oldChild.getName()) && !oldChild.getName().equals("j:published") && !oldChild.getName().equals(Constants.JAHIA_MODULE_TEMPLATE) && !oldChild.getName().equals("j:sourceTemplate")) { oldChild.remove(); } } } mixin = destinationNode.getMixinNodeTypes(); for (NodeType aMixin : mixin) { if (!source.isNodeType(aMixin.getName())) { destinationNode.removeMixin(aMixin.getName()); } } } NodeIterator ni = source.getNodes(); names.clear(); while (ni.hasNext()) { JCRNodeWrapper child = (JCRNodeWrapper) ni.next(); boolean isPageNode = child.isNodeType("jnt:page"); if (doChildren) { names.add(child.getName()); boolean newNode = false; JCRNodeWrapper node; if (destinationNode.hasNode(child.getName())) { node = destinationNode.getNode(child.getName()); } else { node = destinationNode.addNode(child.getName(), child.getPrimaryNodeTypeName()); newNode = true; } templatesSynchro(child, node, session, references, newNode, doChildren && (!isPageNode || newNode)); } } if (doUpdate) { List<String> destNames = new ArrayList<String>(); ni = destinationNode.getNodes(); while (ni.hasNext()) { JCRNodeWrapper oldChild = (JCRNodeWrapper) ni.next(); destNames.add(oldChild.getName()); } if (destinationNode.getPrimaryNodeType().hasOrderableChildNodes() && !names.equals(destNames)) { Collections.reverse(names); String previous = null; for (String name : names) { destinationNode.orderBefore(name, previous); previous = name; } } } } public void uninstallModule(final JahiaTemplatesPackage module, final String sitePath, final JCRSessionWrapper session) throws RepositoryException { uninstallModules(Collections.singletonList(module.getId()), sitePath, session); } private boolean uninstallModule(String sitePath, JCRSessionWrapper session, JCRSiteNode siteNode, String module) throws RepositoryException { logger.info("Uninstalling " + module + " on " + sitePath); try { JCRPropertyWrapper installedModules = siteNode.getProperty(SitesSettings.INSTALLED_MODULES); List<String> stringValues = new LinkedList<>(); Value toBeRemoved = null; Value[] values = installedModules.getValues(); for (Value value : values) { String strValue = value.getString(); if (strValue.equals(module)) { toBeRemoved = value; } else { stringValues.add(strValue); } } if (toBeRemoved != null) { siteNode.setProperty(SitesSettings.INSTALLED_MODULES, stringValues.toArray(new String[] {})); } logger.info("Done uninstalling " + module + " on " + sitePath); } catch (PathNotFoundException e) { logger.warn("Cannot find module for path {}. Skipping deployment to site {}.", module, sitePath); return true; } return false; } public void uninstallModule(final String module, final String sitePath, String username, final boolean purgeAllContent) throws RepositoryException { JCRTemplate.getInstance().doExecuteWithSystemSession(username, new JCRCallback<Object>() { public Object doInJCR(JCRSessionWrapper session) throws RepositoryException { uninstallModules(Collections.singletonList(module), sitePath, session); if (purgeAllContent) { purgeModuleContent(Collections.singletonList(module), sitePath, session); } session.save(); return null; } }); if (purgeAllContent) { JCRTemplate.getInstance().doExecuteWithSystemSession(username, "live", new JCRCallback<Object>() { public Object doInJCR(JCRSessionWrapper session) throws RepositoryException { purgeModuleContent(Collections.singletonList(module), sitePath, session); session.save(); return null; } }); } } public void uninstallModules(final List<String> modules, final String sitePath, final JCRSessionWrapper session) throws RepositoryException { if (!sitePath.startsWith("/sites/")) { return; } final JCRSiteNode siteNode = (JCRSiteNode) session.getNode(sitePath); for (String module : modules) { if (uninstallModule(sitePath, session, siteNode, module)) { return; } } applicationEventPublisher.publishEvent(new JahiaTemplateManagerService.ModuleDeployedOnSiteEvent(sitePath, ModuleInstallationHelper.class.getName())); } public void uninstallModulesFromAllSites(final String module, final JCRSessionWrapper session) throws RepositoryException { uninstallModulesFromAllSites(Collections.singletonList(module), session); } public void uninstallModulesFromAllSites(final List<String> modules, final JCRSessionWrapper session) throws RepositoryException { List<JCRSiteNode> sitesList = siteService.getSitesNodeList(session); for (JCRSiteNode jahiaSite : sitesList) { for (String module : modules) { if (uninstallModule(jahiaSite.getName(), session, jahiaSite, module)) { return; } applicationEventPublisher.publishEvent(new JahiaTemplateManagerService.ModuleDeployedOnSiteEvent( jahiaSite.getName(), ModuleInstallationHelper.class.getName())); } } } public void uninstallModulesFromAllSites(final String module, final String username, final boolean purgeAllContent) throws RepositoryException { JCRTemplate.getInstance().doExecuteWithSystemSession(username, new JCRCallback<Object>() { public Object doInJCR(JCRSessionWrapper session) throws RepositoryException { uninstallModulesFromAllSites(module, session); if (purgeAllContent) { purgeModuleContent(Collections.singletonList(module), "/sites", session); } session.save(); return null; } }); if (purgeAllContent) { JCRTemplate.getInstance().doExecuteWithSystemSession(username, "live", new JCRCallback<Object>() { public Object doInJCR(JCRSessionWrapper session) throws RepositoryException { purgeModuleContent(Collections.singletonList(module), "/sites", session); session.save(); return null; } }); } } }