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 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 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; } }