ProjectBaseImageServlet.java 14.6 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.day.cq.dam.api.Asset
 *  com.day.cq.wcm.api.designer.Style
 *  com.day.cq.wcm.commons.AbstractImageServlet
 *  com.day.cq.wcm.commons.AbstractImageServlet$ImageContext
 *  com.day.cq.wcm.commons.RequestHelper
 *  com.day.cq.wcm.foundation.AdaptiveImageHelper
 *  com.day.cq.wcm.foundation.AdaptiveImageHelper$Quality
 *  com.day.cq.wcm.foundation.Image
 *  com.day.image.Layer
 *  javax.jcr.Binary
 *  javax.jcr.Node
 *  javax.jcr.Property
 *  javax.jcr.RepositoryException
 *  javax.jcr.Session
 *  javax.jcr.ValueFactory
 *  javax.jcr.nodetype.NodeType
 *  javax.servlet.http.HttpServletRequest
 *  javax.servlet.http.HttpServletResponse
 *  org.apache.commons.io.IOUtils
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.SlingHttpServletResponse
 *  org.apache.sling.api.request.RequestPathInfo
 *  org.apache.sling.api.resource.PersistenceException
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.cq.projects.impl.servlet.image;

import com.day.cq.dam.api.Asset;
import com.day.cq.wcm.api.designer.Style;
import com.day.cq.wcm.commons.AbstractImageServlet;
import com.day.cq.wcm.commons.RequestHelper;
import com.day.cq.wcm.foundation.AdaptiveImageHelper;
import com.day.cq.wcm.foundation.Image;
import com.day.image.Layer;
import java.awt.Color;
import java.awt.Dimension;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.ValueFactory;
import javax.jcr.nodetype.NodeType;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestPathInfo;
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.commons.osgi.PropertiesUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=1, label="Adobe CQ Projects Image Base Service", description="Render the image associated with a project in a variety of dimensions and qualities")
@Service
public abstract class ProjectBaseImageServlet
extends AbstractImageServlet {
    @org.apache.felix.scr.annotations.Property(label="Image Quality", description="Quality must be a double between 0.0 and 1.0", value={"0.82"})
    private static final String PROPERTY_IMAGE_QUALITY = "image.quality";
    @org.apache.felix.scr.annotations.Property(value={"319x319"}, label="Supported Resolutions", description="List of resolutions this servlet will respect.")
    private static final String PROPERTY_SUPPORTED_RESOLUTIONS = "image.supported.resolutions";
    private static final Logger log = LoggerFactory.getLogger(ProjectBaseImageServlet.class);
    protected static final String WIDTH = "width";
    protected static final String HEIGHT = "height";
    protected static final String MIMETYPE = "image/png";
    protected static final String BGCOLOR = "bgcolor";
    private double imageQualityFromOsgiConfig;
    private List<Dimension> supportedDimensions;
    private String name;

    public ProjectBaseImageServlet(String name) {
        this.name = name;
        this.supportedDimensions = new ArrayList<Dimension>();
    }

    protected abstract Resource getResource(Resource var1);

    protected abstract Layer createLayer(AbstractImageServlet.ImageContext var1) throws RepositoryException, IOException;

    protected Resource getPreviewResource(Resource resource) {
        return resource.getChild("jcr:content/" + this.getThumbnailName());
    }

    protected Resource createPreviewResource(Resource resource) throws ProjectImageException {
        Node node = (Node)resource.adaptTo(Node.class);
        try {
            Resource thumbnailRes;
            Resource contentRes = resource.getChild("jcr:content");
            if (contentRes == null) {
                if (!node.getPrimaryNodeType().canAddChildNode("jcr:content", "nt:unstructured")) {
                    return null;
                }
                contentRes = this.createChildNode(resource, "jcr:content", "nt:unstructured");
            }
            if ((thumbnailRes = contentRes.getChild(this.getThumbnailName())) == null) {
                thumbnailRes = this.createFolderThumbnailContent(contentRes);
            }
            return thumbnailRes;
        }
        catch (RepositoryException re) {
            log.debug("unable to create preview resource ", (Throwable)re);
            log.warn("unable to create preview resource " + re.getMessage());
        }
        catch (PersistenceException e) {
            throw new ProjectImageException("Unable to create the preview resource", (Throwable)e);
        }
        return null;
    }

    protected Resource createFolderThumbnailContent(Resource resource) throws PersistenceException {
        Resource folderThumbnail = this.createChildNode(resource, this.getThumbnailName(), "nt:file");
        this.createChildNode(folderThumbnail, "jcr:content", "nt:unstructured");
        return folderThumbnail;
    }

    protected String getThumbnailName() {
        return this.name + "Thumbnail";
    }

    private Resource createChildNode(Resource parent, String name, String type) throws PersistenceException {
        return parent.getResourceResolver().create(parent, name, Collections.singletonMap("jcr:primaryType", type));
    }

    protected void savePreview(Layer layer, Resource resource) throws Exception {
        Resource previewResource = this.getPreviewResource(resource);
        if (previewResource == null) {
            previewResource = this.createPreviewResource(resource);
        }
        if (previewResource == null) {
            log.debug("failed to create preview resource");
            return;
        }
        this.saveThumbnail(layer, previewResource, resource);
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void saveThumbnail(Layer layer, Resource previewResource, Resource resource) throws Exception {
        Node node = (Node)previewResource.adaptTo(Node.class);
        FileOutputStream itout = null;
        File imageTmpFile = null;
        FileInputStream is = null;
        try {
            imageTmpFile = File.createTempFile("image", ".tmp");
            itout = new FileOutputStream(imageTmpFile);
            layer.write("image/png", 1.0, (OutputStream)itout);
            is = new FileInputStream(imageTmpFile);
            if (!node.hasNode("jcr:content")) {
                log.debug("Unable to write thumbnail " + node.getPath());
                return;
            }
            Node folderThumbnailContent = node.getNode("jcr:content");
            folderThumbnailContent.setProperty("jcr:data", node.getSession().getValueFactory().createBinary((InputStream)is));
            folderThumbnailContent.setProperty("width", (long)layer.getWidth());
            folderThumbnailContent.setProperty("height", (long)layer.getHeight());
            folderThumbnailContent.setProperty("bgcolor", (long)layer.getBackgroundColor().getRGB());
            Calendar calendar = this.getLastModificationTime(this.getResource(resource));
            if (calendar != null) {
                folderThumbnailContent.setProperty("jcr:lastModified", calendar);
            }
            previewResource.getResourceResolver().commit();
        }
        catch (RepositoryException re) {
            log.debug("could not save thumbnail", (Throwable)re);
            log.warn("could not save thumbnail" + re.getMessage());
        }
        finally {
            IOUtils.closeQuietly((InputStream)is);
            IOUtils.closeQuietly((OutputStream)itout);
            if (imageTmpFile != null) {
                imageTmpFile.delete();
            }
        }
    }

    protected void writeLayer(SlingHttpServletRequest request, SlingHttpServletResponse response, AbstractImageServlet.ImageContext context, Layer layer) throws IOException, RepositoryException {
        double quality;
        String[] selectors = request.getRequestPathInfo().getSelectors();
        if (selectors.length == 4) {
            String imageQualitySelector = selectors[3];
            quality = this.getRequestedImageQuality(imageQualitySelector);
        } else {
            quality = this.getImageQualityFromOsgiConfig();
        }
        Resource previewImage = this.getPreviewResource(request.getResource());
        Calendar lastMod = this.getLastModificationTime(previewImage);
        response.setDateHeader("Last-Modified", lastMod.getTimeInMillis());
        this.writeLayer(request, response, context, layer, quality);
    }

    protected boolean checkModifiedSince(SlingHttpServletRequest req, SlingHttpServletResponse resp) {
        Resource previewResource = this.getResource(req.getResource());
        if (previewResource != null) {
            Resource thumbnail = previewResource.getChild("jcr:content");
            return RequestHelper.handleIfModifiedSince((HttpServletRequest)req, (HttpServletResponse)resp, (Node)((Node)thumbnail.adaptTo(Node.class)));
        }
        return false;
    }

    protected Calendar getLastModificationTime(Resource resource) {
        Calendar last = null;
        if (resource != null) {
            long lastModified = 0;
            try {
                if (resource.getResourceType().equals("dam:Asset")) {
                    Asset asset = (Asset)resource.adaptTo(Asset.class);
                    lastModified = asset.getLastModified();
                } else {
                    Node node = (Node)resource.adaptTo(Node.class);
                    Node content = node.getNode("jcr:content");
                    Property data = content.getProperty("jcr:lastModified");
                    lastModified = data != null ? data.getLong() : 0;
                }
            }
            catch (RepositoryException e) {
                lastModified = System.currentTimeMillis();
            }
            last = Calendar.getInstance();
            last.setTimeInMillis(lastModified);
        }
        return last;
    }

    protected String getImageType() {
        return "image/jpeg";
    }

    protected void activate(ComponentContext componentContext) {
        Dictionary properties = componentContext.getProperties();
        this.setImageQualityFromOsgiConfig(PropertiesUtil.toString(properties.get("image.quality"), (String)Double.toString(AdaptiveImageHelper.Quality.MEDIUM.getQualityValue())));
        String[] supportedResolutionsArray = PropertiesUtil.toStringArray(properties.get("image.supported.resolutions"));
        if (supportedResolutionsArray != null && supportedResolutionsArray.length > 0) {
            for (String resolution : supportedResolutionsArray) {
                String[] widthAndHeight = resolution.split("x");
                if (widthAndHeight.length != 2) continue;
                try {
                    int width = Integer.parseInt(widthAndHeight[0]);
                    int height = Integer.parseInt(widthAndHeight[1]);
                    this.supportedDimensions.add(new Dimension(width, height));
                    continue;
                }
                catch (NumberFormatException ex) {
                    // empty catch block
                }
            }
        }
    }

    protected boolean isDimensionSupported(int width, int height) {
        Iterator<Dimension> iterator = this.getSupportedDimensionsIterator();
        Dimension dimension = new Dimension(width, height);
        while (iterator.hasNext()) {
            if (!dimension.equals(iterator.next())) continue;
            return true;
        }
        return false;
    }

    protected Iterator<Dimension> getSupportedDimensionsIterator() {
        return this.supportedDimensions.iterator();
    }

    private double getRequestedImageQuality(String imageQualitySelector) {
        AdaptiveImageHelper.Quality newQuality = AdaptiveImageHelper.getQualityFromString((String)imageQualitySelector);
        if (newQuality != null) {
            return newQuality.getQualityValue();
        }
        return this.getImageQualityFromOsgiConfig();
    }

    private void setImageQualityFromOsgiConfig(String imageQuality) {
        double newQuality;
        try {
            newQuality = Double.parseDouble(imageQuality);
            if (newQuality > 1.0 || newQuality < 0.0) {
                newQuality = AdaptiveImageHelper.Quality.MEDIUM.getQualityValue();
            }
        }
        catch (NumberFormatException ex) {
            log.error("Could not set imageQuality to: [" + imageQuality + "] because it is not a double.");
            newQuality = AdaptiveImageHelper.Quality.MEDIUM.getQualityValue();
        }
        this.imageQualityFromOsgiConfig = newQuality;
    }

    private double getImageQualityFromOsgiConfig() {
        return this.imageQualityFromOsgiConfig;
    }

    protected boolean isInteger(String string) {
        try {
            Integer.parseInt(string);
        }
        catch (NumberFormatException e) {
            return false;
        }
        return true;
    }

    class ProjectImageException
    extends Exception {
        public ProjectImageException(String message, Throwable e) {
            super(message, e);
        }
    }

    class ProjectImageHelper
    extends AdaptiveImageHelper {
        private InputStream stream;

        public ProjectImageHelper(InputStream stream) {
            this.stream = stream;
        }

        public Layer applyStyleDataToImage(Image image, Style style) throws RepositoryException, IOException {
            Layer layer = new Layer(this.stream);
            image.loadStyleData(style);
            image.crop(layer);
            image.rotate(layer);
            return layer;
        }
    }

}