Implemented configurable resource filters for search and match info APIs
Added tests and settings for ICC scenario.
Change-Id: If22b96cd12f2a39c134a45f9e3e4b2da8bcd36dc
diff --git a/core/Changes b/core/Changes
index cd92fca..3590c21 100644
--- a/core/Changes
+++ b/core/Changes
@@ -2,6 +2,7 @@
- Support token array in matchinfo (fixes #570; diewald)
- Added user info web-service (solved #566)
+- Implemented configurable resource filters for search and match info APIs
# version 0.69.3
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java b/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
index 3cc768b..7c180e8 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
@@ -29,7 +29,7 @@
import org.springframework.stereotype.Controller;
import de.ids_mannheim.korap.web.utils.ResourceFilters;
-
+import de.ids_mannheim.korap.web.utils.SearchResourceFilters;
import de.ids_mannheim.korap.config.KustvaktConfiguration;
import de.ids_mannheim.korap.constant.OAuth2Scope;
import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -154,6 +154,7 @@
@POST
@Path("{version}/search")
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ @SearchResourceFilters
public Response searchPost (@Context SecurityContext context,
@Context Locale locale,
@Context HttpHeaders headers,
@@ -212,6 +213,7 @@
@GET
@Path("{version}/search")
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ @SearchResourceFilters
public Response searchGet (@Context SecurityContext securityContext,
@Context HttpServletRequest request,
@Context HttpHeaders headers, @Context Locale locale,
@@ -251,6 +253,7 @@
@GET
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
@Path("{version}/corpus/{corpusId}/{docId}/{textId}/{matchId}/matchInfo")
+ @SearchResourceFilters
public Response getMatchInfo (@Context SecurityContext ctx,
@Context HttpHeaders headers, @Context Locale locale,
@PathParam("corpusId") String corpusId,
@@ -271,6 +274,7 @@
@GET
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
@Path("{version}/corpus/{corpusId}/{docId}/{textId}/{matchId}")
+ @SearchResourceFilters
public Response retrieveMatchInfo (@Context SecurityContext ctx,
@Context HttpHeaders headers, @Context Locale locale,
@PathParam("corpusId") String corpusId,
@@ -286,37 +290,45 @@
// Highlights may also be a list of valid highlight classes
@QueryParam("hls") Boolean highlights) throws KustvaktException {
- Boolean expandToSentence = true;
- if (expansion != null && (expansion.equals("false") || expansion.equals("null"))) {
- expandToSentence = false;
+ TokenContext tokenContext = (TokenContext) ctx.getUserPrincipal();
+ try {
+ scopeService.verifyScope(tokenContext, OAuth2Scope.MATCH_INFO);
+ }
+ catch (KustvaktException e) {
+ throw kustvaktResponseHandler.throwit(e);
}
- TokenContext tokenContext = (TokenContext) ctx.getUserPrincipal();
- scopeService.verifyScope(tokenContext, OAuth2Scope.MATCH_INFO);
+ Boolean expandToSentence = true;
+ if (expansion != null
+ && (expansion.equals("false") || expansion.equals("null"))) {
+ expandToSentence = false;
+ }
spans = spans != null ? spans : false;
Boolean snippet = true;
Boolean tokens = false;
- if (snippetStr != null && (snippetStr.equals("false") || snippetStr.equals("null")))
+ if (snippetStr != null
+ && (snippetStr.equals("false") || snippetStr.equals("null")))
snippet = false;
- if (tokensStr != null && (tokensStr.equals("true") || tokensStr.equals("1") || tokensStr.equals("yes")))
+ if (tokensStr != null && (tokensStr.equals("true")
+ || tokensStr.equals("1") || tokensStr.equals("yes")))
tokens = true;
highlights = highlights != null ? highlights : false;
- if (layers == null || layers.isEmpty()) layers = new HashSet<>();
+ if (layers == null || layers.isEmpty())
+ layers = new HashSet<>();
- try{
- String results = searchService.retrieveMatchInfo(
- corpusId, docId,
- textId, matchId, true, foundries, tokenContext.getUsername(),
- headers, layers, spans, snippet, tokens,
- expandToSentence, highlights);
+ try {
+ String results = searchService.retrieveMatchInfo(corpusId, docId,
+ textId, matchId, true, foundries,
+ tokenContext.getUsername(), headers, layers, spans, snippet,
+ tokens, expandToSentence, highlights);
return Response.ok(results).build();
}
catch (KustvaktException e) {
throw kustvaktResponseHandler.throwit(e);
}
-
+
}
/*
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/utils/SearchResourceFilters.java b/core/src/main/java/de/ids_mannheim/korap/web/utils/SearchResourceFilters.java
new file mode 100644
index 0000000..12dbf57
--- /dev/null
+++ b/core/src/main/java/de/ids_mannheim/korap/web/utils/SearchResourceFilters.java
@@ -0,0 +1,22 @@
+package de.ids_mannheim.korap.web.utils;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines the list of {@link javax.ws.rs.container.ContainerRequestFilter}
+ * and {@link javax.ws.rs.container.ContainerResponseFilter}
+ * classes associated with a resource method.
+ * <p>
+ * This annotation can be specified on a class or on method(s). Specifying it
+ * at a class level means that it applies to all the methods in the class.
+ * Specifying it on a method means that it is applicable to that method only.
+ * If applied at both the class and methods level , the method value overrides
+ * the class value.
+ */
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SearchResourceFilters {
+}
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/utils/SearchResourceFiltersFeature.java b/core/src/main/java/de/ids_mannheim/korap/web/utils/SearchResourceFiltersFeature.java
new file mode 100644
index 0000000..45a7c4e
--- /dev/null
+++ b/core/src/main/java/de/ids_mannheim/korap/web/utils/SearchResourceFiltersFeature.java
@@ -0,0 +1,58 @@
+package de.ids_mannheim.korap.web.utils;
+
+import java.util.List;
+
+import javax.ws.rs.container.DynamicFeature;
+import javax.ws.rs.container.ResourceInfo;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.ext.Provider;
+
+import org.glassfish.jersey.model.internal.CommonConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import de.ids_mannheim.korap.web.filter.APIVersionFilter;
+import edu.emory.mathcs.backport.java.util.Arrays;
+
+/**
+ * Registers {@link javax.ws.rs.container.ContainerRequestFilter}
+ * and {@link javax.ws.rs.container.ContainerResponseFilter}
+ * classes for a resource method annotated with {@link ResourceFilters}.
+ */
+@Provider
+@Component
+public class SearchResourceFiltersFeature implements DynamicFeature {
+
+ @Value("${search.resource.filters:AuthenticationFilter,DemoUserFilter}")
+ private String[] resourceFilters;
+
+ @Override
+ public void configure (ResourceInfo resourceInfo, FeatureContext context) {
+ SearchResourceFilters filters = resourceInfo.getResourceMethod()
+ .getAnnotation(SearchResourceFilters.class);
+ if (filters != null) {
+ CommonConfig con = (CommonConfig) context.getConfiguration();
+ con.getComponentBag().clear();
+ }
+ else {
+ filters = resourceInfo.getResourceClass()
+ .getAnnotation(SearchResourceFilters.class);
+ }
+
+ if (filters != null) {
+ List<?> list = Arrays.asList(resourceFilters);
+ if (!list.contains("APIVersionFilter")) {
+ context.register(APIVersionFilter.class);
+ }
+
+ for(String c : resourceFilters) {
+ try {
+ context.register(Class.forName("de.ids_mannheim.korap.web.filter." + c));
+ }
+ catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}