Skip to content

Instantly share code, notes, and snippets.

@cpilsworth
Created April 1, 2025 08:41
Show Gist options
  • Save cpilsworth/e220b6ae81eef835f43551c5a3aaf65b to your computer and use it in GitHub Desktop.
Save cpilsworth/e220b6ae81eef835f43551c5a3aaf65b to your computer and use it in GitHub Desktop.
Describe AEM assets and their relationships
package com.chrisp.core.servlets;
import java.io.IOException;
import java.util.Iterator;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.Servlet;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.day.cq.dam.api.Asset;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* Servlet that lists assets and their relationships under a specific path
* Usage: /bin/assets/relationships?path=/content/dam/path
*/
@Component(
service = Servlet.class,
property = {
Constants.SERVICE_DESCRIPTION + "=Asset Relationship Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_GET,
"sling.servlet.paths=" + "/bin/assets/relationships",
"sling.servlet.extensions=" + "json"
}
)
public class AssetRelationshipServlet extends SlingSafeMethodsServlet {
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(AssetRelationshipServlet.class);
@Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
throws IOException {
response.setContentType("application/json");
ResourceResolver resolver = request.getResourceResolver();
String path = request.getParameter("path");
if (path == null || path.isEmpty()) {
response.getWriter().write("{\"error\": \"Please provide a path parameter\"}");
return;
}
Resource resource = resolver.getResource(path);
if (resource == null) {
response.getWriter().write("{\"error\": \"Path not found: " + path + "\"}");
return;
}
try {
JsonArray resultArray = findAssetsWithRelationships(resource, resolver);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(resultArray);
response.getWriter().write(jsonOutput);
} catch (Exception e) {
log.error("Error processing assets", e);
response.getWriter().write("{\"error\": \"" + e.getMessage() + "\"}");
}
}
/**
* Recursively find all assets under the given resource
*/
private JsonArray findAssetsWithRelationships(Resource resource, ResourceResolver resolver)
throws RepositoryException {
JsonArray results = new JsonArray();
// Process current resource if it's an asset
Asset asset = resource.adaptTo(Asset.class);
if (asset != null) {
JsonObject assetJson = processAsset(asset, resolver);
results.add(assetJson);
}
// Process children recursively
Iterator<Resource> children = resource.listChildren();
while (children.hasNext()) {
Resource child = children.next();
JsonArray childResults = findAssetsWithRelationships(child, resolver);
for (int i = 0; i < childResults.size(); i++) {
results.add(childResults.get(i));
}
}
return results;
}
/**
* Process a single asset and find its relationships
*/
private JsonObject processAsset(Asset asset, ResourceResolver resolver) throws RepositoryException {
JsonObject assetJson = new JsonObject();
Resource assetResource = asset.adaptTo(Resource.class);
// Get the JCR node
Node assetNode = assetResource.adaptTo(Node.class);
String uuid = "";
if (assetNode != null && assetNode.hasProperty("jcr:uuid")) {
uuid = assetNode.getProperty("jcr:uuid").getString();
}
assetJson.addProperty("path", asset.getPath());
assetJson.addProperty("name", asset.getName());
assetJson.addProperty("uuid", uuid);
// Find all types of related assets based on the specified structure
JsonArray derivedAssets = findRelatedAssets(asset, "derived", resolver);
assetJson.add("derivedAssets", derivedAssets);
JsonArray sourceAssets = findRelatedAssets(asset, "sources", resolver);
assetJson.add("sourceAssets", sourceAssets);
JsonArray otherAssets = findRelatedAssets(asset, "others", resolver);
assetJson.add("otherAssets", otherAssets);
return assetJson;
}
/**
* Find related assets of a specific type using the structure:
* ./jcr:content/related/{relation-type}/sling:members/{asset-name}
*
* @param asset The asset to find relationships for
* @param relationType The type of relation ("derived", "source", or "other")
* @param resolver The resource resolver
* @return JsonArray containing related assets
*/
private JsonArray findRelatedAssets(Asset asset, String relationType, ResourceResolver resolver) {
JsonArray relatedAssets = new JsonArray();
Resource assetResource = asset.adaptTo(Resource.class);
try {
if (assetResource != null) {
// Path to the related assets based on the specified structure
String relatedPath = assetResource.getPath() + "/jcr:content/related/" + relationType + "/sling:members";
Resource relatedResource = resolver.getResource(relatedPath);
if (relatedResource != null) {
// Iterate through all children (asset-name nodes)
Iterator<Resource> relatedMembers = relatedResource.listChildren();
while (relatedMembers.hasNext()) {
Resource memberResource = relatedMembers.next();
Node memberNode = memberResource.adaptTo(Node.class);
if (memberNode != null && memberNode.hasProperty("sling:resource")) {
// Get the path of the related asset
String linkedAssetPath = memberNode.getProperty("sling:resource").getString();
Resource linkedResource = resolver.getResource(linkedAssetPath);
if (linkedResource != null) {
Asset linkedAsset = linkedResource.adaptTo(Asset.class);
if (linkedAsset != null) {
JsonObject relatedJson = new JsonObject();
relatedJson.addProperty("path", linkedAsset.getPath());
relatedJson.addProperty("name", linkedAsset.getName());
// Get the UUID of the linked asset
Node linkedNode = linkedResource.adaptTo(Node.class);
if (linkedNode != null && linkedNode.hasProperty("jcr:uuid")) {
relatedJson.addProperty("uuid", linkedNode.getProperty("jcr:uuid").getString());
}
relatedAssets.add(relatedJson);
}
}
}
}
}
}
} catch (RepositoryException e) {
log.error("Error finding " + relationType + " related assets", e);
}
return relatedAssets;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment