Added the possibility to list items by specifying query parameters (used

for direct query on Slr via Ckan package_search API)
This commit is contained in:
Luca Frosini 2019-10-01 18:00:40 +02:00
parent 9779afe1e5
commit 78a54707ec
3 changed files with 142 additions and 19 deletions

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.DELETE; 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 // 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 START_KEY = "start";
protected static final String Q_KEY = "q"; protected static final String ORGANIZATION_FILTER_TEMPLATE = GCatConstants.ORGANIZATION_PARAMETER + ":%s";
protected static final String ORGANIZATION_FILTER_TEMPLATE = "organization:%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"; 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 SEARCHABLE_KEY = "searchable";
protected static final String CAPACITY_KEY = "capacity"; protected static final String CAPACITY_KEY = "capacity";
// protected static final String INCLUDE_PRIVATE_KEY = "include_private"; // protected static final String INCLUDE_PRIVATE_KEY = "include_private";
// protected static final String INCLUDE_DRAFTS_KEY = "include_drafts"; // 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)); parameters.put(START_KEY, String.valueOf(offset * limit));
if(uriInfo!=null) {
MultivaluedMap<String,String> queryParameters = uriInfo.getQueryParameters();
parameters = checkListParameters(queryParameters, parameters);
}
return list(parameters);
}
protected void checkOrganizationFilter(String q) {
Matcher m = ORGANIZATION_REGEX_PATTERN.matcher(q);
List<String> 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<String,String> checkListParameters(MultivaluedMap<String,String> queryParameters,
Map<String,String> parameters) {
String organizationName = getOrganizationName(); String organizationName = getOrganizationName();
ScopeBean scopeBean = new ScopeBean(ContextUtility.getCurrentContext()); 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. * 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 * If the request arrive form a VO or from ROOT the request return the item in all organizations
* in the catalog. * in the catalog.
*/ */
String organizationQueryString = null;
if(scopeBean.is(Type.VRE)) { if(scopeBean.is(Type.VRE)) {
organizationQueryString = String.format(ORGANIZATION_FILTER_TEMPLATE, organizationName); if(q != null) {
}else { checkOrganizationFilter(q);
/*
* We provide the possibility for the client to get the list of an item in an organization // Adding organization filter to q
* if the request arrives from a VO o from the ROOT parameters.put(GCatConstants.Q_KEY,
*/ String.format("%s:%s AND %s", GCatConstants.ORGANIZATION_PARAMETER, organizationName, q));
MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
if(queryParameters!=null && queryParameters.containsKey(GCatConstants.ORGANIZATION_PARAMETER)) { } else {
String org = queryParameters.getFirst(GCatConstants.ORGANIZATION_PARAMETER); parameters.put(GCatConstants.Q_KEY,
organizationQueryString = String.format(ORGANIZATION_FILTER_TEMPLATE, org); 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) { for(String key : queryParameters.keySet()) {
parameters.put(Q_KEY, organizationQueryString); // 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)); // parameters.put(INCLUDE_PRIVATE_KEY, String.valueOf(true));
@ -283,6 +347,11 @@ public class CKANPackage extends CKAN {
// By default not including draft // By default not including draft
// parameters.put(INCLUDE_DRAFTS_KEY, String.valueOf(false)); // parameters.put(INCLUDE_DRAFTS_KEY, String.valueOf(false));
return parameters;
}
public String list(Map<String,String> parameters) {
sendGetRequest(LIST, parameters); sendGetRequest(LIST, parameters);
ArrayNode results = (ArrayNode) result.get(RESULTS_KEY); ArrayNode results = (ArrayNode) result.get(RESULTS_KEY);

View File

@ -1,5 +1,7 @@
package org.gcube.gcat.rest; package org.gcube.gcat.rest;
import java.util.Map;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE; import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
@ -30,6 +32,15 @@ public class Item extends REST<CKANPackage> implements org.gcube.gcat.api.interf
super(ITEMS, ITEM_ID_PARAMETER, CKANPackage.class); 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<String,String> parameters) throws WebServiceException {
CKANPackage ckan = getInstance();
return ckan.list(parameters);
}
@GET @GET
@Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8) @Produces(ResourceInitializer.APPLICATION_JSON_CHARSET_UTF_8)
@Override @Override

View File

@ -3,7 +3,12 @@ package org.gcube.gcat.persistence.ckan;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; 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.ContextTest;
import org.gcube.gcat.api.GCatConstants;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -33,12 +38,50 @@ public class CKANPackageTest extends ContextTest {
public void list() throws Exception { public void list() throws Exception {
CKANPackage ckanPackage = new CKANPackage(); CKANPackage ckanPackage = new CKANPackage();
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
String ret = ckanPackage.list(-1, 0); String ret = ckanPackage.list(10, 0);
JsonNode gotList = mapper.readTree(ret); JsonNode gotList = mapper.readTree(ret);
Assert.assertTrue(gotList instanceof ArrayNode); Assert.assertTrue(gotList instanceof ArrayNode);
logger.debug("List :\n{}", mapper.writeValueAsString(gotList)); logger.debug("List :\n{}", mapper.writeValueAsString(gotList));
} }
@Test
public void listWithParameters() throws Exception {
CKANPackage ckanPackage = new CKANPackage();
ObjectMapper mapper = new ObjectMapper();
Map<String, String> 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<String, String> parameters = new HashMap<>();
CKANPackage ckanPackage = new CKANPackage();
MultivaluedMap<String,String> queryParameters = new MultivaluedHashMap<>();
queryParameters.add(GCatConstants.Q_KEY, "organization:nextnext OR organization:devsec");
parameters = ckanPackage.checkListParameters(queryParameters, parameters);
logger.debug("{}", parameters);
}
/* /*
* PRE * PRE
* *