0

I want to write a query and test it using query debugger tool to look for the images that are not being referenced or are unused. I know we can achieve this as shown here:

http://wemcode.wemblog.com/get_asset_reference_in_page

But I was wondering if it is possible to write a query. Also, I would like to know how does the internal References search in the AEM Assets work. Does it fire a query ?

user972418
  • 817
  • 3
  • 25
  • 58

3 Answers3

0
  1. We can search the references to an asset on a page, but we cannot search within a DAM to check if the asset is being referenced by any page or not. The reason is, there is no property on the Assets which indicates any references to a page or any other asset. Which property could be queried here?

  2. The assets referenced on page could be easily determined by the property of the components node. For example, image component creates a property "damAssetReference" when the author drag and drops content from DAM. This property could be queried to find out the references.

To understand references search in AEM, you could take a look to the source code of AssetReferenceSearch Class. It seems like they iterate through each node and each property to find the references. Adobe developers are also doing it via Point 2 as described above.

package com.day.cq.dam.commons.util;

import com.day.cq.dam.api.Asset;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.nodetype.PropertyDefinition;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AssetReferenceSearch
{
  private static final Logger log = LoggerFactory.getLogger(AssetReferenceSearch.class);
  private final Node node;
  private final String searchPath;
  private final ResourceResolver resolver;

  public AssetReferenceSearch(Node node, String searchPath, ResourceResolver resolver)
  {
    this.node = node;
    this.searchPath = searchPath;
    this.resolver = resolver;
  }

  public Map<String, Asset> search()
  {
    Map<String, Asset> assetRefs = new HashMap();
    Pattern pattern = getPattern(this.searchPath);
    search(this.node, assetRefs, pattern);
    return assetRefs;
  }

  protected void search(Node node, Map<String, Asset> assetRefs, Pattern pattern)
  {
    try
    {
      for (pIter = node.getProperties(); pIter.hasNext();)
      {
        Property p = pIter.nextProperty();
        if ((p.getType() == 1) || (p.getType() == 7))
        {
          boolean decode = p.getType() == 1;
          if (p.getDefinition().isMultiple())
          {
            for (Value v : p.getValues())
            {
              String value = v.getString();
              if (pattern.matcher(value).find())
              {
                if (decode) {
                  value = tryDecode(value);
                }
                Set<String> refs = new HashSet();
                if (value.startsWith("/")) {
                  refs.add(value);
                } else {
                  getRefs(value, refs, decode);
                }
                for (String ref : refs) {
                  if ((this.resolver.getResource(ref) != null) && (this.resolver.getResource(ref).adaptTo(Asset.class) != null)) {
                    assetRefs.put(ref, this.resolver.getResource(ref).adaptTo(Asset.class));
                  }
                }
              }
            }
          }
          else
          {
            String value = p.getString();

            String isImageContext = "/is/image";
            if (value.startsWith(isImageContext)) {
              value = value.split(isImageContext)[1];
            }
            Matcher matcher = pattern.matcher(value);
            if (matcher.find())
            {
              Set<String> refs = new HashSet();
              if (value.startsWith("/")) {
                refs.add(decode ? tryDecode(value) : value);
              } else {
                getRefs(value, refs, decode);
              }
              for (String ref : refs) {
                if ((this.resolver.getResource(ref) != null) && (this.resolver.getResource(ref).adaptTo(Asset.class) != null)) {
                  assetRefs.put(ref, this.resolver.getResource(ref).adaptTo(Asset.class));
                }
              }
            }
          }
        }
      }
    }
    catch (RepositoryException re)
    {
      PropertyIterator pIter;
      log.warn("Error occured while reading properties");
    }
    try
    {
      for (nItr = node.getNodes(); nItr.hasNext();)
      {
        Node n = nItr.nextNode();
        search(n, assetRefs, pattern);
      }
    }
    catch (RepositoryException re)
    {
      NodeIterator nItr;
      log.warn("Error occured while reading nodes");
    }
  }

  private String tryDecode(String url)
  {
    try
    {
      return new URI(url).getPath();
    }
    catch (URISyntaxException e) {}
    return url;
  }

  private void getRefs(String value, Set<String> refs, boolean decode)
  {
    int startPos = value.indexOf(this.searchPath, 1);
    while (startPos != -1)
    {
      char charBeforeStartPos = value.charAt(startPos - 1);
      if ((charBeforeStartPos == '\'') || (charBeforeStartPos == '"'))
      {
        int endPos = value.indexOf(charBeforeStartPos, startPos);
        if (endPos > startPos)
        {
          String ref = value.substring(startPos, endPos);
          refs.add(decode ? tryDecode(ref) : ref);
          startPos = endPos;
        }
      }
      startPos = value.indexOf(this.searchPath, startPos + 1);
    }
  }

  protected Pattern getPattern(String path)
  {
    return Pattern.compile("(.[\"']|^|^[\"'])(" + path + ")\\b");
  }
}
Utkarsh
  • 589
  • 3
  • 19
0

ReferenceSearch can also be used to detect assets unreferenced assets. Sample snippet below:

private void findUnreferencedNodes(ResourceResolver resourceResolver, String path) {
    this.resourceResolver = resourceResolver;
    this.path = path; //DAM root path

    try {
      Node root = resourceResolver.getResource(path).adaptTo(Node.class);
      NodeIterator nodeIterator = root.getNodes();

      while (nodeIterator.hasNext()) {
        Node currentNode = nodeIterator.nextNode();
        if (currentNode.getProperty("jcr:primaryType").getString().equals("dam:Asset")) {
          Map<String, ReferenceSearch.Info> searchResult = referenceSearch.search(resourceResolver, currentNode.getPath());
          if (searchResult.isEmpty()) {
            //These are the nodes/assets not referenced anywhere
          }
        }
        //Recursively iterate through all the assets from root path
        findUnreferencedNodes(resourceResolver, currentNode.getPath());
      }
    } catch (RepositoryException e) {
      e.printStackTrace();
    }
  }
SubSul
  • 2,523
  • 1
  • 17
  • 27
0

https://github.com/frappierer/unrefAemAssets

It's not as sophisticated as the already given solutions, but it works :).

Coding is bad, but it solves your Problem.