package com.mwmd.aem.search.core.indexing.impl;
import com.day.cq.commons.jcr.JcrConstants;
import com.mwmd.aem.search.core.indexing.IndexException;
import com.mwmd.aem.search.core.indexing.IndexOperation;
import com.mwmd.aem.search.core.indexing.IndexServer;
import com.mwmd.aem.search.core.indexing.IndexService;
import com.mwmd.aem.search.core.indexing.ResourceBinary;
import com.mwmd.aem.search.core.indexing.ResourceIndexer;
import com.mwmd.aem.search.core.indexing.ResourceReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.version.VersionManager;
import org.apache.commons.lang.StringUtils;
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.ValueMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Matthias Wermund
*/
public class IndexTransfer implements Runnable {
private static final Logger LOG = LoggerFactory.getLogger(IndexTransfer.class);
private IndexServiceImpl indexService;
public boolean terminated;
public void stop() {
this.terminated = true;
}
public IndexTransfer(IndexServiceImpl indexService) {
this.indexService = indexService;
}
@Override
public void run() {
ResourceResolver resolver = null;
IndexServer server = indexService.getServer();
if (server == null) {
if (LOG.isInfoEnabled()) {
LOG.info("No index server available.");
}
return;
}
boolean modifiedIndex = false;
try {
resolver = indexService.getResolverFactory().getAdministrativeResourceResolver(null);
VersionManager versionManager = resolver.adaptTo(Session.class).getWorkspace().getVersionManager();
while (!this.terminated) {
boolean modifiedQueue = false;
modifiedIndex = false;
Resource queueRes = resolver.getResource(IndexService.QUEUE_ROOT);
if (queueRes != null) {
Iterator<Resource> jobs = queueRes.listChildren();
while (jobs.hasNext()) {
Resource jobRes = jobs.next();
try {
ValueMap jobData = jobRes.adaptTo(ValueMap.class);
String jobPath = jobData.get(IndexService.PN_PATH, String.class);
String jobAction = jobData.get(IndexService.PN_ACTION, String.class);
String jobRevision = jobData.get(IndexService.PN_REVISION, String.class);
if (IndexOperation.ADD.toString().equals(jobAction)) {
Resource targetRes = resolver.getResource(jobPath);
if (targetRes != null) {
// resolve any selected content version at this point
targetRes = VersioningUtil.resolveRevision(versionManager, targetRes, jobRevision);
if (targetRes != null) {
// drill into jcr:content
Resource contentRes = targetRes.getChild(JcrConstants.JCR_CONTENT);
if (contentRes != null) {
targetRes = contentRes;
}
if (indexService.getIndexer(targetRes) != null) {
try {
add(server, targetRes, jobPath);
modifiedIndex = true;
if (LOG.isDebugEnabled()) {
LOG.debug("Indexed {} at node {}", jobPath, targetRes.getPath());
}
} catch (Exception e) {
LOG.error("Error transferring item to index: " + jobPath, e);
}
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Ignoring {}", jobPath);
}
}
} else {
LOG.warn("Ignoring due to failed revision resolution: {}", jobPath);
}
} else {
LOG.warn("Ignoring due to content not found: {}", jobPath);
}
} else if (IndexOperation.REMOVE.toString().equals(jobAction)) {
try {
server.remove(jobPath);
} catch (Exception e) {
LOG.error("Error removing item from index: " + jobPath, e);
}
modifiedIndex = true;
}
jobRes.adaptTo(Node.class).remove();
modifiedQueue = true;
} catch (Exception e) {
LOG.error("Error processing index job " + jobRes.getName(), e);
}
}
if (modifiedQueue) {
resolver.adaptTo(Session.class).save();
}
if (modifiedIndex) {
server.commit();
}
}
// if no change to queue, wait until notification or timeout until next attempt
if (!modifiedQueue) {
try {
synchronized (this) {
this.wait(5000);
}
} catch (InterruptedException e) {
if (!this.terminated) {
LOG.error("Interrupted transfer without termination flag.");
break;
}
}
}
}
} catch (LoginException e) {
LOG.error("Error creating resource resolver.", e);
} catch (RepositoryException e) {
LOG.error("Error during repository access.", e);
if (modifiedIndex) {
try {
server.rollback();
} catch (Exception e1) {
LOG.error("Error rolling back index changes.", e1);
}
}
} catch (Exception e) {
LOG.error("Error during queue processing.", e);
} finally {
if (resolver != null) {
resolver.close();
}
}
}
private void add(IndexServer server, Resource resource, String containerPath) throws IndexException, RepositoryException {
Map<String, Object> data = new HashMap<String, Object>();
// start content parsing
ResourceBinary binary = readContent(data, resource, containerPath, null, true);
if (binary != null) {
server.add(containerPath, data, binary);
} else {
server.add(containerPath, data);
}
}
private ResourceBinary readContent(Map<String, Object> data, Resource resource, String containerPath, String forceResourceType, boolean extractBinary) {
String resourceType = StringUtils.defaultIfEmpty(forceResourceType, resource.getResourceType());
ResourceIndexer indexer = indexService.getIndexer(resourceType);
if (indexer == null) {
indexer = indexService.getIndexer(resource);
}
ResourceBinary binary = null;
if (indexer != null && indexer.accepts(resource)) {
indexer.indexData(data, resource, containerPath);
if (extractBinary) {
binary = indexer.getBinary(resource);
}
List<ResourceReference> references = indexer.getReferences(resource);
for (ResourceReference ref : references) {
if (binary == null && extractBinary) {
binary = readContent(data, ref.getResource(), containerPath, ref.getForceResourceType(), true);
} else {
readContent(data, ref.getResource(), containerPath, ref.getForceResourceType(), false);
}
}
}
return binary;
}
}