Added regular expression for paths of the services in order to ensure that it contains one among ram, fishsource, grsf, firms values. Update the methods to delete a stock/fishery by id (they checked the id actually belonged to a fishery/stock of a given group). The methods used to retrieve fishery/stock ids have been changed too: in case grsf source was used it is straightforward, in the other case the full set of records of the group needs to be scanned to separate stock and fishery ones.

git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/grsf-publisher-ws@142734 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Costantino Perciante 2017-02-19 14:53:42 +00:00
parent 3c9b149d54
commit 6b1e41d577
4 changed files with 166 additions and 89 deletions

View File

@ -15,7 +15,7 @@ public class ResponseCreationBean {
private String kbUuid; // the original uuid given by the KB private String kbUuid; // the original uuid given by the KB
@JsonProperty("product_url") @JsonProperty("product_url")
String productUrl; String itemUrl;
@JsonProperty("error") @JsonProperty("error")
private String error; // in case of error private String error; // in case of error
@ -35,7 +35,7 @@ public class ResponseCreationBean {
super(); super();
this.id = id; this.id = id;
this.kbUuid = kbUuid; this.kbUuid = kbUuid;
this.productUrl = productUrl; this.itemUrl = itemUrl;
this.error = error; this.error = error;
} }
@ -47,10 +47,6 @@ public class ResponseCreationBean {
this.id = id; this.id = id;
} }
public void setProductUrl(String productUrl) {
this.productUrl = productUrl;
}
public String getError() { public String getError() {
return error; return error;
} }
@ -67,13 +63,18 @@ public class ResponseCreationBean {
this.kbUuid = kbUuid; this.kbUuid = kbUuid;
} }
public String getProductUrl() { public String getItemUrl() {
return productUrl; return itemUrl;
}
public void setItemUrl(String itemUrl) {
this.itemUrl = itemUrl;
} }
@Override @Override
public String toString() { public String toString() {
return "ResponseCreationBean [id=" + id + ", kbUuid=" + kbUuid return "ResponseCreationBean [id=" + id + ", kbUuid=" + kbUuid
+ ", productUrl=" + productUrl + ", error=" + error + "]"; + ", itemUrl=" + itemUrl + ", error=" + error + "]";
} }
} }

View File

@ -209,9 +209,10 @@ public class CommonServiceUtils {
for (int i = 0; i < asList.size(); i++) { for (int i = 0; i < asList.size(); i++) {
boolean match = conditionToCheck.equals("") ? true : asList.get(i).toString().trim().matches(conditionToCheck); boolean match = conditionToCheck.equals("") ? true : asList.get(i).toString().trim().matches(conditionToCheck);
if(match){ if(match){
String groupName = HelperMethods.getGroupNameOnCkan(source.toString().toLowerCase() + "-" + asList.get(i).toString().trim()); String groupName = HelperMethods.getGroupNameOnCkan(source.toString().toLowerCase() + "-" + asList.get(i).toString().trim());
logger.debug(groupName);
groups.add(groupName); groups.add(groupName);
} }
} }
@ -221,8 +222,10 @@ public class CommonServiceUtils {
// also convert to the group name that should be on ckan // also convert to the group name that should be on ckan
boolean match = conditionToCheck.equals("") ? true : f.toString().trim().matches(conditionToCheck); boolean match = conditionToCheck.equals("") ? true : f.toString().trim().matches(conditionToCheck);
if(match){ if(match){
String groupName = HelperMethods.getGroupNameOnCkan(source.toString().toLowerCase() + "-" + f.toString().trim()); String groupName = HelperMethods.getGroupNameOnCkan(source.toString().toLowerCase() + "-" + f.toString().trim());
groups.add(groupName); groups.add(groupName);
} }
} }
} }
@ -245,7 +248,7 @@ public class CommonServiceUtils {
} }
// add the record among the source group (check for grsf-group) // add the record among the source group (check for grsf-group)
groups.add(source.equals(Sources.GRSF) ? "grsf-group" : source.getOrigName()); groups.add(source.equals(Sources.GRSF) ? "grsf-group" : source.getOrigName().toLowerCase());
} }
/** /**

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -29,6 +30,7 @@ import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.utils.Caller; import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.Common;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.DeleteProductBean; import org.gcube.data_catalogue.grsf_publish_ws.json.input.DeleteProductBean;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.FisheryRecord; import org.gcube.data_catalogue.grsf_publish_ws.json.input.FisheryRecord;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.RefersToBean; import org.gcube.data_catalogue.grsf_publish_ws.json.input.RefersToBean;
@ -41,9 +43,6 @@ import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Sources;
import org.gcube.data_catalogue.grsf_publish_ws.utils.threads.AssociationToGroupThread; import org.gcube.data_catalogue.grsf_publish_ws.utils.threads.AssociationToGroupThread;
import org.gcube.data_catalogue.grsf_publish_ws.utils.threads.ManageTimeSeriesThread; import org.gcube.data_catalogue.grsf_publish_ws.utils.threads.ManageTimeSeriesThread;
import org.gcube.data_catalogue.grsf_publish_ws.utils.threads.WritePostCatalogueManagerThread; import org.gcube.data_catalogue.grsf_publish_ws.utils.threads.WritePostCatalogueManagerThread;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.server.models.ResourceBean;
import org.gcube.datacatalogue.ckanutillibrary.shared.RolesCkanGroupOrOrg;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import eu.trentorise.opendata.jackan.model.CkanDataset; import eu.trentorise.opendata.jackan.model.CkanDataset;
@ -52,19 +51,21 @@ import eu.trentorise.opendata.jackan.model.CkanDataset;
* Fishery web service methods * Fishery web service methods
* @author Costantino Perciante at ISTI-CNR * @author Costantino Perciante at ISTI-CNR
*/ */
@Path("{source}/fishery/") @Path("{source:firms|FIRMS|ram|RAM|grsf|GRSF|FishSource|fishsource}/fishery/")
public class GrsfPublisherFisheryService { public class GrsfPublisherFisheryService {
// the default license for these records
private static final String DEFAULT_FISHERY_LICENSE = "CC-BY-SA-4.0"; private static final String DEFAULT_FISHERY_LICENSE = "CC-BY-SA-4.0";
// item url property
private static final String ITEM_URL_FIELD = "Item URL";
// the context // the context
@Context ServletContext contextServlet; @Context ServletContext contextServlet;
// Logger // Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GrsfPublisherFisheryService.class); private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GrsfPublisherFisheryService.class);
private static final String ITEM_URL_FIELD = "Item URL";
@GET @GET
@Path("hello") @Path("hello")
@Produces(MediaType.TEXT_PLAIN) @Produces(MediaType.TEXT_PLAIN)
@ -113,23 +114,20 @@ public class GrsfPublisherFisheryService {
// Cast the source to the accepted ones // Cast the source to the accepted ones
Sources sourceInPath = Sources.onDeserialize(source); Sources sourceInPath = Sources.onDeserialize(source);
if(sourceInPath == null){
status = Status.BAD_REQUEST;
throw new Exception("The specified source in the path is unrecognized. Values accepted are " + Sources.getAsList());
}
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context); DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
if(catalogue == null){ if(catalogue == null){
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("There was a problem while serving your request"); throw new Exception("There was a problem while serving your request. No catalogue instance was found!");
}else{ }else{
String apiKey = catalogue.getApiKeyFromUsername(username); String apiKey = catalogue.getApiKeyFromUsername(username);
// check the user has editor/admin role into the org
String organization = HelperMethods.retrieveOrgNameFromScope(context); String organization = HelperMethods.retrieveOrgNameFromScope(context);
String role = catalogue.getRoleOfUserInOrganization(username, organization, apiKey); String role = catalogue.getRoleOfUserInOrganization(username, organization, apiKey);
logger.info("Role of the user " + username + " is " + role); logger.info("Role of the user " + username + " is " + role);
if(!role.equalsIgnoreCase(RolesCkanGroupOrOrg.ADMIN.toString())){ if(!role.equalsIgnoreCase(RolesCkanGroupOrOrg.ADMIN.toString())){
status = Status.FORBIDDEN; status = Status.FORBIDDEN;
throw new Exception("You are not authorized to create a product. Please check you have the Catalogue-admin role!"); throw new Exception("You are not authorized to create a product. Please check you have the Catalogue-admin role!");
@ -139,9 +137,12 @@ public class GrsfPublisherFisheryService {
// fishing area and jurisdiction area cannot be empty at the same time // fishing area and jurisdiction area cannot be empty at the same time
String futureName = record.getUuid(); String futureName = record.getUuid();
String futureTitle = record.getFisheryName(); String futureTitle = record.getFisheryName();
if(!HelperMethods.isNameValid(futureName)){ if(!HelperMethods.isNameValid(futureName)){
status = Status.BAD_REQUEST; status = Status.BAD_REQUEST;
throw new Exception("The 'uuid_knowledge_base' must contain only alphanumeric characters, and symbols like '.' or '_', '-'"); throw new Exception("The 'uuid_knowledge_base' must contain only alphanumeric characters, and symbols like '.' or '_', '-'");
}else{ }else{
logger.debug("Checking if such name [" + futureName + "] doesn't exist yet..."); logger.debug("Checking if such name [" + futureName + "] doesn't exist yet...");
@ -165,18 +166,20 @@ public class GrsfPublisherFisheryService {
for (Resource<Sources> resource : recordSources) { for (Resource<Sources> resource : recordSources) {
sources += resource.getName() + ", "; sources += resource.getName() + ", ";
} }
sources = sources.endsWith(", ") ? sources.substring(0, sources.length() -2) : sources; sources = sources.endsWith(", ") ? sources.substring(0, sources.length() -2) : sources;
record.setSourceType(sources); record.setSourceType(sources);
CommonServiceUtils.validateAggregatedRecord(record); CommonServiceUtils.validateAggregatedRecord(record);
} }
} }
// set the type // set the grsf type
record.setGrsfType(Product_Type.FISHERY.getOrigName()); record.setGrsfType(Product_Type.FISHERY.getOrigName());
// product system type is a list of values for sources records, so remove it (so that no group is generated) // product system type is a list of values for sources records, so remove it (so that no group is generated)
if(!sourceInPath.equals(Sources.GRSF)) // if(!sourceInPath.equals(Sources.GRSF))
record.setProductionSystemType(null); // record.setProductionSystemType(null);
// evaluate the custom fields/tags, resources and groups // evaluate the custom fields/tags, resources and groups
Map<String, List<String>> customFields = record.getExtrasFields(); Map<String, List<String>> customFields = record.getExtrasFields();
@ -190,8 +193,8 @@ public class GrsfPublisherFisheryService {
if(sourceInPath.equals(Sources.GRSF)){ if(sourceInPath.equals(Sources.GRSF)){
List<RefersToBean> refersTo = record.getRefersTo(); List<RefersToBean> refersTo = record.getRefersTo();
for (RefersToBean refersToBean : refersTo) { for (RefersToBean refersToBean : refersTo) {
resources.add(new ResourceBean(refersToBean.getUrl(), "Source of product " + futureTitle + " in the catalogue has id: " resources.add(new ResourceBean(refersToBean.getUrl(), "Source of item " + futureTitle + " in the catalogue has id: "
+ refersToBean.getId(), "Information of a source of the product " + futureTitle, null, username, null, null)); + refersToBean.getId(), "Information of a source of the item " + futureTitle, null, username, null, null));
} }
} }
@ -217,7 +220,7 @@ public class GrsfPublisherFisheryService {
else throw new Exception("Please check the license id!"); else throw new Exception("Please check the license id!");
long version = record.getVersion() == null ? 1 : record.getVersion(); long version = record.getVersion() == null ? 1 : record.getVersion();
// set the visibility of the datatest according the context // set the visibility of the datatest according the context
boolean publicDataset = context.equals((String)contextServlet.getInitParameter(HelperMethods.PUBLIC_CONTEX_KEY)); boolean publicDataset = context.equals((String)contextServlet.getInitParameter(HelperMethods.PUBLIC_CONTEX_KEY));
@ -243,16 +246,16 @@ public class GrsfPublisherFisheryService {
if(id != null){ if(id != null){
logger.info("Product created! Id is " + id); logger.info("Item created! Id is " + id);
responseBean.setId(id); responseBean.setId(id);
status = Status.CREATED; status = Status.CREATED;
String productUrl = catalogue.getUnencryptedUrlFromDatasetIdOrName(futureName); String itemUrl = catalogue.getUnencryptedUrlFromDatasetIdOrName(futureName);
responseBean.setProductUrl(productUrl); responseBean.setItemUrl(itemUrl);
responseBean.setKbUuid(record.getUuid()); responseBean.setKbUuid(record.getUuid());
// add the "Product URL" to the field // add the "Product URL" to the field
Map<String, List<String>> addField = new HashMap<String, List<String>>(); Map<String, List<String>> addField = new HashMap<String, List<String>>();
addField.put(ITEM_URL_FIELD, Arrays.asList(productUrl)); addField.put(ITEM_URL_FIELD, Arrays.asList(itemUrl));
catalogue.patchProductCustomFields(id, apiKey, addField); catalogue.patchProductCustomFields(id, apiKey, addField);
if(!groups.isEmpty()){ if(!groups.isEmpty()){
@ -261,7 +264,7 @@ public class GrsfPublisherFisheryService {
threadGroups.start(); threadGroups.start();
logger.info("Waiting association thread to die.."); logger.info("Waiting association thread to die..");
threadGroups.join(); threadGroups.join();
logger.debug("Ok, it died"); logger.debug("Groups-Thread died");
} }
// manage time series // manage time series
@ -274,21 +277,23 @@ public class GrsfPublisherFisheryService {
context, context,
token, token,
futureTitle, futureTitle,
productUrl, itemUrl,
false, false,
null, new ArrayList<String>(tags),
authorFullname).start(); authorFullname).start();
logger.info("Thread to write a post about the new product has been launched"); logger.info("Thread to write a post about the new product has been launched");
} }
}else{ }else{
throw new Exception("There was an error during the product generation, sorry"); throw new Exception("There was an error during the product generation, sorry");
} }
} }
} }
} }
} }
// }
}catch(Exception e){ }catch(Exception e){
logger.error("Failed to create fishery record" + e); logger.error("Failed to create fishery record" + e);
responseBean.setError(e.getMessage()); responseBean.setError(e.getMessage());
@ -328,11 +333,7 @@ public class GrsfPublisherFisheryService {
// Cast the source to the accepted ones // Cast the source to the accepted ones
Sources sourceInPath = Sources.onDeserialize(source); Sources sourceInPath = Sources.onDeserialize(source);
logger.info("The request is to delete a fishery object of source " + sourceInPath);
if(sourceInPath == null)
throw new Exception("The specified source in the path is unrecognized. Values accepted are [ram, firms, fishsource, grsf]");
logger.info("The request is to delete a stock object of source " + sourceInPath);
// retrieve the catalogue instance // retrieve the catalogue instance
CkanDataset fisheryInCkan = catalogue.getDataset(recordToDelete.getId(), catalogue.getApiKeyFromUsername(username)); CkanDataset fisheryInCkan = catalogue.getDataset(recordToDelete.getId(), catalogue.getApiKeyFromUsername(username));
@ -340,32 +341,45 @@ public class GrsfPublisherFisheryService {
if(fisheryInCkan == null){ if(fisheryInCkan == null){
status = Status.NOT_FOUND; status = Status.NOT_FOUND;
throw new Exception("There was a problem while serving your request. This product was not found"); throw new Exception("There was a problem while serving your request. This item was not found");
} }
// get extras and check there is the product type // check it is in the right source and it is a fishery
if(catalogue.isDatasetInGroup(source + "-" + "fishery", recordToDelete.getId())){ String grsfType = fisheryInCkan.getExtrasAsHashMap().get(Common.GRSF_TYPE_KEY);
logger.warn("Ok, this is a fishery, removing it"); String groupToCheck = sourceInPath.equals(Sources.GRSF) ? "grsf-group" : sourceInPath.getOrigName().toLowerCase();
if(catalogue.isDatasetInGroup(groupToCheck, recordToDelete.getId()) && Product_Type.FISHERY.getOrigName().equals(grsfType)){
logger.warn("Ok, this is a fishery of the right source, removing it");
boolean deleted = catalogue.deleteProduct(fisheryInCkan.getId(), catalogue.getApiKeyFromUsername(username), true); boolean deleted = catalogue.deleteProduct(fisheryInCkan.getId(), catalogue.getApiKeyFromUsername(username), true);
if(deleted){ if(deleted){
logger.info("Stock DELETED AND PURGED!");
logger.info("Fishery DELETED AND PURGED!");
status = Status.OK; status = Status.OK;
responseBean.setId(fisheryInCkan.getId()); responseBean.setId(fisheryInCkan.getId());
} }
else{ else{
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("Request failed, sorry"); throw new Exception("Request failed, sorry. Unable to delete/purge the fishery");
} }
}else{ }else{
status = Status.BAD_REQUEST; status = Status.BAD_REQUEST;
throw new Exception("The id you are using doesn't belong to a Fishery product having source " + source + "!"); throw new Exception("The id you are using doesn't belong to a Fishery item having source " + source + "!");
} }
}catch(Exception e){ }catch(Exception e){
logger.error("Failed to delete this ");
logger.error("Failed to delete this", e);
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
responseBean.setError(e.getMessage()); responseBean.setError(e.getMessage());
} }
return Response.status(status).entity(responseBean).build(); return Response.status(status).entity(responseBean).build();
@ -378,7 +392,9 @@ public class GrsfPublisherFisheryService {
@PathParam("source") String source){ @PathParam("source") String source){
// retrieve context and username // retrieve context and username
Caller caller = AuthorizationProvider.instance.get();
String context = ScopeProvider.instance.get(); String context = ScopeProvider.instance.get();
String username = caller.getClient().getId();
ResponseBean responseBean = new ResponseBean(); ResponseBean responseBean = new ResponseBean();
Status status = Status.INTERNAL_SERVER_ERROR; Status status = Status.INTERNAL_SERVER_ERROR;
@ -392,24 +408,44 @@ public class GrsfPublisherFisheryService {
// Cast the source to the accepted ones // Cast the source to the accepted ones
Sources sourceInPath = Sources.onDeserialize(source); Sources sourceInPath = Sources.onDeserialize(source);
if(sourceInPath == null)
throw new Exception("The specified source in the path is unrecognized. Values accepted are [ram, firms, fishsource, grsf]");
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context); DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
if(catalogue == null){ if(catalogue == null){
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("There was a problem while serving your request"); throw new Exception("There was a problem while serving your request");
}
// if it is a request for GRSF records, we have Fishery - Stock groups, so it is easy.
// For other cases, records needs to be parsed
if(sourceInPath.equals(Sources.GRSF))
datasetsIds = HelperMethods.getProductsInGroup(source + "-" + "fishery", catalogue);
else{
List<String> fullGroupListIds = HelperMethods.getProductsInGroup(source, catalogue);
for (String id : fullGroupListIds) {
CkanDataset dataset = catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username));
if(dataset != null){
String grsfType = dataset.getExtrasAsHashMap().get(Common.GRSF_TYPE_KEY);
if(grsfType.equals(Product_Type.FISHERY.getOrigName()))
datasetsIds.add(id);
}
}
} }
datasetsIds = HelperMethods.getProductsInGroup(source + "-" + "fishery", catalogue);
responseBean.setResult(datasetsIds); responseBean.setResult(datasetsIds);
responseBean.setSuccess(true); responseBean.setSuccess(true);
}catch(Exception e){ }catch(Exception e){
logger.error("Failed to fetch this list of ids ", e); logger.error("Failed to fetch this list of ids ", e);
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
responseBean.setSuccess(false);
responseBean.setMessage(e.getMessage()); responseBean.setMessage(e.getMessage());
} }
return Response.status(status).entity(responseBean).build(); return Response.status(status).entity(responseBean).build();
@ -454,14 +490,15 @@ public class GrsfPublisherFisheryService {
responseBean.setResult(result); responseBean.setResult(result);
responseBean.setSuccess(true); responseBean.setSuccess(true);
}else{ }else{
responseBean.setMessage("Unable to retrieve a catalogue product with name " + name); responseBean.setMessage("Unable to retrieve a catalogue item with name " + name);
} }
}catch(Exception e){ }catch(Exception e){
logger.error("Failed to retrieve this product", e); logger.error("Failed to retrieve this product", e);
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
responseBean.setSuccess(false);
responseBean.setMessage(e.getMessage()); responseBean.setMessage(e.getMessage());
} }
return Response.status(status).entity(responseBean).build(); return Response.status(status).entity(responseBean).build();

View File

@ -29,6 +29,7 @@ import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider; import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.authorization.library.utils.Caller; import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider; import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.Common;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.DeleteProductBean; import org.gcube.data_catalogue.grsf_publish_ws.json.input.DeleteProductBean;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.RefersToBean; import org.gcube.data_catalogue.grsf_publish_ws.json.input.RefersToBean;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.Resource; import org.gcube.data_catalogue.grsf_publish_ws.json.input.Resource;
@ -52,7 +53,7 @@ import eu.trentorise.opendata.jackan.model.CkanDataset;
* Stock web service methods * Stock web service methods
* @author Costantino Perciante at ISTI-CNR * @author Costantino Perciante at ISTI-CNR
*/ */
@Path("{source}/stock/") @Path("{source:firms|FIRMS|ram|RAM|grsf|GRSF|FishSource|fishsource}/stock/")
public class GrsfPublisherStockService { public class GrsfPublisherStockService {
private static final String DEFAULT_STOCK_LICENSE = "CC-BY-SA-4.0"; private static final String DEFAULT_STOCK_LICENSE = "CC-BY-SA-4.0";
@ -63,6 +64,7 @@ public class GrsfPublisherStockService {
// Logger // Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GrsfPublisherStockService.class); private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GrsfPublisherStockService.class);
// item url property
private static final String ITEM_URL_FIELD = "Item URL"; private static final String ITEM_URL_FIELD = "Item URL";
@GET @GET
@ -110,9 +112,6 @@ public class GrsfPublisherStockService {
// Cast the source to the accepted ones // Cast the source to the accepted ones
Sources sourceInPath = Sources.onDeserialize(source); Sources sourceInPath = Sources.onDeserialize(source);
if(sourceInPath == null)
throw new Exception("The specified source in the path is unrecogized. Values accepted are [ram, firms, fishsource, grsf]");
logger.info("The request is to create a stock object of source " + sourceInPath); logger.info("The request is to create a stock object of source " + sourceInPath);
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context); DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
@ -121,31 +120,38 @@ public class GrsfPublisherStockService {
}else{ }else{
String apiKey = catalogue.getApiKeyFromUsername(username); String apiKey = catalogue.getApiKeyFromUsername(username);
// check the user has editor/admin role into the org
String organization = HelperMethods.retrieveOrgNameFromScope(context); String organization = HelperMethods.retrieveOrgNameFromScope(context);
String role = catalogue.getRoleOfUserInOrganization(username, organization, apiKey); String role = catalogue.getRoleOfUserInOrganization(username, organization, apiKey);
logger.info("Role of the user " + username + " is " + role); logger.info("Role of the user " + username + " is " + role);
if(!role.equalsIgnoreCase(RolesCkanGroupOrOrg.ADMIN.toString())){ if(!role.equalsIgnoreCase(RolesCkanGroupOrOrg.ADMIN.toString())){
status = Status.FORBIDDEN; status = Status.FORBIDDEN;
throw new Exception("You are not authorized to create a product. Please check you have the Catalogue-Administrator role!"); throw new Exception("You are not authorized to create a product. Please check you have the Catalogue-Administrator role!");
} }
// check the record has a name, at least // check the record has a name, at least
String futureName = record.getUuid(); String futureName = record.getUuid();
String futureTitle = record.getStockName(); String futureTitle = record.getStockName();
if(!HelperMethods.isNameValid(futureName)){ if(!HelperMethods.isNameValid(futureName)){
status = Status.BAD_REQUEST; status = Status.BAD_REQUEST;
throw new Exception("The 'uuid_knowledge_base' must contain only alphanumeric characters, and symbols like '.' or '_', '-'"); throw new Exception("The 'uuid_knowledge_base' must contain only alphanumeric characters, and symbols like '.' or '_', '-'");
}else{ }else{
logger.debug("Checking if such 'uuid_knowledge_base' [" + futureName + "] doesn't exist yet..."); logger.debug("Checking if such 'uuid_knowledge_base' [" + futureName + "] doesn't exist yet...");
boolean alreadyExist = catalogue.existProductWithNameOrId(futureName); boolean alreadyExist = catalogue.existProductWithNameOrId(futureName);
if(alreadyExist){ if(alreadyExist){
logger.debug("A product with 'uuid_knowledge_base' " + futureName + " already exists"); logger.debug("A product with 'uuid_knowledge_base' " + futureName + " already exists");
status = Status.CONFLICT; status = Status.CONFLICT;
throw new Exception("A product with 'uuid_knowledge_base' " + futureName + " already exists"); throw new Exception("A product with 'uuid_knowledge_base' " + futureName + " already exists");
}else{ }else{
// validate the record if it is a GRSF one and set the record type and in manage context // validate the record if it is a GRSF one and set the record type and in manage context
@ -164,7 +170,7 @@ public class GrsfPublisherStockService {
} }
} }
// set the type // set the grsf type
record.setGrsfType(Product_Type.STOCK.getOrigName()); record.setGrsfType(Product_Type.STOCK.getOrigName());
// evaluate the custom fields/tags, resources and groups // evaluate the custom fields/tags, resources and groups
@ -177,11 +183,13 @@ public class GrsfPublisherStockService {
// manage the refers to // manage the refers to
if(sourceInPath.equals(Sources.GRSF)){ if(sourceInPath.equals(Sources.GRSF)){
List<RefersToBean> refersTo = record.getRefersTo(); List<RefersToBean> refersTo = record.getRefersTo();
for (RefersToBean refersToBean : refersTo) { for (RefersToBean refersToBean : refersTo) {
resources.add(new ResourceBean(refersToBean.getUrl(), "Source of product " + futureTitle + " in the catalogue has id: " resources.add(new ResourceBean(refersToBean.getUrl(), "Source of item " + futureTitle + " in the catalogue has id: "
+ refersToBean.getId(), "Information of a source of the product " + futureTitle, null, username, null, null)); + refersToBean.getId(), "Information of a source of the item " + futureTitle, null, username, null, null));
} }
} }
// retrieve the user's email and fullname // retrieve the user's email and fullname
@ -207,7 +215,7 @@ public class GrsfPublisherStockService {
else throw new Exception("Please check the license id!"); else throw new Exception("Please check the license id!");
long version = record.getVersion() == null ? 1 : record.getVersion(); long version = record.getVersion() == null ? 1 : record.getVersion();
// set the visibility of the datatest according the context // set the visibility of the datatest according the context
boolean publicDataset = context.equals((String)contextServlet.getInitParameter(HelperMethods.PUBLIC_CONTEX_KEY)); boolean publicDataset = context.equals((String)contextServlet.getInitParameter(HelperMethods.PUBLIC_CONTEX_KEY));
@ -236,22 +244,24 @@ public class GrsfPublisherStockService {
logger.info("Product created! Id is " + id); logger.info("Product created! Id is " + id);
responseBean.setId(id); responseBean.setId(id);
status = Status.CREATED; status = Status.CREATED;
String productUrl = catalogue.getUnencryptedUrlFromDatasetIdOrName(futureName); String itemUrl = catalogue.getUnencryptedUrlFromDatasetIdOrName(futureName);
responseBean.setProductUrl(productUrl); responseBean.setItemUrl(itemUrl);
responseBean.setKbUuid(record.getUuid()); responseBean.setKbUuid(record.getUuid());
// add the "Product URL" to the field // add the "Product URL" to the field
Map<String, List<String>> addField = new HashMap<String, List<String>>(); Map<String, List<String>> addField = new HashMap<String, List<String>>();
addField.put(ITEM_URL_FIELD, Arrays.asList(productUrl)); addField.put(ITEM_URL_FIELD, Arrays.asList(itemUrl));
catalogue.patchProductCustomFields(id, apiKey, addField); catalogue.patchProductCustomFields(id, apiKey, addField);
if(!groups.isEmpty()){ if(!groups.isEmpty()){
logger.info("Launching thread for association to the list of groups " + groups); logger.info("Launching thread for association to the list of groups " + groups);
AssociationToGroupThread threadGroups = new AssociationToGroupThread(new ArrayList<String>(groups), id, organization, username, catalogue); AssociationToGroupThread threadGroups = new AssociationToGroupThread(new ArrayList<String>(groups), id, organization, username, catalogue);
threadGroups.start(); threadGroups.start();
logger.info("Waiting association thread to die.."); logger.info("Waiting association thread to die..");
threadGroups.join(); threadGroups.join();
logger.debug("Ok, it died"); logger.debug("Ok, it died");
} }
// manage time series // manage time series
@ -264,9 +274,9 @@ public class GrsfPublisherStockService {
context, context,
token, token,
futureTitle, futureTitle,
productUrl, itemUrl,
false, false,
null, new ArrayList<String>(tags),
authorFullname).start(); authorFullname).start();
logger.info("Thread to write a post about the new product has been launched"); logger.info("Thread to write a post about the new product has been launched");
} }
@ -316,11 +326,6 @@ public class GrsfPublisherStockService {
// Cast the source to the accepted ones // Cast the source to the accepted ones
Sources sourceInPath = Sources.onDeserialize(source); Sources sourceInPath = Sources.onDeserialize(source);
if(sourceInPath == null){
status = Status.BAD_REQUEST;
throw new Exception("The specified source in the path is unrecognized. Values accepted are [ram, firms, fishsource, grsf]");
}
logger.info("The request is to delete a stock object of source " + sourceInPath); logger.info("The request is to delete a stock object of source " + sourceInPath);
// retrieve the catalogue instance // retrieve the catalogue instance
@ -331,19 +336,27 @@ public class GrsfPublisherStockService {
throw new Exception("There was a problem while serving your request. This product was not found"); throw new Exception("There was a problem while serving your request. This product was not found");
} }
// get extras and check there is the product type // check it is in the right source and it is a fishery
if(catalogue.isDatasetInGroup(source + "-" + "stock", recordToDelete.getId())){ String grsfType = stockInCkan.getExtrasAsHashMap().get(Common.GRSF_TYPE_KEY);
String groupToCheck = sourceInPath.equals(Sources.GRSF) ? "grsf-group" : sourceInPath.getOrigName().toLowerCase();
logger.warn("Ok, this is a stock of the right type, removing it"); if(catalogue.isDatasetInGroup(groupToCheck, recordToDelete.getId()) && Product_Type.STOCK.getOrigName().equals(grsfType)){
logger.debug("Ok, this is a stock of the right type, removing it");
boolean deleted = catalogue.deleteProduct(stockInCkan.getId(), catalogue.getApiKeyFromUsername(username), true); boolean deleted = catalogue.deleteProduct(stockInCkan.getId(), catalogue.getApiKeyFromUsername(username), true);
if(deleted){ if(deleted){
logger.info("Stock DELETED AND PURGED!"); logger.info("Stock DELETED AND PURGED!");
status = Status.OK; status = Status.OK;
responseBean.setId(stockInCkan.getId()); responseBean.setId(stockInCkan.getId());
} }
else{ else{
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("Request failed, sorry"); throw new Exception("Request failed, sorry. Unable to delete/purge the stock");
} }
}else{ }else{
@ -352,8 +365,10 @@ public class GrsfPublisherStockService {
} }
}catch(Exception e){ }catch(Exception e){
logger.error("Failed to delete this ", e); logger.error("Failed to delete this ", e);
responseBean.setError(e.getMessage()); responseBean.setError(e.getMessage());
} }
return Response.status(status).entity(responseBean).build(); return Response.status(status).entity(responseBean).build();
@ -366,7 +381,9 @@ public class GrsfPublisherStockService {
@PathParam("source") String source){ @PathParam("source") String source){
// retrieve context and username // retrieve context and username
Caller caller = AuthorizationProvider.instance.get();
String context = ScopeProvider.instance.get(); String context = ScopeProvider.instance.get();
String username = caller.getClient().getId();
ResponseBean responseBean = new ResponseBean(); ResponseBean responseBean = new ResponseBean();
Status status = Status.OK; Status status = Status.OK;
@ -381,25 +398,44 @@ public class GrsfPublisherStockService {
// Cast the source to the accepted ones // Cast the source to the accepted ones
Sources sourceInPath = Sources.onDeserialize(source); Sources sourceInPath = Sources.onDeserialize(source);
if(sourceInPath == null){
status = Status.BAD_REQUEST;
throw new Exception("The specified source in the path is unrecognized. Values accepted are [ram, firms, fishsource, grsf]");
}
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context); DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
if(catalogue == null){ if(catalogue == null){
status = Status.INTERNAL_SERVER_ERROR; status = Status.INTERNAL_SERVER_ERROR;
throw new Exception("There was a problem while serving your request"); throw new Exception("There was a problem while serving your request");
}
// if it is a request for GRSF records, we have Fishery - Stock groups, so it is easy.
// For other cases, records needs to be parsed
if(sourceInPath.equals(Sources.GRSF))
datasetsIds = HelperMethods.getProductsInGroup(source + "-" + "stock", catalogue);
else{
List<String> fullGroupListIds = HelperMethods.getProductsInGroup(source, catalogue);
for (String id : fullGroupListIds) {
CkanDataset dataset = catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username));
if(dataset != null){
String grsfType = dataset.getExtrasAsHashMap().get(Common.GRSF_TYPE_KEY);
if(grsfType.equals(Product_Type.STOCK.getOrigName()))
datasetsIds.add(id);
}
}
} }
datasetsIds = HelperMethods.getProductsInGroup(source + "-" + "stock", catalogue);
responseBean.setResult(datasetsIds); responseBean.setResult(datasetsIds);
responseBean.setSuccess(true); responseBean.setSuccess(true);
}catch(Exception e){ }catch(Exception e){
logger.error("Failed to fetch this list of ids " + source, e); logger.error("Failed to fetch this list of ids " + source, e);
responseBean.setSuccess(false); responseBean.setSuccess(false);
responseBean.setMessage(e.getMessage()); responseBean.setMessage(e.getMessage());
} }
return Response.status(status).entity(responseBean).build(); return Response.status(status).entity(responseBean).build();