From 78a54707ecb0a8bf2b99b64f0f1ad94868af327f Mon Sep 17 00:00:00 2001 From: Luca Frosini Date: Tue, 1 Oct 2019 18:00:40 +0200 Subject: [PATCH] Added the possibility to list items by specifying query parameters (used for direct query on Slr via Ckan package_search API) --- .../gcat/persistence/ckan/CKANPackage.java | 105 +++++++++++++++--- src/main/java/org/gcube/gcat/rest/Item.java | 11 ++ .../persistence/ckan/CKANPackageTest.java | 45 +++++++- 3 files changed, 142 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/gcube/gcat/persistence/ckan/CKANPackage.java b/src/main/java/org/gcube/gcat/persistence/ckan/CKANPackage.java index 3056a28..c8c3390 100644 --- a/src/main/java/org/gcube/gcat/persistence/ckan/CKANPackage.java +++ b/src/main/java/org/gcube/gcat/persistence/ckan/CKANPackage.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.ws.rs.BadRequestException; import javax.ws.rs.DELETE; @@ -63,8 +65,15 @@ public class CKANPackage extends CKAN { // offset in https://docs.ckan.org/en/latest/api/index.html#ckan.logic.action.get.package_search protected static final String START_KEY = "start"; - protected static final String Q_KEY = "q"; - protected static final String ORGANIZATION_FILTER_TEMPLATE = "organization:%s"; + protected static final String ORGANIZATION_FILTER_TEMPLATE = GCatConstants.ORGANIZATION_PARAMETER + ":%s"; + + protected static final String ORGANIZATION_REGEX = GCatConstants.ORGANIZATION_PARAMETER + ":[a-zA-Z_\"]*"; + + protected static final Pattern ORGANIZATION_REGEX_PATTERN; + + static { + ORGANIZATION_REGEX_PATTERN = Pattern.compile(ORGANIZATION_REGEX); + } protected static final String LICENSE_KEY = "license_id"; @@ -88,8 +97,6 @@ public class CKANPackage extends CKAN { protected static final String SEARCHABLE_KEY = "searchable"; protected static final String CAPACITY_KEY = "capacity"; - - // protected static final String INCLUDE_PRIVATE_KEY = "include_private"; // protected static final String INCLUDE_DRAFTS_KEY = "include_drafts"; @@ -251,31 +258,88 @@ public class CKANPackage extends CKAN { } parameters.put(START_KEY, String.valueOf(offset * limit)); + if(uriInfo!=null) { + MultivaluedMap queryParameters = uriInfo.getQueryParameters(); + parameters = checkListParameters(queryParameters, parameters); + } + + return list(parameters); + } + + protected void checkOrganizationFilter(String q) { + Matcher m = ORGANIZATION_REGEX_PATTERN.matcher(q); + + List matches = new ArrayList<>(); + while(m.find()) { + matches.add(q.substring(m.start(), m.end())); + } + + if(matches.size()>0) { + StringBuilder error = new StringBuilder(); + error.append("Organization filters is constrained to VRE. "); + if(matches.size()>1) { + error.append("Remove these filters "); + }else { + error.append("Remove this filter "); + } + boolean first = true; + for(String match : matches) { + if(!first) { + error.append(", "); + }else { + first = false; + } + error.append("["); + error.append(match); + error.append("]"); + } + throw new BadRequestException(error.toString()); + } + } + + protected Map checkListParameters(MultivaluedMap queryParameters, + Map parameters) { + String organizationName = getOrganizationName(); ScopeBean scopeBean = new ScopeBean(ContextUtility.getCurrentContext()); + String q = null; + if(queryParameters.containsKey(GCatConstants.Q_KEY)) { + q = queryParameters.getFirst(GCatConstants.Q_KEY); + } + /* * List is filter per organization only is the request arriving in a VRE. * If the request arrive form a VO or from ROOT the request return the item in all organizations * in the catalog. - */ - String organizationQueryString = null; + */ if(scopeBean.is(Type.VRE)) { - organizationQueryString = String.format(ORGANIZATION_FILTER_TEMPLATE, organizationName); - }else { - /* - * We provide the possibility for the client to get the list of an item in an organization - * if the request arrives from a VO o from the ROOT - */ - MultivaluedMap queryParameters = uriInfo.getQueryParameters(); - if(queryParameters!=null && queryParameters.containsKey(GCatConstants.ORGANIZATION_PARAMETER)) { - String org = queryParameters.getFirst(GCatConstants.ORGANIZATION_PARAMETER); - organizationQueryString = String.format(ORGANIZATION_FILTER_TEMPLATE, org); + if(q != null) { + checkOrganizationFilter(q); + + // Adding organization filter to q + parameters.put(GCatConstants.Q_KEY, + String.format("%s:%s AND %s", GCatConstants.ORGANIZATION_PARAMETER, organizationName, q)); + + } else { + parameters.put(GCatConstants.Q_KEY, + String.format(GCatConstants.ORGANIZATION_FILTER_TEMPLATE, organizationName)); } + + } else { + // We are in VO or in ROOT. + // The organization filtering is allowed for the client which must provide q parameter in the form: + // q=organization:nextnext } - if(organizationQueryString!=null) { - parameters.put(Q_KEY, organizationQueryString); + for(String key : queryParameters.keySet()) { + // if 'rows' and 'start' are provided they replace the values imposed by caller + // provided limit and offset parameter which are the gCat interface are not passed to CKAN + if(key.compareTo(GCatConstants.LIMIT_PARAMETER) == 0 + || key.compareTo(GCatConstants.OFFSET_PARAMETER) == 0) { + continue; + } + parameters.put(key, queryParameters.getFirst(key)); } // parameters.put(INCLUDE_PRIVATE_KEY, String.valueOf(true)); @@ -283,6 +347,11 @@ public class CKANPackage extends CKAN { // By default not including draft // parameters.put(INCLUDE_DRAFTS_KEY, String.valueOf(false)); + return parameters; + } + + public String list(Map parameters) { + sendGetRequest(LIST, parameters); ArrayNode results = (ArrayNode) result.get(RESULTS_KEY); diff --git a/src/main/java/org/gcube/gcat/rest/Item.java b/src/main/java/org/gcube/gcat/rest/Item.java index 89f031f..211896c 100644 --- a/src/main/java/org/gcube/gcat/rest/Item.java +++ b/src/main/java/org/gcube/gcat/rest/Item.java @@ -1,5 +1,7 @@ package org.gcube.gcat.rest; +import java.util.Map; + import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; @@ -30,6 +32,15 @@ public class Item extends REST implements org.gcube.gcat.api.interf super(ITEMS, ITEM_ID_PARAMETER, CKANPackage.class); } + /* + * Not used as REST method, implemented to respect {@link org.gcube.gcat.api.interfaces.Item} interface + */ + @Override + public String list(Map parameters) throws WebServiceException { + CKANPackage ckan = getInstance(); + return ckan.list(parameters); + } + @GET @Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8) @Override diff --git a/src/test/java/org/gcube/gcat/persistence/ckan/CKANPackageTest.java b/src/test/java/org/gcube/gcat/persistence/ckan/CKANPackageTest.java index 9b18351..788e6dc 100644 --- a/src/test/java/org/gcube/gcat/persistence/ckan/CKANPackageTest.java +++ b/src/test/java/org/gcube/gcat/persistence/ckan/CKANPackageTest.java @@ -3,7 +3,12 @@ package org.gcube.gcat.persistence.ckan; import java.util.HashMap; import java.util.Map; +import javax.ws.rs.BadRequestException; +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; + import org.gcube.gcat.ContextTest; +import org.gcube.gcat.api.GCatConstants; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -33,12 +38,50 @@ public class CKANPackageTest extends ContextTest { public void list() throws Exception { CKANPackage ckanPackage = new CKANPackage(); ObjectMapper mapper = new ObjectMapper(); - String ret = ckanPackage.list(-1, 0); + String ret = ckanPackage.list(10, 0); JsonNode gotList = mapper.readTree(ret); Assert.assertTrue(gotList instanceof ArrayNode); logger.debug("List :\n{}", mapper.writeValueAsString(gotList)); } + @Test + public void listWithParameters() throws Exception { + CKANPackage ckanPackage = new CKANPackage(); + ObjectMapper mapper = new ObjectMapper(); + Map parameters = new HashMap<>(); + parameters.put(GCatConstants.Q_KEY, "organization:ckand4scienceharvest OR organization:dorne"); + // parameters.put(GCatConstants.Q_KEY, "organization:ckand4scienceharvest"); + // parameters.put(GCatConstants.Q_KEY, "organization:dorne"); + parameters.put(CKANPackage.ROWS_KEY, String.valueOf(10)); + parameters.put(CKANPackage.START_KEY, String.valueOf(0)); + //parameters.put("",""); + + String ret = ckanPackage.list(parameters); + JsonNode gotList = mapper.readTree(ret); + Assert.assertTrue(gotList instanceof ArrayNode); + + logger.debug("List :\n{}", mapper.writeValueAsString(gotList)); + + } + + + + @Test(expected=BadRequestException.class) + public void checkParameter() throws Exception { + + Map parameters = new HashMap<>(); + + CKANPackage ckanPackage = new CKANPackage(); + + MultivaluedMap queryParameters = new MultivaluedHashMap<>(); + queryParameters.add(GCatConstants.Q_KEY, "organization:nextnext OR organization:devsec"); + + parameters = ckanPackage.checkListParameters(queryParameters, parameters); + + logger.debug("{}", parameters); + } + + /* * PRE *