blob: b16d65c9c9b870aa17210c5d84d559797d05e826 [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 Hanlbcb48c72015-11-17 22:11:05 +010025 private Collection<RewriteTask> query_processors;
Michael Hanl022543e2015-11-17 21:25:25 +010026
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.IterableRewriteAt)
48 return this.node_processors
49 .add((RewriteTask.IterableRewriteAt) rewriter);
Michael Hanlbcb48c72015-11-17 22:11:05 +010050 else if (rewriter instanceof RewriteTask.RewriteBefore
51 | rewriter instanceof RewriteTask.RewriteAfter)
52 return this.query_processors.add(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 Hanlbcb48c72015-11-17 22:11:05 +0100124 processNode(name, KoralNode.wrapNode(root), user,
Michael Hanl4b42baa2015-11-17 21:46:04 +0100125 this.token_node_processors, post);
Michael Hanl022543e2015-11-17 21:25:25 +0100126 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 Hanl4b42baa2015-11-17 21:46:04 +0100142 private JsonNode process(JsonNode root, User user, boolean post) {
Michael Hanl022543e2015-11-17 21:25:25 +0100143 Iterator<Map.Entry<String, JsonNode>> it = root.fields();
144 while (it.hasNext()) {
145 Map.Entry<String, JsonNode> next = it.next();
146 process(next.getKey(), next.getValue(), user, post);
147 }
148 processFixedNode(root, user, this.query_processors, post);
Michael Hanl1e18cb42015-08-06 20:57:35 +0200149 return root;
150 }
151
Michael Hanl4b42baa2015-11-17 21:46:04 +0100152 public JsonNode preProcess(JsonNode root, User user) {
153 return process(root, user, false);
154 }
155
Michael Hanlf0785322015-11-13 16:14:45 +0100156 public String preProcess(String json, User user) {
157 return JsonUtils.toJSON(preProcess(JsonUtils.readTree(json), user));
Michael Hanl1e18cb42015-08-06 20:57:35 +0200158 }
159
Michael Hanlf0785322015-11-13 16:14:45 +0100160 public JsonNode postProcess(JsonNode root, User user) {
Michael Hanl4b42baa2015-11-17 21:46:04 +0100161 return process(root, user, true);
Michael Hanlf0785322015-11-13 16:14:45 +0100162 }
163
164 public String postProcess(String json, User user) {
165 return JsonUtils.toJSON(postProcess(JsonUtils.readTree(json), user));
166 }
167
168 /**
169 * @param node
170 * @param user
171 * @param tasks
172 * @return boolean true if node is to be removed from parent! Only applies if parent is an array node
173 */
Michael Hanl59bff812015-10-27 23:10:32 +0100174 // todo: integrate notifications into system!
Michael Hanl022543e2015-11-17 21:25:25 +0100175 private boolean processNode(String rootNode, KoralNode node, User user,
Michael Hanl4b42baa2015-11-17 21:46:04 +0100176 Collection<? extends RewriteTask> tasks, boolean post) {
Michael Hanl1e18cb42015-08-06 20:57:35 +0200177 for (RewriteTask task : tasks) {
Michael Hanl022543e2015-11-17 21:25:25 +0100178 jlog.debug("running processor on node: " + node);
179 jlog.debug("on processor: " + task.getClass().toString());
180
181 if (task instanceof RewriteTask.IterableRewriteAt) {
182 RewriteTask.IterableRewriteAt rw = (RewriteTask.IterableRewriteAt) task;
183 if (rw.path() != null && !rw.path().equals(rootNode)) {
184 jlog.debug("skipping node: " + node);
185 continue;
186 }
Michael Hanlac4962c2015-09-21 22:21:05 +0200187 }
Michael Hanl022543e2015-11-17 21:25:25 +0100188
189 if (!post && task instanceof RewriteTask.RewriteBefore)
Michael Hanlf0785322015-11-13 16:14:45 +0100190 ((RewriteTask.RewriteBefore) task)
191 .preProcess(node, this.config, user);
Michael Hanl022543e2015-11-17 21:25:25 +0100192 else if (task instanceof RewriteTask.RewriteAfter)
Michael Hanlf0785322015-11-13 16:14:45 +0100193 ((RewriteTask.RewriteAfter) task).postProcess(node);
Michael Hanl022543e2015-11-17 21:25:25 +0100194
Michael Hanl2760cc42015-11-16 19:30:01 +0100195 if (node.isRemove())
Michael Hanl1e18cb42015-08-06 20:57:35 +0200196 break;
197 }
Michael Hanl2760cc42015-11-16 19:30:01 +0100198 return node.isRemove();
Michael Hanl1e18cb42015-08-06 20:57:35 +0200199 }
200
Michael Hanl022543e2015-11-17 21:25:25 +0100201 private void processFixedNode(JsonNode node, User user,
Michael Hanlbcb48c72015-11-17 22:11:05 +0100202 Collection<RewriteTask> tasks, boolean post) {
203 for (RewriteTask task : tasks) {
Michael Hanl4b42baa2015-11-17 21:46:04 +0100204 JsonNode next = node;
Michael Hanlbcb48c72015-11-17 22:11:05 +0100205 if (task instanceof RewriteTask.RewriteNodeAt) {
206 RewriteTask.RewriteNodeAt rwa = (RewriteTask.RewriteNodeAt) task;
207 if ((rwa.at() != null && !node.at(rwa.at()).isMissingNode()))
208 next = node.at(rwa.at());
209 }
Michael Hanl4b42baa2015-11-17 21:46:04 +0100210
Michael Hanlbcb48c72015-11-17 22:11:05 +0100211 if (!post && task instanceof RewriteTask.RewriteBefore)
212 ((RewriteTask.RewriteBefore) task)
213 .preProcess(KoralNode.wrapNode(next), this.config,
214 user);
Michael Hanl4b42baa2015-11-17 21:46:04 +0100215 else
Michael Hanlbcb48c72015-11-17 22:11:05 +0100216 ((RewriteTask.RewriteAfter) task)
217 .postProcess(KoralNode.wrapNode(next));
Michael Hanl022543e2015-11-17 21:25:25 +0100218 }
219 }
220
Michael Hanl1e18cb42015-08-06 20:57:35 +0200221}