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

com.adobe.cq.social.commons.comments.endpoints.UploadOperationUtils Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2015 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/
package com.adobe.cq.social.commons.comments.endpoints;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool.impl.GenericKeyedObjectPool.Config;
import org.apache.jackrabbit.commons.JcrUtils;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.social.commons.comments.api.Comment;
import com.adobe.cq.social.scf.ClientUtilities;
import com.adobe.cq.social.ugcbase.SocialUtils;
import com.day.cq.commons.Externalizer;
import com.day.image.Layer;
import com.day.text.Text;

public class UploadOperationUtils {
    private static String UGC_ROOT_DIR = "/content/usergenerated";
    private static String TEMP_ROOT_DIR = "tmp";
    private static String SOCIAL_DIR = "social";
    private static String SKIP_DIRS[] = {"jcr:content"};
    private static String IMAGES_DIR = "images";
    private static String TEMP_DIR = UGC_ROOT_DIR + "/" + TEMP_ROOT_DIR + "/" + SOCIAL_DIR + "/" + IMAGES_DIR;
    private static final Logger LOG = LoggerFactory.getLogger(UploadOperationUtils.class);

    private static final Pattern IMG_SRC_PATTERN = Pattern.compile("(]*?src=\")(.+?)(\"[^<>]*?>)");
    private static final Pattern IMG_WIDTH_PATTERN = Pattern.compile("(]*?width=\")(.+?)(\"[^<>]*?>)");
    private static final Pattern IMG_HEIGHT_PATTERN = Pattern.compile("(]*?height=\")(.+?)(\"[^<>]*?>)");

    private static final String THUMBNAIL_PREFIX = "rendition_";

    private static final String ACTUAL_IMAGE_PREFIX = "original_";

    private static class ThumbnailConfig {
        private  int width;
        private  int height;
        private  boolean doCenter;

        public ThumbnailConfig(int width, int height, boolean doCenter) {
            super();
            this.width = width;
            this.height = height;
            this.doCenter = doCenter;
        }
        public void setWidth(int width) {
            this.width = width;
        }
        public void setHeight(int height) {
            this.height = height;
        }
        public int getWidth() {
            return width;
        }
        public int getHeight() {
            return height;
        }
        public boolean doCenter() {
            return doCenter;
        }
    }

    public static Node addAttachment(final Node root, final String name, final InputStream inputStream,
        final String mimeType) throws RepositoryException {
        /*
         * if (!socialUtils.checkPermission(resource.getResourceResolver(), resource.getPath(),
         * Session.ACTION_ADD_NODE)) { throw new
         * CommentException(String.format("Not allowed to add an attachment to the comment: %s", resource.getPath()));
         * }
         */
        // Some browsers supply full path
        final String fileName = FilenameUtils.getName(name);
        Node attachmentNode;
        Node contentNode;
        if (root.hasNode(fileName)) {
            attachmentNode = root.getNode(fileName);
            contentNode = attachmentNode.getNode("jcr:content");
        } else {
            attachmentNode = root.addNode(fileName, "nt:file");
            contentNode = attachmentNode.addNode("jcr:content", "nt:resource");
        }
        contentNode.setProperty("jcr:mimeType", mimeType);
        contentNode.setProperty("jcr:data", inputStream);
        contentNode.setProperty("jcr:lastModified", Calendar.getInstance());

        return attachmentNode;
    }

    public static Node createOrGetUploadResource(final Session session, final String path)
        throws PathNotFoundException, RepositoryException {
        final Node ugc = session.getNode(UGC_ROOT_DIR);
        if (ugc != null) {
            final Node tmp = JcrUtils.getOrAddFolder(ugc, TEMP_ROOT_DIR);
            final String folders[] = path.split("/");
            Node parent = JcrUtils.getOrAddFolder(tmp, SOCIAL_DIR);
            parent = JcrUtils.getOrAddFolder(parent, IMAGES_DIR);
            for (int i = path.startsWith("/") ? 0 : 1; i < folders.length; i++) {
                if (!skipFolder(folders[i])) {
                    parent = JcrUtils.getOrAddFolder(parent, folders[i]);
                }
            }
            return parent;
        } else {
            return null;
        }
    }

    public static void moveImages(final Externalizer externalizer, final boolean author,
        final SocialUtils socialUtils, final Comment comment) throws PersistenceException {
        moveImages(null, externalizer, author, socialUtils, comment);
    }

    public static void moveImages(final String contextPath, final Externalizer externalizer, final boolean author,
        final SocialUtils socialUtils, final Comment comment) throws PersistenceException {
        String message = comment.getMessage();

        final Resource resource = comment.getResource();
        final com.adobe.cq.social.commons.Comment ocomment =
            resource.adaptTo(com.adobe.cq.social.commons.Comment.class);
        final ResourceResolver resolver = comment.getResource().getResourceResolver();

        boolean updated = false;
        Matcher imgMatcher = IMG_SRC_PATTERN.matcher(message);
        StringBuffer updatedMessage = new StringBuffer();
        while (imgMatcher.find()) {
            String startTag = imgMatcher.group(1);
            String imgUrl = imgMatcher.group(2);
            String endTag = imgMatcher.group(3);

            String externalUrl = null;
            if (imgUrl.startsWith(TEMP_DIR)) {
                final String name = FilenameUtils.getName(imgUrl);
                Resource imgResource = resolver.getResource(imgUrl);
                if (imgResource != null && imgResource.hasChildren()) {
                    imgResource = imgResource.getChild("jcr:content");
                }
                if (imgResource != null) {
                    final InputStream inputStream = imgResource.adaptTo(InputStream.class);
                    final ValueMap valueMap = imgResource.adaptTo(ValueMap.class);
                    final String mimeType = valueMap.get("jcr:mimeType", String.class);
                    final Resource image = ocomment.addImage(name, inputStream, mimeType);
                    externalUrl = externalizeLink(contextPath, externalizer, author, resolver, image.getPath());
                }
            }
            if (externalUrl != null) {
                imgMatcher.appendReplacement(updatedMessage, Matcher.quoteReplacement(startTag + externalUrl + endTag));
                updated = true;
            }
        }
        imgMatcher.appendTail(updatedMessage);
        if (updated) {
            final ModifiableValueMap mvm = resource.adaptTo(ModifiableValueMap.class);
            mvm.put("jcr:description", updatedMessage.toString());
            resolver.commit();
        }
    }

    public static void moveImages(final ClientUtilities clientUtils, final Comment comment,
        final ResourceResolver serviceUserResolver) throws PersistenceException {
        moveImages(clientUtils, comment, serviceUserResolver, null);
    }

    public static void moveImages(final ClientUtilities clientUtils, final Comment comment,
        final ResourceResolver serviceUserResolver, final String contextPath) throws PersistenceException {
        String message = comment.getMessage();
        final String commentPath = comment.getResource().getPath();
        final Resource resource = serviceUserResolver.getResource(commentPath);
        final com.adobe.cq.social.commons.Comment ocomment =
                resource.adaptTo(com.adobe.cq.social.commons.Comment.class);
        int thumbNailSize = comment.getConfiguration().getThumbNailSize();

        boolean updated = false;
        final Set deletedResources = new HashSet();
        Matcher imgMatcher = IMG_SRC_PATTERN.matcher(message);
        Matcher heightMatcher = null;
        Matcher widthMatcher = null;
        StringBuffer updatedMessage = new StringBuffer();
        while (imgMatcher.find()) {
            heightMatcher = IMG_HEIGHT_PATTERN.matcher(imgMatcher.group());
            widthMatcher =  IMG_WIDTH_PATTERN.matcher(imgMatcher.group());
            String startTag = getStartTag(imgMatcher);
            String imgUrl = getImgUrl(imgMatcher);
            String endTag = getEndTag(imgMatcher);
            ThumbnailConfig  config = new ThumbnailConfig(thumbNailSize,thumbNailSize,false);
            int imageHeight = getImageAttributeValue(heightMatcher);
            int imageWidth  = getImageAttributeValue(widthMatcher);
            if(imageWidth < config.getWidth() && imageHeight < config.getHeight()) {
                config.setHeight(imageHeight);
                config.setWidth(imageWidth);
            }
            imgUrl = Text.unescape(imgUrl);
            String externalUrl = null;
            String renditionUrl =null;
            if (imgUrl.startsWith(contextPath)) {
                imgUrl = imgUrl.substring(contextPath.length());
            }
            String imageName = FilenameUtils.getName(imgUrl);
            if (imgUrl.startsWith(TEMP_DIR)) {
                Resource imgResource = serviceUserResolver.getResource(imgUrl);
                Resource targetResource = imgResource;
                if (imgResource != null && imgResource.hasChildren()) {
                    targetResource = imgResource.getChild("jcr:content");
                }
                final InputStream inputStream = targetResource.adaptTo(InputStream.class);
                final ValueMap valueMap = targetResource.adaptTo(ValueMap.class);
                final String mimeType = valueMap.get("jcr:mimeType", String.class);
                final Resource imageSource= ocomment.addImage(ACTUAL_IMAGE_PREFIX + imageName, inputStream, mimeType);
                if (imageSource != null) {
                    deletedResources.add(imgResource.getPath());
                    externalUrl = encode(StringUtils.isBlank(contextPath) ? imageSource.getPath() : contextPath
                            + imageSource.getPath(), clientUtils);
                }
                // Upload rendition Image
                InputStream targetInputStream = targetResource.adaptTo(InputStream.class);
                InputStream renditionInputStream = generateRenditionImage(targetInputStream, mimeType, config);
                if(renditionInputStream!=null) {
                    final Resource rendImageSource= ocomment.addImage(THUMBNAIL_PREFIX + imageName, renditionInputStream, mimeType);
                    if (rendImageSource != null) {
                        renditionUrl = encode(StringUtils.isBlank(contextPath) ? rendImageSource.getPath() : contextPath
                                + rendImageSource.getPath(), clientUtils);
                    }
                }
            }else{
                Resource imgResource = serviceUserResolver.getResource(imgUrl);
                if(imgResource!=null){
                    final ValueMap valueMap = imgResource.adaptTo(ValueMap.class);
                    final String mimeType = valueMap.get("mimetype", String.class);
                    InputStream imgResourceInputStream = imgResource.adaptTo(InputStream.class);
                    InputStream renditionInputStream = generateRenditionImage(imgResourceInputStream, mimeType, config);
                    final Resource rendImageSource= ocomment.addImage(THUMBNAIL_PREFIX + imageName, renditionInputStream, mimeType);
                    if (rendImageSource != null) {
                        externalUrl = encode(StringUtils.isBlank(contextPath) ? imgResource.getPath() : contextPath
                                + imgResource.getPath(), clientUtils);
                        renditionUrl = encode(StringUtils.isBlank(contextPath) ? rendImageSource.getPath() : contextPath
                                + rendImageSource.getPath(), clientUtils);
                    }
                }
            }
            if (externalUrl!=null) {
                if(renditionUrl !=null ) {
                    // Create a thumbnail tag
                    String resultUrl = createThumbnailURL(imgMatcher, imageWidth, imageHeight, config, externalUrl, renditionUrl);
                    imgMatcher.appendReplacement(updatedMessage, Matcher.quoteReplacement(resultUrl));
                }
                else {
                    imgMatcher.appendReplacement(updatedMessage, Matcher.quoteReplacement(startTag + externalUrl + endTag));
                }
                updated = true;
            }
        }
        imgMatcher.appendTail(updatedMessage);
        if (updated) {
            final ModifiableValueMap mvm = resource.adaptTo(ModifiableValueMap.class);
            mvm.put("jcr:description", updatedMessage.toString());
            for (String deletedResourcePath : deletedResources) {
                Resource resourceToDelete = serviceUserResolver.getResource(deletedResourcePath);
                serviceUserResolver.delete(resourceToDelete);
            }
            serviceUserResolver.commit();
        }

    }

    public static InputStream generateAttachmentRenditionImage(final InputStream inputStream, String thumbnailMimeType ,int thumbnailSize){
        ThumbnailConfig thumbnailConfig  = new ThumbnailConfig(thumbnailSize, thumbnailSize, false);
        InputStream thumbnailStream = generateRenditionImage(inputStream, thumbnailMimeType , thumbnailConfig);
        return thumbnailStream;
    }

    private static String getStartTag(Matcher imgMatcher){
        String startTag = imgMatcher.group(1);
        return startTag;
    }

    private static String getImgUrl(Matcher imgMatcher){
        String endTag = imgMatcher.group(2);
        return endTag;
    }

    private static String getEndTag(Matcher imgMatcher){
        String endTag = imgMatcher.group(3);
        return endTag;
    }

    private static String createThumbnailURL(Matcher imgMatcher, int imageWidth, int imageHeight, ThumbnailConfig config, String externalUrl, String renditionUrl) {
        String startTag = getStartTag(imgMatcher);
        String endTag = getEndTag(imgMatcher);
        String aTagOpen = "";
        String imgTag = startTag + renditionUrl + endTag;
        String aTagClose ="";
        String resultUrl = aTagOpen+imgTag+aTagClose;
        resultUrl = resultUrl.replaceAll("height=\""+imageHeight +"\"", "height=\""+config.getHeight() +"\"");
        resultUrl = resultUrl.replaceAll("width=\""+imageWidth +"\"", "width=\""+config.getWidth() +"\"");
        return resultUrl;
    }

    private static int getImageAttributeValue(Matcher matcher) {
        int result = Integer.MAX_VALUE;
        if(matcher.find()){
            String attributeValue = matcher.group(2);
            if(StringUtils.isNumeric(attributeValue)){
                result = Integer.parseInt(attributeValue);
            }
        }
        return result;
    }

    private static InputStream generateRenditionImage(final InputStream inputStream, String thumbnailMimeType, ThumbnailConfig config) {

        BufferedImage image =null;
        try {
            image = ImageIO.read(inputStream);
        } catch (Exception e) {
            LOG.error("Error in creating image from inpustream ",e.getStackTrace());
            IOUtils.closeQuietly(inputStream);
            return null;
        }
        Layer layer = new Layer(image);
        Layer tLayer = createThumb(layer,config);
        config.setHeight(layer.getHeight());
        config.setWidth(layer.getWidth());
        OutputStream out = null;
        InputStream in = null;
        try {
            File tmpFile = File.createTempFile("thumbnail", ".tmp");
            out = FileUtils.openOutputStream(tmpFile);
            tLayer.write(thumbnailMimeType, 0.8, out);
            in = FileUtils.openInputStream(tmpFile);
        } catch (Exception e) {
            LOG.error("Error in writing thumbnail image",e.getStackTrace());
            IOUtils.closeQuietly(in);
        } finally {
            IOUtils.closeQuietly(out);
        }
        // if image was centered, create a new layer for further processing
        if (tLayer != layer) {
            tLayer.dispose();
        }
        return in;
    }

    private static Layer createThumb(Layer layer, ThumbnailConfig config) {
        Layer finalLayer = null;
        final int maxWidth = config.getWidth();
        final int maxHeight = config.getHeight();
        final boolean doCenter = config.doCenter();
        final int width = layer.getWidth();
        final int height = layer.getHeight();
        final Color bgColor = layer.getBackgroundColor();
        if (height > maxHeight || width > maxWidth) {
            // resize image
            int newWidth, newHeight;
            if (height > width) {
                newHeight = maxHeight;
                newWidth = (width * maxHeight / height);
                if (newWidth > maxWidth) {
                    newWidth = maxWidth;
                    newHeight = (height * maxWidth / width);
                }
            } else {
                newWidth = maxWidth;
                newHeight = (height * maxWidth / width);
                if (newHeight > maxHeight) {
                    newHeight = maxHeight;
                    newWidth = (width * maxHeight / height);
                }
            }
            layer.resize(newWidth, newHeight, true);
        }

        // merge and center image so that the "requested" height and width   are respected
        if ((layer.getHeight() < maxHeight || layer.getWidth() < maxWidth) && doCenter) {

            final Color bg = (null != bgColor) ? bgColor : Color.WHITE;
            finalLayer = new Layer(maxWidth, maxHeight, bg);
            finalLayer.setTransparency(bg);
            int y = (maxHeight - layer.getHeight()) / 2;
            int x = (maxWidth - layer.getWidth()) / 2;
            layer.setX(x);
            layer.setY(y);
            finalLayer.merge(layer);
            layer = finalLayer;
        }
        return layer;
    }


    private static String encode(final String str, final ClientUtilities clientUtils) {
        final String result = clientUtils.externalLink(str, false);
        // TODO: We can't really externalize the link since the clientUtils that the OperationExtension
        // doesn't have access to the HttpRequest..
        return Text.escapePath(str);
    }

    private static String replace(final String text, final String replacement, final int startIndex, final int length) {

        final int replLength = replacement.length();
        int increase = replacement.length() - length;
        increase = (increase < 0 ? 0 : increase);
        increase *= 16;
        StringBuilder buf = new StringBuilder(text.length() + increase);
        buf = buf.append(text, 0, startIndex + 1).append(replacement).append(text.substring(startIndex + length));

        return buf.toString();
    }

    private static String externalizeLink(final String contextPath, final Externalizer externalizer,
        final boolean author, final ResourceResolver resolver, final String url) {
        String externalUrl = (StringUtils.isBlank(contextPath)) ? url : contextPath + "/" + url;
        if (externalizer != null) {
            if (author) {
                externalUrl = externalizer.authorLink(resolver, externalUrl);
            } else {
                externalUrl = externalizer.publishLink(resolver, externalUrl);
            }
        }
        return getRootBasedURL(url);
    }

    private static String getRootBasedURL(final String url) {
        try {
            final URL startURL = new URL(url);
            final String HOST_CHECK_HEADER = "origin";
            // Only mess with stuff if it's http[s]
            if (StringUtils.startsWithIgnoreCase(startURL.getProtocol(), "http")) {
                return StringUtils.removeStart(url.toString(), startURL.getProtocol() + "://" + startURL.getHost()
                        + ((startURL.getPort() == -1) ? "" : ":" + startURL.getPort()));

            }
        } catch (final MalformedURLException e) {
            // Not sure if we can even get here because that means the externalizer generated a link without http?
        }
        return url;
    }

    private static boolean skipFolder(final String name) {
        for (int i = 0; i < SKIP_DIRS.length; i++) {
            if (name.equals(SKIP_DIRS[i])) {
                return true;
            }
        }
        return false;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy