blob: fe9840237e576ed0fbb0095a2863cd6e509fe084 [file] [log] [blame]
package de.ids_mannheim.korap.resource.rewrite;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.fasterxml.jackson.databind.JsonNode;
import de.ids_mannheim.korap.config.BeanInjectable;
import de.ids_mannheim.korap.config.ContextHolder;
import de.ids_mannheim.korap.config.KustvaktConfiguration;
import de.ids_mannheim.korap.exceptions.KustvaktException;
import de.ids_mannheim.korap.user.User;
import de.ids_mannheim.korap.utils.JsonUtils;
/**
* @author hanl
* @date 30/06/2015
*/
// todo: do post processing!
//todo: load rewritenode and rewritequery automatically from classpath by default, but namespaced from package
public class RewriteHandler{
//implements BeanInjectable {
private static Logger jlog = LoggerFactory.getLogger(RewriteHandler.class);
private Collection<RewriteTask.IterableRewritePath> node_processors;
private Collection<RewriteTask.RewriteKoralToken> token_node_processors;
private Collection<RewriteTask> query_processors;
private Set<Class> failed_task_registration;
@Autowired
private KustvaktConfiguration config;
private ContextHolder beans;
public RewriteHandler (KustvaktConfiguration config) {
this();
this.config = config;
}
public RewriteHandler () {
this.node_processors = new HashSet<>();
this.token_node_processors = new HashSet<>();
this.query_processors = new HashSet<>();
this.failed_task_registration = new HashSet<>();
this.beans = null;
this.add(FoundryInject.class);
}
public Set getFailedProcessors () {
return this.failed_task_registration;
}
public boolean addProcessor (RewriteTask rewriter) {
if (rewriter instanceof RewriteTask.RewriteKoralToken)
return this.token_node_processors
.add((RewriteTask.RewriteKoralToken) rewriter);
else if (rewriter instanceof RewriteTask.IterableRewritePath)
return this.node_processors
.add((RewriteTask.IterableRewritePath) rewriter);
else if (rewriter instanceof RewriteTask.RewriteQuery
| rewriter instanceof RewriteTask.RewriteResult)
return this.query_processors.add(rewriter);
this.failed_task_registration.add(rewriter.getClass());
return false;
}
@Override
public String toString () {
StringBuilder b = new StringBuilder();
b.append("--------------------------");
b.append("pre/post: " + this.node_processors.toString()).append("\n")
.append("\n")
.append("query: " + this.query_processors.toString())
.append("\n")
.append("koraltoken: " + this.token_node_processors.toString());
b.append("---------------------------");
return b.toString();
}
/**
* expects extended RewriteNode/Query class with empty default
* constructor
*
* @param rewriter
* @return boolean if rewriter class was successfully added to
* rewrite handler!
*/
public boolean add (Class<? extends RewriteTask> rewriter) {
RewriteTask task;
try {
Constructor c = rewriter.getConstructor();
task = (RewriteTask) c.newInstance();
}
catch (NoSuchMethodException | InvocationTargetException
| IllegalAccessException | InstantiationException e) {
this.failed_task_registration.add(rewriter);
return false;
}
return addProcessor(task);
}
public String processQuery (JsonNode root, User user)
throws KustvaktException {
RewriteProcess process = new RewriteProcess(root, user);
JsonNode pre = process.start(false);
return JsonUtils.toJSON(pre);
}
public String processQuery (String json, User user)
throws KustvaktException {
return processQuery(JsonUtils.readTree(json), user);
}
public String processResult (String json, User user)
throws KustvaktException {
return processResult(JsonUtils.readTree(json), user);
}
public String processResult (JsonNode node, User user)
throws KustvaktException {
RewriteProcess process = new RewriteProcess(node, user);
JsonNode pre = process.start(true);
return JsonUtils.toJSON(pre);
}
public void clear () {
this.node_processors.clear();
this.query_processors.clear();
this.token_node_processors.clear();
}
public <T extends ContextHolder> void insertBeans (T beans) {
this.beans = beans;
this.config = beans.getConfiguration();
}
public class RewriteProcess {
private JsonNode root;
private User user;
private RewriteProcess (JsonNode root, User user) {
this.root = root;
this.user = user;
}
private KoralNode processNode (String key, JsonNode value,
boolean result) throws KustvaktException {
KoralNode kroot = KoralNode.wrapNode(value);
if (value.isObject()) {
if (value.has("operands")) {
JsonNode ops = value.at("/operands");
Iterator<JsonNode> it = ops.elements();
while (it.hasNext()) {
JsonNode next = it.next();
KoralNode kn = processNode(key, next, result);
if (kn.isRemove())
it.remove();
}
}
else if (value.path("@type").asText().equals("koral:token")) {
// todo: koral:token nodes cannot be flagged for deletion --> creates the possibility for empty koral:token nodes
rewrite(key, kroot,
RewriteHandler.this.token_node_processors, result);
return processNode(key, value.path("wrap"), result);
}
else {
return rewrite(key, kroot,
RewriteHandler.this.node_processors, result);
}
}
else if (value.isArray()) {
Iterator<JsonNode> it = value.elements();
while (it.hasNext()) {
JsonNode next = it.next();
KoralNode kn = processNode(key, next, result);
if (kn.isRemove())
it.remove();
}
}
return kroot;
}
private JsonNode start (boolean result) throws KustvaktException {
jlog.debug("Running rewrite process on query {}", root);
if (root != null) {
Iterator<Map.Entry<String, JsonNode>> it = root.fields();
while (it.hasNext()) {
Map.Entry<String, JsonNode> next = it.next();
processNode(next.getKey(), next.getValue(), result);
}
processFixedNode(root, RewriteHandler.this.query_processors,
result);
}
return root;
}
/**
* @param node
* @param tasks
* @return boolean true if node is to be removed from parent!
* Only
* applies if parent is an array node
*/
private KoralNode rewrite (String rootNode, KoralNode node,
Collection<? extends RewriteTask> tasks, boolean result)
throws KustvaktException {
if (RewriteHandler.this.config == null)
throw new RuntimeException("KustvaktConfiguration must be set!");
for (RewriteTask task : tasks) {
jlog.debug("running processor on node: " + node);
jlog.debug("on processor: " + task.getClass().toString());
if (RewriteHandler.this.beans != null
&& task instanceof BeanInjectable)
((BeanInjectable) task)
.insertBeans(RewriteHandler.this.beans);
if (task instanceof RewriteTask.IterableRewritePath) {
RewriteTask.IterableRewritePath rw = (RewriteTask.IterableRewritePath) task;
if (rw.path() != null && !rw.path().equals(rootNode)) {
jlog.debug("skipping node: " + node);
continue;
}
}
if (!result && task instanceof RewriteTask.RewriteQuery) {
((RewriteTask.RewriteQuery) task).rewriteQuery(node,
RewriteHandler.this.config, this.user);
}
else if (task instanceof RewriteTask.RewriteResult) {
((RewriteTask.RewriteResult) task).rewriteResult(node);
}
if (node.isRemove()) {
node.buildRewrites(this.root.at("/" + rootNode));
break;
}
else
node.buildRewrites();
}
return node;
}
// fixme: merge with processNode!
private void processFixedNode (JsonNode node,
Collection<RewriteTask> tasks, boolean post)
throws KustvaktException {
for (RewriteTask task : tasks) {
KoralNode next = KoralNode.wrapNode(node);
if (task instanceof RewriteTask.RewriteNodeAt) {
RewriteTask.RewriteNodeAt rwa = (RewriteTask.RewriteNodeAt) task;
if ((rwa.at() != null && !node.at(rwa.at()).isMissingNode()))
next = next.at(rwa.at());
}
if (!post & task instanceof RewriteTask.RewriteQuery)
((RewriteTask.RewriteQuery) task).rewriteQuery(next,
RewriteHandler.this.config, user);
else if (task instanceof RewriteTask.RewriteResult)
((RewriteTask.RewriteResult) task).rewriteResult(next);
next.buildRewrites();
}
}
}
}