Expand my Community achievements bar.

Submissions are now open for the 2026 Adobe Experience Maker Awards.
SOLVED

On Asset deletion, how to get its properties/details before its deleted.

Avatar

Level 3

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 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

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.

View solution in original post

5 Replies

Avatar

Community Advisor

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.


Santosh Sai

AEM BlogsLinkedIn


Avatar

Level 3

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.

Avatar

Community Advisor

@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

 


Santosh Sai

AEM BlogsLinkedIn


Avatar

Correct answer by
Community Advisor

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.

Avatar

Level 3

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.