org.jahia.services.importexport.ExternalUsersImportUpdater.java Source code

Java tutorial

Introduction

Here is the source code for org.jahia.services.importexport.ExternalUsersImportUpdater.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.importexport;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.jahia.commons.Version;
import org.jahia.services.content.JCRSessionFactory;
import org.jahia.utils.xml.JahiaDocumentBuilderFactory;
import org.jahia.utils.zip.DirectoryZipInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.jcr.RepositoryException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ExternalUsersImportUpdater extends ImportFileUpdater {

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

    private static final String LIVE_REPOSITORY_XML = "live-repository.xml";
    private static final String REPOSITORY_XML = "repository.xml";
    private static final String LIVE_CONTENT = "live-content";
    private static final String CONTENT = "content";

    public boolean mustUpdate(Version version, int buildNumber) {
        Version sevenOne = new Version("7.1");
        return version.compareTo(sevenOne) < 0 || (version.compareTo(sevenOne) == 0 && buildNumber < 50366); // User & group refactoring
    }

    public File updateImport(File importFile, String fileName, String fileType) {
        Map<String, String> pathMapping = new HashMap<String, String>();
        File newImportFile = null;
        ZipInputStream zin = null;
        OutputStream out = null;
        ZipOutputStream zout = null;
        boolean updated = false;
        try {
            newImportFile = File.createTempFile("import", ".zip");
            zin = importFile.isDirectory() ? new DirectoryZipInputStream(importFile)
                    : new NoCloseZipInputStream(new BufferedInputStream(new FileInputStream(importFile)));
            out = new FileOutputStream(newImportFile);
            zout = new ZipOutputStream(out);

            while (true) {
                ZipEntry zipentry = zin.getNextEntry();
                if (zipentry == null)
                    break;
                String name = zipentry.getName();

                if (LIVE_REPOSITORY_XML.equals(name) || REPOSITORY_XML.equals(name)) {
                    zout.putNextEntry(new ZipEntry(name));
                    if ("users.zip".equalsIgnoreCase(fileName)) {
                        updated |= transform(zin, zout, pathMapping);
                    } else {
                        updated |= clean(zin, zout, pathMapping);
                    }
                }

            }
            if (!updated) {
                FileUtils.deleteQuietly(newImportFile);
                return importFile;
            }

            zin.closeEntry();
            if (zin instanceof NoCloseZipInputStream) {
                ((NoCloseZipInputStream) zin).reallyClose();
            }
            zin = importFile.isDirectory() ? new DirectoryZipInputStream(importFile)
                    : new NoCloseZipInputStream(new BufferedInputStream(new FileInputStream(importFile)));
            while (true) {
                ZipEntry zipentry = zin.getNextEntry();
                if (zipentry == null)
                    break;
                String name = zipentry.getName();

                if (!LIVE_REPOSITORY_XML.equals(name) && !REPOSITORY_XML.equals(name)) {
                    if (name.startsWith(LIVE_CONTENT + "/")) {
                        for (String key : pathMapping.keySet()) {
                            if (StringUtils.startsWith(name, LIVE_CONTENT + key)) {
                                name = StringUtils.replace(name, LIVE_CONTENT + key,
                                        LIVE_CONTENT + pathMapping.get(key));
                                break;
                            }
                        }
                    } else if (name.startsWith(CONTENT + "/")) {
                        for (String key : pathMapping.keySet()) {
                            if (StringUtils.startsWith(name, CONTENT + key)) {
                                name = StringUtils.replace(name, CONTENT + key, CONTENT + pathMapping.get(key));
                                break;
                            }
                        }
                    }
                    File content = File.createTempFile("content", null);
                    IOUtils.copy(zin, new FileOutputStream(content));
                    zout.putNextEntry(new ZipEntry(name));
                    IOUtils.copy(new FileInputStream(content), zout);
                }

            }
            JCRSessionFactory.getInstance().getCurrentUserSession().getPathMapping().putAll(pathMapping);
            return newImportFile;
        } catch (IOException | RepositoryException | ParserConfigurationException | XPathExpressionException
                | SAXException | TransformerException e) {
            logger.error("An error occurred while updating import file", e);
        } finally {
            try {
                if (zout != null) {
                    zout.closeEntry();
                    zout.finish();
                }
                if (out != null) {
                    out.close();
                }
                if (zin != null) {
                    zin.closeEntry();
                    if (zin instanceof NoCloseZipInputStream) {
                        ((NoCloseZipInputStream) zin).reallyClose();
                    }
                }
            } catch (IOException e) {
                logger.debug("Stream already closed", e);
            }
        }

        FileUtils.deleteQuietly(newImportFile);
        return importFile;
    }

    private boolean clean(InputStream inputStream, OutputStream outputStream, Map<String, String> pathMapping)
            throws IOException, ParserConfigurationException, SAXException, XPathExpressionException,
            TransformerException {
        Document doc = JahiaDocumentBuilderFactory.newInstance().newDocumentBuilder()
                .parse(new InputSource(inputStream));

        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList nodes = (NodeList) xpath.evaluate("//*[@*[name()='jcr:primaryType'] = 'jnt:usersFolder']", doc,
                XPathConstants.NODESET);

        for (int i = 0; i < nodes.getLength(); i++) {
            Node legacyExtUser = nodes.item(i);
            Node parent = legacyExtUser.getParentNode();
            if (!getNodePath(parent).startsWith("/sites/")) {
                parent.removeChild(legacyExtUser);
            }
        }

        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(new DOMSource(doc), new StreamResult(outputStream));

        return nodes.getLength() > 0;
    }

    private boolean transform(InputStream inputStream, OutputStream outputStream, Map<String, String> pathMapping)
            throws IOException, ParserConfigurationException, SAXException, XPathExpressionException,
            TransformerException {
        Document doc = JahiaDocumentBuilderFactory.newInstance().newDocumentBuilder()
                .parse(new InputSource(inputStream));

        XPath xpath = XPathFactory.newInstance().newXPath();
        NodeList nodes = (NodeList) xpath.evaluate(
                "//*[@*[name()='jcr:primaryType'] = 'jnt:user' and @*[name()='j:external'] = 'true']", doc,
                XPathConstants.NODESET);

        for (int i = 0; i < nodes.getLength(); i++) {
            Node legacyExtUser = nodes.item(i);
            ArrayList<Node> tree = new ArrayList<Node>();
            Element extUser = (Element) legacyExtUser.cloneNode(true);
            extUser.setAttribute("jcr:primaryType", "jnt:externalUser");
            String externalSource = extUser.getAttribute("j:externalSource");
            extUser.setAttribute("j:externalSource", externalSource + ".users");
            tree.add(extUser);

            Node parent = legacyExtUser.getParentNode();
            parent.removeChild(legacyExtUser);
            boolean removeParent = !hasChildElement(parent);
            while (parent != null && !"users".equals(parent.getNodeName())) {
                tree.add(0, parent.cloneNode(false));
                Node n = parent.getParentNode();
                if (removeParent) {
                    n.removeChild(parent);
                    removeParent = !hasChildElement(n);
                }
                parent = n;
            }
            if (parent == null)
                continue;
            StringBuilder mappingSrc = new StringBuilder(getNodePath(parent));
            StringBuilder mappingDst = new StringBuilder(getNodePath(parent));

            NodeList nodeList = ((Element) parent).getElementsByTagName("providers");
            if (nodeList.getLength() == 0) {
                Element e = doc.createElement("providers");
                e.setAttribute("jcr:primaryType", "jnt:usersFolder");
                e.setAttribute("jcr:mixinTypes", "jmix:hasExternalProviderExtension");
                e.setAttribute("j:published", "true");
                e.setAttribute("j:publicationStatus", "1");
                parent.appendChild(e);
                parent = e;
            } else {
                parent = nodeList.item(0);
            }
            mappingDst.append("/").append(parent.getNodeName());

            nodeList = ((Element) parent).getElementsByTagName(externalSource);
            if (nodeList.getLength() == 0) {
                Element e = doc.createElement(externalSource);
                e.setAttribute("jcr:primaryType", "jnt:usersFolder");
                e.setAttribute("provider", externalSource + ".users");
                e.setAttribute("j:publicationStatus", "4");
                parent.appendChild(e);
                parent = e;
            } else {
                parent = nodeList.item(0);
            }
            mappingDst.append("/").append(parent.getNodeName());

            for (Node n : tree) {
                String nodeName = n.getNodeName();
                mappingSrc.append("/").append(nodeName);
                mappingDst.append("/").append(nodeName);
                nodeList = ((Element) parent).getElementsByTagName(nodeName);
                if (nodeList.getLength() == 0) {
                    Node node = parent.appendChild(n);
                    parent = node;
                } else {
                    parent = nodeList.item(0);
                }
            }
            pathMapping.put(mappingSrc.toString(), mappingDst.toString());
        }

        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(new DOMSource(doc), new StreamResult(outputStream));

        return nodes.getLength() > 0;
    }

    private boolean hasChildElement(Node node) {
        for (Node n = node.getFirstChild(); n.getNextSibling() != null; n = n.getNextSibling()) {
            if (n instanceof Element) {
                return true;
            }
        }
        return false;
    }

    private String getNodePath(Node node) {
        if (node.getParentNode() == null || node.getParentNode() instanceof Document) {
            return "";
        } else {
            return getNodePath(node.getParentNode()) + "/" + node.getNodeName();
        }
    }
}