All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.cq.contentsync.handler.AbstractSlingResourceUpdateHandler Maven / Gradle / Ivy

There is a newer version: 2024.11.18751.20241128T090041Z-241100
Show newest version
/*
 * Copyright 1997-2011 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.cq.contentsync.handler;

import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.commons.jcr.JcrUtil;
import com.day.cq.contentsync.handler.util.RequestResponseFactory;
import com.day.cq.contentsync.impl.handler.util.RequestResponseFactoryImpl;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.engine.SlingRequestProcessor;
import org.apache.sling.jcr.resource.JcrResourceConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.Collections;
import org.apache.commons.io.output.DeferredFileOutputStream;

/**
 * The {@code AbstractSlingResourceUpdateHandler} is an abstract base class
 * for cache update handlers that would like to use the Sling request processing.
 */
@Component(metatype = false, componentAbstract = true)
public abstract class AbstractSlingResourceUpdateHandler extends AbstractDefaultContentUpdateHandler implements ContentUpdateHandler {

    private static final Logger log = LoggerFactory.getLogger(AbstractSlingResourceUpdateHandler.class);

    @Reference
    protected SlingRequestProcessor slingServlet;

    @Reference
    protected ResourceResolverFactory resourceResolverFactory;

    @Reference
    protected RequestResponseFactory requestResponseFactory;

    /**
     * This method renders the given request URI using the Sling request processing
     * and stores the result at the request's location relative to the cache root
     * folder. The request is processed in the context of the given user's session.
     *
     * @param uri             The request URI including selectors and extensions
     * @param configCacheRoot The cache root folder
     * @param admin           The admin session used to store the result in the cache
     * @param session         The user's session
     * @return {@code true} if the cache was updated
     * @throws IOException         if an I/O error occurrs.
     * @throws RepositoryException if an error accessing the repository occurrs.
     * @throws ServletException    if a generic servlet error occurrs.
     * @throws NoSuchAlgorithmException
     */
    protected boolean renderResource(String uri, String configCacheRoot, Session admin, Session session) throws RepositoryException, ServletException, IOException, NoSuchAlgorithmException {
        String cachePath = configCacheRoot + getTargetPath(uri);
        DeferredFileOutputStream out = new DeferredFileOutputStream(1024 * 64, "content-sync", ".tmp", null);
        boolean isHashMatched = false;

        try {
            ResourceResolver resolver = resourceResolverFactory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object) session));

            // render resource
            HttpServletRequest request = createRequest(uri);
            HttpServletResponse response = ((RequestResponseFactoryImpl) requestResponseFactory).createBufferedResponse(out);

            slingServlet.processRequest(request, response, resolver);
            response.getWriter().flush();

            InputStream inputStream = null;
            String hash;
            try {
                if (out.isInMemory()) {
                    // Data is in memory, create ByteArrayInputStream from the byte array
                    inputStream = new ByteArrayInputStream(out.getData());
                } else {
                    // Data spilled to a temporary file, create FileInputStream from the file
                    inputStream = new FileInputStream(out.getFile());
                }
                hash = DigestUtils.sha256Hex(inputStream);

            } finally {
                IOUtils.closeQuietly(inputStream);
            }

            isHashMatched = hashMatches(session, cachePath, hash);

            if (!isHashMatched) {
                log.debug("Hash missing or not equal, updating content sync cache: {}", cachePath);

                JcrUtil.createPath(cachePath, JcrResourceConstants.NT_SLING_FOLDER, JcrConstants.NT_FILE, admin, false);

                Node cacheContentNode = JcrUtil.createPath(cachePath + "/" + JcrConstants.JCR_CONTENT, JcrConstants.NT_RESOURCE, admin);
                if(out.isInMemory()){
                    cacheContentNode.setProperty(JcrConstants.JCR_DATA, admin.getValueFactory().createBinary(new ByteArrayInputStream(out.getData())));
                }
                else {
                    cacheContentNode.setProperty(JcrConstants.JCR_DATA, admin.getValueFactory().createBinary(new FileInputStream(out.getFile())));
                }
                cacheContentNode.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance());
                if (response.getContentType() != null) {
                    cacheContentNode.setProperty(JcrConstants.JCR_MIMETYPE, response.getContentType());
                }
                if (response.getCharacterEncoding() != null) {
                    cacheContentNode.setProperty(JcrConstants.JCR_ENCODING, response.getCharacterEncoding());
                }

                writeHash(cacheContentNode, hash);

                admin.save();

                return true;
            } else {
                log.debug("Skipping update of content sync cache: {}", uri);

                return false;
            }
        } catch (LoginException e) {
            log.error("Creating resource resolver for resource rendering failed: ", e);
            return false;
        } finally {
            IOUtils.closeQuietly(out);
            if (!isHashMatched && admin.hasPendingChanges()) {
                admin.refresh(false);
            }
        }
    }


    /**
     * Creates a GET request for the given uri. This method can
     * be overridden to provide a customized request object,
     * e.g. with added parameters.
     *
     * @param uri The uri
     * @return The request object
     * @see com.day.cq.contentsync.handler.util.RequestResponseFactory
     */
    protected HttpServletRequest createRequest(String uri) {
        return requestResponseFactory.createRequest("GET", uri);
    }

    /**
     * Returns the target path of a rendered resource relative
     * to the cache root. This method can be overridden to
     * adjust the output path in the zip file. The default
     * implementation simply returns the input path.
     *
     * @param path The initial path
     * @return The adjusted path
     */
    protected String getTargetPath(String path) {
        return path;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy