
com.day.cq.dam.commons.util.AssetReferenceRecursiveSearch Maven / Gradle / Ivy
package com.day.cq.dam.commons.util;
import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.dam.api.Asset;
import com.day.cq.dam.api.DamConstants;
import com.day.cq.dam.api.collection.SmartCollection;
import com.day.cq.dam.api.s7dam.constants.S7damConstants;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.resource.collection.ResourceCollection;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jcr.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* The AssetReferenceRecursiveSearch
searches in a specified path for referenced assets recursively.
* If it encounters a SmartCollection
, ResourceCollection
or a S7Set
it iterates
* over its children and looks for the referenced assets within their children and their children's children and so on.
*/
public class AssetReferenceRecursiveSearch {
/**
* The logging facility.
*/
private static final Logger log = LoggerFactory.getLogger(AssetReferenceRecursiveSearch.class);
private final Node node;
private final String searchPath;
private final ResourceResolver resolver;
/**
* Maintain a list of recursion traversal history to prevent cyclic references and infinite recursion
*/
private List pathsTraversed = new ArrayList();
/**
* List of nodes which contain phantom references. Better to skip them.
*/
private final List ignoredNodes = new ArrayList(){{
this.add(DamConstants.THUMBNAIL_NODE); //ignore any references to assets in thumbnail. traverse list of children instead
this.add(DamConstants.RENDITIONS_FOLDER);
}};
/**
* The constructor.
*
* @param node node to start search for references
* @param searchPath search for assets starting with searchPath
* @param resolver resource resolver
*/
public AssetReferenceRecursiveSearch(Node node, String searchPath, ResourceResolver resolver) {
this.node = node;
this.searchPath = searchPath;
this.resolver = resolver;
}
/**
* Search all asset references
*
* @return map containing all asset refs
*/
public Map search() {
Map assetRefs = new HashMap();
Pattern pattern = getPattern(searchPath);
search(node, assetRefs, pattern);
return assetRefs;
}
/**
* Search method with recursive functionality.
* Searches recursively within items which are DAM asset containers.
*
* @param node node to start search for references
* @param resourceRefs map to store the references found
* @param pattern pattern to look for
*/
protected void search(Node node, Map resourceRefs, Pattern pattern) {
try {
if(node.hasProperty("sling:resource")) {
Resource referencedResource = resolver.resolve(node.getProperty("sling:resource").getString());
if(referencedResource != null && !ResourceUtil.isNonExistingResource(referencedResource)) {
if(S7SetHelper.isS7Set(referencedResource)
|| S7SetHelper.isS7Video(referencedResource)
|| isS7Preset(referencedResource)
|| referencedResource.adaptTo(ResourceCollection.class) != null
|| referencedResource.adaptTo(SmartCollection.class) != null
|| referencedResource.adaptTo(Node.class).isNodeType(JcrConstants.NT_FOLDER)) {
if(!pathsTraversed.contains(referencedResource.getPath())) {
pathsTraversed.add(referencedResource.getPath());
search(referencedResource.adaptTo(Node.class), resourceRefs, pattern);
}
}
}
}
if(!ignoredNodes.contains(node.getName()) && !node.getPath().equals(this.node.getPath())) {
locateMatch(pattern, node.getPath(), true, resourceRefs);
searchPresets(node.getPath(), resourceRefs, true);
}
if(!ignoredNodes.contains(node.getName())) {
searchInProps(node, resourceRefs, pattern);
searchInChildren(node, resourceRefs, pattern);
}
} catch (RepositoryException re) {
log.warn("Error occurred while reading properties", re);
}
}
/**
* ViewerPreset is a special type that is not an Asset and is not in the /content/dam area,
* but it is still associated with a viewer or asset, and needs to be included as a reference.
*
* @param resource The actual resource referenced by the reference node.
* @return True if the resource is a ViewerPreset type.
*/
private boolean isS7Preset(Resource resource) {
Resource contentResource = resource.getChild(JcrConstants.JCR_CONTENT);
if (contentResource != null) {
ValueMap vm = contentResource.adaptTo(ValueMap.class);
String s7Type = vm.get(S7damConstants.PN_S7_TYPE, "");
if (S7damConstants.S7_VIEWER_PRESET.equals(s7Type)) {
return true;
}
}
return false;
}
/**
* Add presets to related resource list. These may exist outside DAM asset containers.
*
* @param value Path to inspect.
* @param resourceRefs Found resources.
* @param decode Decode before searching.
* @throws RepositoryException
*/
private void searchPresets(String value, Map resourceRefs, boolean decode)
throws RepositoryException {
Set refs = new HashSet();
if (value.startsWith("/")) {
// looks like just a single path
refs.add(decode? tryDecode(value) : value);
} else {
// ref might be somewhere in the string
getRefs(value, refs, decode);
}
for (String ref : refs) {
Resource resource = resolver.getResource(ref);
if (resource != null && !ResourceUtil.isNonExistingResource(resource)) {
if (isS7Preset(resource)) {
resourceRefs.put(ref, resource);
}
}
}
}
protected void searchInProps(Node node, Map resourceRefs, Pattern pattern) {
try {
for (PropertyIterator pIter = node.getProperties(); pIter.hasNext();) {
Property p = pIter.nextProperty();
// only check string and name properties
if (p.getType() == PropertyType.STRING || p.getType() == PropertyType.NAME) {
boolean decode = p.getType() == PropertyType.STRING;
if (p.getDefinition().isMultiple()) {
for (Value v : p.getValues()) {
locateMatch(pattern, v.getString(), decode, resourceRefs);
}
} else {
locateMatch(pattern, p.getString(), decode, resourceRefs);
}
}
}
} catch (RepositoryException re) {
log.warn("Error occured while reading properties");
}
}
protected void searchInChildren(Node node, Map resourceRefs, Pattern pattern) {
try {
for (NodeIterator nItr = node.getNodes(); nItr.hasNext();) {
Node n = nItr.nextNode();
search(n, resourceRefs, pattern);
}
} catch (RepositoryException re) {
log.warn("Error occured while reading nodes");
}
}
private void locateMatch(Pattern pattern, String value, boolean decode, Map resourceRefs)
throws RepositoryException {
Matcher matcher = pattern.matcher(value);
if (matcher.find()) {
Set refs = new HashSet();
if (value.startsWith("/")) {
// looks like just a single path
refs.add(decode? tryDecode(value) : value);
} else {
// ref might be somewhere in the string
getRefs(value, refs, decode);
}
for (String ref : refs) {
Resource resource = resolver.getResource(ref);
if (resource != null && !ResourceUtil.isNonExistingResource(resource)) {
if (resource.adaptTo(Asset.class) != null
|| S7SetHelper.isS7Set(resource)
|| S7SetHelper.isS7Video(resource)
|| isS7Preset(resource)
|| resource.adaptTo(ResourceCollection.class) != null
|| resource.adaptTo(Node.class).isNodeType(JcrConstants.NT_FOLDER)) {
resourceRefs.put(ref, resolver.getResource(ref));
}
}
}
}
}
private String tryDecode(String url) {
try {
return new URI(url).getPath();
} catch(URISyntaxException e) {
return url;
}
}
/**
* Search for asset paths in text
*
* @param value text as string
* @param refs set to which found asset paths are added
*/
private void getRefs(String value, Set refs, boolean decode) {
int startPos = value.indexOf(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(searchPath, startPos + 1);
}
}
/**
* Returns the replacement pattern for the rewrite method.
*
* @param path source path
* @return replacement pattern
*/
protected Pattern getPattern(String path) {
return Pattern.compile("(.[\"']|^|^[\"'])(" + path + ")\\b");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy