blob: 76bf89ddf83187fa3f7d3828fe4a21931eebe225 [file] [log] [blame]
margarethad3c0fc92017-10-25 15:03:32 +02001package de.ids_mannheim.korap.web.controller;// package
2 // de.ids_mannheim.korap.ext.web;
Michael Hanl19390652016-01-16 11:01:24 +01003
margaretha0ba34ef2017-02-21 14:19:05 +01004import java.util.HashSet;
5import java.util.Locale;
margaretha0ba34ef2017-02-21 14:19:05 +01006import java.util.Set;
7
margaretha3d55b002019-03-19 12:00:44 +01008import javax.servlet.ServletContext;
margaretha2544cdf2019-07-08 11:39:43 +02009import javax.servlet.http.HttpServletRequest;
margaretha3d55b002019-03-19 12:00:44 +010010import javax.ws.rs.FormParam;
margaretha0ba34ef2017-02-21 14:19:05 +010011import javax.ws.rs.GET;
12import javax.ws.rs.POST;
13import javax.ws.rs.Path;
14import javax.ws.rs.PathParam;
15import javax.ws.rs.Produces;
16import javax.ws.rs.QueryParam;
17import javax.ws.rs.core.Context;
Bodmoca3dcfb2017-05-24 16:36:00 +020018import javax.ws.rs.core.HttpHeaders;
margaretha0ba34ef2017-02-21 14:19:05 +010019import javax.ws.rs.core.MediaType;
margaretha0ba34ef2017-02-21 14:19:05 +010020import javax.ws.rs.core.Response;
21import javax.ws.rs.core.SecurityContext;
margaretha0ba34ef2017-02-21 14:19:05 +010022
margaretha49cb6882018-07-04 04:19:54 +020023import org.apache.logging.log4j.LogManager;
24import org.apache.logging.log4j.Logger;
margarethaade7d4a2017-07-20 19:53:35 +020025import org.springframework.beans.factory.annotation.Autowired;
26import org.springframework.stereotype.Controller;
margaretha0ba34ef2017-02-21 14:19:05 +010027
Michael Hanl19390652016-01-16 11:01:24 +010028import com.sun.jersey.spi.container.ResourceFilters;
margaretha0ba34ef2017-02-21 14:19:05 +010029
margaretha2df06602018-11-14 19:10:30 +010030import de.ids_mannheim.korap.constant.OAuth2Scope;
Michael Hanl19390652016-01-16 11:01:24 +010031import de.ids_mannheim.korap.exceptions.KustvaktException;
margaretha20f31232018-07-09 17:49:39 +020032import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
margaretha0e8f4e72018-04-05 14:11:52 +020033import de.ids_mannheim.korap.security.context.TokenContext;
margaretha20f31232018-07-09 17:49:39 +020034import de.ids_mannheim.korap.service.SearchService;
margaretha2df06602018-11-14 19:10:30 +010035import de.ids_mannheim.korap.web.KustvaktResponseHandler;
margaretha398f4722019-01-09 19:07:20 +010036import de.ids_mannheim.korap.web.filter.APIVersionFilter;
margarethafde771a2017-11-14 15:02:10 +010037import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
Michael Hanl99cb9632016-06-29 16:24:40 +020038import de.ids_mannheim.korap.web.filter.DemoUserFilter;
Michael Hanl19390652016-01-16 11:01:24 +010039import de.ids_mannheim.korap.web.filter.PiwikFilter;
Michael Hanl19390652016-01-16 11:01:24 +010040
41/**
margaretha894a7d72017-11-08 19:24:20 +010042 *
margaretha20f31232018-07-09 17:49:39 +020043 * @author hanl, margaretha, diewald
Michael Hanl19390652016-01-16 11:01:24 +010044 * @date 29/01/2014
margaretha2544cdf2019-07-08 11:39:43 +020045 * @lastUpdate 05/07/2019
margarethaefc18a42018-03-01 16:01:42 +010046 *
Michael Hanl19390652016-01-16 11:01:24 +010047 */
margarethaade7d4a2017-07-20 19:53:35 +020048@Controller
margaretha7926adc2018-08-30 13:45:33 +020049@Path("/")
margarethaee0cbfe2018-08-28 17:47:14 +020050@ResourceFilters({ APIVersionFilter.class, AuthenticationFilter.class,
51 DemoUserFilter.class, PiwikFilter.class })
Michael Hanl19390652016-01-16 11:01:24 +010052@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
margarethad3c0fc92017-10-25 15:03:32 +020053public class SearchController {
Michael Hanl19390652016-01-16 11:01:24 +010054
margarethaa85965d2018-12-19 15:58:21 +010055 private static final boolean DEBUG = false;
56
margaretha20f31232018-07-09 17:49:39 +020057 private static Logger jlog = LogManager.getLogger(SearchController.class);
margaretha3d55b002019-03-19 12:00:44 +010058 private @Context ServletContext context;
59
margarethaade7d4a2017-07-20 19:53:35 +020060 @Autowired
margaretha20f31232018-07-09 17:49:39 +020061 private KustvaktResponseHandler kustvaktResponseHandler;
Michael Hanl19390652016-01-16 11:01:24 +010062
margaretha20f31232018-07-09 17:49:39 +020063 @Autowired
64 private SearchService searchService;
65 @Autowired
66 private OAuth2ScopeService scopeService;
margaretha3d55b002019-03-19 12:00:44 +010067
68 @POST
69 @Path("{version}/index/close")
70 public Response closeIndexReader (@FormParam("token") String token){
71 try {
72 searchService.closeIndexReader(token, context);
73 }
74 catch (KustvaktException e) {
75 throw kustvaktResponseHandler.throwit(e);
76 }
77 return Response.ok().build();
78 }
79
80
margaretha2544cdf2019-07-08 11:39:43 +020081// EM: This web service is DISABLED until there is a need for it.
82// ND: In case rewrite is supported, it could be used to check the authorization
83// scope without searching etc. In case not, it helps to compare queries in
84// different query languages.
85// MH: ref query parameter removed!
86// @GET
87// @Path("{version}/query")
margaretha20f31232018-07-09 17:49:39 +020088 public Response serializeQuery (@Context Locale locale,
89 @Context SecurityContext securityContext, @QueryParam("q") String q,
90 @QueryParam("ql") String ql, @QueryParam("v") String v,
91 @QueryParam("context") String context,
92 @QueryParam("cutoff") Boolean cutoff,
93 @QueryParam("count") Integer pageLength,
94 @QueryParam("offset") Integer pageIndex,
95 @QueryParam("page") Integer startPage,
margaretha2544cdf2019-07-08 11:39:43 +020096 @QueryParam("access-rewrite-disabled") boolean accessRewriteDisabled,
margaretha20f31232018-07-09 17:49:39 +020097 @QueryParam("cq") String cq) {
98 TokenContext ctx = (TokenContext) securityContext.getUserPrincipal();
99 try {
100 scopeService.verifyScope(ctx, OAuth2Scope.SERIALIZE_QUERY);
margaretha34954472018-10-24 20:05:17 +0200101 String result = searchService.serializeQuery(q, ql, v, cq,
margaretha2544cdf2019-07-08 11:39:43 +0200102 pageIndex, startPage, pageLength, context, cutoff,
103 accessRewriteDisabled);
margarethaa85965d2018-12-19 15:58:21 +0100104 if (DEBUG){
105 jlog.debug("Query: " + result);
106 }
margaretha34954472018-10-24 20:05:17 +0200107 return Response.ok(result).build();
margaretha20f31232018-07-09 17:49:39 +0200108 }
109 catch (KustvaktException e) {
margaretha34954472018-10-24 20:05:17 +0200110 throw kustvaktResponseHandler.throwit(e);
margaretha20f31232018-07-09 17:49:39 +0200111 }
margarethafc2040a2017-04-18 12:07:23 +0200112 }
margarethad3c0fc92017-10-25 15:03:32 +0200113
margaretha2544cdf2019-07-08 11:39:43 +0200114
115// This web service is DISABLED until there is a need for it.
116// @POST
117// @Path("{version}/search")
margaretha20f31232018-07-09 17:49:39 +0200118 public Response searchPost (@Context SecurityContext context,
margaretha2544cdf2019-07-08 11:39:43 +0200119 @Context Locale locale,
120 @Context HttpHeaders headers,
margaretha20f31232018-07-09 17:49:39 +0200121 String jsonld) {
margaretha2544cdf2019-07-08 11:39:43 +0200122
123 if (DEBUG){
124 jlog.debug("Serialized search: " + jsonld);
125 }
126
margaretha20f31232018-07-09 17:49:39 +0200127 TokenContext ctx = (TokenContext) context.getUserPrincipal();
128 try {
129 scopeService.verifyScope(ctx, OAuth2Scope.SEARCH);
margaretha2544cdf2019-07-08 11:39:43 +0200130 String result = searchService.search(jsonld, ctx.getUsername(),
131 headers);
132 return Response.ok(result).build();
margaretha20f31232018-07-09 17:49:39 +0200133 }
134 catch (KustvaktException e) {
135 throw kustvaktResponseHandler.throwit(e);
136 }
margaretha20f31232018-07-09 17:49:39 +0200137 }
138
margaretha1d1c73e2019-12-03 18:07:28 +0100139 /** Performs for the given query
140 *
141 * @param securityContext
142 * @param request
143 * @param headers
144 * @param locale
145 * @param q
146 * query
147 * @param ql
148 * query language
149 * @param v
150 * query language version
151 * @param ctx
152 * result context
153 * @param cutoff
154 * determines to limit search results to one page only
155 * or not (default false)
156 * @param pageLength
157 * the number of results should be included in a page
158 * @param pageIndex
159 * @param pageInteger page number
160 * @param fields
161 * metadata fields to be included, separated by comma
162 * @param pipes
163 * external plugins for additional processing,
164 * separated by comma
165 * @param accessRewriteDisabled
166 * determine if access rewrite should be disabled
167 * (default false)
168 * @param cq
169 * corpus query defining a virtual corpus
170 * @param engine
171 * @return search results in JSON
172 */
margaretha20f31232018-07-09 17:49:39 +0200173 @GET
margaretha7926adc2018-08-30 13:45:33 +0200174 @Path("{version}/search")
margaretha20f31232018-07-09 17:49:39 +0200175 public Response searchGet (@Context SecurityContext securityContext,
margaretha2544cdf2019-07-08 11:39:43 +0200176 @Context HttpServletRequest request,
margaretha20f31232018-07-09 17:49:39 +0200177 @Context HttpHeaders headers, @Context Locale locale,
178 @QueryParam("q") String q, @QueryParam("ql") String ql,
179 @QueryParam("v") String v, @QueryParam("context") String ctx,
180 @QueryParam("cutoff") Boolean cutoff,
181 @QueryParam("count") Integer pageLength,
182 @QueryParam("offset") Integer pageIndex,
183 @QueryParam("page") Integer pageInteger,
margarethaa85965d2018-12-19 15:58:21 +0100184 @QueryParam("fields") String fields,
margaretha1d1c73e2019-12-03 18:07:28 +0100185 @QueryParam("pipes") String pipes,
margaretha2544cdf2019-07-08 11:39:43 +0200186 @QueryParam("access-rewrite-disabled") boolean accessRewriteDisabled,
187 @QueryParam("cq") String cq,
188 @QueryParam("engine") String engine) {
margaretha20f31232018-07-09 17:49:39 +0200189
190 TokenContext context =
191 (TokenContext) securityContext.getUserPrincipal();
192
193 String result;
194 try {
195 scopeService.verifyScope(context, OAuth2Scope.SEARCH);
196 result = searchService.search(engine, context.getUsername(),
margaretha1d1c73e2019-12-03 18:07:28 +0100197 headers, q, ql, v, cq, fields, pipes, pageIndex,
198 pageInteger, ctx, pageLength, cutoff,
199 accessRewriteDisabled);
margaretha20f31232018-07-09 17:49:39 +0200200 }
201 catch (KustvaktException e) {
202 throw kustvaktResponseHandler.throwit(e);
203 }
204
205 return Response.ok(result).build();
206 }
207
margaretha351f7692019-02-06 19:36:52 +0100208 // EM: legacy support
209 @Deprecated
margaretha20f31232018-07-09 17:49:39 +0200210 @GET
margaretha7926adc2018-08-30 13:45:33 +0200211 @Path("{version}/corpus/{corpusId}/{docId}/{textId}/{matchId}/matchInfo")
margaretha20f31232018-07-09 17:49:39 +0200212 public Response getMatchInfo (@Context SecurityContext ctx,
213 @Context HttpHeaders headers, @Context Locale locale,
214 @PathParam("corpusId") String corpusId,
215 @PathParam("docId") String docId,
216 @PathParam("textId") String textId,
217 @PathParam("matchId") String matchId,
218 @QueryParam("foundry") Set<String> foundries,
219 @QueryParam("layer") Set<String> layers,
margaretha34954472018-10-24 20:05:17 +0200220 @QueryParam("spans") Boolean spans,
221 // Highlights may also be a list of valid highlight classes
222 @QueryParam("hls") Boolean highlights) throws KustvaktException {
margaretha20f31232018-07-09 17:49:39 +0200223
margaretha351f7692019-02-06 19:36:52 +0100224 return retrieveMatchInfo(ctx, headers, locale, corpusId, docId, textId,
225 matchId, foundries, layers, spans, highlights);
226 }
227
228 @GET
229 @Path("{version}/corpus/{corpusId}/{docId}/{textId}/{matchId}")
230 public Response retrieveMatchInfo (@Context SecurityContext ctx,
231 @Context HttpHeaders headers, @Context Locale locale,
232 @PathParam("corpusId") String corpusId,
233 @PathParam("docId") String docId,
234 @PathParam("textId") String textId,
235 @PathParam("matchId") String matchId,
236 @QueryParam("foundry") Set<String> foundries,
237 @QueryParam("layer") Set<String> layers,
238 @QueryParam("spans") Boolean spans,
239 // Highlights may also be a list of valid highlight classes
240 @QueryParam("hls") Boolean highlights) throws KustvaktException {
241
margaretha20f31232018-07-09 17:49:39 +0200242 TokenContext tokenContext = (TokenContext) ctx.getUserPrincipal();
243 scopeService.verifyScope(tokenContext, OAuth2Scope.MATCH_INFO);
244 spans = spans != null ? spans : false;
margaretha34954472018-10-24 20:05:17 +0200245 highlights = highlights != null ? highlights : false;
margaretha20f31232018-07-09 17:49:39 +0200246 if (layers == null || layers.isEmpty()) layers = new HashSet<>();
247
margaretha351f7692019-02-06 19:36:52 +0100248 try{
249 String results = searchService.retrieveMatchInfo(corpusId, docId,
250 textId, matchId, foundries, tokenContext.getUsername(),
251 headers, layers, spans, highlights);
252 return Response.ok(results).build();
253 }
254 catch (KustvaktException e) {
255 throw kustvaktResponseHandler.throwit(e);
256 }
257
margaretha20f31232018-07-09 17:49:39 +0200258 }
259
margaretha20f31232018-07-09 17:49:39 +0200260 /*
261 * Returns the meta data fields of a certain document
262 */
263 // This is currently identical to LiteService#getMeta(),
264 // but may need auth code to work following policies
265 @GET
margaretha7926adc2018-08-30 13:45:33 +0200266 @Path("{version}/corpus/{corpusId}/{docId}/{textId}")
margaretha20f31232018-07-09 17:49:39 +0200267 public Response getMetadata (@PathParam("corpusId") String corpusId,
margaretha351f7692019-02-06 19:36:52 +0100268 @PathParam("docId") String docId,
margaretha852a0f62019-02-19 12:14:30 +0100269 @PathParam("textId") String textId,
270 @QueryParam("fields") String fields,
margaretha351f7692019-02-06 19:36:52 +0100271 @Context SecurityContext ctx,
272 @Context HttpHeaders headers
273 // @QueryParam("fields") Set<String> fields
margaretha20f31232018-07-09 17:49:39 +0200274 ) throws KustvaktException {
margaretha351f7692019-02-06 19:36:52 +0100275 TokenContext tokenContext = (TokenContext) ctx.getUserPrincipal();
276 try {
277 String results = searchService.retrieveDocMetadata(corpusId, docId,
margaretha852a0f62019-02-19 12:14:30 +0100278 textId, fields, tokenContext.getUsername(), headers);
margaretha351f7692019-02-06 19:36:52 +0100279 return Response.ok(results).build();
280 }
281 catch (KustvaktException e) {
282 throw kustvaktResponseHandler.throwit(e);
283 }
margaretha20f31232018-07-09 17:49:39 +0200284 }
285
margaretha2544cdf2019-07-08 11:39:43 +0200286// EM: This web service requires Karang and is DISABLED.
287// @POST
288// @Path("{version}/colloc")
margaretha20f31232018-07-09 17:49:39 +0200289 public Response getCollocationBase (@QueryParam("q") String query) {
290 String result;
291 try {
292 result = searchService.getCollocationBase(query);
293 }
294 catch (KustvaktException e) {
295 throw kustvaktResponseHandler.throwit(e);
296 }
297 return Response.ok(result).build();
margarethaade7d4a2017-07-20 19:53:35 +0200298 }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200299
margarethafc2040a2017-04-18 12:07:23 +0200300 // @GET
301 // @Path("colloc")
margaretha20f31232018-07-09 17:49:39 +0200302 // public Response getCollocationsAll(@Context SecurityContext
303 // ctx,
margarethafc2040a2017-04-18 12:07:23 +0200304 // @Context Locale locale, @QueryParam("props") String properties,
305 // @QueryParam("sfskip") Integer sfs,
margaretha20f31232018-07-09 17:49:39 +0200306 // @QueryParam("sflimit") Integer limit, @QueryParam("q") String
307 // query,
308 // @QueryParam("ql") String ql, @QueryParam("context") Integer
309 // context,
margarethafc2040a2017-04-18 12:07:23 +0200310 // @QueryParam("foundry") String foundry,
311 // @QueryParam("paths") Boolean wPaths) {
margaretha20f31232018-07-09 17:49:39 +0200312 // TokenContext tokenContext = (TokenContext)
313 // ctx.getUserPrincipal();
margarethafc2040a2017-04-18 12:07:23 +0200314 // ColloQuery.ColloQueryBuilder builder;
margaretha20f31232018-07-09 17:49:39 +0200315 // KoralCollectionQueryBuilder cquery = new
316 // KoralCollectionQueryBuilder();
margarethafc2040a2017-04-18 12:07:23 +0200317 // String result;
318 // try {
319 // User user = controller.getUser(tokenContext.getUsername());
320 // Set<VirtualCollection> resources = ResourceFinder
321 // .search(user, VirtualCollection.class);
322 // for (KustvaktResource c : resources)
323 // cquery.addResource(((VirtualCollection) c).getQuery());
324 //
325 // builder = functions
326 // .buildCollocations(query, ql, properties, context, limit,
327 // sfs, foundry, new ArrayList<Dependency>(), wPaths,
328 // cquery);
329 //
330 // result = graphDBhandler
331 // .getResponse("distCollo", "q", builder.build().toJSON());
332 // }catch (KustvaktException e) {
333 // throw KustvaktResponseHandler.throwit(e);
334 // }catch (JsonProcessingException e) {
margaretha20f31232018-07-09 17:49:39 +0200335 // throw
336 // KustvaktResponseHandler.throwit(StatusCodes.ILLEGAL_ARGUMENT);
margarethafc2040a2017-04-18 12:07:23 +0200337 // }
338 // return Response.ok(result).build();
339 // }
Michael Hanl8abaf9e2016-05-23 16:46:35 +0200340
margarethafc2040a2017-04-18 12:07:23 +0200341 // /**
342 // * @param locale
margaretha20f31232018-07-09 17:49:39 +0200343 // * @param properties a json object string containing field, op
344 // and value
margarethafc2040a2017-04-18 12:07:23 +0200345 // for the query
346 // * @param query
347 // * @param context
348 // * @return
349 // */
350 // @GET
351 // @Path("{type}/{id}/colloc")
352 // public Response getCollocations(@Context SecurityContext ctx,
353 // @Context Locale locale, @QueryParam("props") String properties,
354 // @QueryParam("sfskip") Integer sfs,
margaretha20f31232018-07-09 17:49:39 +0200355 // @QueryParam("sflimit") Integer limit, @QueryParam("q") String
356 // query,
357 // @QueryParam("ql") String ql, @QueryParam("context") Integer
358 // context,
margarethafc2040a2017-04-18 12:07:23 +0200359 // @QueryParam("foundry") String foundry,
margaretha20f31232018-07-09 17:49:39 +0200360 // @QueryParam("paths") Boolean wPaths, @PathParam("id") String
361 // id,
margarethafc2040a2017-04-18 12:07:23 +0200362 // @PathParam("type") String type) {
363 // ColloQuery.ColloQueryBuilder builder;
364 // type = StringUtils.normalize(type);
365 // id = StringUtils.decodeHTML(id);
margaretha20f31232018-07-09 17:49:39 +0200366 // TokenContext tokenContext = (TokenContext)
367 // ctx.getUserPrincipal();
margarethafc2040a2017-04-18 12:07:23 +0200368 // String result;
369 // try {
margaretha20f31232018-07-09 17:49:39 +0200370 // KoralCollectionQueryBuilder cquery = new
371 // KoralCollectionQueryBuilder();
margarethafc2040a2017-04-18 12:07:23 +0200372 // try {
373 // User user = controller.getUser(tokenContext.getUsername());
374 //
375 // KustvaktResource resource = this.resourceHandler
376 // .findbyStrId(id, user, type);
377 //
378 // if (resource instanceof VirtualCollection)
379 // cquery.addResource(
380 // ((VirtualCollection) resource).getQuery());
381 // else if (resource instanceof Corpus)
382 // cquery.addMetaFilter("corpusID",
383 // resource.getPersistentID());
384 // else
385 // throw KustvaktResponseHandler
386 // .throwit(StatusCodes.ILLEGAL_ARGUMENT,
387 // "Type parameter not supported", type);
388 //
389 // }catch (KustvaktException e) {
390 // throw KustvaktResponseHandler.throwit(e);
391 // }catch (NumberFormatException ex) {
392 // throw KustvaktResponseHandler
393 // .throwit(StatusCodes.ILLEGAL_ARGUMENT);
394 // }
395 //
396 // builder = functions
397 // .buildCollocations(query, ql, properties, context, limit,
398 // sfs, foundry, new ArrayList<Dependency>(), wPaths,
399 // cquery);
400 //
401 // result = graphDBhandler
402 // .getResponse("distCollo", "q", builder.build().toJSON());
403 //
404 // }catch (JsonProcessingException e) {
margaretha20f31232018-07-09 17:49:39 +0200405 // throw
406 // KustvaktResponseHandler.throwit(StatusCodes.ILLEGAL_ARGUMENT);
margarethafc2040a2017-04-18 12:07:23 +0200407 // }catch (KustvaktException e) {
408 // throw KustvaktResponseHandler.throwit(e);
409 // }
410 //
411 // return Response.ok(result).build();
412 // }
Akronac049e82018-02-22 20:54:09 +0100413
Michael Hanl19390652016-01-16 11:01:24 +0100414}