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: 6.5.21
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 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.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.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Collections;

/**
 * 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);

    /** Mixin node type for hash value */
    private final static String NT_MD5_HASH = "cq:ContentSyncHash";
    
    /** Hash property name */
    private final static String MD5_HASH_PROPERTY = "md5";
    
    @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.
     */
	protected boolean renderResource(String uri, String configCacheRoot, Session admin, Session session) throws RepositoryException, ServletException, IOException {
		String cachePath = configCacheRoot + getTargetPath(uri);
		try {
			ResourceResolver resolver = resourceResolverFactory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object) session));

            // render resource
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			HttpServletRequest request = createRequest(uri);
			HttpServletResponse response = requestResponseFactory.createResponse(out);
			
			slingServlet.processRequest(request, response, resolver);
			response.getWriter().flush();
	
			// compare md5 checksum with cache
			String md5 = requestResponseFactory.getMD5(response);
			String md5Path = cachePath + "/" + JcrConstants.JCR_CONTENT + "/" + MD5_HASH_PROPERTY;

			if(!admin.propertyExists(md5Path) || !admin.getProperty(md5Path).getString().equals(md5)) {
				log.debug("MD5 hash missing or not equal, updating content sync cache: {}", cachePath);

				JcrUtil.createPath(cachePath, "sling:Folder", "nt:file", admin, false);
				
				Node cacheContentNode = JcrUtil.createPath(cachePath + "/jcr:content", "nt:resource", admin);
	            if (needsUtf8Encoding(response)) {
	                String encoding = response.getCharacterEncoding();
					cacheContentNode.setProperty(JcrConstants.JCR_DATA, admin.getValueFactory().createBinary(IOUtils.toInputStream(out.toString(encoding),encoding)));
	            } else {
	                cacheContentNode.setProperty(JcrConstants.JCR_DATA, admin.getValueFactory().createBinary(new ByteArrayInputStream(out.toByteArray())));
	            }
	            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());
	            }
				
	            cacheContentNode.addMixin(NT_MD5_HASH);
				cacheContentNode.setProperty(MD5_HASH_PROPERTY, md5);
	
				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 {
    		if(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.
	 * @see com.day.cq.contentsync.handler.util.RequestResponseFactory 
	 * @param uri	The uri
	 * @return		The request object 
	 */
	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;
	}

    /**
     * Don't know if this check is correct...
     *
     * @param response the servlet response
     * @return {@code true} if needs utf8 encoding.
     */
    private boolean needsUtf8Encoding(HttpServletResponse response) {
        String contentType = response.getContentType();

        return contentType != null ? contentType.endsWith("/json") : false;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy