blob: dc74cabfd9129824df73fcd744c1b81e52db4a0e [file] [log] [blame]
Michael Hanl1e18cb42015-08-06 20:57:35 +02001package de.ids_mannheim.korap.resource.rewrite;
2
3import com.fasterxml.jackson.databind.JsonNode;
Michael Hanl59bff812015-10-27 23:10:32 +01004import de.ids_mannheim.korap.config.KustvaktConfiguration;
Michael Hanl1e18cb42015-08-06 20:57:35 +02005import de.ids_mannheim.korap.user.User;
6import de.ids_mannheim.korap.utils.JsonUtils;
7import de.ids_mannheim.korap.utils.KustvaktLogger;
8import org.slf4j.Logger;
9
Michael Hanl59bff812015-10-27 23:10:32 +010010import java.lang.reflect.Constructor;
11import java.lang.reflect.InvocationTargetException;
Michael Hanl022543e2015-11-17 21:25:25 +010012import java.util.*;
Michael Hanl1e18cb42015-08-06 20:57:35 +020013
14/**
15 * @author hanl
16 * @date 30/06/2015
17 */
Michael Hanlf0785322015-11-13 16:14:45 +010018// todo: do post processing!
Michael Hanlf21773f2015-10-16 23:02:31 +020019//todo: load rewritenode and rewritequery automatically from classpath by default, but namespaced from package
Michael Hanl1e18cb42015-08-06 20:57:35 +020020public class RewriteHandler {
21
Michael Hanlf0785322015-11-13 16:14:45 +010022 private static Logger jlog = KustvaktLogger.getLogger(RewriteHandler.class);
Michael Hanl022543e2015-11-17 21:25:25 +010023 private Collection<RewriteTask.IterableRewriteAt> node_processors;
Michael Hanlf0785322015-11-13 16:14:45 +010024 private Collection<RewriteTask.RewriteKoralToken> token_node_processors;
Michael Hanl022543e2015-11-17 21:25:25 +010025 private Collection<RewriteTask.RewriteNodeAt> query_processors;
26
27 // private Collection<RewriteTask.RewriteNode2> fixed_nodes;
28 // private Collection<RewriteTask.IterableRewrite> iterable_nodes;
Michael Hanlf0785322015-11-13 16:14:45 +010029
Michael Hanl2760cc42015-11-16 19:30:01 +010030 private Set<Class> failed_task_registration;
31
Michael Hanl59bff812015-10-27 23:10:32 +010032 private KustvaktConfiguration config;
Michael Hanl1e18cb42015-08-06 20:57:35 +020033
Michael Hanl59bff812015-10-27 23:10:32 +010034 // fixme: make default constructor with configuration!
35 public RewriteHandler(KustvaktConfiguration config) {
36 this.config = config;
Michael Hanl1e18cb42015-08-06 20:57:35 +020037 this.node_processors = new HashSet<>();
Michael Hanlf0785322015-11-13 16:14:45 +010038 this.token_node_processors = new HashSet<>();
Michael Hanl1e18cb42015-08-06 20:57:35 +020039 this.query_processors = new HashSet<>();
Michael Hanl2760cc42015-11-16 19:30:01 +010040 this.failed_task_registration = new HashSet<>();
Michael Hanl1e18cb42015-08-06 20:57:35 +020041 }
42
Michael Hanlf0785322015-11-13 16:14:45 +010043 public boolean addProcessor(RewriteTask rewriter) {
44 if (rewriter instanceof RewriteTask.RewriteKoralToken)
45 return this.token_node_processors
46 .add((RewriteTask.RewriteKoralToken) rewriter);
Michael Hanl022543e2015-11-17 21:25:25 +010047 else if (rewriter instanceof RewriteTask.RewriteNodeAt)
Michael Hanlf0785322015-11-13 16:14:45 +010048 return this.query_processors
Michael Hanl022543e2015-11-17 21:25:25 +010049 .add((RewriteTask.RewriteNodeAt) rewriter);
50 else if (rewriter instanceof RewriteTask.IterableRewriteAt)
51 return this.node_processors
52 .add((RewriteTask.IterableRewriteAt) rewriter);
Michael Hanl2760cc42015-11-16 19:30:01 +010053
54 this.failed_task_registration.add(rewriter.getClass());
Michael Hanlf0785322015-11-13 16:14:45 +010055 return false;
Michael Hanl1e18cb42015-08-06 20:57:35 +020056 }
57
Michael Hanl022543e2015-11-17 21:25:25 +010058 public boolean addProcessor2(RewriteTask rewriteTask) {
59 // if (rewriteTask instanceof RewriteTask.RewriteNode2)
60 // return this.fixed_nodes.add((RewriteTask.RewriteNode2) rewriteTask);
61 // else if (rewriteTask instanceof RewriteTask.IterableRewrite)
62 // return this.iterable_nodes
63 // .add((RewriteTask.IterableRewrite) rewriteTask);
64 // else if (rewriteTask instanceof RewriteTask.RewriteBefore)
65 // gets the entire pre processed query injected.
66 return false;
67 }
68
Michael Hanl2760cc42015-11-16 19:30:01 +010069 public final Collection<Class> getFailedHandlers() {
70 return this.failed_task_registration;
71 }
72
Michael Hanlf0785322015-11-13 16:14:45 +010073 @Override
74 public String toString() {
75 StringBuilder b = new StringBuilder();
76 b.append("--------------------------");
77 b.append("pre/post: " + this.node_processors.toString()).append("\n")
78 .append("\n")
79 .append("query: " + this.query_processors.toString())
80 .append("\n")
81 .append("koraltoken: " + this.token_node_processors.toString());
82 b.append("---------------------------");
83 return b.toString();
Michael Hanl59bff812015-10-27 23:10:32 +010084 }
85
86 /**
Michael Hanlf0785322015-11-13 16:14:45 +010087 * expects extended RewriteNode/Query class with empty default constructor
Michael Hanl59bff812015-10-27 23:10:32 +010088 *
89 * @param rewriter
Michael Hanlf0785322015-11-13 16:14:45 +010090 * @return boolean if rewriter class was successfully added to rewrite handler!
Michael Hanl59bff812015-10-27 23:10:32 +010091 */
Michael Hanl59bff812015-10-27 23:10:32 +010092 public boolean add(Class<? extends RewriteTask> rewriter) {
93 RewriteTask task;
94 try {
95 Constructor c = rewriter.getConstructor();
96 task = (RewriteTask) c.newInstance();
97 }catch (NoSuchMethodException | InvocationTargetException
98 | IllegalAccessException | InstantiationException e) {
Michael Hanl2760cc42015-11-16 19:30:01 +010099 this.failed_task_registration.add(rewriter);
Michael Hanl59bff812015-10-27 23:10:32 +0100100 return false;
101 }
Michael Hanlf0785322015-11-13 16:14:45 +0100102 return addProcessor(task);
Michael Hanl1e18cb42015-08-06 20:57:35 +0200103 }
104
105 public void clear() {
106 this.node_processors.clear();
107 this.query_processors.clear();
Michael Hanlf0785322015-11-13 16:14:45 +0100108 this.token_node_processors.clear();
Michael Hanl1e18cb42015-08-06 20:57:35 +0200109 }
110
Michael Hanl022543e2015-11-17 21:25:25 +0100111 private boolean process(String name, JsonNode root, User user,
112 boolean post) {
Michael Hanl1e18cb42015-08-06 20:57:35 +0200113 if (root.isObject()) {
114 if (root.has("operands")) {
Michael Hanlf0785322015-11-13 16:14:45 +0100115 JsonNode ops = root.at("/operands");
116 Iterator<JsonNode> it = ops.elements();
Michael Hanl1e18cb42015-08-06 20:57:35 +0200117 while (it.hasNext()) {
Michael Hanl022543e2015-11-17 21:25:25 +0100118 JsonNode next = it.next();
119 if (process(name, next, user, post))
Michael Hanl1e18cb42015-08-06 20:57:35 +0200120 it.remove();
121 }
Michael Hanlf0785322015-11-13 16:14:45 +0100122 }else if (root.path("@type").asText().equals("koral:token")) {
123 // todo: koral:token nodes cannot be flagged for deletion --> creates the possibility for empty koral:token nodes
Michael Hanl022543e2015-11-17 21:25:25 +0100124 // processIterableNode(KoralNode.wrapNode(root), user,
125 // this.token_node_processors, post);
126 return process(name, root.path("wrap"), user, post);
Michael Hanlf0785322015-11-13 16:14:45 +0100127 }else {
Michael Hanl022543e2015-11-17 21:25:25 +0100128 return processNode(name, KoralNode.wrapNode(root), user,
Michael Hanlf0785322015-11-13 16:14:45 +0100129 this.node_processors, post);
130 }
131 }else if (root.isArray()) {
Michael Hanlf0785322015-11-13 16:14:45 +0100132 Iterator<JsonNode> it = root.elements();
133 while (it.hasNext()) {
Michael Hanl022543e2015-11-17 21:25:25 +0100134 JsonNode next = it.next();
135 if (process(name, next, user, post))
Michael Hanlf0785322015-11-13 16:14:45 +0100136 it.remove();
Michael Hanlf0785322015-11-13 16:14:45 +0100137 }
Michael Hanl1e18cb42015-08-06 20:57:35 +0200138 }
Michael Hanlf0785322015-11-13 16:14:45 +0100139 return false;
Michael Hanl1e18cb42015-08-06 20:57:35 +0200140 }
141
Michael Hanlf0785322015-11-13 16:14:45 +0100142 public JsonNode preProcess(JsonNode root, User user) {
143 boolean post = false;
Michael Hanl022543e2015-11-17 21:25:25 +0100144 Iterator<Map.Entry<String, JsonNode>> it = root.fields();
145 while (it.hasNext()) {
146 Map.Entry<String, JsonNode> next = it.next();
147 process(next.getKey(), next.getValue(), user, post);
148 }
149 processFixedNode(root, user, this.query_processors, post);
Michael Hanl1e18cb42015-08-06 20:57:35 +0200150 return root;
151 }
152
Michael Hanlf0785322015-11-13 16:14:45 +0100153 public String preProcess(String json, User user) {
154 return JsonUtils.toJSON(preProcess(JsonUtils.readTree(json), user));
Michael Hanl1e18cb42015-08-06 20:57:35 +0200155 }
156
Michael Hanlf0785322015-11-13 16:14:45 +0100157 public JsonNode postProcess(JsonNode root, User user) {
158 boolean post = true;
Michael Hanl022543e2015-11-17 21:25:25 +0100159 Iterator<Map.Entry<String, JsonNode>> it = root.fields();
160 while (it.hasNext()) {
161 Map.Entry<String, JsonNode> next = it.next();
162 process(next.getKey(), next.getValue(), user, post);
163 }
164 processFixedNode(root, user, this.query_processors, post);
Michael Hanlf0785322015-11-13 16:14:45 +0100165 return root;
166 }
167
168 public String postProcess(String json, User user) {
169 return JsonUtils.toJSON(postProcess(JsonUtils.readTree(json), user));
170 }
171
172 /**
173 * @param node
174 * @param user
175 * @param tasks
176 * @return boolean true if node is to be removed from parent! Only applies if parent is an array node
177 */
Michael Hanl59bff812015-10-27 23:10:32 +0100178 // todo: integrate notifications into system!
Michael Hanl022543e2015-11-17 21:25:25 +0100179 private boolean processNode(String rootNode, KoralNode node, User user,
180 Collection<? extends RewriteTask.IterableRewriteAt> tasks,
181 boolean post) {
Michael Hanl1e18cb42015-08-06 20:57:35 +0200182 for (RewriteTask task : tasks) {
Michael Hanl022543e2015-11-17 21:25:25 +0100183 jlog.debug("running processor on node: " + node);
184 jlog.debug("on processor: " + task.getClass().toString());
185
186 if (task instanceof RewriteTask.IterableRewriteAt) {
187 RewriteTask.IterableRewriteAt rw = (RewriteTask.IterableRewriteAt) task;
188 if (rw.path() != null && !rw.path().equals(rootNode)) {
189 jlog.debug("skipping node: " + node);
190 continue;
191 }
Michael Hanlac4962c2015-09-21 22:21:05 +0200192 }
Michael Hanl022543e2015-11-17 21:25:25 +0100193
194 if (!post && task instanceof RewriteTask.RewriteBefore)
Michael Hanlf0785322015-11-13 16:14:45 +0100195 ((RewriteTask.RewriteBefore) task)
196 .preProcess(node, this.config, user);
Michael Hanl022543e2015-11-17 21:25:25 +0100197 else if (task instanceof RewriteTask.RewriteAfter)
Michael Hanlf0785322015-11-13 16:14:45 +0100198 ((RewriteTask.RewriteAfter) task).postProcess(node);
Michael Hanl022543e2015-11-17 21:25:25 +0100199
Michael Hanl2760cc42015-11-16 19:30:01 +0100200 if (node.isRemove())
Michael Hanl1e18cb42015-08-06 20:57:35 +0200201 break;
202 }
Michael Hanl2760cc42015-11-16 19:30:01 +0100203 return node.isRemove();
Michael Hanl1e18cb42015-08-06 20:57:35 +0200204 }
205
Michael Hanl022543e2015-11-17 21:25:25 +0100206 private void processFixedNode(JsonNode node, User user,
207 Collection<RewriteTask.RewriteNodeAt> tasks, boolean post) {
208 for (RewriteTask.RewriteNodeAt task : tasks) {
209 if (!node.at(task.at()).isMissingNode()) {
210 if (!post)
211 task.preProcess(KoralNode.wrapNode(node.at(task.at())),
212 this.config, user);
213 else
214 task.postProcess(KoralNode.wrapNode(node.at(task.at())));
215 }
216 }
217 }
218
Michael Hanl1e18cb42015-08-06 20:57:35 +0200219}