blob: 6bad856c490098c66310eebd6e5356db7e4049eb [file] [log] [blame]
margaretha398f4722019-01-09 19:07:20 +01001package de.ids_mannheim.korap.rewrite;
Michael Hanl1e18cb42015-08-06 20:57:35 +02002
margaretha56e8e552017-12-05 16:31:21 +01003import java.lang.reflect.Constructor;
4import java.lang.reflect.InvocationTargetException;
5import java.util.Collection;
6import java.util.HashSet;
7import java.util.Iterator;
margaretha563aabe2018-09-13 20:39:45 +02008import java.util.LinkedHashSet;
margaretha4fa4b062019-01-28 19:43:30 +01009import java.util.List;
margaretha56e8e552017-12-05 16:31:21 +010010import java.util.Map;
11import java.util.Set;
12
margaretha49cb6882018-07-04 04:19:54 +020013import org.apache.logging.log4j.LogManager;
14import org.apache.logging.log4j.Logger;
margaretha56e8e552017-12-05 16:31:21 +010015import org.springframework.beans.factory.annotation.Autowired;
16
Michael Hanl1e18cb42015-08-06 20:57:35 +020017import com.fasterxml.jackson.databind.JsonNode;
margaretha56e8e552017-12-05 16:31:21 +010018
Michael Hanl59bff812015-10-27 23:10:32 +010019import de.ids_mannheim.korap.config.KustvaktConfiguration;
Michael Hanl3a1dfe12016-02-17 11:26:07 +010020import de.ids_mannheim.korap.exceptions.KustvaktException;
Michael Hanl1e18cb42015-08-06 20:57:35 +020021import de.ids_mannheim.korap.user.User;
22import de.ids_mannheim.korap.utils.JsonUtils;
Michael Hanl1e18cb42015-08-06 20:57:35 +020023
24/**
25 * @author hanl
26 * @date 30/06/2015
27 */
Michael Hanlf0785322015-11-13 16:14:45 +010028// todo: do post processing!
Michael Hanlf21773f2015-10-16 23:02:31 +020029//todo: load rewritenode and rewritequery automatically from classpath by default, but namespaced from package
margaretha35e1ca22023-11-16 22:00:01 +010030public class RewriteHandler {
margarethaade7d4a2017-07-20 19:53:35 +020031 //implements BeanInjectable {
Michael Hanl1e18cb42015-08-06 20:57:35 +020032
margaretha49cb6882018-07-04 04:19:54 +020033 private static Logger jlog = LogManager.getLogger(RewriteHandler.class);
Michael Hanle56bb892016-05-25 17:34:41 +020034 private Collection<RewriteTask.IterableRewritePath> node_processors;
Michael Hanlf0785322015-11-13 16:14:45 +010035 private Collection<RewriteTask.RewriteKoralToken> token_node_processors;
Michael Hanlbcb48c72015-11-17 22:11:05 +010036 private Collection<RewriteTask> query_processors;
Michael Hanl022543e2015-11-17 21:25:25 +010037
Michael Hanl2760cc42015-11-16 19:30:01 +010038 private Set<Class> failed_task_registration;
margarethaade7d4a2017-07-20 19:53:35 +020039 @Autowired
Michael Hanl59bff812015-10-27 23:10:32 +010040 private KustvaktConfiguration config;
Michael Hanl1e18cb42015-08-06 20:57:35 +020041
margaretha4fa4b062019-01-28 19:43:30 +010042 public RewriteHandler (List<RewriteTask> rewriteTasks) {
43 this();
margaretha35e1ca22023-11-16 22:00:01 +010044 for (RewriteTask t : rewriteTasks) {
margaretha4fa4b062019-01-28 19:43:30 +010045 addProcessor(t);
46 }
47 }
margaretha35e1ca22023-11-16 22:00:01 +010048
margaretha4fa4b062019-01-28 19:43:30 +010049 // EM: for testing
Michael Hanl8abaf9e2016-05-23 16:46:35 +020050 public RewriteHandler (KustvaktConfiguration config) {
Michael Hanldaf86602016-05-12 14:31:52 +020051 this();
margaretha35e1ca22023-11-16 22:00:01 +010052 this.config = config;
Michael Hanldaf86602016-05-12 14:31:52 +020053 }
54
Michael Hanl8abaf9e2016-05-23 16:46:35 +020055 public RewriteHandler () {
Michael Hanl1e18cb42015-08-06 20:57:35 +020056 this.node_processors = new HashSet<>();
Michael Hanlf0785322015-11-13 16:14:45 +010057 this.token_node_processors = new HashSet<>();
margaretha563aabe2018-09-13 20:39:45 +020058 this.query_processors = new LinkedHashSet<>();
Michael Hanl2760cc42015-11-16 19:30:01 +010059 this.failed_task_registration = new HashSet<>();
Michael Hanldaf86602016-05-12 14:31:52 +020060 }
61
Michael Hanl8abaf9e2016-05-23 16:46:35 +020062 public Set getFailedProcessors () {
Michael Hanldaf86602016-05-12 14:31:52 +020063 return this.failed_task_registration;
Michael Hanl1e18cb42015-08-06 20:57:35 +020064 }
65
Michael Hanl8abaf9e2016-05-23 16:46:35 +020066 public boolean addProcessor (RewriteTask rewriter) {
Michael Hanlf0785322015-11-13 16:14:45 +010067 if (rewriter instanceof RewriteTask.RewriteKoralToken)
68 return this.token_node_processors
69 .add((RewriteTask.RewriteKoralToken) rewriter);
Michael Hanle56bb892016-05-25 17:34:41 +020070 else if (rewriter instanceof RewriteTask.IterableRewritePath)
Michael Hanl022543e2015-11-17 21:25:25 +010071 return this.node_processors
Michael Hanle56bb892016-05-25 17:34:41 +020072 .add((RewriteTask.IterableRewritePath) rewriter);
Michael Hanl33829ec2016-05-28 17:03:38 +020073 else if (rewriter instanceof RewriteTask.RewriteQuery
74 | rewriter instanceof RewriteTask.RewriteResult)
Michael Hanlbcb48c72015-11-17 22:11:05 +010075 return this.query_processors.add(rewriter);
Michael Hanl2760cc42015-11-16 19:30:01 +010076
77 this.failed_task_registration.add(rewriter.getClass());
Michael Hanlf0785322015-11-13 16:14:45 +010078 return false;
Michael Hanl1e18cb42015-08-06 20:57:35 +020079 }
80
Michael Hanlf0785322015-11-13 16:14:45 +010081 @Override
Michael Hanl8abaf9e2016-05-23 16:46:35 +020082 public String toString () {
Michael Hanlf0785322015-11-13 16:14:45 +010083 StringBuilder b = new StringBuilder();
84 b.append("--------------------------");
85 b.append("pre/post: " + this.node_processors.toString()).append("\n")
86 .append("\n")
87 .append("query: " + this.query_processors.toString())
88 .append("\n")
89 .append("koraltoken: " + this.token_node_processors.toString());
90 b.append("---------------------------");
91 return b.toString();
Michael Hanl59bff812015-10-27 23:10:32 +010092 }
93
94 /**
Michael Hanl8abaf9e2016-05-23 16:46:35 +020095 * expects extended RewriteNode/Query class with empty default
96 * constructor
97 *
Michael Hanl59bff812015-10-27 23:10:32 +010098 * @param rewriter
Michael Hanl8abaf9e2016-05-23 16:46:35 +020099 * @return boolean if rewriter class was successfully added to
100 * rewrite handler!
Michael Hanl59bff812015-10-27 23:10:32 +0100101 */
margaretha4fa4b062019-01-28 19:43:30 +0100102 @Deprecated
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200103 public boolean add (Class<? extends RewriteTask> rewriter) {
Michael Hanl59bff812015-10-27 23:10:32 +0100104 RewriteTask task;
105 try {
106 Constructor c = rewriter.getConstructor();
107 task = (RewriteTask) c.newInstance();
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200108 }
109 catch (NoSuchMethodException | InvocationTargetException
Michael Hanl59bff812015-10-27 23:10:32 +0100110 | IllegalAccessException | InstantiationException e) {
Michael Hanl2760cc42015-11-16 19:30:01 +0100111 this.failed_task_registration.add(rewriter);
Michael Hanl59bff812015-10-27 23:10:32 +0100112 return false;
113 }
Michael Hanlf0785322015-11-13 16:14:45 +0100114 return addProcessor(task);
Michael Hanl1e18cb42015-08-06 20:57:35 +0200115 }
116
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200117 public String processQuery (JsonNode root, User user)
118 throws KustvaktException {
Michael Hanl86d598e2016-05-26 15:13:00 +0200119 RewriteProcess process = new RewriteProcess(root, user);
120 JsonNode pre = process.start(false);
Michael Hanlcedf7212016-05-28 10:43:09 +0200121 return JsonUtils.toJSON(pre);
Michael Hanl4b42baa2015-11-17 21:46:04 +0100122 }
123
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200124 public String processQuery (String json, User user)
125 throws KustvaktException {
Michael Hanl33829ec2016-05-28 17:03:38 +0200126 return processQuery(JsonUtils.readTree(json), user);
Michael Hanlf0785322015-11-13 16:14:45 +0100127 }
128
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200129 public String processResult (String json, User user)
130 throws KustvaktException {
Michael Hanl33829ec2016-05-28 17:03:38 +0200131 return processResult(JsonUtils.readTree(json), user);
132 }
133
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200134 public String processResult (JsonNode node, User user)
135 throws KustvaktException {
Michael Hanl33829ec2016-05-28 17:03:38 +0200136 RewriteProcess process = new RewriteProcess(node, user);
137 JsonNode pre = process.start(true);
138 return JsonUtils.toJSON(pre);
139 }
140
Michael Hanl86d598e2016-05-26 15:13:00 +0200141 public void clear () {
142 this.node_processors.clear();
143 this.query_processors.clear();
144 this.token_node_processors.clear();
Michael Hanl022543e2015-11-17 21:25:25 +0100145 }
146
margaretha35e1ca22023-11-16 22:00:01 +0100147 // public <T extends ContextHolder> void insertBeans (T beans) {
148 // this.beans = beans;
149 // this.config = beans.getConfiguration();
150 // }
Michael Hanl86d598e2016-05-26 15:13:00 +0200151
152 public class RewriteProcess {
153
margarethaa85965d2018-12-19 15:58:21 +0100154 private static final boolean DEBUG = false;
Michael Hanl86d598e2016-05-26 15:13:00 +0200155 private JsonNode root;
156 private User user;
157
Michael Hanl33829ec2016-05-28 17:03:38 +0200158 private RewriteProcess (JsonNode root, User user) {
Michael Hanl86d598e2016-05-26 15:13:00 +0200159 this.root = root;
160 this.user = user;
161 }
162
Michael Hanl33829ec2016-05-28 17:03:38 +0200163 private KoralNode processNode (String key, JsonNode value,
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200164 boolean result) throws KustvaktException {
Michael Hanl86d598e2016-05-26 15:13:00 +0200165 KoralNode kroot = KoralNode.wrapNode(value);
166 if (value.isObject()) {
167 if (value.has("operands")) {
168 JsonNode ops = value.at("/operands");
169 Iterator<JsonNode> it = ops.elements();
170 while (it.hasNext()) {
171 JsonNode next = it.next();
Michael Hanl33829ec2016-05-28 17:03:38 +0200172 KoralNode kn = processNode(key, next, result);
Michael Hanl86d598e2016-05-26 15:13:00 +0200173 if (kn.isRemove())
174 it.remove();
175 }
176 }
177 else if (value.path("@type").asText().equals("koral:token")) {
178 // todo: koral:token nodes cannot be flagged for deletion --> creates the possibility for empty koral:token nodes
179 rewrite(key, kroot,
Michael Hanl33829ec2016-05-28 17:03:38 +0200180 RewriteHandler.this.token_node_processors, result);
181 return processNode(key, value.path("wrap"), result);
Michael Hanl86d598e2016-05-26 15:13:00 +0200182 }
183 else {
184 return rewrite(key, kroot,
Michael Hanl33829ec2016-05-28 17:03:38 +0200185 RewriteHandler.this.node_processors, result);
Michael Hanl86d598e2016-05-26 15:13:00 +0200186 }
187 }
188 else if (value.isArray()) {
189 Iterator<JsonNode> it = value.elements();
190 while (it.hasNext()) {
191 JsonNode next = it.next();
Michael Hanl33829ec2016-05-28 17:03:38 +0200192 KoralNode kn = processNode(key, next, result);
Michael Hanl86d598e2016-05-26 15:13:00 +0200193 if (kn.isRemove())
194 it.remove();
195 }
196 }
197 return kroot;
198 }
199
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200200 private JsonNode start (boolean result) throws KustvaktException {
margaretha35e1ca22023-11-16 22:00:01 +0100201 if (DEBUG) {
202 jlog.debug("Running rewrite process on query " + root);
margarethaa85965d2018-12-19 15:58:21 +0100203 }
Michael Hanl86d598e2016-05-26 15:13:00 +0200204 if (root != null) {
205 Iterator<Map.Entry<String, JsonNode>> it = root.fields();
206 while (it.hasNext()) {
207 Map.Entry<String, JsonNode> next = it.next();
Michael Hanl33829ec2016-05-28 17:03:38 +0200208 processNode(next.getKey(), next.getValue(), result);
Michael Hanl86d598e2016-05-26 15:13:00 +0200209 }
Michael Hanl33829ec2016-05-28 17:03:38 +0200210 processFixedNode(root, RewriteHandler.this.query_processors,
211 result);
Michael Hanl86d598e2016-05-26 15:13:00 +0200212 }
213 return root;
214 }
215
216 /**
217 * @param node
218 * @param tasks
Michael Hanl33829ec2016-05-28 17:03:38 +0200219 * @return boolean true if node is to be removed from parent!
220 * Only
Michael Hanl86d598e2016-05-26 15:13:00 +0200221 * applies if parent is an array node
222 */
223 private KoralNode rewrite (String rootNode, KoralNode node,
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200224 Collection<? extends RewriteTask> tasks, boolean result)
225 throws KustvaktException {
Michael Hanl86d598e2016-05-26 15:13:00 +0200226 if (RewriteHandler.this.config == null)
margaretha35e1ca22023-11-16 22:00:01 +0100227 throw new RuntimeException(
228 "KustvaktConfiguration must be set!");
Michael Hanl86d598e2016-05-26 15:13:00 +0200229
230 for (RewriteTask task : tasks) {
margarethaa85965d2018-12-19 15:58:21 +0100231 if (DEBUG) {
232 jlog.debug("running processor on node: " + node);
233 jlog.debug("on processor: " + task.getClass().toString());
234 }
Michael Hanl86d598e2016-05-26 15:13:00 +0200235
margaretha35e1ca22023-11-16 22:00:01 +0100236 // if (RewriteHandler.this.beans != null
237 // && task instanceof BeanInjectable)
238 // ((BeanInjectable) task)
239 // .insertBeans(RewriteHandler.this.beans);
Michael Hanl86d598e2016-05-26 15:13:00 +0200240
241 if (task instanceof RewriteTask.IterableRewritePath) {
242 RewriteTask.IterableRewritePath rw = (RewriteTask.IterableRewritePath) task;
243 if (rw.path() != null && !rw.path().equals(rootNode)) {
margaretha35e1ca22023-11-16 22:00:01 +0100244 if (DEBUG) {
margarethaa85965d2018-12-19 15:58:21 +0100245 jlog.debug("skipping node: " + node);
246 }
Michael Hanl86d598e2016-05-26 15:13:00 +0200247 continue;
248 }
249 }
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200250 if (!result && task instanceof RewriteTask.RewriteQuery) {
251 ((RewriteTask.RewriteQuery) task).rewriteQuery(node,
252 RewriteHandler.this.config, this.user);
Michael Hanl86d598e2016-05-26 15:13:00 +0200253 }
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200254 else if (task instanceof RewriteTask.RewriteResult) {
255 ((RewriteTask.RewriteResult) task).rewriteResult(node);
Michael Hanl86d598e2016-05-26 15:13:00 +0200256 }
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200257
Michael Hanl86d598e2016-05-26 15:13:00 +0200258 if (node.isRemove()) {
Michael Hanl33829ec2016-05-28 17:03:38 +0200259 node.buildRewrites(this.root.at("/" + rootNode));
Michael Hanl86d598e2016-05-26 15:13:00 +0200260 break;
Michael Hanl33829ec2016-05-28 17:03:38 +0200261 }
262 else
Michael Hanl86d598e2016-05-26 15:13:00 +0200263 node.buildRewrites();
264 }
265 return node;
266 }
267
268 // fixme: merge with processNode!
269 private void processFixedNode (JsonNode node,
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200270 Collection<RewriteTask> tasks, boolean post)
271 throws KustvaktException {
Michael Hanl86d598e2016-05-26 15:13:00 +0200272 for (RewriteTask task : tasks) {
273 KoralNode next = KoralNode.wrapNode(node);
274 if (task instanceof RewriteTask.RewriteNodeAt) {
275 RewriteTask.RewriteNodeAt rwa = (RewriteTask.RewriteNodeAt) task;
margaretha35e1ca22023-11-16 22:00:01 +0100276 if ((rwa.at() != null
277 && !node.at(rwa.at()).isMissingNode()))
Michael Hanl86d598e2016-05-26 15:13:00 +0200278 next = next.at(rwa.at());
279 }
280
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200281 if (!post & task instanceof RewriteTask.RewriteQuery)
margaretha1bc9cca2018-12-11 15:09:44 +0100282 next = ((RewriteTask.RewriteQuery) task).rewriteQuery(next,
Michael Hanlf8fcc7a2016-06-03 17:41:07 +0200283 RewriteHandler.this.config, user);
284 else if (task instanceof RewriteTask.RewriteResult)
285 ((RewriteTask.RewriteResult) task).rewriteResult(next);
286 next.buildRewrites();
287
Michael Hanl86d598e2016-05-26 15:13:00 +0200288 }
289 }
290
Michael Hanl86d598e2016-05-26 15:13:00 +0200291 }
margaretha34954472018-10-24 20:05:17 +0200292
Michael Hanl1e18cb42015-08-06 20:57:35 +0200293}