Create Image Renditions with an Event Handler
Goal
Create an event handler that creates image renditions after the image has been uploaded in your DAM.
Use Case
Generally, you can update your workflow launchers, or even extend them. In my case, I didn’t to modify the existent workflow because we had different projects on our instance. I remember I tried to extend it, but sometimes we got different errors, regarding some Oak conflicts and concurrency. For this reason, I came up with the idea to use an Event Handler that had to be triggered after the image had been uploaded.
Procedure
Let’s create our Event Handler as follows:
package com.adobe.training.core.listeners;
import com.adobe.training.core.utils.Lab2020CommonMethods;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.DamEvent;
import com.day.cq.dam.api.Rendition;
import com.day.cq.dam.api.renditions.RenditionMaker;
import com.day.cq.dam.api.renditions.RenditionTemplate;
import org.apache.commons.lang3.StringUtils;
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.ResourceResolverFactory;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Modified;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Created by r.teruzzi on 18/09/2019.
*/
@Designate(ocd = UpdateAssetListener.UpdateAssetListenerConfiguration.class)
@Component(
service = EventHandler.class,
immediate = true,
enabled = true,
property = {
Constants.SERVICE_DESCRIPTION + "=Lab2020 Activation Event Listener ",
EventConstants.EVENT_TOPIC + "=" + DamEvent.EVENT_TOPIC
}
)
public class UpdateAssetListener implements EventHandler {
@ObjectClassDefinition(name = "Lab2020 - Event Handler for Update Asset Workflow")
public @interface UpdateAssetListenerConfiguration {
@AttributeDefinition(
name = "List of Renditions",
description = "Enter the renditions needed with the following format: 'width:height:false' e.g. '800:533:false"
)
String[] getListOfRenditions();
}
@Reference
private ResourceResolverFactory resourceResolverFactory;
@Reference
private RenditionMaker renditionMaker;
@Activate
@Modified
protected void activate(UpdateAssetListenerConfiguration config) {
renditions = config.getListOfRenditions();
}
private String[] renditions;
private final Logger LOG = LoggerFactory.getLogger(getClass());
@Override
public void handleEvent(Event event) {
Object type = event.getProperty("type");
if (type == DamEvent.Type.DAM_UPDATE_ASSET_WORKFLOW_COMPLETED) {
String path = DamEvent.fromEvent(event).getAssetPath();
LOG.info("EVENT TYPE: " + type);
LOG.info("PATH: " + path);
if (StringUtils.startsWith(path, "/content/dam/Lab2020")) { //The IF case is just an additional check
//The resource should be null because the resource resolver should not has the permission for other paths except for costa-app
try (ResourceResolver resourceResolver = Lab2020CommonMethods.getResourceResolver(resourceResolverFactory)) {
Resource resource = resourceResolver.getResource(path);
if (resource != null) {
Asset asset = resource.adaptTo(Asset.class);
createRenditions(asset);
resourceResolver.commit();
}
} catch (PersistenceException e) {
LOG.error("Failed to commit changes", e);
}
}
}
}
private void createRenditions(Asset asset) {
if (asset != null) {
for (String rendition : renditions) {
String[] renditionValues = rendition.split(":");
if (renditionValues.length == 3) {
String renditionWidthValue = renditionValues[0];
int renditionWidth = Integer.parseInt(renditionWidthValue);
String renditionHeightValue = renditionValues[1];
int renditionHeight = Integer.parseInt(renditionHeightValue);
boolean center = Boolean.parseBoolean(renditionValues[2]);
RenditionTemplate thumbnailTemplate = renditionMaker.createThumbnailTemplate(asset,
renditionWidth, renditionHeight, center);
List<Rendition> renditions = renditionMaker.generateRenditions(asset, thumbnailTemplate);
for (Rendition r : renditions) {
asset.addRendition("cq5dam.thumbnail.".concat(renditionWidthValue).concat(".")
.concat(renditionHeightValue).concat(".png"), r.getStream(), "image/png");
}
}
}
}
}
}
As you can see:
- The event topic is: DamEvent.EVENT_TOPIC
- But then the specific event type checked is related to the completed workflow: DamEvent.Type.DAM_UPDATE_ASSET_WORKFLOW_COMPLETED
- The list of renditions has been configured. You could do the same for the list fo path or whatever you want like extensions and so on!
- It’s been used a resource resolver associated with a system user with specific ACLs. If you don’t know how to create it, check this article.
- The rendition maker service will do the job
That’s all guys! Here you can find different articles with some OSGi examples.
Cheers! ðŸ¥
Any git repo URL for this use cases.
LikeLike
Nope sorry, I haven’t
LikeLike