Defined new annotation for custom fields to map them in extras fields. Defined methods to retrieve custom fields, tags and groups at run time.

git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-catalogue/grsf-publisher-ws@132956 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Costantino Perciante 2016-10-08 21:10:25 +00:00
parent e940cb5abb
commit b7f35033c9
14 changed files with 362 additions and 40 deletions

View File

@ -0,0 +1,18 @@
package org.gcube.data_catalogue.grsf_publish_ws.custom_annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Custom field annotation
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CustomField {
public String key() default "";
}

View File

@ -4,13 +4,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.CustomField;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Group;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Tag;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Source;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Status;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Type;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
@ -25,11 +25,11 @@ public class Common {
@JsonProperty("license")
private String license;
@JsonIgnoreProperties(ignoreUnknown=true) // ignore in serialization/deserialization
private String author; // this will be filled with the username of the token's owner
@JsonProperty("author") // @JsonIgnoreProperties(ignoreUnknown=true) // ignore in serialization/deserialization
private String author;
@JsonProperty("version")
private long version;
private Long version;
@JsonProperty("author_contact")
private String authorContact;
@ -41,34 +41,41 @@ public class Common {
private String maintainerContact;
@JsonProperty("catches_or_landings")
@CustomField(key="Catches or landings")
private String catchesOrLandings;
@JsonProperty("database_sources")
@Group
@CustomField(key="Database sources")
private Source databaseSources;
@JsonProperty("source_of_information")
@CustomField(key="Source of information")
private String sourceOfInformation;
@JsonProperty("data_owner")
@CustomField(key="Data owner")
private String dataOwner;
@JsonProperty("type")
@Tag
@Group
@CustomField(key="Type")
private Type type;
@JsonProperty("status")
@Tag
@CustomField(key="Status")
private Status status;
@JsonProperty("resources")
private List<Resource> resources;
@JsonProperty("extras")
private Map<String, Object> extras = new HashMap<>();
private Map<String, String> extras = new HashMap<>();
@JsonProperty("spatial")
@CustomField(key="Spatial")
private String spatial;
public Common() {
@ -76,11 +83,11 @@ public class Common {
}
public Common(String description, String license, String author,
long version, String authorContact, String maintainer,
Long version, String authorContact, String maintainer,
String maintainerContact, String catchesOrLandings,
Source databaseSources, String sourceOfInformation,
String dataOwner, Type type, Status status,
List<Resource> resources, Map<String, Object> extras,
List<Resource> resources, Map<String, String> extras,
String spatial) {
super();
this.description = description;
@ -133,11 +140,11 @@ public class Common {
this.author = author;
}
public long getVersion() {
public Long getVersion() {
return version;
}
public void setVersion(long version) {
public void setVersion(Long version) {
this.version = version;
}
@ -221,11 +228,11 @@ public class Common {
this.resources = resources;
}
public void setProperties(Map<String, Object> extras) {
public void setProperties(Map<String, String> extras) {
this.extras = extras;
}
public Map<String, Object> getExtras() {
public Map<String, String> getExtras() {
return extras;
}

View File

@ -1,5 +1,6 @@
package org.gcube.data_catalogue.grsf_publish_ws.json.input;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.CustomField;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Group;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Tag;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Production_System_Type;
@ -16,35 +17,44 @@ public class FisheryRecord extends Common{
private String fisheryName;
@JsonProperty("fishery_id")
@CustomField(key="Fishery id")
private String fisheryId;
@JsonProperty("scientific_name")
@Tag
@CustomField(key="Scientific name")
private String scientificName;
@JsonProperty("fishing_area")
@CustomField(key="Fishing area")
private String fishingArea;
@JsonProperty("exploiting_stocks")
@CustomField(key="Exploiting stocks")
private String exploitingStocks;
@JsonProperty("management_entity")
@Tag
@CustomField(key="Management entity")
private String managementEntity;
@JsonProperty("jurisdiction_area")
@CustomField(key="Jurisdiction Area")
private String jurisdictionArea;
@JsonProperty("production_system_type")
@Group
@CustomField(key="Production system type")
private Production_System_Type productionSystemType;
@JsonProperty("flag_state")
@Tag
@CustomField(key="Flag state")
private String flagState;
@JsonProperty("fishing_gear")
@Tag
@CustomField(key="Fishing gear")
private String fishingGear;
public FisheryRecord() {

View File

@ -1,5 +1,6 @@
package org.gcube.data_catalogue.grsf_publish_ws.json.input;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.CustomField;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Group;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Tag;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Abundance_Level;
@ -17,46 +18,59 @@ public class StockRecord extends Common{
private String stockName;
@JsonProperty("stock_id")
@CustomField(key="Stock Id")
private String stockID;
@JsonProperty("species_scientific_name")
@Tag
@CustomField(key="Species scientific name")
private String speciesScientificName;
@JsonProperty("area")
@CustomField(key="Area")
private String area;
@JsonProperty("exploiting_fishery")
@CustomField(key="Exploiting fishery")
private String exploitingFishery;
@JsonProperty("management_entity")
@CustomField(key="Management entity")
private String managementEntity;
@JsonProperty("assessment_methods")
@CustomField(key="Assessment methods")
private String assessmentMethods;
@JsonProperty("state_of_marine_resource")
@CustomField(key="State of marine resources")
private String stateOfMarineResource;
@JsonProperty("exploitation_rate")
@CustomField(key="Exploitation rate")
@Group
private Exploitation_Rate exploitationRate;
@JsonProperty("abundance_level")
@CustomField(key="Abundance level")
@Group
private Abundance_Level abundanceLevel;
@JsonProperty("narrative_state_and_trend")
@CustomField(key="Narrative state and trend")
private String narrativeStateAndTrend;
@JsonProperty("scientific_advice")
@CustomField(key="Scientific advice")
private String scientificAdvice;
@JsonProperty("reporting_entity")
@CustomField(key="Reporting entity")
private String reportingEntity;
@JsonProperty("reporting_year")
private long reportingYear;
@CustomField(key="Reporting year")
private Long reportingYear;
/**
*
@ -87,7 +101,7 @@ public class StockRecord extends Common{
String assessmentMethods, String stateOfMarineResource,
Exploitation_Rate exploitationRate, Abundance_Level abundanceLevel,
String narrativeStateAndTrend, String scientificAdvice,
String reportingEntity, long reportingYear) {
String reportingEntity, Long reportingYear) {
super();
this.stockName = stockName;
this.stockID = stockID;
@ -209,11 +223,11 @@ public class StockRecord extends Common{
this.reportingEntity = reportingEntity;
}
public long getReportingYear() {
public Long getReportingYear() {
return reportingYear;
}
public void setReportingYear(long reportingYear) {
public void setReportingYear(Long reportingYear) {
this.reportingYear = reportingYear;
}

View File

@ -1,13 +1,23 @@
package org.gcube.data_catalogue.grsf_publish_ws.services;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.gcube.common.authorization.library.provider.AuthorizationProvider;
import org.gcube.common.authorization.library.utils.Caller;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.StockRecord;
import org.gcube.data_catalogue.grsf_publish_ws.json.output.ResponseCreationBean;
import org.gcube.data_catalogue.grsf_publish_ws.utils.HelperMethods;
import org.gcube.datacatalogue.ckanutillibrary.DataCatalogue;
import org.slf4j.LoggerFactory;
/**
@ -16,21 +26,55 @@ import org.slf4j.LoggerFactory;
*/
@Path("stock/")
public class GrsfPublisherStockService {
// Logger
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GrsfPublisherStockService.class);
@POST
@Path("publish-product")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response publishStock(StockRecord record){
// retrieve context and username
Caller caller = AuthorizationProvider.instance.get();
String username = caller.getClient().getId();
String context = ScopeProvider.instance.get();
logger.info("Incoming request for creating a stock record by user with id " + username);
logger.info("Incoming request for creating a stock record");
ResponseCreationBean responseBean = new ResponseCreationBean();
Status status = Status.CREATED;
String id = "";
try{
DataCatalogue catalogue = HelperMethods.getDataCatalogueRunningInstance(context);
// check the user has editor/admin role into the org TODO pending or accepted?
// check the record has a name, at least
// evaluate the tags of the product
// evaluate the resources
// evaluate tags and groups using reflection
List<String> tags = new ArrayList<String>();
List<String> groups = new ArrayList<String>();
// create the product
//catalogue.createCKanDataset(apiKey, title, organizationNameOrId, author, authorMail, maintainer, maintainerMail, version, description, licenseId, tags, customFields, resources, setPublic)
// TODO
return null;
}catch(Exception e){
logger.error("Failed to create stock record", e);
status = Status.INTERNAL_SERVER_ERROR;
responseBean.setError(e.toString());
responseBean.setId(id);
}
return Response.status(status).entity(responseBean).build();
}
}

View File

@ -0,0 +1,66 @@
package org.gcube.data_catalogue.grsf_publish_ws.utils;
import java.util.List;
import org.gcube.datacatalogue.ckanutillibrary.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.models.RolesCkanGroupOrOrg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Associate the dataset to a group.
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class AssociationToGroupThread extends Thread {
private static final Logger logger = LoggerFactory.getLogger(AssociationToGroupThread.class);
private List<String> groupsTitles;
private String datasetId;
private String username;
private DataCatalogue catalogue;
private String organization;
/**
* @param groupTitle
* @param datasetId
* @param username
* @param catalogue
*/
public AssociationToGroupThread(List<String> groupsTitles, String datasetId,
String username, DataCatalogue catalogue, String organization) {
this.groupsTitles = groupsTitles;
this.datasetId = datasetId;
this.username = username;
this.catalogue = catalogue;
this.organization = organization;
}
@Override
public void run() {
logger.info("Association thread started to put the dataset with id="+ datasetId + " into group with title " + groupsTitles + " for user " + username);
// create the group
for (String groupTitle : groupsTitles) {
logger.debug("Group exists, going to add the user " + username + " as its admin...");
// retrieve the role to be assigned according the one the user has into the organization of the dataset
RolesCkanGroupOrOrg role = RolesCkanGroupOrOrg.valueOf(catalogue.getRoleOfUserInOrganization(username, organization, catalogue.getApiKeyFromUsername(username)).toUpperCase());
boolean assigned = catalogue.checkRoleIntoGroup(username, groupTitle, role);
if(assigned){
logger.debug("Admin/editor role was assigned for this group, going to associate the product to the group");
boolean putIntoGroup = catalogue.assignDatasetToGroup(groupTitle, datasetId, catalogue.getApiKeyFromUsername(username));
logger.info("Was product put into group? " + putIntoGroup);
}
}
}
}

View File

@ -1,7 +1,17 @@
package org.gcube.data_catalogue.grsf_publish_ws.utils;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.CustomField;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Group;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Tag;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.Common;
import org.gcube.datacatalogue.ckanutillibrary.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.DataCatalogueFactory;
import org.slf4j.LoggerFactory;
/**
@ -10,29 +20,107 @@ import org.gcube.datacatalogue.ckanutillibrary.DataCatalogueFactory;
*/
public abstract class HelperMethods {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(HelperMethods.class);
/**
* Convert a group name to its id on ckan
* @param origName
* @return
*/
public static String getGroupNameOnCkan(String origName){
if(origName == null)
throw new IllegalArgumentException("origName cannot be null");
return origName.trim().toLowerCase().replaceAll("[^A-Za-z0-9_.]", "_");
}
/**
* Retrieve the running instance of the data catalogue for this scope
* @return
* @throws Exception
*/
public static DataCatalogue getDataCatalogueRunningInstance(String scope) throws Exception{
return DataCatalogueFactory.getFactory().getUtilsPerScope(scope);
}
/**
* Retrieve the list of tags for this object
*/
public static void getTags(List<String> tags, Common record){
Class<?> current = record.getClass();
do{
Field[] fields = current.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(Tag.class)){
try{
Object f = new PropertyDescriptor(field.getName(), current).getReadMethod().invoke(record);
if(f != null){
tags.add(f.toString());
}
}catch(Exception e){
logger.error("Failed ot read value for field " + field.getName() + " skipping", e);
}
}
}
}
while((current = current.getSuperclass())!=null);
}
/**
* Retrieve the list of groups for this object
*/
public static void getGroups(List<String> groups, Common record){
Class<?> current = record.getClass();
do{
Field[] fields = current.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(Group.class)){
try{
Object f = new PropertyDescriptor(field.getName(), current).getReadMethod().invoke(record);
if(f != null){
groups.add(getGroupNameOnCkan(f.toString()));
}
}catch(Exception e){
logger.error("Failed ot read value for field " + field.getName() + " skipping", e);
}
}
}
}
while((current = current.getSuperclass())!=null);
}
/**
* Retrieve the list of extras for this object
*/
public static void getExtras(Map<String, Object> extras, Common record){
Class<?> current = record.getClass();
do{
Field[] fields = current.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(CustomField.class)){
try{
Object f = new PropertyDescriptor(field.getName(), current).getReadMethod().invoke(record);
if(f != null){
// get the key to put into the map first
extras.put(field.getAnnotation(CustomField.class).key(), f);
}
}catch(Exception e){
logger.error("Failed ot read value for field " + field.getName() + " skipping", e);
}
}
}
}
while((current = current.getSuperclass())!=null);
}
}

View File

@ -54,5 +54,10 @@ public enum Abundance_Level {
}
return null;
}
@Override
public String toString() {
return getOrigName();
}
}

View File

@ -54,4 +54,9 @@ public enum Exploitation_Rate {
}
return null;
}
@Override
public String toString() {
return getOrigName();
}
}

View File

@ -59,5 +59,10 @@ public enum Production_System_Type {
}
return null;
}
@Override
public String toString() {
return getOrigName();
}
}

View File

@ -54,4 +54,9 @@ public enum Source {
}
return null;
}
@Override
public String toString() {
return getOrigName();
}
}

View File

@ -53,5 +53,10 @@ public enum Status {
}
return null;
}
@Override
public String toString() {
return getOrigName();
}
}

View File

@ -56,5 +56,10 @@ public enum Type {
}
return null;
}
@Override
public String toString() {
return getOrigName();
}
}

View File

@ -4,42 +4,87 @@ import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.CustomField;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Group;
import org.gcube.data_catalogue.grsf_publish_ws.custom_annotations.Tag;
import org.gcube.data_catalogue.grsf_publish_ws.json.input.FisheryRecord;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Abundance_Level;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Source;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Status;
import org.gcube.data_catalogue.grsf_publish_ws.utils.groups.Type;
import org.junit.Test;
public class JTests {
@Test
//@Test
public void test() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, IntrospectionException {
// Common instance = new Common();
// instance.setType(Type.Assesment_Unit);
FisheryRecord recordFishery = new FisheryRecord();
recordFishery.setType(Type.Fishing_Description);
recordFishery.setDatabaseSources(Source.FIRMS);
// Class<Common> commonClass = Common.class;
Class<FisheryRecord> fisheryClass = FisheryRecord.class;
recordFishery.setStatus(Status.Pending);
// bottom up, looks up for Tag fields
Class<?> current = fisheryClass;
List<String> tags = new ArrayList<String>();
List<String> groupsTitles = new ArrayList<String>();
Map<String, Object> extras = new HashMap<String, Object>();
// bottom up, looks up for Tag/Group fields
Class<?> current = recordFishery.getClass();
do{
// do something with current's fields
System.out.println("Class is " + current.getCanonicalName());
Field[] fields = current.getDeclaredFields();
for (Field field : fields) {
if(field.isAnnotationPresent(Tag.class) || field.isAnnotationPresent(Group.class)){
System.out.println("Annotated field is " + field.getName());
Object f = new PropertyDescriptor(field.getName(), fisheryClass).getReadMethod().invoke(recordFishery);
System.out.println("Field is " + field.getName() + " and its value for instance is " + f);
if(field.isAnnotationPresent(Tag.class)){
Object f = new PropertyDescriptor(field.getName(), current).getReadMethod().invoke(recordFishery);
if(f != null){
tags.add(f.toString());
}
}
if(field.isAnnotationPresent(Group.class)){
Object f = new PropertyDescriptor(field.getName(), current).getReadMethod().invoke(recordFishery);
if(f != null){
groupsTitles.add(f.toString());
}
}
if(field.isAnnotationPresent(CustomField.class)){
Object f = new PropertyDescriptor(field.getName(), current).getReadMethod().invoke(recordFishery);
if(f != null){
// get the key to put into the map first
extras.put(field.getAnnotation(CustomField.class).key(), f);
}
}
}
}
while((current = current.getSuperclass())!=null);
// print
System.out.println("TAGS " + tags);
System.out.println("GROUPS " + groupsTitles);
System.out.println("EXTRAS " + extras);
}
//@Test
public void testJsonSerializer(){
//
// String pendingAsString = "pending";
// Status resSatus = Status.onDeserialize(pendingAsString);
// System.out.println("Res is " + resSatus);
//
// System.out.println("To string is " + resSatus.onSerialize());
Abundance_Level type = Abundance_Level.onDeserialize("Uncertain Not assessed");
System.out.println("Res is " + type.onSerialize());
}
}