| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 1 | package de.ids_mannheim.korap.resource.rewrite; |
| 2 | |
| 3 | import com.fasterxml.jackson.databind.JsonNode; |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 4 | import de.ids_mannheim.korap.config.KustvaktConfiguration; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 5 | import de.ids_mannheim.korap.user.User; |
| 6 | import de.ids_mannheim.korap.utils.JsonUtils; |
| 7 | import de.ids_mannheim.korap.utils.KustvaktLogger; |
| 8 | import org.slf4j.Logger; |
| 9 | |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 10 | import java.lang.reflect.Constructor; |
| 11 | import java.lang.reflect.InvocationTargetException; |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 12 | import java.util.*; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 13 | |
| 14 | /** |
| 15 | * @author hanl |
| 16 | * @date 30/06/2015 |
| 17 | */ |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 18 | // todo: do post processing! |
| Michael Hanl | f21773f | 2015-10-16 23:02:31 +0200 | [diff] [blame] | 19 | //todo: load rewritenode and rewritequery automatically from classpath by default, but namespaced from package |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 20 | public class RewriteHandler { |
| 21 | |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 22 | private static Logger jlog = KustvaktLogger.getLogger(RewriteHandler.class); |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 23 | private Collection<RewriteTask.IterableRewriteAt> node_processors; |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 24 | private Collection<RewriteTask.RewriteKoralToken> token_node_processors; |
| Michael Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 25 | private Collection<RewriteTask> query_processors; |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 26 | |
| 27 | // private Collection<RewriteTask.RewriteNode2> fixed_nodes; |
| 28 | // private Collection<RewriteTask.IterableRewrite> iterable_nodes; |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 29 | |
| Michael Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 30 | private Set<Class> failed_task_registration; |
| 31 | |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 32 | private KustvaktConfiguration config; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 33 | |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 34 | // fixme: make default constructor with configuration! |
| 35 | public RewriteHandler(KustvaktConfiguration config) { |
| 36 | this.config = config; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 37 | this.node_processors = new HashSet<>(); |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 38 | this.token_node_processors = new HashSet<>(); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 39 | this.query_processors = new HashSet<>(); |
| Michael Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 40 | this.failed_task_registration = new HashSet<>(); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 41 | } |
| 42 | |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 43 | public boolean addProcessor(RewriteTask rewriter) { |
| 44 | if (rewriter instanceof RewriteTask.RewriteKoralToken) |
| 45 | return this.token_node_processors |
| 46 | .add((RewriteTask.RewriteKoralToken) rewriter); |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 47 | else if (rewriter instanceof RewriteTask.IterableRewriteAt) |
| 48 | return this.node_processors |
| 49 | .add((RewriteTask.IterableRewriteAt) rewriter); |
| Michael Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 50 | else if (rewriter instanceof RewriteTask.RewriteBefore |
| 51 | | rewriter instanceof RewriteTask.RewriteAfter) |
| 52 | return this.query_processors.add(rewriter); |
| Michael Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 53 | |
| 54 | this.failed_task_registration.add(rewriter.getClass()); |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 55 | return false; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 56 | } |
| 57 | |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 58 | 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 Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 69 | public final Collection<Class> getFailedHandlers() { |
| 70 | return this.failed_task_registration; |
| 71 | } |
| 72 | |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 73 | @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 Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | /** |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 87 | * expects extended RewriteNode/Query class with empty default constructor |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 88 | * |
| 89 | * @param rewriter |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 90 | * @return boolean if rewriter class was successfully added to rewrite handler! |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 91 | */ |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 92 | 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 Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 99 | this.failed_task_registration.add(rewriter); |
| Michael Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 100 | return false; |
| 101 | } |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 102 | return addProcessor(task); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | public void clear() { |
| 106 | this.node_processors.clear(); |
| 107 | this.query_processors.clear(); |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 108 | this.token_node_processors.clear(); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 109 | } |
| 110 | |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 111 | private boolean process(String name, JsonNode root, User user, |
| 112 | boolean post) { |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 113 | if (root.isObject()) { |
| 114 | if (root.has("operands")) { |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 115 | JsonNode ops = root.at("/operands"); |
| 116 | Iterator<JsonNode> it = ops.elements(); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 117 | while (it.hasNext()) { |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 118 | JsonNode next = it.next(); |
| 119 | if (process(name, next, user, post)) |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 120 | it.remove(); |
| 121 | } |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 122 | }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 Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 124 | processNode(name, KoralNode.wrapNode(root), user, |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 125 | this.token_node_processors, post); |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 126 | return process(name, root.path("wrap"), user, post); |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 127 | }else { |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 128 | return processNode(name, KoralNode.wrapNode(root), user, |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 129 | this.node_processors, post); |
| 130 | } |
| 131 | }else if (root.isArray()) { |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 132 | Iterator<JsonNode> it = root.elements(); |
| 133 | while (it.hasNext()) { |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 134 | JsonNode next = it.next(); |
| 135 | if (process(name, next, user, post)) |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 136 | it.remove(); |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 137 | } |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 138 | } |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 139 | return false; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 140 | } |
| 141 | |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 142 | private JsonNode process(JsonNode root, User user, boolean post) { |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 143 | 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 Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 149 | return root; |
| 150 | } |
| 151 | |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 152 | public JsonNode preProcess(JsonNode root, User user) { |
| 153 | return process(root, user, false); |
| 154 | } |
| 155 | |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 156 | public String preProcess(String json, User user) { |
| 157 | return JsonUtils.toJSON(preProcess(JsonUtils.readTree(json), user)); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 158 | } |
| 159 | |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 160 | public JsonNode postProcess(JsonNode root, User user) { |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 161 | return process(root, user, true); |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 162 | } |
| 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 Hanl | 59bff81 | 2015-10-27 23:10:32 +0100 | [diff] [blame] | 174 | // todo: integrate notifications into system! |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 175 | private boolean processNode(String rootNode, KoralNode node, User user, |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 176 | Collection<? extends RewriteTask> tasks, boolean post) { |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 177 | for (RewriteTask task : tasks) { |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 178 | 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 Hanl | ac4962c | 2015-09-21 22:21:05 +0200 | [diff] [blame] | 187 | } |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 188 | |
| 189 | if (!post && task instanceof RewriteTask.RewriteBefore) |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 190 | ((RewriteTask.RewriteBefore) task) |
| 191 | .preProcess(node, this.config, user); |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 192 | else if (task instanceof RewriteTask.RewriteAfter) |
| Michael Hanl | f078532 | 2015-11-13 16:14:45 +0100 | [diff] [blame] | 193 | ((RewriteTask.RewriteAfter) task).postProcess(node); |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 194 | |
| Michael Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 195 | if (node.isRemove()) |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 196 | break; |
| 197 | } |
| Michael Hanl | 2760cc4 | 2015-11-16 19:30:01 +0100 | [diff] [blame] | 198 | return node.isRemove(); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 199 | } |
| 200 | |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 201 | private void processFixedNode(JsonNode node, User user, |
| Michael Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 202 | Collection<RewriteTask> tasks, boolean post) { |
| 203 | for (RewriteTask task : tasks) { |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 204 | JsonNode next = node; |
| Michael Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 205 | 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 Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 210 | |
| Michael Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 211 | if (!post && task instanceof RewriteTask.RewriteBefore) |
| 212 | ((RewriteTask.RewriteBefore) task) |
| 213 | .preProcess(KoralNode.wrapNode(next), this.config, |
| 214 | user); |
| Michael Hanl | 4b42baa | 2015-11-17 21:46:04 +0100 | [diff] [blame] | 215 | else |
| Michael Hanl | bcb48c7 | 2015-11-17 22:11:05 +0100 | [diff] [blame^] | 216 | ((RewriteTask.RewriteAfter) task) |
| 217 | .postProcess(KoralNode.wrapNode(next)); |
| Michael Hanl | 022543e | 2015-11-17 21:25:25 +0100 | [diff] [blame] | 218 | } |
| 219 | } |
| 220 | |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 221 | } |