Expand my Community achievements bar.

SOLVED

How to keep track of old and new path after asset is moved

Avatar

Level 4

Hello, community!!

My current project has used 3rd party search provider to index the pages and documents. A scheduler runs and indexes the published documents to the 3rd party source. If a document is unpublished and is present in the 3rd party source it is deleted from the source. For all these indexing there is a scheduler that runs every midnight. 

The problem arises when someone moves a document in aem, the scheduler runs and indexes the document in the 3rd party source once again as a new entry. As the document in the old path was never unpublished, we cannot even delete it from the source. 

 

I need a solution so that whenever I move a document (asset under a certain path), I can keep track of the old and new paths. On completion of the move operation, I want to remove the old path from the source (3rd party) and index the new path. Is there a way to keep track of the paths? Can we do this with the help of the event listener or handler? 

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @Ankan_Ghosh,

You can use EventHandler together with DAM EVENT_TOPIC, which provides DAM/Asset specific events. Next you can use below properties form event to get old and new path:

  • srcAbsPath - contains information about old/original path
  • assetPath - contains information about new/destination path

Here is a code example.

package com.sample.events;

import com.day.cq.dam.api.DamEvent;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(
        immediate = true,
        service = EventHandler.class,
        property = EventConstants.EVENT_TOPIC + "=" + DamEvent.EVENT_TOPIC)
public class DAMEventHandler implements EventHandler {

    private static final Logger LOG = LoggerFactory.getLogger(DAMEventHandler.class);

    @Override
    public void handleEvent(Event event) {
        DamEvent damEvent = DamEvent.fromEvent(event);
        if (DamEvent.Type.ASSET_MOVED.equals(damEvent.getType())) {
            if (event.containsProperty("assetPath") && event.containsProperty("srcAbsPath")) {
                String oldPath = event.getProperty("srcAbsPath").toString();
                String newPath = event.getProperty("assetPath").toString();
                LOG.info("Old path: " + oldPath);
                LOG.info("New path: " + newPath);
                // place for some other code
            }
        }
    }
}

Please make sure you do not put any heavy logic inside EventHandler, rather use Sling Jobs to delegate this. Heavy logic can cause an issue that EventHandler will be blacklisted an will not be run anymore.

View solution in original post

6 Replies

Avatar

Correct answer by
Community Advisor

Hi @Ankan_Ghosh,

You can use EventHandler together with DAM EVENT_TOPIC, which provides DAM/Asset specific events. Next you can use below properties form event to get old and new path:

  • srcAbsPath - contains information about old/original path
  • assetPath - contains information about new/destination path

Here is a code example.

package com.sample.events;

import com.day.cq.dam.api.DamEvent;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(
        immediate = true,
        service = EventHandler.class,
        property = EventConstants.EVENT_TOPIC + "=" + DamEvent.EVENT_TOPIC)
public class DAMEventHandler implements EventHandler {

    private static final Logger LOG = LoggerFactory.getLogger(DAMEventHandler.class);

    @Override
    public void handleEvent(Event event) {
        DamEvent damEvent = DamEvent.fromEvent(event);
        if (DamEvent.Type.ASSET_MOVED.equals(damEvent.getType())) {
            if (event.containsProperty("assetPath") && event.containsProperty("srcAbsPath")) {
                String oldPath = event.getProperty("srcAbsPath").toString();
                String newPath = event.getProperty("assetPath").toString();
                LOG.info("Old path: " + oldPath);
                LOG.info("New path: " + newPath);
                // place for some other code
            }
        }
    }
}

Please make sure you do not put any heavy logic inside EventHandler, rather use Sling Jobs to delegate this. Heavy logic can cause an issue that EventHandler will be blacklisted an will not be run anymore.

Avatar

Level 7

Hi @Ankan_Ghosh 
Above solve by @lukasz-m is apt for finding new and old paths of a moved asset/resource.

But considering your use case , as the scheduler runs every midnight :  what if the asset is moved multiple times during the day. 
Considering above solution , in which every time an asset is move -> we send a server push to 3rd party to unpublish the previous path.
1. Sending unpublished asset push in real time using EventListener will be quite an overhead. 

2. Also I think if you are reindexing at the end of the day but publishing content on every Asset Move Listener might create data discrepancy at third party.

So in addition to above logic what you can do is for each move operation you can store oldpath and newpath at a node under var
Like for eg. at /var/movedAssets
you can store such mapping
{
"movedAssets": [
{"oldPath": "/content/dam/old/path1.jpg", "newPath": "/content/dam/new/path1.jpg"},
{"oldPath": "/content/dam/old/path2.jpg", "newPath": "/content/dam/new/path2.jpg"},

and so on..
]
}
This mapping you can update using above EventListener for each asset.


Then in your scheduler you can modify the logic to pick mapping from above node and unpublish all your oldpaths and reindex newPaths.


At the end of your scheduler job, you can clear the above logs from the node as they are no longer needed.



I would add that these movements can be stored in the asset metadata as movements multi-value property. So, no need to worry about permissions under var for the service. 

@konstantyn_diachenko I did not want to modify the resource, as resource/asset modification also needs to be replicated at source(3rd party)
Also we would need to remove this property after the scheduler job. Then again asset modification would take place.
So keeping it separate makes sense to me.

Avatar

Level 4

I am going with this solution. I have also created two jobs for deleting and indexing at the third-party source. Sometimes it worked as it should, but in many cases move operation is completely ignored by the handler and goes ignored. What is wrong with the code? Do I need to do something else so that it can react to every move operation?

Avatar

Level 7

In the handler properties , you can mention event filter
property = {
EventConstants.EVENT_TOPIC + "=" + DamEvent.EVENT_TOPIC,
EventConstants.EVENT_FILTER + "=(event.damType=moved)"
}

Check if this works.