Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.day.cq.wcm.commons.AbstractImageServlet Maven / Gradle / Ivy
/*
* Copyright 1997-2008 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.wcm.commons;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Calendar;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import com.day.cq.commons.DiffInfo;
import com.day.cq.commons.DiffService;
import com.day.cq.commons.ImageResource;
import com.day.cq.commons.SlingRepositoryException;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.components.Component;
import com.day.cq.wcm.api.designer.Style;
import com.day.image.Layer;
/**
* Servers as base for image servlets
*/
public abstract class AbstractImageServlet extends SlingSafeMethodsServlet {
/**
* Handles a GET request and created the desired image.
* calls the following methods:
*
*
* {@link #checkModifiedSince(SlingHttpServletRequest, SlingHttpServletResponse)}
* {@link #createLayer(ImageContext)}
* {@link #writeLayer(SlingHttpServletRequest, SlingHttpServletResponse, ImageContext, Layer)}
*
*
* If the requested extension does not map to a known image type via
* {@link #getImageType(String)}, a 404 is responded.
*/
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response)
throws ServletException, IOException {
try {
if (checkModifiedSince(request, response)) {
return;
}
String type = getImageType(request.getRequestPathInfo().getExtension());
if (type == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, "Image type not supported");
return;
}
ImageContext context = new ImageContext(request, type);
Layer layer = createLayer(context);
if (layer != null) {
applyDiff(layer, context);
}
writeLayer(request, response, context, layer);
} catch (RepositoryException e) {
throw new SlingRepositoryException(e);
}
}
/**
* Writes the layer to the response.
*
* @param request servlet request
* @param response servlet response
* @param context the context
* @param layer layer
* @throws IOException if an I/O error occurs.
* @throws RepositoryException if an repository error occurs.
*/
protected void writeLayer(SlingHttpServletRequest request,
SlingHttpServletResponse response,
ImageContext context, Layer layer)
throws IOException, RepositoryException {
writeLayer(request, response, context, layer, getImageQuality());
}
/**
* Writes the layer to the response at the specified quality.
*
* @param request servlet request
* @param response servlet response
* @param context the context
* @param layer layer
* @param quality image quality
* @throws IOException if an I/O error occurs.
* @throws RepositoryException if an repository error occurs.
*/
protected void writeLayer(SlingHttpServletRequest request,
SlingHttpServletResponse response,
ImageContext context, Layer layer, double quality)
throws IOException, RepositoryException {
String imageType = getImageType();
if (context != null && context.requestImageType != null &&
context.requestImageType.startsWith("image/")) {
imageType = context.requestImageType;
}
response.setContentType(imageType);
if (layer == null) {
return;
}
// calculate size if not too big
int size = layer.getHeight() * layer.getWidth();
if (size < 1024*1024) {
// cache and spool
ByteArrayOutputStream out = new ByteArrayOutputStream(size);
layer.write(imageType, quality, out);
byte[] bytes = out.toByteArray();
response.setContentLength(bytes.length);
response.getOutputStream().write(bytes);
} else {
// write directly
layer.write(imageType, quality, response.getOutputStream());
}
}
/**
* Returns the image type. default "image/png"
* @return the image type.
*/
protected String getImageType() {
return "image/png";
}
/**
* Returns the image type for the given extension. currently there are only
* "png", "gif" and "jpg" supported, but an subclass can provide other
* mappings.
*
* @param ext the extension
* @return the image type or null
.
*/
protected String getImageType(String ext) {
if (ext != null) {
ext = ext.toLowerCase();
}
if ("png".equals(ext)) {
return "image/png";
} else if ("gif".equals(ext)) {
return "image/gif";
} else if ("jpg".equals(ext) || "jpeg".equals(ext)) {
return "image/jpeg";
} else {
return null;
}
}
/**
* Returns the image quality. default 1.0
* @return the image quality.
*/
protected double getImageQuality() {
return 1.0;
}
/**
* Checks if the request contains a if-last-modified-since header and if the
* node has a jcr:lastModified property. if the properties were modified
* before the header a 304 is sent otherwise the response last modified header
* is set. If the give doesn't have the property, the parent node is searched.
*
* @param req the request
* @param resp the response
* @return true
if the response was sent
*/
protected boolean checkModifiedSince(SlingHttpServletRequest req,
SlingHttpServletResponse resp) {
Resource resource = req.getResource();
Node node = resource.adaptTo(Node.class);
if (node != null) {
return RequestHelper.handleIfModifiedSince(req, resp, node);
}
ValueMap properties = resource.adaptTo(ValueMap.class);
if (properties != null) {
return RequestHelper.handleIfModifiedSince(req, resp, properties);
}
return false;
}
/**
* Creates the image layer.
*
* @param c the convenience context
* @return the layer
* @throws RepositoryException if an error occurs.
* @throws IOException if an I/O error occurs
*/
protected abstract Layer createLayer(ImageContext c)
throws RepositoryException, IOException;
/**
* Default behavior that applies diff information to the layer
* @param layer the layer
* @param c the context
* @return true
if the layer was modified.
*/
protected boolean applyDiff(Layer layer, ImageContext c) {
if (layer == null || c.diffInfo == null) {
return false;
}
if (isRemovedDiff(c)) {
layer.setPaint(Color.RED);
layer.setStroke(new BasicStroke(2));
layer.drawLine(0,0, layer.getWidth(), layer.getHeight());
layer.drawLine(layer.getWidth(), 0, 0 ,layer.getHeight());
return true;
} else if (isAddedDiff(c)) {
layer.setPaint(Color.GREEN);
layer.setStroke(new BasicStroke(3));
layer.drawRect(new Rectangle(layer.getWidth(), layer.getHeight()));
return true;
} else if (isModifiedDiff(c)) {
layer.setPaint(Color.RED);
layer.setStroke(new BasicStroke(3));
layer.drawRect(new Rectangle(layer.getWidth(), layer.getHeight()));
return true;
}
return false;
}
/**
* Creates an image resource based on the resource in the image context.
* Subclasses can override this to create extended variants of image
* resources.
*
* @param resource the resource
* @return the image resource
*/
protected ImageResource createImageResource(Resource resource) {
return new ImageResource(resource);
}
/**
* Calculates if the underlying image was modified in respect to the versioned
* diff.
*
* @param c the image context
* @return true
if modified
*/
protected boolean isModifiedDiff(ImageContext c) {
if (c.diffInfo == null || c.diffInfo.getContent() == null) {
return false;
}
ImageResource img0 = createImageResource(c.resource);
if (!img0.hasContent()) {
return false;
}
ImageResource img1 = createImageResource(c.diffInfo.getContent());
if (!img1.hasContent()) {
return false;
}
try {
Calendar c0 = img0.getLastModified();
Calendar c1 = img1.getLastModified();
if (!(c0 == c1 || c0 != null && c0.equals(c1))) {
return true;
}
} catch (RepositoryException e) {
// ignore
}
Rectangle r0 = img0.getCropRect();
Rectangle r1 = img1.getCropRect();
if (!(r0 == r1 || r0 != null && r0.equals(r1))) {
return true;
}
if (img0.getRotation() != img1.getRotation()) {
return true;
}
Dimension d0 = new Dimension(
img0.get(img0.getItemName(ImageResource.PN_WIDTH), 0),
img0.get(img0.getItemName(ImageResource.PN_HEIGHT), 0));
Dimension d1 = new Dimension(
img1.get(img1.getItemName(ImageResource.PN_WIDTH), 0),
img1.get(img1.getItemName(ImageResource.PN_HEIGHT), 0));
return !d0.equals(d1);
}
/**
* Calculates if the underlying image was added with respect to the versioned
* diff.
*
* @param c the image context
* @return true
if added
*/
protected boolean isAddedDiff(ImageContext c) {
if (c.diffInfo == null) {
return false;
}
ImageResource img0 = createImageResource(c.resource);
if (!img0.hasContent()) {
return false;
}
if (c.diffInfo.getType() == DiffInfo.TYPE.ADDED) {
return true;
}
if (c.resource.getPath().contains(JcrConstants.JCR_FROZENNODE)) {
return false;
}
Resource diffContent = c.diffInfo.getContent();
if (diffContent == null) {
return true;
}
ImageResource img1 = createImageResource(diffContent);
if (!img1.hasContent()) {
return true;
}
return false;
}
/**
* Calculates if the underlying image was removed with respect to the versioned
* diff.
*
* @param c the image context
* @return true
if removed
*/
protected boolean isRemovedDiff(ImageContext c) {
if (c.diffInfo == null) {
return false;
}
Resource diffContent = c.diffInfo.getContent();
if (diffContent == null) {
return false;
}
ImageResource img1 = createImageResource(diffContent);
if (!img1.hasContent()) {
return false;
}
if (c.diffInfo.getType() == DiffInfo.TYPE.REMOVED) {
return true;
}
ImageResource img0 = createImageResource(c.resource);
if (!img0.hasContent()) {
return true;
}
return false;
}
/**
* Convenience class that holds useful stuff needed for image generation
*/
public static class ImageContext {
public final SlingHttpServletRequest request;
public final Resource resource;
public final Resource defaultResource;
public final ResourceResolver resolver;
public final Node node;
public final ValueMap properties;
public final Style style;
public final Page currentPage;
public final ValueMap pageProperties;
public final Component component;
public final String requestImageType;
public final DiffInfo diffInfo;
public ImageContext(SlingHttpServletRequest request, String type) {
this.request = request;
resource = request.getResource();
resolver = request.getResourceResolver();
node = resource.adaptTo(Node.class);
ValueMap props = resource.adaptTo(ValueMap.class);
properties = props == null ? ValueMap.EMPTY : props;
style = WCMUtils.getStyle(request);
PageManager pageManager = resolver.adaptTo(PageManager.class);
currentPage = pageManager.getContainingPage(resource);
pageProperties = currentPage == null ? ValueMap.EMPTY : currentPage.getProperties();
component = WCMUtils.getComponent(resource);
requestImageType = type;
// get diff information
Resource vRes = null;
DiffInfo.TYPE diffType = null;
String vType = request.getParameter(DiffService.REQUEST_PARAM_DIFF_TYPE);
if (vType != null) {
try {
diffType = DiffInfo.TYPE.valueOf(vType);
} catch (IllegalArgumentException e) {
// ignore
}
}
String vLabel = request.getParameter(DiffService.REQUEST_PARAM_DIFF_TO);
if (vLabel != null) {
vRes = DiffInfo.getVersionedResource(resource, vLabel);
if (vRes == null && diffType == null) {
// calculate missing vType
if (!resource.getPath().contains(JcrConstants.JCR_FROZENNODE)) {
diffType = DiffInfo.TYPE.ADDED;
}
}
}
String defaultResourcePath = request.getParameter(ImageResource.PN_DEFAULT_IMAGE_PATH);
Resource defRes = null;
if (defaultResourcePath != null) {
defRes = resolver.resolve(defaultResourcePath);
}
defaultResource = defRes;
//
if (vRes != null || diffType != null) {
diffInfo = new DiffInfo(vRes, diffType == null ? DiffInfo.TYPE.SAME : diffType);
} else {
diffInfo = null;
}
}
}
}