higher performance implementation for rewrite handler, test suite for rest functions, fast jersey junit tester, rewrite test suite
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionCleanupFilter.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionCleanupFilter.java
new file mode 100644
index 0000000..93db8ae
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionCleanupFilter.java
@@ -0,0 +1,79 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+import java.util.Iterator;
+
+/**
+ * @author hanl
+ * @date 28/07/2015
+ */
+//todo: test
+public class CollectionCleanupFilter extends RewriteQuery {
+
+ // track path to operand
+ private StringBuilder builder;
+
+ public CollectionCleanupFilter() {
+ this.builder = new StringBuilder();
+ }
+
+ @Override
+ public JsonNode rewrite(KoralNode node) {
+ if (node.rawNode().has("collection")) {
+ JsonNode coll = node.rawNode().path("collection");
+ process(coll);
+ }
+ return null;
+ }
+
+ private JsonNode process(JsonNode root) {
+ if (root.isObject()) {
+ if (root.has("operands")) {
+ JsonNode node = root.at("/operands");
+ Iterator<JsonNode> it = node.elements();
+ while (it.hasNext()) {
+ JsonNode n = it.next();
+ JsonNode s = process(n);
+ if (s == null)
+ it.remove();
+ }
+ }
+
+ JsonNode sub = processNodes(root);
+ if (!root.equals(sub)) {
+ if (sub == null) {
+ //can't do anything here -- fixme: edge case?!
+ return null;
+ }else if (sub.isObject()) {
+ ObjectNode ob = (ObjectNode) root;
+ ob.removeAll();
+ ob.putAll((ObjectNode) sub);
+ }
+
+ }
+ }
+ return root;
+ }
+
+ // return null deletes node, if node return replace at level -1
+ private JsonNode processNodes(JsonNode jsonNode) {
+ if (jsonNode.isObject()) {
+ if (jsonNode.has("operands")) {
+ JsonNode node = jsonNode.at("/operands");
+ int count = node.size();
+ if (count == 1) {
+ // move to super node if any
+ return node.path(0);
+ }else if (count == 0) {
+ // remove container
+ return null;
+ }
+ return jsonNode;
+ }
+ }
+ return JsonUtils.createArrayNode();
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionConstraint.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionConstraint.java
new file mode 100644
index 0000000..a4cf771
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionConstraint.java
@@ -0,0 +1,29 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import de.ids_mannheim.korap.user.User;
+
+/**
+ * @author hanl
+ * @date 03/07/2015
+ */
+public class CollectionConstraint extends RewriteNode {
+
+ @Override
+ public JsonNode rewrite(KoralNode koralnode) {
+ JsonNode node = koralnode.rawNode();
+ if (node.at("/@type").asText().equals("koral:doc")) {
+ if (node.at("/key").asText().equals("corpusID") && !check(node,
+ koralnode.getUser())) {
+ koralnode.removeNode();
+ // todo: add message that node was removed!
+ }
+ }
+ return node;
+ }
+
+ private boolean check(JsonNode node, User user) {
+ return false;
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
new file mode 100644
index 0000000..58e3ff2
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/FoundryInject.java
@@ -0,0 +1,39 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import de.ids_mannheim.korap.config.KustvaktConfiguration;
+import de.ids_mannheim.korap.resource.LayerMapper;
+
+/**
+ * @author hanl
+ * @date 30/06/2015
+ */
+public class FoundryInject extends RewriteNode {
+
+ private KustvaktConfiguration config;
+
+ public FoundryInject(KustvaktConfiguration config) {
+ this.config = config;
+ }
+
+ @Override
+ public JsonNode rewrite(KoralNode node) {
+ LayerMapper mapper;
+ if (node.hasUser())
+ mapper = new LayerMapper(config, node.getUser().getSettings());
+ else
+ mapper = new LayerMapper(config);
+
+ if (node.rawNode().path("@type").asText().equals("koral:term") && !node
+ .rawNode().has("foundry")) {
+ String layer;
+ if (node.rawNode().has("layer"))
+ layer = node.rawNode().path("layer").asText();
+ else
+ layer = node.rawNode().path("key").asText();
+ String foundry = mapper.findFoundry(layer);
+ node.set("foundry", foundry);
+ }
+ return node.rawNode();
+ }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/KoralNode.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/KoralNode.java
new file mode 100644
index 0000000..e708504
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/KoralNode.java
@@ -0,0 +1,145 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author hanl
+ * @date 04/07/2015
+ */
+public abstract class KoralNode {
+ private JsonNode node;
+ private KoralRewriteBuilder builder;
+ private boolean toRemove;
+ private final User user;
+
+ private KoralNode(JsonNode node) {
+ this(node, null);
+ }
+
+ public KoralNode(JsonNode node, User user) {
+ this.node = node;
+ this.builder = new KoralRewriteBuilder();
+ this.toRemove = false;
+ this.user = user;
+ }
+
+ public boolean hasUser() {
+ return this.user != null;
+ }
+
+ public User getUser() {
+ return this.user;
+ }
+
+ public static KoralNode getNode(JsonNode node) {
+ return new KoralNode(node) {
+ };
+ }
+
+ public void set(String name, Object value) {
+
+ if (this.node.isObject()) {
+ ObjectNode node = (ObjectNode) this.node;
+ if (value instanceof String)
+ node.put(name, (String) value);
+ else if (value instanceof Integer)
+ node.put(name, (Integer) value);
+ builder.setOperation("injection");
+ builder.build(this.node);
+ }else
+ throw new UnsupportedOperationException(
+ "node doesn't support this operation");
+ }
+
+ public void remove(Object identifier) {
+ boolean set = false;
+ if (this.node.isObject() && identifier instanceof String) {
+ ObjectNode n = (ObjectNode) this.node;
+ n.remove((String) identifier);
+ set = true;
+ }else if (this.node.isArray() && identifier instanceof Integer) {
+ ArrayNode n = (ArrayNode) this.node;
+ n.remove((Integer) identifier);
+ set = true;
+ }
+ if (set) {
+ builder.setOperation("deletion");
+ builder.build(this.node);
+ }
+ }
+
+ public void replace(String name, String value) {
+ if (this.node.isObject() && this.node.has(name)) {
+ ObjectNode n = (ObjectNode) this.node;
+ n.put(name, value);
+ builder.setOperation("override");
+ builder.build(this.node);
+ }
+ }
+
+ public JsonNode rawNode() {
+ return this.node;
+ }
+
+ public void removeNode() {
+ this.toRemove = true;
+ }
+
+ public boolean toRemove() {
+ return this.toRemove;
+ }
+
+ private static class KoralRewriteBuilder {
+
+ private Map<String, String> map;
+
+ public KoralRewriteBuilder() {
+ this.map = new LinkedHashMap<>();
+ this.map.put("@type", "koral:rewrite");
+ this.map.put("src", "Kustvakt");
+ }
+
+ public KoralRewriteBuilder setOperation(String op) {
+ if (!op.startsWith("operation:"))
+ op = "operation:" + op;
+ this.map.put("operation", op);
+ return this;
+ }
+
+ public KoralRewriteBuilder setScope(String scope) {
+ this.map.put("scope", scope);
+ return this;
+ }
+
+ public JsonNode build(JsonNode node) {
+ if (this.map.get("operation") == null)
+ throw new UnsupportedOperationException(
+ "operation not set properly");
+
+ if (node.has("rewrites")) {
+ ArrayNode n = (ArrayNode) node.path("rewrites");
+ n.add(JsonUtils.valueToTree(this.map));
+ }else {
+ ObjectNode n = (ObjectNode) node;
+ List l = new LinkedList<>();
+ l.add(JsonUtils.valueToTree(this.map));
+ n.put("rewrites", JsonUtils.valueToTree(l));
+ }
+ return node;
+ }
+
+ }
+}
+
+
+
+
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
new file mode 100644
index 0000000..5676817
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
@@ -0,0 +1,87 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.utils.KustvaktLogger;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * @author hanl
+ * @date 30/06/2015
+ */
+//todo: load rewritenode and rewritequery automatically from classpath, but namespaced from package
+public class RewriteHandler {
+
+ private static Logger jlog = KustvaktLogger.initiate(RewriteHandler.class);
+ private Collection<RewriteNode> node_processors;
+ private Collection<RewriteQuery> query_processors;
+
+ public RewriteHandler() {
+ this.node_processors = new HashSet<>();
+ this.query_processors = new HashSet<>();
+ // add defaults?!
+ }
+
+ public void add(RewriteNode node) {
+ this.node_processors.add(node);
+ }
+
+ public void add(RewriteQuery node) {
+ this.query_processors.add(node);
+ }
+
+ public void clear() {
+ this.node_processors.clear();
+ this.query_processors.clear();
+ }
+
+ private boolean process(JsonNode root, User user) {
+ if (root.isObject()) {
+ if (root.has("operands")) {
+ JsonNode node = root.at("/operands");
+ Iterator<JsonNode> it = node.elements();
+ while (it.hasNext()) {
+ JsonNode n = it.next();
+ if (!process(n, user))
+ it.remove();
+ }
+ }else if (root.has("wrap")) {
+ JsonNode node = root.at("/wrap");
+ //todo: remove object nodes as well
+ process(node, user);
+ }else
+ return processNode(root, user, this.node_processors);
+ }
+ return true;
+ }
+
+ public JsonNode apply(JsonNode root, User user) {
+ for (JsonNode n : root)
+ process(n, user);
+ processNode(root, user, this.query_processors);
+ return root;
+ }
+
+ public String apply(String json, User user) {
+ return JsonUtils.toJSON(apply(JsonUtils.readTree(json), user));
+ }
+
+ private static boolean processNode(JsonNode node, User user,
+ Collection<? extends RewriteTask> tasks) {
+ KoralNode knode = KoralNode.getNode(node);
+ for (RewriteTask task : tasks) {
+ jlog.debug("running node in processor " + node);
+ jlog.debug("on processor " + task.getClass().toString());
+ task.rewrite(knode);
+ if (knode.toRemove())
+ break;
+ }
+ return !knode.toRemove();
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteNode.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteNode.java
new file mode 100644
index 0000000..cb0a06c
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteNode.java
@@ -0,0 +1,20 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+/**
+ * node rewrites get injected typically object nodes that are subject to altering.
+ * Be aware that node rewrites are processed before query rewrites. Thus query rewrite may override previous node rewrites
+ *
+ * {@link de.ids_mannheim.korap.resource.rewrite.RewriteNode} rewrite support the deletion of the respective node by simply setting the node invalid in KoralNode
+ *
+ * @author hanl
+ * @date 03/07/2015
+ */
+public abstract class RewriteNode extends RewriteTask {
+
+ public RewriteNode() {
+ super();
+ }
+
+
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteQuery.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteQuery.java
new file mode 100644
index 0000000..99bfb34
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteQuery.java
@@ -0,0 +1,18 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+/**
+ * query rewrites get injected the entire query from root containing all child nodes
+ * <p/>
+ * {@link de.ids_mannheim.korap.resource.rewrite.RewriteQuery} does not allow the deletion of the root node or subnode through KoralNode.
+ * The {@link de.ids_mannheim.korap.resource.rewrite.RewriteHandler} will igonore respecitve invalid requests
+ *
+ * @author hanl
+ * @date 03/07/2015
+ */
+public abstract class RewriteQuery extends RewriteTask {
+
+ public RewriteQuery() {
+ super();
+ }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteTask.java b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteTask.java
new file mode 100644
index 0000000..ed5ad34
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteTask.java
@@ -0,0 +1,17 @@
+package de.ids_mannheim.korap.resource.rewrite;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import lombok.Getter;
+
+/**
+ * @author hanl
+ * @date 30/06/2015
+ */
+@Getter
+public abstract class RewriteTask {
+
+ protected RewriteTask() {
+ }
+
+ public abstract JsonNode rewrite(KoralNode node);
+}