blob: 27c16e7da98af4b947fc826b3b169e6eb135791c [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/**
Joachim Bingela6954de2015-03-20 16:37:37 +010015 * Main class for Koral, serializes queries from concrete QLs to
16 * KoralQuery
Michael Hanlf33f7062015-06-24 21:14:26 +020017 *
Joachim Bingela6954de2015-03-20 16:37:37 +010018 * @author Joachim Bingel (bingel@ids-mannheim.de),
Joachim Bingel364085b2015-03-11 15:28:37 +010019 * Michael Hanl (hanl@ids-mannheim.de)
Joachim Bingel7cb346e2015-03-09 10:56:20 +010020 * @version 0.3.0
21 * @since 0.1.0
Michael Hanl44c73f02013-12-06 03:12:52 +000022 */
Michael Hanl4fe41cc2013-12-10 17:59:51 +000023public class QuerySerializer {
Joachim Bingel4b405f52013-11-15 15:29:30 +000024
Michael Hanl3f0c4c42015-07-02 20:21:23 +020025 // fixme: not used in any way!
26 @Deprecated
Joachim Bingel20e06ac2015-01-15 10:31:33 +000027 static HashMap<String, Class<? extends AbstractQueryProcessor>> qlProcessorAssignment;
28
Michael Hanl3f0c4c42015-07-02 20:21:23 +020029
30
31
Joachim Bingel20e06ac2015-01-15 10:31:33 +000032 static {
Michael Hanl26a826e2015-01-29 16:26:09 +000033 qlProcessorAssignment = new HashMap<String, Class<? extends AbstractQueryProcessor>>();
Michael Hanlf33f7062015-06-24 21:14:26 +020034 qlProcessorAssignment
35 .put("poliqarpplus", PoliqarpPlusQueryProcessor.class);
Joachim Bingel20e06ac2015-01-15 10:31:33 +000036 qlProcessorAssignment.put("cosmas2", Cosmas2QueryProcessor.class);
37 qlProcessorAssignment.put("annis", AnnisQueryProcessor.class);
38 qlProcessorAssignment.put("cql", CqlQueryProcessor.class);
39 }
40
Michael Hanl26a826e2015-01-29 16:26:09 +000041 private static ObjectMapper mapper = new ObjectMapper();
42 private Logger qllogger = LoggerFactory.getLogger("ql");
Michael Hanl2a30f422014-04-01 16:41:44 +000043 public static String queryLanguageVersion;
44
Joachim Bingel1faf8a52015-01-09 13:17:34 +000045 private AbstractQueryProcessor ast;
Michael Hanlf3553c92015-06-25 18:17:43 +020046 private Map<String, Object> collection = new LinkedHashMap<>();
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;
Michael Hanl9ca5edd2013-12-06 05:13:24 +000051 private org.slf4j.Logger log = LoggerFactory
Michael Hanl4fe41cc2013-12-10 17:59:51 +000052 .getLogger(QuerySerializer.class);
Joachim Bingel4b405f52013-11-15 15:29:30 +000053
Michael Hanlf33f7062015-06-24 21:14:26 +020054 public QuerySerializer() {
55 this.errors = new LinkedList<>();
56 this.warnings = new LinkedList<>();
57 this.messages = new LinkedList<>();
58 }
Joachim Bingela6954de2015-03-20 16:37:37 +010059
Joachim Bingel009623f2014-12-16 10:46:43 +000060 /**
61 * @param args
Joachim Bingel009623f2014-12-16 10:46:43 +000062 */
Michael Hanlf33f7062015-06-24 21:14:26 +020063 public static void main(String[] args) {
Joachim Bingel009623f2014-12-16 10:46:43 +000064 /*
65 * just for testing...
Joachim Bingel20e06ac2015-01-15 10:31:33 +000066 */
Joachim Bingel6e4e9f32015-01-30 18:59:31 +000067 BasicConfigurator.configure();
Joachim Bingel009623f2014-12-16 10:46:43 +000068 QuerySerializer jg = new QuerySerializer();
69 int i = 0;
Joachim Bingel2b00f492015-01-31 18:25:49 +000070 String[] queries = null;
Joachim Bingel6e4e9f32015-01-30 18:59:31 +000071 String ql = "poliqarpplus";
72 if (args.length < 2) {
Joachim Bingela6954de2015-03-20 16:37:37 +010073 System.err
74 .println("Usage: QuerySerializer \"query\" queryLanguage");
Joachim Bingel2b00f492015-01-31 18:25:49 +000075 System.exit(1);
Michael Hanlf33f7062015-06-24 21:14:26 +020076 }else {
Joachim Bingel20e06ac2015-01-15 10:31:33 +000077 queries = new String[] { args[0] };
Joachim Bingela6954de2015-03-20 16:37:37 +010078 ql = args[1];
Joachim Bingel6e4e9f32015-01-30 18:59:31 +000079 }
Joachim Bingel009623f2014-12-16 10:46:43 +000080 for (String q : queries) {
81 i++;
82 try {
Joachim Bingel1f8f3782015-01-19 17:58:41 +000083 jg.run(q, ql);
Joachim Bingel009623f2014-12-16 10:46:43 +000084 System.out.println();
Michael Hanlf33f7062015-06-24 21:14:26 +020085 }catch (NullPointerException npe) {
Joachim Bingel009623f2014-12-16 10:46:43 +000086 npe.printStackTrace();
87 System.out.println("null\n");
Michael Hanlf33f7062015-06-24 21:14:26 +020088 }catch (IOException e) {
Joachim Bingel009623f2014-12-16 10:46:43 +000089 e.printStackTrace();
Joachim Bingel009623f2014-12-16 10:46:43 +000090 }
91 }
92 }
Michael Hanl44c73f02013-12-06 03:12:52 +000093
94 /**
Joachim Bingel20e06ac2015-01-15 10:31:33 +000095 * Runs the QuerySerializer by initializing the relevant
96 * AbstractSyntaxTree implementation (depending on specified query
97 * language) and transforms and writes the tree's requestMap to
98 * the specified output file.
Michael Hanlf33f7062015-06-24 21:14:26 +020099 *
100 * @param query The query string
101 * @param queryLanguage The query language. As of 17 Dec 2014, this must be
102 * one of 'poliqarpplus', 'cosmas2', 'annis' or 'cql'.
Michael Hanl44c73f02013-12-06 03:12:52 +0000103 * @throws IOException
104 */
Michael Hanlf33f7062015-06-24 21:14:26 +0200105 public void run(String query, String queryLanguage) throws IOException {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000106 if (queryLanguage.equalsIgnoreCase("poliqarp")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000107 ast = new PoliqarpPlusQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200108 }else if (queryLanguage.equalsIgnoreCase("cosmas2")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000109 ast = new Cosmas2QueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200110 }else if (queryLanguage.equalsIgnoreCase("poliqarpplus")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000111 ast = new PoliqarpPlusQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200112 }else if (queryLanguage.equalsIgnoreCase("cql")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000113 ast = new CqlQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200114 }else if (queryLanguage.equalsIgnoreCase("annis")) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000115 ast = new AnnisQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200116 }else {
117 throw new IllegalArgumentException(
118 queryLanguage + " is not a supported query language!");
Joachim Bingel009623f2014-12-16 10:46:43 +0000119 }
Joachim Bingel017915d2014-12-16 13:03:04 +0000120 toJSON();
Joachim Bingel009623f2014-12-16 10:46:43 +0000121 }
Michael Hanl44c73f02013-12-06 03:12:52 +0000122
Michael Hanlf33f7062015-06-24 21:14:26 +0200123 public QuerySerializer setQuery(String query, String ql, String version) {
Joachim Bingel20e06ac2015-01-15 10:31:33 +0000124 ast = new DummyQueryProcessor();
125 if (query == null || query.isEmpty()) {
126 ast.addError(StatusCodes.NO_QUERY, "You did not specify a query!");
Michael Hanlf33f7062015-06-24 21:14:26 +0200127 }else if (ql == null || ql.isEmpty()) {
Joachim Bingel20e06ac2015-01-15 10:31:33 +0000128 ast.addError(StatusCodes.NO_QUERY,
129 "You did not specify any query language!");
Michael Hanlf33f7062015-06-24 21:14:26 +0200130 }else if (ql.equalsIgnoreCase("poliqarp")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000131 ast = new PoliqarpPlusQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200132 }else if (ql.equalsIgnoreCase("cosmas2")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000133 ast = new Cosmas2QueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200134 }else if (ql.equalsIgnoreCase("poliqarpplus")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000135 ast = new PoliqarpPlusQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200136 }else if (ql.equalsIgnoreCase("cql")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000137 if (version == null)
138 ast = new CqlQueryProcessor(query);
139 else
140 ast = new CqlQueryProcessor(query, version);
Michael Hanlf33f7062015-06-24 21:14:26 +0200141 }else if (ql.equalsIgnoreCase("annis")) {
Joachim Bingel3d5b69b2015-01-14 10:46:44 +0000142 ast = new AnnisQueryProcessor(query);
Michael Hanlf33f7062015-06-24 21:14:26 +0200143 }else {
144 ast.addError(StatusCodes.UNKNOWN_QL,
145 ql + " is not a supported query language!");
Michael Hanl44c73f02013-12-06 03:12:52 +0000146 }
Michael Hanl0b70bb32014-05-06 16:09:41 +0000147 return this;
148 }
Michael Hanl034be0d2014-02-14 10:17:34 +0000149
Michael Hanlf33f7062015-06-24 21:14:26 +0200150 public QuerySerializer setQuery(String query, String ql) {
Michael Hanlbaf1a5e2014-05-15 19:51:40 +0000151 return setQuery(query, ql, "");
152 }
153
Michael Hanlf33f7062015-06-24 21:14:26 +0200154 public void setVerbose(boolean verbose) {
Joachim Bingela6465ef2015-01-16 14:24:34 +0000155 AbstractQueryProcessor.verbose = verbose;
156 }
Michael Hanl26a826e2015-01-29 16:26:09 +0000157
Michael Hanlf33f7062015-06-24 21:14:26 +0200158 public final String toJSON() {
Michael Hanl26a826e2015-01-29 16:26:09 +0000159 String ser;
160 try {
161 ser = mapper.writeValueAsString(raw());
162 qllogger.info("Serialized query: " + ser);
Michael Hanlf33f7062015-06-24 21:14:26 +0200163 }catch (JsonProcessingException e) {
Michael Hanl26a826e2015-01-29 16:26:09 +0000164 return "";
165 }
Michael Hanl85d4b5d2014-07-25 12:07:20 +0000166 return ser;
Michael Hanl44c73f02013-12-06 03:12:52 +0000167 }
Michael Hanl0b70bb32014-05-06 16:09:41 +0000168
Michael Hanlf33f7062015-06-24 21:14:26 +0200169 public final Map build() {
Michael Hanl91917f22014-06-04 14:38:48 +0000170 return raw();
171 }
Michael Hanl0b70bb32014-05-06 16:09:41 +0000172
Michael Hanlf33f7062015-06-24 21:14:26 +0200173 private Map raw() {
Michael Hanl2bd00c62014-11-04 16:26:42 +0000174 if (ast != null) {
Michael Hanl15311e02016-06-02 17:20:34 +0200175 Map<String, Object> requestMap = new HashMap<>(ast.getRequestMap());
Michael Hanl2bd00c62014-11-04 16:26:42 +0000176 Map meta = (Map) requestMap.get("meta");
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000177 Map collection = (Map) requestMap.get("collection");
Joachim Bingel017915d2014-12-16 13:03:04 +0000178 List errors = (List) requestMap.get("errors");
179 List warnings = (List) requestMap.get("warnings");
180 List messages = (List) requestMap.get("messages");
Michael Hanl78208a82016-05-23 16:25:02 +0200181 collection = mergeCollection(collection, this.collection);
182 requestMap.put("collection", collection);
Michael Hanl2bd00c62014-11-04 16:26:42 +0000183 if (this.meta != null) {
Michael Hanl15311e02016-06-02 17:20:34 +0200184 meta.putAll(this.meta);
185 requestMap.put("meta", meta);
Michael Hanl2bd00c62014-11-04 16:26:42 +0000186 }
Michael Hanlf3553c92015-06-25 18:17:43 +0200187 if (this.errors != null && !this.errors.isEmpty()) {
Joachim Bingel017915d2014-12-16 13:03:04 +0000188 errors.addAll(this.errors);
189 requestMap.put("errors", errors);
190 }
Michael Hanlf3553c92015-06-25 18:17:43 +0200191 if (this.warnings != null && !this.warnings.isEmpty()) {
Joachim Bingel017915d2014-12-16 13:03:04 +0000192 warnings.addAll(this.warnings);
193 requestMap.put("warnings", warnings);
194 }
Michael Hanlf3553c92015-06-25 18:17:43 +0200195 if (this.messages != null && !this.messages.isEmpty()) {
Joachim Bingel20e06ac2015-01-15 10:31:33 +0000196 messages.addAll(this.messages);
Joachim Bingel017915d2014-12-16 13:03:04 +0000197 requestMap.put("messages", messages);
198 }
Michael Hanl2bd00c62014-11-04 16:26:42 +0000199
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200200 return cleanup(requestMap);
Michael Hanl2bd00c62014-11-04 16:26:42 +0000201 }
202 return new HashMap<>();
Michael Hanl0b70bb32014-05-06 16:09:41 +0000203 }
204
Michael Hanl3f0c4c42015-07-02 20:21:23 +0200205 private Map<String, Object> cleanup(Map<String, Object> requestMap) {
206 Iterator<Map.Entry<String, Object>> set = requestMap.entrySet()
207 .iterator();
208 while (set.hasNext()) {
209 Map.Entry<String, Object> entry = set.next();
210 if (entry.getValue() instanceof List && ((List) entry.getValue())
211 .isEmpty())
212 set.remove();
213 else if (entry.getValue() instanceof Map && ((Map) entry.getValue())
214 .isEmpty())
215 set.remove();
216 else if (entry.getValue() instanceof String && ((String) entry
217 .getValue()).isEmpty())
218 set.remove();
219 }
220 return requestMap;
221 }
222
Michael Hanlf33f7062015-06-24 21:14:26 +0200223 private Map<String, Object> mergeCollection(Map<String, Object> collection1,
224 Map<String, Object> collection2) {
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000225 if (collection1 == null || collection1.isEmpty()) {
226 return collection2;
Michael Hanlf33f7062015-06-24 21:14:26 +0200227 }else if (collection2 == null || collection2.isEmpty()) {
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000228 return collection1;
Michael Hanl78208a82016-05-23 16:25:02 +0200229 }else if (collection1.equals(collection2)) {
230 return collection1;
Michael Hanlf33f7062015-06-24 21:14:26 +0200231 }else {
Michael Hanlf3553c92015-06-25 18:17:43 +0200232 LinkedHashMap<String, Object> docGroup = KoralObjectGenerator
233 .makeDocGroup("and");
234 ArrayList<Object> operands = (ArrayList<Object>) docGroup
235 .get("operands");
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000236 operands.add(collection1);
237 operands.add(collection2);
Michael Hanl26a826e2015-01-29 16:26:09 +0000238 return docGroup;
Joachim Bingel1f8f3782015-01-19 17:58:41 +0000239 }
240 }
Michael Hanl26a826e2015-01-29 16:26:09 +0000241
Michael Hanlf33f7062015-06-24 21:14:26 +0200242 @Deprecated
243 public QuerySerializer addMeta(String cli, String cri, int cls, int crs,
Michael Hanl0b70bb32014-05-06 16:09:41 +0000244 int num, int pageIndex) {
Michael Hanldf206ab2014-05-13 10:22:27 +0000245 MetaQueryBuilder meta = new MetaQueryBuilder();
Michael Hanldd5c9652014-09-02 18:51:08 +0000246 meta.setSpanContext(cls, cli, crs, cri);
Michael Hanl0b70bb32014-05-06 16:09:41 +0000247 meta.addEntry("startIndex", pageIndex);
248 meta.addEntry("count", num);
249 this.meta = meta.raw();
250 return this;
251 }
252
Michael Hanlf33f7062015-06-24 21:14:26 +0200253 public QuerySerializer setMeta(Map<String, Object> meta) {
254 this.meta = meta;
255 return this;
256 }
Joachim Bingela6954de2015-03-20 16:37:37 +0100257
Michael Hanlf33f7062015-06-24 21:14:26 +0200258 public QuerySerializer setCollection(String collection) {
Joachim Bingel1faf8a52015-01-09 13:17:34 +0000259 CollectionQueryProcessor tree = new CollectionQueryProcessor();
Michael Hanlf1fead42014-05-14 15:13:33 +0000260 tree.process(collection);
Michael Hanlf3553c92015-06-25 18:17:43 +0200261 Map<String, Object> collectionRequest = tree.getRequestMap();
Michael Hanlf33f7062015-06-24 21:14:26 +0200262 if (collectionRequest.get("errors") != null)
263 this.errors.addAll((List) collectionRequest.get("errors"));
264 if (collectionRequest.get("warnings") != null)
265 this.warnings.addAll((List) collectionRequest.get("warnings"));
266 if (collectionRequest.get("messages") != null)
267 this.messages.addAll((List) collectionRequest.get("messages"));
Michael Hanlf3553c92015-06-25 18:17:43 +0200268 this.collection = (Map<String, Object>) collectionRequest
269 .get("collection");
Michael Hanlf1fead42014-05-14 15:13:33 +0000270 return this;
271 }
Joachim Bingel4b405f52013-11-15 15:29:30 +0000272}