blob: d629997099769986e59fddcb0337052eedcead0a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.sling.thumbnails.internal;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.IOUtils;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.thumbnails.BadRequestException;
import org.apache.sling.thumbnails.OutputFileFormat;
import org.apache.sling.thumbnails.RenditionSupport;
import org.apache.sling.thumbnails.Transformation;
import org.apache.sling.thumbnails.Transformer;
import org.apache.sling.thumbnails.internal.models.TransformationHandlerConfigImpl;
import org.apache.sling.thumbnails.internal.models.TransformationImpl;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A servlet to transform images using the Thumbnails API using a post body to
* transform the images
*/
@Component(immediate = true, service = Servlet.class, property = { "sling.servlet.methods=POST",
"sling.servlet.paths=/bin/sling/thumbnails/transform" })
public class DynamicTransformServlet extends SlingAllMethodsServlet {
private static final Logger log = LoggerFactory.getLogger(DynamicTransformServlet.class);
private final transient Transformer transformer;
private final transient RenditionSupport renditionSupport;
@Activate
public DynamicTransformServlet(@Reference Transformer transformer, @Reference RenditionSupport renditionSupport) {
this.renditionSupport = renditionSupport;
this.transformer = transformer;
}
@Override
protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws ServletException, IOException {
log.trace("doPost");
try {
Resource resource = request.getResourceResolver()
.getResource(Optional.ofNullable(request.getParameter("resource"))
.orElseThrow(() -> new BadRequestException("Parameter resource must be supplied")));
if (resource == null) {
response.sendError(404, "No resource found at: " + request.getParameter("resource"));
return;
}
OutputFileFormat format = OutputFileFormat
.forValue(Optional.ofNullable(request.getParameter("format")).orElse("jpeg"));
response.setHeader("Content-Disposition", "filename=" + resource.getName());
response.setContentType(format.getMimeType());
Transformation transformation = getTransformation(request);
log.debug("Transforming resource: {} with transformation: {} to {}", resource, transformation, format);
ByteArrayOutputStream baos = transform(resource, response, format.toString(), transformation);
String renditionName = request.getParameter("renditionName");
if (renditionName != null) {
if (StringUtils.isBlank(renditionName) && transformation.getName() != null) {
renditionName = transformation.getName() + "." + format.toString().toLowerCase();
}
log.debug("Setting rendition: {}", renditionName);
if (renditionSupport.supportsRenditions(resource)) {
renditionSupport.setRendition(resource, renditionName,
new ByteArrayInputStream(baos.toByteArray()));
} else {
throw new BadRequestException(
"Type " + resource.getResourceType() + " does not support persisting renditions");
}
}
} catch (BadRequestException e) {
log.error("Could not render thumbnail due to bad request", e);
response.sendError(400, "Could not render thumbnail due to bad request: " + e.getMessage());
} catch (Exception e) {
log.error("Failed to render thumbnail", e);
response.sendError(500, "Failed to render thumbnail");
}
}
private Transformation getTransformation(SlingHttpServletRequest request) throws IOException {
String transformationPath = request.getParameter("transformationResource");
if (StringUtils.isNotBlank(request.getParameter("transformationResource"))) {
return Optional.ofNullable(request.getResourceResolver().getResource(transformationPath))
.map(r -> r.adaptTo(Transformation.class)).orElseThrow(
() -> new BadRequestException("Requested invalid transformation: " + transformationPath));
} else {
return new TransformationImpl(parsePostBody(request));
}
}
private List<TransformationHandlerConfigImpl> parsePostBody(SlingHttpServletRequest request) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.readValue(request.getReader(),
new TypeReference<List<TransformationHandlerConfigImpl>>() {
});
} catch (JsonProcessingException pe) {
throw new BadRequestException("Could not parse transformation request", pe);
}
}
private ByteArrayOutputStream transform(Resource resource, SlingHttpServletResponse response, String format,
Transformation transformation) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
transformer.transform(resource, transformation, OutputFileFormat.valueOf(format.toUpperCase()), baos);
IOUtils.copy(new ByteArrayInputStream(baos.toByteArray()), response.getOutputStream());
return baos;
}
}