blob: 4b192b0cf5e292212cc0e0e37578d67701b6d18d [file] [log] [blame]
Joachim Bingel4b405f52013-11-15 15:29:30 +00001package de.ids_mannheim.korap.query.serialize;
2
Michael Hanl26a826e2015-01-29 16:26:09 +00003import com.fasterxml.jackson.core.JsonProcessingException;
Michael Hanl26a826e2015-01-29 16:26:09 +00004import com.fasterxml.jackson.databind.ObjectMapper;
Joachim Bingel1f8f3782015-01-19 17:58:41 +00005import de.ids_mannheim.korap.query.serialize.util.KoralObjectGenerator;
Joachim Bingele3fe3672014-12-17 18:35:58 +00006import de.ids_mannheim.korap.query.serialize.util.StatusCodes;
Joachim Bingel6e4e9f32015-01-30 18:59:31 +00007import org.apache.log4j.BasicConfigurator;
Michael Hanl85d4b5d2014-07-25 12:07:20 +00008import org.slf4j.Logger;
Michael Hanl9ca5edd2013-12-06 05:13:24 +00009import org.slf4j.LoggerFactory;
Joachim Bingel4b405f52013-11-15 15:29:30 +000010
Michael Hanl44c73f02013-12-06 03:12:52 +000011import java.io.IOException;
Michael Hanl26a826e2015-01-29 16:26:09 +000012import java.util.*;
Joachim Bingelb5ada902013-11-19 14:46:04 +000013
Michael Hanl44c73f02013-12-06 03:12:52 +000014/**
margaretha2ffa9552016-05-27 17:20:00 +020015 * Main class for Koral, serializes queries from concrete QLs to KoralQuery
Akron3ac85c92016-06-06 16:14:40 +020016 *
margaretha2ffa9552016-05-27 17:20:00 +020017 * @author Joachim Bingel (bingel@ids-mannheim.de), Michael Hanl
18 * (hanl@ids-mannheim.de), Eliza Margaretha (margaretha@ids-mannheim.de)
Joachim Bingel7cb346e2015-03-09 10:56:20 +010019 * @version 0.3.0
20 * @since 0.1.0
Michael Hanl44c73f02013-12-06 03:12:52 +000021 */
Michael Hanl4fe41cc2013-12-10 17:59:51 +000022public class QuerySerializer {
Joachim Bingel4b405f52013-11-15 15:29:30 +000023
Michael Hanl3f0c4c42015-07-02 20:21:23 +020024 // fixme: not used in any way!
25 @Deprecated
Joachim Bingel20e06ac2015-01-15 10:31:33 +000026 static HashMap<String, Class<? extends AbstractQueryProcessor>> qlProcessorAssignment;
27
Michael Hanl3f0c4c42015-07-02 20:21:23 +020028
29
Joachim Bingel20e06ac2015-01-15 10:31:33 +000030 static {
margaretha7d980e02017-11-12 21:49:36 +010031 qlProcessorAssignment =
32 new HashMap<String, Class<? extends AbstractQueryProcessor>>();
33 qlProcessorAssignment.put("poliqarpplus",
34 PoliqarpPlusQueryProcessor.class);
Joachim Bingel20e06ac2015-01-15 10:31:33 +000035 qlProcessorAssignment.put("cosmas2", Cosmas2QueryProcessor.class);
36 qlProcessorAssignment.put("annis", AnnisQueryProcessor.class);
37 qlProcessorAssignment.put("cql", CqlQueryProcessor.class);
38 }
39
Michael Hanl26a826e2015-01-29 16:26:09 +000040 private static ObjectMapper mapper = new ObjectMapper();
margaretha7d980e02017-11-12 21:49:36 +010041 private static Logger qllogger =
42 LoggerFactory.getLogger(QuerySerializer.class);
Michael Hanl2a30f422014-04-01 16:41:44 +000043 public static String queryLanguageVersion;
44
Joachim Bingel1faf8a52015-01-09 13:17:34 +000045 private AbstractQueryProcessor ast;
margarethad7e75b52017-01-20 13:52:28 +010046 private Map<String, Object> collection = new HashMap<>();
Joachim Bingel1f8f3782015-01-19 17:58:41 +000047 private Map<String, Object> meta;
48 private List<Object> errors;
49 private List<Object> warnings;
50 private List<Object> messages;
Joachim Bingel4b405f52013-11-15 15:29:30 +000051
margaretha7d980e02017-11-12 21:49:36 +010052 public QuerySerializer () {
margaretha7fd32922017-04-27 14:15:06 +020053 this.errors = new ArrayList<>();
54 this.warnings = new ArrayList<>();
55 this.messages = new ArrayList<>();
Michael Hanlf33f7062015-06-24 21:14:26 +020056 }
Joachim Bingela6954de2015-03-20 16:37:37 +010057
Joachim Bingel009623f2014-12-16 10:46:43 +000058 /**
59 * @param args
Joachim Bingel009623f2014-12-16 10:46:43 +000060 */
margaretha7d980e02017-11-12 21:49:36 +010061 public static void main (String[] args) {
Joachim Bingel009623f2014-12-16 10:46:43 +000062 /*
63 * just for testing...
Joachim Bingel20e06ac2015-01-15 10:31:33 +000064 */
Joachim Bingel6e4e9f32015-01-30 18:59:31 +000065 BasicConfigurator.configure();
Joachim Bingel009623f2014-12-16 10:46:43 +000066 QuerySerializer jg = new QuerySerializer();
67 int i = 0;
Joachim Bingel2b00f492015-01-31 18:25:49 +000068 String[] queries = null;
Joachim Bingel6e4e9f32015-01-30 18:59:31 +000069 String ql = "poliqarpplus";
70 if (args.length < 2) {
Joachim Bingela6954de2015-03-20 16:37:37 +010071 System.err
72 .println("Usage: QuerySerializer \"query\" queryLanguage");
Joachim Bingel2b00f492015-01-31 18:25:49 +000073 System.exit(1);
margaretha7d980e02017-11-12 21:49:36 +010074 }
75 else {
Joachim Bingel20e06ac2015-01-15 10:31:33 +000076 queries = new String[] { args[0] };
Joachim Bingela6954de2015-03-20 16:37:37 +010077 ql = args[1];
Joachim Bingel6e4e9f32015-01-30 18:59:31 +000078 }
Joachim Bingel009623f2014-12-16 10:46:43 +000079 for (String q : queries) {
80 i++;
81 try {
Joachim Bingel1f8f3782015-01-19 17:58:41 +000082 jg.run(q, ql);
Joachim Bingel009623f2014-12-16 10:46:43 +000083 System.out.println();
margaretha7d980e02017-11-12 21:49:36 +010084 }
85 catch (NullPointerException npe) {
Joachim Bingel009623f2014-12-16 10:46:43 +000086 npe.printStackTrace();
87 System.out.println("null\n");
margaretha7d980e02017-11-12 21:49:36 +010088 }
89 catch (IOException e) {
Joachim Bingel009623f2014-12-16 10:46:43 +000090 e.printStackTrace();
Joachim Bingel009623f2014-12-16 10:46:43 +000091 }
92 }
93 }
Michael Hanl44c73f02013-12-06 03:12:52 +000094
95 /**
margaretha7d980e02017-11-12 21:49:36 +010096 * Runs the QuerySerializer by initializing the relevant AbstractSyntaxTree
97 * implementation (depending on specified query language) and transforms and
98 * writes the tree's requestMap to the specified output file.
99 *
100 * @param query
101 * The query string
102 * @param queryLanguage
103 * The query language. As of 17 Dec 2014, this must be one of
104 * 'poliqarpplus', 'cosmas2', 'annis' or 'cql'.
105 * @throws IOException
106 */
107 public void run (String query, String queryLanguage) throws IOException {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000108 if (queryLanguage.equalsIgnoreCase("poliqarp")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000109 ast = new PoliqarpPlusQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100110 }
111 else if (queryLanguage.equalsIgnoreCase("cosmas2")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000112 ast = new Cosmas2QueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100113 }
114 else if (queryLanguage.equalsIgnoreCase("poliqarpplus")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000115 ast = new PoliqarpPlusQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100116 }
117 else if (queryLanguage.equalsIgnoreCase("cql")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000118 ast = new CqlQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100119 }
120 else if (queryLanguage.equalsIgnoreCase("fcsql")) {
121 ast = new FCSQLQueryProcessor(query, "2.0");
122 }
123 else if (queryLanguage.equalsIgnoreCase("annis")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000124 ast = new AnnisQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100125 }
126 else {
127 throw new IllegalArgumentException(
128 queryLanguage + " is not a supported query language!");
Joachim Bingel009623f2014-12-16 10:46:43 +0000129 }
Akroncf886dd2017-08-09 12:18:31 +0200130 System.out.println(this.toJSON());
Joachim Bingel009623f2014-12-16 10:46:43 +0000131 }
Michael Hanl44c73f02013-12-06 03:12:52 +0000132
margaretha7d980e02017-11-12 21:49:36 +0100133 public QuerySerializer setQuery (String query, String ql, String version) {
Joachim Bingel20e06ac2015-01-15 10:31:33 +0000134 ast = new DummyQueryProcessor();
135 if (query == null || query.isEmpty()) {
136 ast.addError(StatusCodes.NO_QUERY, "You did not specify a query!");
margaretha7d980e02017-11-12 21:49:36 +0100137 }
138 else if (ql == null || ql.isEmpty()) {
Joachim Bingel20e06ac2015-01-15 10:31:33 +0000139 ast.addError(StatusCodes.NO_QUERY,
140 "You did not specify any query language!");
margaretha7d980e02017-11-12 21:49:36 +0100141 }
142 else if (ql.equalsIgnoreCase("poliqarp")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000143 ast = new PoliqarpPlusQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100144 }
145 else if (ql.equalsIgnoreCase("cosmas2")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000146 ast = new Cosmas2QueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100147 }
148 else if (ql.equalsIgnoreCase("poliqarpplus")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000149 ast = new PoliqarpPlusQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100150 }
151 else if (ql.equalsIgnoreCase("cql")) {
152 if (version == null) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000153 ast = new CqlQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100154 }
155 else {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000156 ast = new CqlQueryProcessor(query, version);
margaretha7d980e02017-11-12 21:49:36 +0100157 }
158 }
159 else if (ql.equalsIgnoreCase("fcsql")) {
160 if (version == null) {
margaretha9c3a5e72017-11-21 19:42:28 +0100161 ast = new FCSQLQueryProcessor(query);
162// ast.addError(StatusCodes.MISSING_VERSION,
163// "SRU Version is missing!");
margaretha7d980e02017-11-12 21:49:36 +0100164 }
165 else {
166 ast = new FCSQLQueryProcessor(query, version);
167 }
168 }
169 else if (ql.equalsIgnoreCase("annis")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000170 ast = new AnnisQueryProcessor(query);
margaretha7d980e02017-11-12 21:49:36 +0100171 }
172 else {
173 ast.addError(StatusCodes.UNKNOWN_QUERY_LANGUAGE,
Michael Hanlf33f7062015-06-24 21:14:26 +0200174 ql + " is not a supported query language!");
Michael Hanl44c73f02013-12-06 03:12:52 +0000175 }
Michael Hanl0b70bb32014-05-06 16:09:41 +0000176 return this;
177 }
Michael Hanl034be0d2014-02-14 10:17:34 +0000178
margaretha7d980e02017-11-12 21:49:36 +0100179 public QuerySerializer setQuery (String query, String ql) {
Michael Hanlbaf1a5e2014-05-15 19:51:40 +0000180 return setQuery(query, ql, "");
181 }
182
margaretha7d980e02017-11-12 21:49:36 +0100183 public void setVerbose (boolean verbose) {
Joachim Bingela6465ef2015-01-16 14:24:34 +0000184 AbstractQueryProcessor.verbose = verbose;
185 }
Michael Hanl26a826e2015-01-29 16:26:09 +0000186
margaretha7d980e02017-11-12 21:49:36 +0100187 public final String toJSON () {
Michael Hanl26a826e2015-01-29 16:26:09 +0000188 String ser;
189 try {
190 ser = mapper.writeValueAsString(raw());
margaretha7d980e02017-11-12 21:49:36 +0100191 // System.out.println(ser);
192 }
193 catch (JsonProcessingException e) {
194 ast.addError(StatusCodes.SERIALIZATION_FAILED,
195 "Serialization failed.");
Michael Hanl26a826e2015-01-29 16:26:09 +0000196 return "";
197 }
Michael Hanl85d4b5d2014-07-25 12:07:20 +0000198 return ser;
Michael Hanl44c73f02013-12-06 03:12:52 +0000199 }
Michael Hanl0b70bb32014-05-06 16:09:41 +0000200
margaretha7d980e02017-11-12 21:49:36 +0100201 public final Map<String, Object> build () {
Michael Hanl91917f22014-06-04 14:38:48 +0000202 return raw();
203 }
Michael Hanl0b70bb32014-05-06 16:09:41 +0000204
margaretha7fd32922017-04-27 14:15:06 +0200205 @SuppressWarnings("unchecked")
206 private Map<String, Object> raw () {
Michael Hanl2bd00c62014-11-04 16:26:42 +0000207 if (ast != null) {
Michael Hanl15311e02016-06-02 17:20:34 +0200208 Map<String, Object> requestMap = new HashMap<>(ast.getRequestMap());
margaretha7d980e02017-11-12 21:49:36 +0100209 Map<String, Object> meta =
210 (Map<String, Object>) requestMap.get("meta");
211 Map<String, Object> collection =
212 (Map<String, Object>) requestMap.get("collection");
margaretha7fd32922017-04-27 14:15:06 +0200213 List<Object> errors = (List<Object>) requestMap.get("errors");
214 List<Object> warnings = (List<Object>) requestMap.get("warnings");
215 List<Object> messages = (List<Object>) requestMap.get("messages");
Michael Hanl78208a82016-05-23 16:25:02 +0200216 collection = mergeCollection(collection, this.collection);
217 requestMap.put("collection", collection);
Michael Hanl12aea4d2016-06-16 15:18:16 +0200218
margaretha7d980e02017-11-12 21:49:36 +0100219 if (meta == null) meta = new HashMap<String, Object>();
220 if (errors == null) errors = new ArrayList<Object>();
221 if (warnings == null) warnings = new ArrayList<Object>();
222 if (messages == null) messages = new ArrayList<Object>();
Michael Hanlc61b3922016-06-06 20:02:53 +0200223
Michael Hanl2bd00c62014-11-04 16:26:42 +0000224 if (this.meta != null) {
Michael Hanl15311e02016-06-02 17:20:34 +0200225 meta.putAll(this.meta);
226 requestMap.put("meta", meta);
Michael Hanl2bd00c62014-11-04 16:26:42 +0000227 }
Michael Hanlf3553c92015-06-25 18:17:43 +0200228 if (this.errors != null && !this.errors.isEmpty()) {
Joachim Bingel017915d2014-12-16 13:03:04 +0000229 errors.addAll(this.errors);
230 requestMap.put("errors", errors);
231 }
Michael Hanlf3553c92015-06-25 18:17:43 +0200232 if (this.warnings != null && !this.warnings.isEmpty()) {
Joachim Bingel017915d2014-12-16 13:03:04 +0000233 warnings.addAll(this.warnings);
234 requestMap.put("warnings", warnings);
235 }
Michael Hanlf3553c92015-06-25 18:17:43 +0200236 if (this.messages != null && !this.messages.isEmpty()) {
Joachim Bingel20e06ac2015-01-15 10:31:33 +0000237 messages.addAll(this.messages);
Joachim Bingel017915d2014-12-16 13:03:04 +0000238 requestMap.put("messages", messages);
239 }
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200240 return cleanup(requestMap);
Michael Hanl2bd00c62014-11-04 16:26:42 +0000241 }
margaretha7fd32922017-04-27 14:15:06 +0200242 return new HashMap<String, Object>();
Michael Hanl0b70bb32014-05-06 16:09:41 +0000243 }
244
margarethaf7dbe332016-06-16 20:14:26 +0200245 private Map<String, Object> cleanup (Map<String, Object> requestMap) {
margaretha7d980e02017-11-12 21:49:36 +0100246 Iterator<Map.Entry<String, Object>> set =
247 requestMap.entrySet().iterator();
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200248 while (set.hasNext()) {
249 Map.Entry<String, Object> entry = set.next();
margarethaf7dbe332016-06-16 20:14:26 +0200250 if (entry.getValue() instanceof List
251 && ((List) entry.getValue()).isEmpty())
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200252 set.remove();
margarethaf7dbe332016-06-16 20:14:26 +0200253 else if (entry.getValue() instanceof Map
254 && ((Map) entry.getValue()).isEmpty())
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200255 set.remove();
margarethaf7dbe332016-06-16 20:14:26 +0200256 else if (entry.getValue() instanceof String
257 && ((String) entry.getValue()).isEmpty())
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200258 set.remove();
259 }
260 return requestMap;
261 }
262
margaretha7d980e02017-11-12 21:49:36 +0100263 private Map<String, Object> mergeCollection (
margarethaf7dbe332016-06-16 20:14:26 +0200264 Map<String, Object> collection1, Map<String, Object> collection2) {
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000265 if (collection1 == null || collection1.isEmpty()) {
266 return collection2;
margarethaf7dbe332016-06-16 20:14:26 +0200267 }
268 else if (collection2 == null || collection2.isEmpty()) {
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000269 return collection1;
margarethaf7dbe332016-06-16 20:14:26 +0200270 }
271 else if (collection1.equals(collection2)) {
Michael Hanl78208a82016-05-23 16:25:02 +0200272 return collection1;
margarethaf7dbe332016-06-16 20:14:26 +0200273 }
274 else {
margaretha7d980e02017-11-12 21:49:36 +0100275 Map<String, Object> docGroup =
276 KoralObjectGenerator.makeDocGroup("and");
277 ArrayList<Object> operands =
278 (ArrayList<Object>) docGroup.get("operands");
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000279 operands.add(collection1);
280 operands.add(collection2);
Michael Hanl26a826e2015-01-29 16:26:09 +0000281 return docGroup;
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000282 }
283 }
Michael Hanl26a826e2015-01-29 16:26:09 +0000284
Michael Hanlf33f7062015-06-24 21:14:26 +0200285 @Deprecated
margaretha7d980e02017-11-12 21:49:36 +0100286 public QuerySerializer addMeta (String cli, String cri, int cls, int crs,
Michael Hanl0b70bb32014-05-06 16:09:41 +0000287 int num, int pageIndex) {
Michael Hanldf206ab2014-05-13 10:22:27 +0000288 MetaQueryBuilder meta = new MetaQueryBuilder();
Michael Hanldd5c9652014-09-02 18:51:08 +0000289 meta.setSpanContext(cls, cli, crs, cri);
Michael Hanl0b70bb32014-05-06 16:09:41 +0000290 meta.addEntry("startIndex", pageIndex);
291 meta.addEntry("count", num);
292 this.meta = meta.raw();
293 return this;
294 }
295
margaretha7d980e02017-11-12 21:49:36 +0100296 public QuerySerializer setMeta (Map<String, Object> meta) {
Michael Hanlf33f7062015-06-24 21:14:26 +0200297 this.meta = meta;
298 return this;
299 }
Joachim Bingela6954de2015-03-20 16:37:37 +0100300
margaretha7d980e02017-11-12 21:49:36 +0100301 public QuerySerializer setMeta (MetaQueryBuilder meta) {
302 this.meta = meta.raw();
303 return this;
304 }
Akron3ac85c92016-06-06 16:14:40 +0200305
margaretha7d980e02017-11-12 21:49:36 +0100306 @SuppressWarnings("unchecked")
307 public QuerySerializer setCollection (String collection) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000308 CollectionQueryProcessor tree = new CollectionQueryProcessor();
Michael Hanlf1fead42014-05-14 15:13:33 +0000309 tree.process(collection);
Michael Hanlf3553c92015-06-25 18:17:43 +0200310 Map<String, Object> collectionRequest = tree.getRequestMap();
Michael Hanlf33f7062015-06-24 21:14:26 +0200311 if (collectionRequest.get("errors") != null)
margaretha7fd32922017-04-27 14:15:06 +0200312 this.errors.addAll((List<Object>) collectionRequest.get("errors"));
margaretha7d980e02017-11-12 21:49:36 +0100313 if (collectionRequest.get("warnings") != null) this.warnings
314 .addAll((List<Object>) collectionRequest.get("warnings"));
315 if (collectionRequest.get("messages") != null) this.messages
316 .addAll((List<Object>) collectionRequest.get("messages"));
317 this.collection =
318 (Map<String, Object>) collectionRequest.get("collection");
Michael Hanlf1fead42014-05-14 15:13:33 +0000319 return this;
320 }
margaretha7d980e02017-11-12 21:49:36 +0100321
322 public String convertCollectionToJson ()
323 throws JsonProcessingException {
324 Map<String, Object> map = new HashMap<>();
325 map.put("collection", collection);
326 return mapper.writeValueAsString(map);
327 }
Joachim Bingel4b405f52013-11-15 15:29:30 +0000328}