Hi,
Upon deletion of asset resource, I need to retrieve a property from the resource before it becomes null.
I tried this using an Event Listener, Event Handler, ResourceChangeListener, setting up a workflow triggered by a launcher upon deletion, SlingFilter but the resource is null in all these cases.
Is there any way other than overlaying Delete Button and obtain the resource details before asset is deleted? We are using AEM6.5.
TIA.
@arunpatidar @SantoshSai @EstebanBustamante
Solved! Go to Solution.
Views
Replies
Total Likes
Hi @Divya_T13
Using solutions that base on events will not work. Basically because events like Event.NODE_REMOVED, are triggered after specific node/resource is removed - so it is too late to read any information.
If you will observer how delete button is working, you can see that POST request is send to /bin/wcmcommand with parameter cmd set to deletePage - yes deletePage is used for both page and asset.
Having that knowledge you can utilize https://developer.adobe.com/experience-manager/reference-materials/6-5/javadoc/com/day/cq/wcm/api/co... to register your own command that will be used whenever user clicks on Delete button. This will give you full control, and allow to run some activities before asset is removed.
Here is a sample code:
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.commands.WCMCommand;
import com.day.cq.wcm.api.commands.WCMCommandContext;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HtmlResponse;
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.component.annotations.ReferenceCardinality;
import org.osgi.service.component.propertytypes.ServiceRanking;
import java.util.ArrayList;
import java.util.List;
@ServiceRanking(100)
@Component(service = WCMCommand.class, immediate = true)
public class CustomDeleteCommand implements WCMCommand {
@Reference(cardinality = ReferenceCardinality.MULTIPLE)
private List<WCMCommand> commands = new ArrayList<WCMCommand>();
private WCMCommand deleteCommand;
@Activate
@Modified
void activate(){
System.out.println("Activating CustomDeleteCommand");
for (WCMCommand command : commands) {
if (command.getCommandName().equalsIgnoreCase("deletePage")
&& !(command instanceof CustomDeleteCommand)) {
deleteCommand = command;
}
}
}
@Override
public String getCommandName() {
return "deletePage";
}
@Override
public HtmlResponse performCommand(WCMCommandContext wcmCommandContext, SlingHttpServletRequest slingHttpServletRequest, SlingHttpServletResponse slingHttpServletResponse, PageManager pageManager) {
String path = slingHttpServletRequest.getParameter("path");
if (path != null && path.startsWith("/content/dam")) {
// place for you logic
}
// executing original delete command to remove page/asset
return deleteCommand.performCommand(wcmCommandContext, slingHttpServletRequest, slingHttpServletResponse, pageManager);
}
}
To be clear in above code we are registering new custom command that will be run instead of original OOTB one. But it is utilizing original command to run deletion process. Thanks to that you can easily combine your custom logic with OOTB behavior. Also you do not have to do any other modification on client side etc.
In case of any issue with above code try to restart AEM instance after installing above code.
Hi @Divya_T13,
I think, it's possible you juts need to intercept the event at the JCR level, before the delete is committed.
Let's give a try using using a JCR Observation Listener (Jackrabbit API).
As we know , a JackrabbitEventListener can listen to pre-deletion events (specifically NODE_REMOVED) and still access the node via the Event object before the session refreshes.
Sample setup:
@Component(immediate = true, service = EventListener.class)
public class AssetDeleteEventListener implements EventListener {
@Reference
private SlingRepository repository;
@Activate
public void activate() throws Exception {
Session session = repository.loginService("datawrite", null);
Workspace workspace = session.getWorkspace();
ObservationManager observationManager = workspace.getObservationManager();
observationManager.addEventListener(
this,
Event.NODE_REMOVED,
"/content/dam",
true,
null,
null,
false
);
}
@Override
public void onEvent(EventIterator events) {
while (events.hasNext()) {
Event event = events.nextEvent();
String path = event.getPath();
try {
String parentPath = ResourceUtil.getParent(path);
Session session = repository.loginService("datawrite", null);
if (session.nodeExists(parentPath)) {
Node parentNode = session.getNode(parentPath);
// If needed, traverse children or log metadata before deletion
log.info("Parent Node Name: {}", parentNode.getName());
}
log.info("Node being deleted: {}", path);
// You can also track deletion in an audit log here
} catch (Exception e) {
log.error("Error while handling deletion", e);
}
}
}
}
Make sure you are running with a system user (eg. datawrite) with appropriate permissions.
Alternatevely, You can intercept via custom servlet/command - If you need full control and this is for a custom deletion flow, you could: create a custom servlet to handle deletion.
Hi @SantoshSai
With this action Event.NODE_REMOVED , node no longer exists in JCR as it is already deleted. So, Event listener will not work here.
Is there any way other than overlaying Delete Button and obtain the resource details before asset is deleted?
Thank you.
@Divya_T13 Ohhh yeah, missed it. Ok can you use a custom workflow launcher (Pre-delete Path)?
If your deletion happens through a custom process, or you can enforce deletion via a workflow (e.g., asset archive request, trash bin process), you can:
Trigger a custom workflow launcher on a flag (like deleteMe=true)
Capture all asset properties while node is still available
Then delete the asset at the end of the workflow step using resourceResolver.delete()
OR
Use a Sling Model or Servlet to Pre-cache Deletion Metadata
If you're in control of how deletions happen (like through a custom UI button or API), you could:
Capture properties into a temporary store (JCR node, database, external system)
Then proceed with deletion programmatically
Hi @Divya_T13
Using solutions that base on events will not work. Basically because events like Event.NODE_REMOVED, are triggered after specific node/resource is removed - so it is too late to read any information.
If you will observer how delete button is working, you can see that POST request is send to /bin/wcmcommand with parameter cmd set to deletePage - yes deletePage is used for both page and asset.
Having that knowledge you can utilize https://developer.adobe.com/experience-manager/reference-materials/6-5/javadoc/com/day/cq/wcm/api/co... to register your own command that will be used whenever user clicks on Delete button. This will give you full control, and allow to run some activities before asset is removed.
Here is a sample code:
import com.day.cq.wcm.api.PageManager;
import com.day.cq.wcm.api.commands.WCMCommand;
import com.day.cq.wcm.api.commands.WCMCommandContext;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.HtmlResponse;
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.component.annotations.ReferenceCardinality;
import org.osgi.service.component.propertytypes.ServiceRanking;
import java.util.ArrayList;
import java.util.List;
@ServiceRanking(100)
@Component(service = WCMCommand.class, immediate = true)
public class CustomDeleteCommand implements WCMCommand {
@Reference(cardinality = ReferenceCardinality.MULTIPLE)
private List<WCMCommand> commands = new ArrayList<WCMCommand>();
private WCMCommand deleteCommand;
@Activate
@Modified
void activate(){
System.out.println("Activating CustomDeleteCommand");
for (WCMCommand command : commands) {
if (command.getCommandName().equalsIgnoreCase("deletePage")
&& !(command instanceof CustomDeleteCommand)) {
deleteCommand = command;
}
}
}
@Override
public String getCommandName() {
return "deletePage";
}
@Override
public HtmlResponse performCommand(WCMCommandContext wcmCommandContext, SlingHttpServletRequest slingHttpServletRequest, SlingHttpServletResponse slingHttpServletResponse, PageManager pageManager) {
String path = slingHttpServletRequest.getParameter("path");
if (path != null && path.startsWith("/content/dam")) {
// place for you logic
}
// executing original delete command to remove page/asset
return deleteCommand.performCommand(wcmCommandContext, slingHttpServletRequest, slingHttpServletResponse, pageManager);
}
}
To be clear in above code we are registering new custom command that will be run instead of original OOTB one. But it is utilizing original command to run deletion process. Thanks to that you can easily combine your custom logic with OOTB behavior. Also you do not have to do any other modification on client side etc.
In case of any issue with above code try to restart AEM instance after installing above code.
Thank you @lukasz-m @SantoshSai .
Is there a similar approach for when the same asset is re-uploaded? Is there a way to retrieve the asset's metadata properties during a re-upload? Currently, when the same asset is re-uploaded, all the previous metadata properties are lost because new metadata is being written. How can we read the previous metadata before the asset is replaced?
Thank you.
Views
Replies
Total Likes
Views
Likes
Replies