package com.mwmd.aem.search.core.indexing.impl; import com.day.cq.commons.jcr.JcrConstants; import com.mwmd.aem.search.core.indexing.IndexOperation; import static com.mwmd.aem.search.core.indexing.IndexService.PN_ACTION; import static com.mwmd.aem.search.core.indexing.IndexService.PN_PATH; import static com.mwmd.aem.search.core.indexing.IndexService.PN_REVISION; import static com.mwmd.aem.search.core.indexing.IndexService.QUEUE_ROOT; import com.mwmd.aem.search.core.indexing.IndexTask; import com.mwmd.aem.search.core.indexing.ResourceIndexer; import java.util.Calendar; import java.util.Iterator; import java.util.UUID; import javax.jcr.Node; import javax.jcr.RepositoryException; import javax.jcr.Session; import org.apache.sling.api.resource.LoginException; import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ResourceResolver; import org.apache.sling.api.resource.ResourceUtil; import org.apache.sling.jcr.resource.JcrResourceConstants; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Matthias Wermund */ public class IndexQueueWriter implements Runnable { private static final Logger LOG = LoggerFactory.getLogger(IndexQueueWriter.class); private IndexServiceImpl indexService; public boolean terminated; public void stop() { this.terminated = true; } public IndexQueueWriter(IndexServiceImpl indexService) { this.indexService = indexService; } @Override public void run() { ResourceResolver resolver = null; try { resolver = indexService.getResolverFactory().getAdministrativeResourceResolver(null); while (!terminated) { boolean relevant = true; IndexTask task = indexService.getTasks().take(); String path = task.getPath(); /** * AEM will deactivate all child resources within this branch , so remove them too. */ if (IndexOperation.REMOVE.equals(task.getOp())) { Resource resource = resolver.getResource(path); if (resource != null) { Iterator<Resource> children = resource.listChildren(); while (children.hasNext()) { Resource child = children.next(); // jcr:content nodes are never indexed standalone in the first place if (!JcrConstants.JCR_CONTENT.equals(child.getName())) { if (LOG.isDebugEnabled()) { LOG.debug("Triggered automatic removal of child {}", child.getPath()); } indexService.getTasks().add(new IndexTask(IndexOperation.REMOVE, child.getPath(), null)); } } } /** * Only in case it's ADD, filter further, because it has to be indexable content. */ } else if (IndexOperation.ADD.equals(task.getOp())) { Resource resource = resolver.getResource(path); if (resource == null) { LOG.warn("Resource not found: {})", path); relevant = false; } else { // drill into jcr:content Resource contentRes = resource.getChild(JcrConstants.JCR_CONTENT); if (contentRes != null) { resource = contentRes; } // filter by known ResourceIndexer ResourceIndexer indexer = indexService.getIndexer(resource); if (indexer == null || !indexer.accepts(resource)) { if (LOG.isTraceEnabled()) { LOG.trace("Didn't find valid indexer for {} {}", resource.getResourceType(), resource.getPath()); } relevant = false; } } } if (relevant) { /* * At this point the index operation is considered valid and should get written to persistant queue in the repository. */ try { Resource queueRes = resolver.getResource(QUEUE_ROOT); Node queueNode; if (queueRes == null) { // create queue root Node parent = resolver.getResource(ResourceUtil.getParent(QUEUE_ROOT)).adaptTo(Node.class); queueNode = parent.addNode(ResourceUtil.getName(QUEUE_ROOT), JcrResourceConstants.NT_SLING_ORDERED_FOLDER); } else { queueNode = queueRes.adaptTo(Node.class); } Node itemNode = queueNode.addNode(UUID.randomUUID().toString(), JcrConstants.NT_UNSTRUCTURED); itemNode.setProperty(PN_PATH, task.getPath()); itemNode.setProperty(PN_ACTION, task.getOp().toString()); itemNode.setProperty(PN_REVISION, task.getRevision()); itemNode.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance()); resolver.adaptTo(Session.class).save(); if (LOG.isDebugEnabled()) { LOG.debug("Added index queue node {}", task); } indexService.notifyTransfer(); } catch (RepositoryException e) { LOG.error("Error during index queue modification.", e); } } } } catch (InterruptedException e) { if (this.terminated) { if (LOG.isDebugEnabled()) { LOG.debug("Writer interrupted during shutdown."); } } else { LOG.error("Interrupted writer without termination flag."); } } catch (LoginException e) { LOG.error("Error creating resource resolver.", e); } catch (Exception e) { LOG.error("Error during queue writing.", e); } finally { if (resolver != null) { resolver.close(); } } if (LOG.isDebugEnabled()) { LOG.debug("Queue writer stopped"); } } }