DPSPageExporterImpl.java 12.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.xss.XSSAPI
 *  com.day.cq.commons.jcr.JcrUtil
 *  com.day.cq.contentsync.ContentSyncManager
 *  com.day.cq.i18n.I18n
 *  com.day.cq.wcm.api.Page
 *  com.day.cq.wcm.api.WCMException
 *  com.day.cq.wcm.api.designer.Designer
 *  javax.jcr.Node
 *  javax.jcr.NodeIterator
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.resource.LoginException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceResolverFactory
 *  org.apache.sling.api.resource.ValueMap
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.mobile.dps.impl.export;

import com.adobe.cq.mobile.dps.DPSException;
import com.adobe.cq.mobile.dps.DPSObject;
import com.adobe.cq.mobile.dps.DPSProject;
import com.adobe.cq.mobile.dps.impl.DPSPageExporter;
import com.adobe.cq.mobile.dps.impl.export.ExportOptions;
import com.adobe.cq.mobile.dps.impl.utils.DPSUtil;
import com.adobe.granite.xss.XSSAPI;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.contentsync.ContentSyncManager;
import com.day.cq.i18n.I18n;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.WCMException;
import com.day.cq.wcm.api.designer.Designer;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(label="Adobe Experience Manager Mobile Page Exporter")
@Service
public class DPSPageExporterImpl
implements DPSPageExporter {
    @Reference
    protected XSSAPI xssAPI;
    public static final String CACHE_ROOT = "/var/contentsync";
    private static final String ZIP_CACHE_SUFFIX = "-zips";
    private static final Logger log = LoggerFactory.getLogger(DPSPageExporterImpl.class);
    private static final String DEFAULT_RESOURCES_TEMPLATE = "dps-HTMLResources";
    private static final String DEFAULT_FOLIO_CONTENT_TEMPLATE = "dps-article";
    private static final String CONFIG_VAR_PATH_PATH = "{page.path}";
    private static final String CONFIG_VAR_DESIGN_PATH = "{design.path}";
    @Reference
    protected ContentSyncManager contentSyncManager;
    @Reference
    protected ResourceResolverFactory resolverFactory;
    private I18n i18n = null;

    @Override
    public void export(Page page, SlingHttpServletRequest request, HttpServletResponse response, ExportOptions exportOptions) throws WCMException {
        ResourceResolver resolver = null;
        this.i18n = new I18n((HttpServletRequest)request);
        try {
            resolver = request.getResourceResolver();
            Session userSession = (Session)resolver.adaptTo(Session.class);
            String zipPath = this.buildArticleZip(page, request, exportOptions, userSession, resolver, this.i18n);
            String name = DPSUtil.getZipName(page, exportOptions);
            DPSUtil.sendZip(userSession, response, zipPath, name);
            this.cleanupZips(userSession, zipPath);
            userSession.save();
        }
        catch (Exception e) {
            throw new WCMException((Throwable)e);
        }
    }

    @Override
    public void export(Page page, Session userSession, OutputStream outStream, ExportOptions exportOptions) throws WCMException {
        Object resolver = null;
        try {
            HashMap<String, Session> authInfo = new HashMap<String, Session>();
            authInfo.put("user.jcr.session", userSession);
            ResourceResolver userResolver = this.resolverFactory.getResourceResolver(authInfo);
            String zipPath = this.buildArticleZip(page, null, exportOptions, userSession, userResolver, null);
            DPSUtil.writeNodeToStream(userSession, outStream, zipPath);
            this.cleanupZips(userSession, zipPath);
            userSession.save();
        }
        catch (Exception e) {
            throw new WCMException((Throwable)e);
        }
    }

    private String buildArticleZip(Page page, SlingHttpServletRequest request, ExportOptions exportOptions, Session userSession, ResourceResolver userResolver, I18n i18n) throws Exception {
        String configPath = this.getConfigPath(page.getPath());
        this.createConfig(page, configPath, userSession, exportOptions);
        if (request != null) {
            this.updatePageParams(userSession, request, configPath);
        }
        Resource config = userResolver.getResource(configPath);
        String zipPath = this.contentSyncManager.getZip(config, null, userSession);
        this.cleanupNodeAtPath(userSession, configPath);
        this.cleanupNodeAtPath(userSession, this.getCachePath(configPath, zipPath));
        return zipPath;
    }

    private String getConfigPath(String pagePath) {
        return "/var/contentsync/tmp/dpsexport" + pagePath + System.currentTimeMillis();
    }

    private void updatePageParams(Session session, SlingHttpServletRequest request, String configPath) throws RepositoryException {
        if (session.nodeExists(configPath + "/page")) {
            Node paramNode = JcrUtil.createPath((String)(configPath + "/page/parameters"), (String)"nt:unstructured", (Session)session);
            for (Object param : request.getParameterMap().keySet()) {
                String[] values = request.getParameterValues((String)param);
                if (values.length == 1) {
                    paramNode.setProperty((String)param, values);
                    continue;
                }
                if (values.length <= 1) continue;
                paramNode.setProperty((String)param, values);
            }
            session.save();
        } else {
            log.warn("Config node not found: 'page'. Any request parameters passed will be ignored. ");
        }
    }

    protected void createConfig(Page page, String configPath, Session userSession, ExportOptions exportOptions) throws RepositoryException, IOException, DPSException {
        String designPath = this.getDesignPath(userSession, page);
        Node configNode = this.createConfigNode(configPath, userSession);
        String templatePathRoot = this.findConfigTemplate(page);
        if (templatePathRoot == null) {
            String message = this.i18n != null ? this.i18n.get("Export template not found for {0}", "path to page", new Object[]{page.getPath()}) : this.i18n.get("Export template not found for " + page.getPath());
            throw new DPSException(message);
        }
        String templatePath = this.findConfigTemplate(templatePathRoot, exportOptions.getExportMode());
        log.debug("Content sync configuration template selected: {}, exporting using {}", (Object)templatePathRoot, (Object)templatePath);
        Node templateNode = userSession.getNode(templatePath);
        NodeIterator nodes = templateNode.getNodes();
        while (nodes.hasNext()) {
            Node n = nodes.nextNode();
            JcrUtil.copy((Node)n, (Node)configNode, (String)n.getName(), (boolean)true);
        }
        NodeIterator configNodes = configNode.getNodes();
        while (configNodes.hasNext()) {
            String pathAfter;
            Node n = configNodes.nextNode();
            if (!n.hasProperty("path")) continue;
            String path = n.getProperty("path").getString();
            if (path.equals("{page.path}")) {
                n.setProperty("path", page.getPath());
            } else if (path.equals("{design.path}")) {
                n.setProperty("path", designPath);
            }
            if (path.equals(pathAfter = n.getProperty("path").getString())) continue;
            log.debug("Path injected. Replacing {} with {}", (Object)path, (Object)pathAfter);
        }
        userSession.save();
    }

    private Node createConfigNode(String configPath, Session userSession) throws RepositoryException {
        Node configNode = JcrUtil.createPath((String)configPath, (String)"sling:Folder", (String)"cq:ContentSyncConfig", (Session)userSession, (boolean)false);
        configNode.setProperty("cache", false);
        configNode.setProperty("authorizable", userSession.getUserID());
        log.debug("Created config node " + configNode.getPath());
        return configNode;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private String getDesignPath(Session userSession, Page page) {
        String designPath = null;
        ResourceResolver userResolver = null;
        try {
            HashMap<String, Session> authInfo = new HashMap<String, Session>();
            authInfo.put("user.jcr.session", userSession);
            userResolver = this.resolverFactory.getResourceResolver(authInfo);
            Designer designer = (Designer)userResolver.adaptTo(Designer.class);
            designPath = designer.getDesignPath(page);
        }
        catch (LoginException ex) {
            log.error("failed to adapt user session to ResourceResolver", (Throwable)ex);
        }
        finally {
            if (userResolver != null) {
                userResolver.close();
            }
        }
        return designPath;
    }

    private String findConfigTemplate(String templateRootPath, ExportOptions.ExportMode exportMode) {
        String modeTemplate = "dps-article";
        if (exportMode == ExportOptions.ExportMode.EXPORT_RESOURCES) {
            modeTemplate = "dps-HTMLResources";
        } else if (exportMode == ExportOptions.ExportMode.EXPORT_ARTICLE) {
            modeTemplate = "dps-article";
        }
        return templateRootPath + "/" + modeTemplate;
    }

    protected void cleanupZips(Session session, String zipPath) throws RepositoryException {
        String pathToDelete = zipPath;
        try {
            String parentPath;
            if (zipPath.endsWith(".zip") && (parentPath = session.getNode(zipPath).getParent().getPath()).endsWith("-zips")) {
                pathToDelete = parentPath;
            }
        }
        catch (Exception ex) {
            log.warn("Failed to find parent CS zip folder for cleanup given zip path " + zipPath);
        }
        this.cleanupNodeAtPath(session, pathToDelete);
    }

    protected void cleanupNodeAtPath(Session session, String path) throws RepositoryException {
        log.debug("Cleaning up {}", (Object)path);
        if (session.nodeExists(path)) {
            session.getNode(path).remove();
        } else {
            log.debug("Node not found to cleanup {}", (Object)path);
        }
    }

    protected String findConfigTemplate(Page page) throws RepositoryException {
        DPSObject dpsObject = DPSUtil.getDPSObject(page);
        DPSProject dpsProject = DPSUtil.getDPSProject(dpsObject);
        Page dpsProjectPage = (Page)dpsProject.adaptTo(Page.class);
        String templatePath = (String)dpsProjectPage.getProperties().get("dps-exportTemplate", String.class);
        return templatePath;
    }

    protected String getCachePath(String configPath, String zipPath) {
        String cachePath = "/var/contentsync" + configPath;
        int index = zipPath.indexOf("-zips");
        if (index > 0) {
            cachePath = zipPath.substring(0, index);
        }
        return cachePath;
    }

    protected void bindXssAPI(XSSAPI xSSAPI) {
        this.xssAPI = xSSAPI;
    }

    protected void unbindXssAPI(XSSAPI xSSAPI) {
        if (this.xssAPI == xSSAPI) {
            this.xssAPI = null;
        }
    }

    protected void bindContentSyncManager(ContentSyncManager contentSyncManager) {
        this.contentSyncManager = contentSyncManager;
    }

    protected void unbindContentSyncManager(ContentSyncManager contentSyncManager) {
        if (this.contentSyncManager == contentSyncManager) {
            this.contentSyncManager = null;
        }
    }

    protected void bindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        this.resolverFactory = resourceResolverFactory;
    }

    protected void unbindResolverFactory(ResourceResolverFactory resourceResolverFactory) {
        if (this.resolverFactory == resourceResolverFactory) {
            this.resolverFactory = null;
        }
    }
}