From c21a7b1fbccc5d60db3ed377679bb7721d727559 Mon Sep 17 00:00:00 2001 From: Costantino Perciante Date: Thu, 9 Nov 2017 13:49:07 +0000 Subject: [PATCH] server side almost finished git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/widgets/grsf-manage-widget@158328 82a268e6-3cf1-43bd-a215-b396298e98cf --- .classpath | 2 +- .settings/org.eclipse.jdt.core.prefs | 2 +- .../client/GRSFManageWidgetService.java | 12 +- .../events/HideManagementPanelEvent.java | 11 +- .../HideManagementPanelEventHandler.java | 2 +- .../client/view/ManageProductWidget.java | 14 +- .../manage/GRSFNotificationService.java | 468 ++++-------------- .../server/manage/Utils.java | 468 +++++++++++++++++- .../shared/ManageProductBean.java | 87 ++-- .../shared/SimilarGRSFRecord.java | 28 ++ 10 files changed, 632 insertions(+), 462 deletions(-) diff --git a/.classpath b/.classpath index c927652..618f83b 100644 --- a/.classpath +++ b/.classpath @@ -22,7 +22,7 @@ - + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index b257af7..443e085 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,6 +1,6 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 org.eclipse.jdt.core.compiler.compliance=1.7 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java index 1be9497..d087a63 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java @@ -10,9 +10,10 @@ import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; public interface GRSFManageWidgetService extends RemoteService { /** - * Notify product update + * check if the user has the rights to manage the item */ - String notifyProductUpdate(ManageProductBean bean); + boolean isAdminUser(); + /** * Get the product bean from the product identifier @@ -21,9 +22,10 @@ public interface GRSFManageWidgetService extends RemoteService { * @throws Exception */ ManageProductBean getProductBeanById(String identifier) throws Exception; - + /** - * check if the user has the rights to manage the item + * Notify product update */ - boolean isAdminUser(); + String notifyProductUpdate(ManageProductBean bean); + } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEvent.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEvent.java index 1f0565d..8bfec05 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEvent.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEvent.java @@ -4,29 +4,20 @@ import com.google.gwt.event.shared.GwtEvent; /** - * Hide management panel + * Hide management panel event. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class HideManagementPanelEvent extends GwtEvent { public static Type TYPE = new Type(); - /** - * Instantiates a new hide event. - */ public HideManagementPanelEvent() { } - /* (non-Javadoc) - * @see com.google.gwt.event.shared.GwtEvent#getAssociatedType() - */ @Override public Type getAssociatedType() { return TYPE; } - /* (non-Javadoc) - * @see com.google.gwt.event.shared.GwtEvent#dispatch(com.google.gwt.event.shared.EventHandler) - */ @Override protected void dispatch(HideManagementPanelEventHandler handler) { handler.onEvent(this); diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEventHandler.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEventHandler.java index d340303..ab5d77f 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEventHandler.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/events/HideManagementPanelEventHandler.java @@ -4,7 +4,7 @@ import com.google.gwt.event.shared.EventHandler; /** - * Hide management panel event handler + * Hide management panel event handler. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public interface HideManagementPanelEventHandler extends EventHandler { diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java index 9f1e3c9..86aaa93 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java @@ -10,6 +10,7 @@ import java.util.Map.Entry; import org.gcube.datacatalogue.common.enums.Status; import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetService; import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetServiceAsync; +import org.gcube.datacatalogue.grsf_manage_widget.client.events.HideManagementPanelEvent; import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean; import org.gcube.datacatalogue.grsf_manage_widget.shared.ex.NoGRSFRecordException; @@ -29,6 +30,7 @@ import com.github.gwtbootstrap.client.ui.constants.ControlGroupType; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.SelectElement; import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; @@ -116,14 +118,17 @@ public class ManageProductWidget extends Composite{ + " You are suggested to contact the VRE Manager if something is wrong with this"; private ManageProductBean bean; - public ManageProductWidget(String productIdentifier) { + private HandlerManager eventBus = null; + + public ManageProductWidget(String productIdentifier, HandlerManager eventBus) { initWidget(uiBinder.createAndBindUi(this)); - + this.eventBus = eventBus; + if(productIdentifier == null || productIdentifier.isEmpty()){ GWT.log("The received item identifier is null.."); return; } - + GWT.log("item identifier is " + productIdentifier); // start loader service @@ -152,6 +157,9 @@ public class ManageProductWidget extends Composite{ formUpdate.setVisible(false); confirmButton.setEnabled(false); loadingImage.setVisible(false); + + // ask to hide management panel + eventBus.fireEvent(new HideManagementPanelEvent()); }else{ service.getProductBeanById(productIdentifier, new AsyncCallback() { diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java index d065e2a..881c109 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java @@ -1,74 +1,53 @@ package org.gcube.datacatalogue.grsf_manage_widget.server.manage; -import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; -import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; - -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; +import java.util.ArrayList; import java.util.List; import java.util.Map; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - import org.gcube.common.portal.PortalContext; -import org.gcube.common.resources.gcore.ServiceEndpoint; -import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; -import org.gcube.common.scope.api.ScopeProvider; -import org.gcube.datacatalogue.ckanutillibrary.server.ApplicationProfileScopePerUrlReader; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory; import org.gcube.datacatalogue.ckanutillibrary.server.utils.UtilMethods; import org.gcube.datacatalogue.common.Constants; -import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetService; +import org.gcube.datacatalogue.common.enums.Sources; import org.gcube.datacatalogue.common.enums.Status; +import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetService; import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean; +import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord; +import org.gcube.datacatalogue.grsf_manage_widget.shared.SourceRecord; import org.gcube.datacatalogue.grsf_manage_widget.shared.ex.NoGRSFRecordException; -import org.gcube.resources.discovery.client.api.DiscoveryClient; -import org.gcube.resources.discovery.client.queries.api.SimpleQuery; +import org.gcube.vomanagement.usermanagement.RoleManager; import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager; -import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; +import org.gcube.vomanagement.usermanagement.model.GCubeRole; import org.gcube.vomanagement.usermanagement.model.GCubeTeam; -import org.gcube.vomanagement.usermanagement.model.GCubeUser; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; +import org.gcube.vomanagement.usermanagement.model.GatewayRolesNames; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; -import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse; -import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost; -import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity; -import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient; -import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder; -import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils; import eu.trentorise.opendata.jackan.model.CkanDataset; -import eu.trentorise.opendata.jackan.model.CkanGroup; import eu.trentorise.opendata.jackan.model.CkanPair; -import eu.trentorise.opendata.jackan.model.CkanTag; +import eu.trentorise.opendata.jackan.model.CkanResource; /** - * Endpoint for sending update records information to GRSF KB + * Endpoint for sending update records information to GRSF KnowledgeBase. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class GRSFNotificationService extends RemoteServiceServlet implements GRSFManageWidgetService{ private static final long serialVersionUID = -4534905087994875893L; private static final Log logger = LogFactoryUtil.getLog(GRSFNotificationService.class); - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - private static final int MAX_TRIAL = 5; /** * Instanciate the ckan util library. * Since it needs the scope, we need to check if it is null or not * @param discoverScope if you want to the discover the utils library in this specified scope - * @return + * @return DataCatalogue object + * @throws Exception */ - public DataCatalogue getCatalogue(String discoverScope){ - String currentScope = getCurrentContext(getThreadLocalRequest(), false); + public DataCatalogue getCatalogue(String discoverScope) throws Exception{ + String currentScope = Utils.getCurrentContext(getThreadLocalRequest(), false); DataCatalogue instance = null; try{ String scopeInWhichDiscover = discoverScope != null && !discoverScope.isEmpty() ? discoverScope : currentScope; @@ -76,6 +55,7 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS instance = DataCatalogueFactory.getFactory().getUtilsPerScope(scopeInWhichDiscover); }catch(Exception e){ logger.error("Unable to retrieve ckan utils. Error was " + e.toString()); + throw e; } return instance; } @@ -86,17 +66,17 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS logger.info("Creating notification for the bean " + bean + " to send to the knowledge base"); try{ - String context = getScopeFromClientUrl(getThreadLocalRequest()); + String context = Utils.getScopeFromClientUrl(getThreadLocalRequest()); DataCatalogue catalogue = getCatalogue(context); // check if the base url of the service is in session String keyPerContext = UtilMethods.concatenateSessionKeyScope(Constants.GRSF_UPDATER_SERVICE, context); String baseUrl = (String)getThreadLocalRequest().getSession().getAttribute(keyPerContext); if(baseUrl == null || baseUrl.isEmpty()){ - baseUrl = GRSFNotificationService.discoverEndPoint(context); + baseUrl = Utils.discoverEndPoint(context); getThreadLocalRequest().getSession().setAttribute(keyPerContext, baseUrl); } - return GRSFNotificationService.updateCatalogueRecord(baseUrl, bean, catalogue, getCurrentUser(getThreadLocalRequest()).getUsername()); + return Utils.updateCatalogueRecord(baseUrl, bean, catalogue, Utils.getCurrentUser(getThreadLocalRequest()).getUsername()); }catch(Exception e){ logger.error("Unable to update the product.." + e.getMessage()); @@ -110,373 +90,79 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS ManageProductBean toReturn = null; // retrieve scope per current portlet url - String scopePerCurrentUrl = getScopeFromClientUrl(getThreadLocalRequest()); + String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest()); DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl); - String username = getCurrentUser(getThreadLocalRequest()).getUsername(); + String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername(); CkanDataset record = catalogue.getDataset(productIdentifier, catalogue.getApiKeyFromUsername(username)); // it cannot be enabled in this case ... if(record == null) - throw new Exception("Unable to retrieve information for the selected item, sorry"); + throw new Exception("Unable to retrieve information for the selected record, sorry"); else{ - // check it is a grsf record + // check it is a grsf record (Source records have a different System Type) String systemType = record.getExtrasAsHashMap().get(Constants.SYSTEM_TYPE_CUSTOM_KEY); if(systemType == null || systemType.isEmpty() || systemType.equals(Constants.SYSTEM_TYPE_FOR_SOURCES_VALUE)) - throw new NoGRSFRecordException("This is not a GRSF Item"); + throw new NoGRSFRecordException("This is not a GRSF Record"); - Map extrasAsHashMap = record.getExtrasAsHashMap(); + // get extras as hashmap and pairs + List extrasAsPairs = record.getExtras(); // fetch map for namespaces Map fieldsNamespacesMap = Utils.getFieldToFieldNameSpaceMapping(getThreadLocalRequest().getSession(), - extrasAsHashMap.get(Constants.DOMAIN_CUSTOM_KEY).equals(Constants.STOCK_NAME_CUSTOM_KEY) ? Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_STOCK + record.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY).equals(Constants.STOCK_NAME_CUSTOM_KEY) ? Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_STOCK : Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_FISHERY); - Map extrasWithoutNamespaces = Utils.replaceFieldsKey(extrasAsHashMap, fieldsNamespacesMap); + Map> extrasWithoutNamespaces = Utils.replaceFieldsKey(extrasAsPairs, fieldsNamespacesMap); - //// other info to show TODO - // Set extrasToShow = Utils.getLookedUpExtrasKeys(); - // if(extrasToShow != null && !extrasToShow.isEmpty()){ - // Map extrasKeyValuePair = new HashMap(); - // List extrasAsPairs = product.getExtras(); - // for (CkanPair ckanPair : extrasAsPairs) { - // String key = ckanPair.getKey(); - // String value = ckanPair.getValue(); - // - // if(extrasToShow.contains(key)){ - // String currentValueInMap = extrasKeyValuePair.get(key); - // if(currentValueInMap == null) - // currentValueInMap = value; - // else - // currentValueInMap += ", " + value; - // extrasKeyValuePair.put(key, currentValueInMap); - // } - // } - // toReturn.setExtrasIfAvailable(extrasKeyValuePair); - // } - - String status = extrasWithoutNamespaces.get(Constants.STATUS_CUSTOM_FIELD_KEY); - String uuidKB = extrasWithoutNamespaces.get(Constants.KB_UUID_FIELD_KEY); - String semanticId = extrasWithoutNamespaces.get(Constants.SEMANTIC_IDENTIFIER); - String shortName = extrasWithoutNamespaces.get(Constants.SHORT_NAME_FIELD_KEY); - String grsfType = extrasWithoutNamespaces.get(Constants.GRSF_TYPE_FIELD_KEY); - String grsfDomain = extrasWithoutNamespaces.get(Constants.GRSF_DOMAIN); - String grsfName = extrasWithoutNamespaces.get(grsfDomain.equals(Constants.STOCK) ? Constants.STOCK_GRSF_NAME : Constants.FISHERY_GRSF_NAME); - String traceabilityFlag = extrasWithoutNamespaces.get(Constants.TRACEABILITY_FLAG); - String sources = extrasWithoutNamespaces.get(Constants.GRSF_DATABASE_SOURCE); + // get extras fields (wrt the mandatory ones) to show in the management panel TODO + // Utils.getExtrasToShow(); + String catalogueIdentifier = record.getId(); + String status = extrasWithoutNamespaces.get(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY).get(0); + String uuidKB = extrasWithoutNamespaces.get(Constants.UUID_KB_CUSTOM_KEY).get(0); + String grsfDomain = extrasWithoutNamespaces.get(Constants.DOMAIN_CUSTOM_KEY).get(0); if(status == null || uuidKB == null) throw new Exception("Some information is missing in this record: Status = " + status + ", knowledge base uuid = " + uuidKB + ", and grsf domain is = " + grsfDomain); - - // set the values - toReturn = new ManageProductBean(semanticId, productIdentifier, uuidKB, - grsfType, grsfDomain, sources, grsfName, traceabilityFlag.equalsIgnoreCase("true"), Status.fromString(status), null, null, shortName, null); - logger.info("Returning item bean " + toReturn); + String semanticId = extrasWithoutNamespaces.get(Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY).get(0); + String shortName = extrasWithoutNamespaces.get(Constants.SHORT_NAME_CUSTOM_KEY).get(0); + String grsfType = extrasWithoutNamespaces.get(Constants.GRSF_TYPE_CUSTOM_KEY).get(0); + String grsfName = extrasWithoutNamespaces.get(grsfDomain.equals(Constants.STOCK_NAME_CUSTOM_KEY) ? + Constants.STOCK_NAME_CUSTOM_KEY : Constants.FISHERY_NAME_CUSTOM_KEY).get(0); + boolean traceabilityFlag = extrasWithoutNamespaces.get(Constants.TRACEABILITY_FLAG_CUSTOM_KEY).get(0).equalsIgnoreCase("true"); - return toReturn; + // Get similar GRSF records, if any (each of which should have name, description, url and id(i.e semantic identifier)) + List similarGrsfRecordsAsStrings = + extrasWithoutNamespaces.containsKey(Constants.SIMILAR_GRSF_RECORDS_CUSTOM_KEY) ? + extrasWithoutNamespaces.get(Constants.SIMILAR_GRSF_RECORDS_CUSTOM_KEY): null; + + List similarRecords = new ArrayList(0); + if(similarGrsfRecordsAsStrings != null) + for (String similarGRSFRecord : similarGrsfRecordsAsStrings) { + similarRecords.add(SimilarGRSFRecord.fromJson(similarGRSFRecord)); + } + + // Get sources + List resources = record.getResources(); + List sources = new ArrayList(3); + for (CkanResource ckanResource : resources) { + if(Sources.getListNames().contains(ckanResource.getName())) + sources.add(new SourceRecord(ckanResource.getName(), ckanResource.getUrl())); + } + + // set the values + toReturn = new ManageProductBean(semanticId, catalogueIdentifier, uuidKB, grsfType, + grsfDomain, grsfName, shortName, traceabilityFlag, Status.fromString(status), null, + null, null, sources, similarRecords); + + logger.info("Returning item bean " + toReturn); + + return toReturn; } } - /** - * Discover the service endpoint and return its url - * @param context - * @return the url of the service on success, null otherwise - */ - public static String discoverEndPoint(String context){ - - String oldContext = ScopeProvider.instance.get(); - ScopeProvider.instance.set(context); - String toReturn = null; - try{ - SimpleQuery query = queryFor(ServiceEndpoint.class); - query.addCondition("$resource/Profile/Name/text() eq '"+ Constants.SERVICE_NAME +"'"); - query.addCondition("$resource/Profile/Category/text() eq '"+ Constants.SERVICE_CATEGORY +"'"); - DiscoveryClient client = clientFor(ServiceEndpoint.class); - List resources = client.submit(query); - - if (resources.size() == 0){ - logger.error("There is no Runtime Resource having name " + Constants.SERVICE_NAME +" and Category " + Constants.SERVICE_CATEGORY + " in this scope."); - throw new Exception("There is no Runtime Resource having name " + Constants.SERVICE_NAME +" and Category " + Constants.SERVICE_CATEGORY + " in this scope."); - } - else { - - for (ServiceEndpoint res : resources) { - - Iterator accessPointIterator = res.profile().accessPoints().iterator(); - - while (accessPointIterator.hasNext()) { - ServiceEndpoint.AccessPoint accessPoint = (ServiceEndpoint.AccessPoint) accessPointIterator - .next(); - - // return the path - toReturn = accessPoint.address(); - } - } - } - }catch(Exception e){ - logger.error("Unable to retrieve such service endpoint information!", e); - }finally{ - if(oldContext != null && !oldContext.equals(context)) - ScopeProvider.instance.set(oldContext); - } - - return toReturn; - } - - /** - * Send an update for this bean - * @param baseUrl - * @param bean - * @param username - * @param catalogue - * @return true on success, false otherwise - */ - @SuppressWarnings("unchecked") - public static String updateCatalogueRecord(String serviceUrl, ManageProductBean bean, DataCatalogue catalogue, String username){ - - if(serviceUrl == null) - throw new IllegalArgumentException("GRSF Updater service url cannot be null"); - - if(bean == null) - throw new IllegalArgumentException("Item bean to manage cannot be null"); - - try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){ - - JSONObject obj = new JSONObject(); - obj.put(Constants.CATALOGUE_ID, bean.getCatalogueIdentifier()); - obj.put(Constants.KB_ID, bean.getKnowledgeBaseIdentifier()); - obj.put(Constants.PRODUCT_TYPE, bean.getGrsfDomain().toLowerCase()); - obj.put(Constants.STATUS, bean.getNewStatus().toString().toLowerCase()); - - String annotation = bean.getAnnotation(); - if(annotation != null) - obj.put(Constants.ANNOTATION, annotation.replaceAll("\"", "")); - - logger.debug("Update request looks like " + obj.toJSONString()); - - HttpPost request = new HttpPost(serviceUrl + Constants.SERVICE_POST_METHOD); - request.setHeader("Accept", "application/json"); - request.setHeader("Content-type", "application/json"); - StringEntity params = new StringEntity(obj.toJSONString()); - request.setEntity(params); - HttpResponse response = httpClient.execute(request); - - logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase()); - - String result = EntityUtils.toString(response.getEntity()); - JSONParser parser = new JSONParser(); - JSONObject parsedJSON = (JSONObject)parser.parse(result); - - if(response.getStatusLine().getStatusCode() != Constants.STATUS_SUCCESS) - throw new IllegalArgumentException( - "Error while performing the update request: " + response.getStatusLine().getReasonPhrase() + - "and error in the result bean is " + parsedJSON.get(Constants.ERROR)); - - // patch the catalogue product - return patchProduct(catalogue, bean, username); - - }catch(Exception e){ - logger.error("Unable to update this Item " + e.getMessage()); - return e.getMessage(); - } - - } - - /** - * Patch the product - * @param catalogue - * @param bean - * @param username - */ - @SuppressWarnings("unchecked") - private static String patchProduct(DataCatalogue catalogue, - ManageProductBean bean, String username) { - - logger.info("Going to patch record in the catalogue with identifier " + bean.getCatalogueIdentifier() + - " from user " + username); - - String apiKey = catalogue.getApiKeyFromUsername(username); - CkanDataset dataset = catalogue.getDataset(bean.getCatalogueIdentifier(), apiKey); - String errorMessage = null; - - for (int i = 0; i < MAX_TRIAL; i++) { - - try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){ - - JSONObject jsonRequest = new JSONObject(); - JSONArray tagsAsJson = new JSONArray(); - JSONArray groupsAsJson = new JSONArray(); - JSONArray customFieldsAsJson = new JSONArray(); - - // manage the custom fields - List extras = dataset.getExtras(); - for (CkanPair ckanPair : extras) { - if(ckanPair.getKey().equals(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY) && ckanPair.getValue().equals(bean.getCurrentStatus().toString())) - continue; - - JSONObject obj = new JSONObject(); - obj.put("key", ckanPair.getKey()); - obj.put("value", ckanPair.getValue()); - customFieldsAsJson.add(obj); - } - - // add the new one and the annotation message - JSONObject newStatus = new JSONObject(); - newStatus.put("key", Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY); - newStatus.put("value", bean.getNewStatus().toString()); - customFieldsAsJson.add(newStatus); - - JSONObject newAnnotation = new JSONObject(); - newAnnotation.put("key", Constants.ANNOTATION_CUSTOM_KEY); - newAnnotation.put("value", "date: " + DATE_FORMAT.format(new Date()) - + ", admin: " + new LiferayUserManager().getUserByUsername(username).getFullname() - + ", message: " + (bean.getAnnotation() != null ? bean.getAnnotation().replaceAll("\"", "") : "none") - + ", old status: " + bean.getCurrentStatus().toString() - + ", new status: " + bean.getNewStatus().toString() - ); - customFieldsAsJson.add(newAnnotation); - - // manage the tags - List tags = dataset.getTags(); - - for(CkanTag ckanTag : tags){ - if(!ckanTag.getName().equals(bean.getCurrentStatus().toString())){ - JSONObject obj = new JSONObject(); - obj.put("vocabulary_id", ckanTag.getVocabularyId()); - obj.put("state", ckanTag.getState().toString()); - obj.put("display_name", ckanTag.getDisplayName()); - obj.put("id", ckanTag.getId()); - obj.put("name", ckanTag.getName()); - tagsAsJson.add(obj); - } - } - - // add the new one - JSONObject newTag = new JSONObject(); - newTag.put("name", bean.getNewStatus().toString()); - newTag.put("display_name", bean.getNewStatus().toString()); - tagsAsJson.add(newTag); - - // manage the groups - List groups = dataset.getGroups(); - for (CkanGroup ckanGroup : groups) { - if(!ckanGroup.getName().equals("grsf" + "-" + bean.getCurrentStatus().toString().toLowerCase())){ - JSONObject obj = new JSONObject(); - obj.put("name", ckanGroup.getName()); - groupsAsJson.add(obj); - } - } - - JSONObject newGroup = new JSONObject(); - newGroup.put("name", "grsf" + "-" + bean.getNewStatus().toString().toLowerCase()); - groupsAsJson.add(newGroup); - - // perform the request - jsonRequest.put("id", bean.getCatalogueIdentifier()); - jsonRequest.put("tags", tagsAsJson); - jsonRequest.put("extras", customFieldsAsJson); - jsonRequest.put("groups", groupsAsJson); - - logger.debug("Request param is going to be " + jsonRequest); - - if((errorMessage = catalogue.patchProductWithJSON(bean.getCatalogueIdentifier(), jsonRequest, apiKey)) == null){ - logger.info("Record patched ..."); - break; - }else - continue; // retry - - }catch(Exception e){ - logger.error("Error while trying to patch grsf record (iteration " + i + " of " + MAX_TRIAL + ")" + e.getMessage()); - errorMessage = e.getMessage(); - } - } - return errorMessage; - } - - /** - * Get the scope in which ckan information needs to be discovered from the url - * @param httpServletRequest - * @return - */ - public static String getScopeFromClientUrl(HttpServletRequest httpServletRequest){ - - if(httpServletRequest == null) - throw new IllegalArgumentException("HttpServletRequest is null!"); - - String scopeToReturn = null; - try{ - String clientUrl = getCurrentClientUrl(httpServletRequest).split("\\?")[0]; - logger.debug("Client url is " + clientUrl); - - // check if this information is in session, otherwise set it and return - HttpSession session = httpServletRequest.getSession(); - - if((scopeToReturn = (String) session.getAttribute(clientUrl)) != null){ - logger.debug("Scope to return is " + scopeToReturn); - }else{ - // ask to the ckan library and set it - scopeToReturn = ApplicationProfileScopePerUrlReader.getScopePerUrl(clientUrl); - logger.debug("Scope to return is " + scopeToReturn); - session.setAttribute(clientUrl, scopeToReturn); - } - }catch(Exception e){ - scopeToReturn = getCurrentContext(httpServletRequest, false); - logger.warn("Failed to determine the scope from the client url, returning the current one: " + scopeToReturn); - } - return scopeToReturn; - } - - /** - * Needed to get the url of the client - * @param httpServletRequest the httpServletRequest object - * @return the instance of the user - * @see the url at client side - */ - public static String getCurrentClientUrl(HttpServletRequest httpServletRequest) { - if(httpServletRequest == null) - throw new IllegalArgumentException("HttpServletRequest is null!"); - - return httpServletRequest.getHeader(Constants.GCUBE_REQUEST_URL); - } - - /** - * Retrieve the current scope by using the portal manager - * @param b - * @return a GcubeUser object - */ - public static String getCurrentContext(HttpServletRequest request, boolean setInThread){ - - if(request == null) - throw new IllegalArgumentException("HttpServletRequest is null!"); - - PortalContext pContext = PortalContext.getConfiguration(); - String context = pContext.getCurrentScope(request); - logger.debug("Returning context " + context); - - if(context != null && setInThread) - ScopeProvider.instance.set(context); - - return context; - } - - /** - * Retrieve the current user by using the portal manager - * @return a GcubeUser object - */ - public static GCubeUser getCurrentUser(HttpServletRequest request){ - - if(request == null) - throw new IllegalArgumentException("HttpServletRequest is null!"); - - PortalContext pContext = PortalContext.getConfiguration(); - GCubeUser user = pContext.getCurrentUser(request); - logger.debug("Returning user " + user); - return user; - } - - @Override public boolean isAdminUser() { try{ @@ -487,20 +173,38 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS return inSession; else{ PortalContext pContext = PortalContext.getConfiguration(); - List teamRoles = new LiferayRoleManager().listTeamsByUserAndGroup(pContext.getCurrentUser(getThreadLocalRequest()).getUserId(), pContext.getCurrentGroupId(getThreadLocalRequest())); + RoleManager roleManager = new LiferayRoleManager(); + String username = pContext.getCurrentUser(getThreadLocalRequest()).getUsername(); + long userId = pContext.getCurrentUser(getThreadLocalRequest()).getUserId(); + long groupId = pContext.getCurrentGroupId(getThreadLocalRequest()); + List vreRoles = roleManager.listRolesByUserAndGroup(userId, groupId); + List teamRoles = new LiferayRoleManager().listTeamsByUserAndGroup(userId, groupId); boolean toSetInSession = false; for (GCubeTeam team : teamRoles) { if(team.getTeamName().equals(Constants.GRSF_CATALOGUE_MANAGER_ROLE)){ + logger.info("User " + username + " is " + Constants.GRSF_CATALOGUE_MANAGER_ROLE); toSetInSession = true; break; } } + + if(!toSetInSession) + for (GCubeRole gCubeTeam : vreRoles) { + if(gCubeTeam.getRoleName().equals(GatewayRolesNames.VRE_MANAGER.getRoleName())){ + logger.info("User " + username + " is " + GatewayRolesNames.VRE_MANAGER.getRoleName()); + toSetInSession = true; + break; + } + } + getThreadLocalRequest().getSession().setAttribute(Constants.GRSF_ADMIN_SESSION_KEY, toSetInSession); return toSetInSession; } }catch(Exception e){ - logger.error("Failed to check if the user has team " + Constants.GRSF_CATALOGUE_MANAGER_ROLE, e); + logger.error("Failed to check if the user has team " + Constants.GRSF_CATALOGUE_MANAGER_ROLE + + " or " + GatewayRolesNames.VRE_MANAGER.getRoleName() +"!", e); } return false; } + } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java index ea672e6..9278066 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java @@ -1,34 +1,65 @@ package org.gcube.datacatalogue.grsf_manage_widget.server.manage; import static org.gcube.resources.discovery.icclient.ICFactory.client; +import static org.gcube.resources.discovery.icclient.ICFactory.clientFor; +import static org.gcube.resources.discovery.icclient.ICFactory.queryFor; import java.io.StringReader; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import org.gcube.common.portal.PortalContext; +import org.gcube.common.resources.gcore.ServiceEndpoint; +import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint; import org.gcube.common.resources.gcore.utils.XPathHelper; import org.gcube.common.scope.api.ScopeProvider; +import org.gcube.datacatalogue.ckanutillibrary.server.ApplicationProfileScopePerUrlReader; +import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue; import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ApplicationProfileNotFoundException; +import org.gcube.datacatalogue.common.Constants; +import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean; import org.gcube.resources.discovery.client.api.DiscoveryClient; import org.gcube.resources.discovery.client.queries.api.Query; +import org.gcube.resources.discovery.client.queries.api.SimpleQuery; import org.gcube.resources.discovery.client.queries.impl.QueryBox; +import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager; +import org.gcube.vomanagement.usermanagement.model.GCubeUser; +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpResponse; +import eu.trentorise.opendata.jackan.internal.org.apache.http.client.methods.HttpPost; +import eu.trentorise.opendata.jackan.internal.org.apache.http.entity.StringEntity; +import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.CloseableHttpClient; +import eu.trentorise.opendata.jackan.internal.org.apache.http.impl.client.HttpClientBuilder; +import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils; +import eu.trentorise.opendata.jackan.model.CkanDataset; +import eu.trentorise.opendata.jackan.model.CkanGroup; +import eu.trentorise.opendata.jackan.model.CkanPair; +import eu.trentorise.opendata.jackan.model.CkanTag; + /** - * Look up from the IS other information that the widget should show + * Utility methods for GRSF Management panel widget. * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) */ public class Utils { @@ -36,7 +67,14 @@ public class Utils { private static final String GENERIC_RESOURCE_NAME = "GRSFManageEntries"; private static final String GENERIC_RESOURCE_SECONDARY_TYPE = "ApplicationProfile"; private static final Logger logger = LoggerFactory.getLogger(Utils.class); + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static final String REGEX_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + private static final int MAX_TRIAL = 5; + /** + * Look up from the IS other information that can be potentially displayed in read only mode in the management panel. + * @return a list of extra keys to show. + */ public static Set getLookedUpExtrasKeys() { Set lookedUpExtrasKeys = new HashSet(); String scope = ScopeProvider.instance.get(); @@ -89,13 +127,14 @@ public class Utils { * @param httpSession * @return a map */ + @SuppressWarnings("unchecked") public static Map getFieldToFieldNameSpaceMapping(HttpSession httpSession, String resourceName){ - + // check if this information is available in session String sessionKey = ScopeProvider.instance.get() + resourceName; if(httpSession.getAttribute(sessionKey) != null) return (Map) httpSession.getAttribute(sessionKey); - + Map namespacesMap = new HashMap(); // e.g. fishery_identity:Short Title -> Short Title try { Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource " + @@ -136,28 +175,425 @@ public class Utils { } /** - * Replace the extras' keys if needed - * @param customFields + * Replace the extras' keys if needed, e.g. fishery_identity:Short Title -> Short Title + * @param extrasAsPairs * @param namespaces - * @return + * @return a map with replaced key value pairs */ - public static Map replaceFieldsKey(Map customFields, + public static Map> replaceFieldsKey(List extrasAsPairs, Map namespaces) { - Map toReturn = new HashMap(); + Map> toReturn = new HashMap>(); - Iterator> iterator = customFields.entrySet().iterator(); + for (CkanPair ckanPair : extrasAsPairs) { + String pairKey = ckanPair.getKey(); + String pairValue = ckanPair.getValue(); + String replacedKey = namespaces.containsKey(pairKey) ? namespaces.get(pairKey) : pairKey; - while (iterator.hasNext()) { - Map.Entry entry = (Map.Entry) iterator - .next(); - if(namespaces.containsKey(entry.getKey())) - toReturn.put(namespaces.get(entry.getKey()), entry.getValue()); + List values = null; + if(toReturn.containsKey(replacedKey)) + values = toReturn.get(replacedKey); else - toReturn.put(entry.getKey(), entry.getValue()); + values = new ArrayList(1); + + values.add(pairValue); + + toReturn.put(replacedKey, values); + } + + + return toReturn; + } + + /** + * Discover the service endpoint and return its url + * @param context + * @return the url of the service on success, null otherwise + */ + public static String discoverEndPoint(String context){ + + String oldContext = ScopeProvider.instance.get(); + ScopeProvider.instance.set(context); + String toReturn = null; + try{ + SimpleQuery query = queryFor(ServiceEndpoint.class); + query.addCondition("$resource/Profile/Name/text() eq '"+ Constants.SERVICE_NAME +"'"); + query.addCondition("$resource/Profile/Category/text() eq '"+ Constants.SERVICE_CATEGORY +"'"); + DiscoveryClient client = clientFor(ServiceEndpoint.class); + List resources = client.submit(query); + + if (resources.size() == 0){ + logger.error("There is no Runtime Resource having name " + Constants.SERVICE_NAME +" and Category " + Constants.SERVICE_CATEGORY + " in this scope."); + throw new Exception("There is no Runtime Resource having name " + Constants.SERVICE_NAME +" and Category " + Constants.SERVICE_CATEGORY + " in this scope."); + } + else { + + for (ServiceEndpoint res : resources) { + + Iterator accessPointIterator = res.profile().accessPoints().iterator(); + + while (accessPointIterator.hasNext()) { + ServiceEndpoint.AccessPoint accessPoint = (ServiceEndpoint.AccessPoint) accessPointIterator + .next(); + + // return the path + toReturn = accessPoint.address(); + } + } + } + }catch(Exception e){ + logger.error("Unable to retrieve such service endpoint information!", e); + }finally{ + if(oldContext != null && !oldContext.equals(context)) + ScopeProvider.instance.set(oldContext); } return toReturn; } + /** + * Send an update for this bean + * @param baseUrl + * @param bean + * @param username + * @param catalogue + * @return true on success, false otherwise + */ + @SuppressWarnings("unchecked") + public static String updateCatalogueRecord(String serviceUrl, ManageProductBean bean, DataCatalogue catalogue, String username){ + + if(serviceUrl == null) + throw new IllegalArgumentException("GRSF Updater service url cannot be null"); + + if(bean == null) + throw new IllegalArgumentException("Item bean to manage cannot be null"); + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){ + + JSONObject obj = new JSONObject(); + obj.put(Constants.CATALOGUE_ID, bean.getCatalogueIdentifier()); + obj.put(Constants.KB_ID, bean.getKnowledgeBaseIdentifier()); + obj.put(Constants.PRODUCT_TYPE, bean.getGrsfDomain().toLowerCase()); + obj.put(Constants.STATUS, bean.getNewStatus().toString().toLowerCase()); + + String annotation = bean.getAnnotation(); + if(annotation != null) + obj.put(Constants.ANNOTATION, annotation.replaceAll("\"", "")); + + logger.debug("Update request looks like " + obj.toJSONString()); + + HttpPost request = new HttpPost(serviceUrl + Constants.SERVICE_POST_METHOD); + request.setHeader("Accept", "application/json"); + request.setHeader("Content-type", "application/json"); + StringEntity params = new StringEntity(obj.toJSONString()); + request.setEntity(params); + HttpResponse response = httpClient.execute(request); + + logger.debug("Response code is " + response.getStatusLine().getStatusCode() + " and response message is " + response.getStatusLine().getReasonPhrase()); + + String result = EntityUtils.toString(response.getEntity()); + JSONParser parser = new JSONParser(); + JSONObject parsedJSON = (JSONObject)parser.parse(result); + + if(response.getStatusLine().getStatusCode() != Constants.STATUS_SUCCESS) + throw new IllegalArgumentException( + "Error while performing the update request: " + response.getStatusLine().getReasonPhrase() + + "and error in the result bean is " + parsedJSON.get(Constants.ERROR)); + + // patch the catalogue product + return patchProduct(catalogue, bean, username); + + }catch(Exception e){ + logger.error("Unable to update this Item " + e.getMessage()); + return e.getMessage(); + } + + } + + /** + * Patch the product + * @param catalogue + * @param bean + * @param username + */ + @SuppressWarnings("unchecked") + private static String patchProduct(DataCatalogue catalogue, + ManageProductBean bean, String username) { + + logger.info("Going to patch record in the catalogue with identifier " + bean.getCatalogueIdentifier() + + " from user " + username); + + String apiKey = catalogue.getApiKeyFromUsername(username); + CkanDataset dataset = catalogue.getDataset(bean.getCatalogueIdentifier(), apiKey); + String errorMessage = null; + + for (int i = 0; i < MAX_TRIAL; i++) { + + try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){ + + JSONObject jsonRequest = new JSONObject(); + JSONArray tagsAsJson = new JSONArray(); + JSONArray groupsAsJson = new JSONArray(); + JSONArray customFieldsAsJson = new JSONArray(); + + // manage the custom fields + List extras = dataset.getExtras(); + for (CkanPair ckanPair : extras) { + if(ckanPair.getKey().equals(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY) && ckanPair.getValue().equals(bean.getCurrentStatus().toString())) + continue; + + JSONObject obj = new JSONObject(); + obj.put("key", ckanPair.getKey()); + obj.put("value", ckanPair.getValue()); + customFieldsAsJson.add(obj); + } + + // add the new one and the annotation message + JSONObject newStatus = new JSONObject(); + newStatus.put("key", Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY); + newStatus.put("value", bean.getNewStatus().toString()); + customFieldsAsJson.add(newStatus); + + JSONObject newAnnotation = new JSONObject(); + newAnnotation.put("key", Constants.ANNOTATION_CUSTOM_KEY); + newAnnotation.put("value", "date: " + DATE_FORMAT.format(new Date()) + + ", admin: " + new LiferayUserManager().getUserByUsername(username).getFullname() + + ", message: " + (bean.getAnnotation() != null ? bean.getAnnotation().replaceAll("\"", "") : "none") + + ", old status: " + bean.getCurrentStatus().toString() + + ", new status: " + bean.getNewStatus().toString() + ); + customFieldsAsJson.add(newAnnotation); + + // manage the tags + List tags = dataset.getTags(); + + for(CkanTag ckanTag : tags){ + if(!ckanTag.getName().equals(bean.getCurrentStatus().toString())){ + JSONObject obj = new JSONObject(); + obj.put("vocabulary_id", ckanTag.getVocabularyId()); + obj.put("state", ckanTag.getState().toString()); + obj.put("display_name", ckanTag.getDisplayName()); + obj.put("id", ckanTag.getId()); + obj.put("name", ckanTag.getName()); + tagsAsJson.add(obj); + } + } + + // add the new one + JSONObject newTag = new JSONObject(); + newTag.put("name", bean.getNewStatus().toString()); + newTag.put("display_name", bean.getNewStatus().toString()); + tagsAsJson.add(newTag); + + // manage the groups + List groups = dataset.getGroups(); + for (CkanGroup ckanGroup : groups) { + if(!ckanGroup.getName().equals("grsf" + "-" + bean.getCurrentStatus().toString().toLowerCase())){ + JSONObject obj = new JSONObject(); + obj.put("name", ckanGroup.getName()); + groupsAsJson.add(obj); + } + } + + JSONObject newGroup = new JSONObject(); + newGroup.put("name", "grsf" + "-" + bean.getNewStatus().toString().toLowerCase()); + groupsAsJson.add(newGroup); + + // perform the request + jsonRequest.put("id", bean.getCatalogueIdentifier()); + jsonRequest.put("tags", tagsAsJson); + jsonRequest.put("extras", customFieldsAsJson); + jsonRequest.put("groups", groupsAsJson); + + logger.debug("Request param is going to be " + jsonRequest); + + if((errorMessage = catalogue.patchProductWithJSON(bean.getCatalogueIdentifier(), jsonRequest, apiKey)) == null){ + logger.info("Record patched ..."); + break; + }else + continue; // retry + + }catch(Exception e){ + logger.error("Error while trying to patch grsf record (iteration " + i + " of " + MAX_TRIAL + ")" + e.getMessage()); + errorMessage = e.getMessage(); + } + } + return errorMessage; + } + + /** + * Get the scope in which ckan information needs to be discovered from the url + * @param httpServletRequest + * @return + */ + public static String getScopeFromClientUrl(HttpServletRequest httpServletRequest){ + + if(httpServletRequest == null) + throw new IllegalArgumentException("HttpServletRequest is null!"); + + String scopeToReturn = null; + try{ + String clientUrl = getCurrentClientUrl(httpServletRequest).split("\\?")[0]; + logger.debug("Client url is " + clientUrl); + + // check if this information is in session, otherwise set it and return + HttpSession session = httpServletRequest.getSession(); + + if((scopeToReturn = (String) session.getAttribute(clientUrl)) != null){ + logger.debug("Scope to return is " + scopeToReturn); + }else{ + // ask to the ckan library and set it + scopeToReturn = ApplicationProfileScopePerUrlReader.getScopePerUrl(clientUrl); + logger.debug("Scope to return is " + scopeToReturn); + session.setAttribute(clientUrl, scopeToReturn); + } + }catch(Exception e){ + scopeToReturn = getCurrentContext(httpServletRequest, false); + logger.warn("Failed to determine the scope from the client url, returning the current one: " + scopeToReturn); + } + return scopeToReturn; + } + + /** + * Needed to get the url of the client + * @param httpServletRequest the httpServletRequest object + * @return the instance of the user + * @see the url at client side + */ + public static String getCurrentClientUrl(HttpServletRequest httpServletRequest) { + if(httpServletRequest == null) + throw new IllegalArgumentException("HttpServletRequest is null!"); + + return httpServletRequest.getHeader(Constants.GCUBE_REQUEST_URL); + } + + /** + * Retrieve the current scope by using the portal manager + * @param b + * @return a GcubeUser object + */ + public static String getCurrentContext(HttpServletRequest request, boolean setInThread){ + + if(request == null) + throw new IllegalArgumentException("HttpServletRequest is null!"); + + PortalContext pContext = PortalContext.getConfiguration(); + String context = pContext.getCurrentScope(request); + logger.debug("Returning context " + context); + + if(context != null && setInThread) + ScopeProvider.instance.set(context); + + return context; + } + + /** + * Retrieve the current user by using the portal manager + * @return a GcubeUser object + */ + public static GCubeUser getCurrentUser(HttpServletRequest request){ + + if(request == null) + throw new IllegalArgumentException("HttpServletRequest is null!"); + + PortalContext pContext = PortalContext.getConfiguration(); + GCubeUser user = pContext.getCurrentUser(request); + logger.debug("Returning user " + user); + return user; + } + + /** + * Given a semantic identifier, check if a record exists and return it + * @param suggestedRecordSemanticIdentifier + * @param catalogue + * @return CkanDataset + * @throws Exception in case no record matches the semantic identifier + */ + public static CkanDataset getRecordBySemanticIdentifier( + String suggestedRecordSemanticIdentifier, DataCatalogue catalogue, + String apiKey) throws Exception { + + if(suggestedRecordSemanticIdentifier == null || suggestedRecordSemanticIdentifier.isEmpty()) + throw new Exception(Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY + " cannot be null or emtpy"); + + String query = Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY + "\"" + suggestedRecordSemanticIdentifier+ "\""; + List datasets = catalogue.searchForPackageInOrganization(apiKey, query, 0, 10, Constants.GRSF_ADMIN_ORGANIZATION_NAME); + + if(datasets == null || datasets.isEmpty()){ + String message = "Unable to find dataset with such " + Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY; + logger.warn(message); + throw new Exception(message); + } + + if(datasets.size() == 1) + return datasets.get(0); + else{ + + // worst situation.. we need to check for the right one + for(CkanDataset dataset: datasets) + for(CkanPair extra : dataset.getExtras()) + if(extra.getKey().contains(Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY) && extra.getValue().equals(suggestedRecordSemanticIdentifier)) + return dataset; + + } + + // in the end .... + throw new Exception("Unable to find record with " + Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY + " equals to " + suggestedRecordSemanticIdentifier); + + } + + /** + * Exploits the fact that in GRSF the url of a record contains the name (which is unique) of the record itself + * @param url + * @param clg + * @return + */ + public static CkanDataset getDatasetFromUrl(String url, DataCatalogue clg, String apiKey){ + + if(url == null || url.isEmpty()) + return null; + + // Parse url + // Create a Pattern object + Pattern r = Pattern.compile(REGEX_UUID); + + // Now create matcher object. + Matcher m = r.matcher(url); + if (m.find()) { + String uuidFound = m.group(); + logger.debug("Found match for uuid " + uuidFound); + return clg.getDataset(uuidFound, apiKey); + } + + return null; + } + + // /** + // * Get extra information to show in the management panel, if any + // * @param extrasAsPairs + // */ + // public static void getExtrasToShow(List extrasAsPairs, ){ + // + // Set extrasToShow = getLookedUpExtrasKeys(); + // if(extrasToShow != null && !extrasToShow.isEmpty()){ + // Map extrasKeyValuePair = new HashMap(); + // = product.getExtras(); + // for (CkanPair ckanPair : extrasAsPairs) { + // String key = ckanPair.getKey(); + // String value = ckanPair.getValue(); + // + // if(extrasToShow.contains(key)){ + // String currentValueInMap = extrasKeyValuePair.get(key); + // if(currentValueInMap == null) + // currentValueInMap = value; + // else + // currentValueInMap += ", " + value; + // extrasKeyValuePair.put(key, currentValueInMap); + // } + // } + // toReturn.setExtrasIfAvailable(extrasKeyValuePair); + // } + // + // } + } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ManageProductBean.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ManageProductBean.java index 76929b6..2217ea9 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ManageProductBean.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ManageProductBean.java @@ -1,6 +1,7 @@ package org.gcube.datacatalogue.grsf_manage_widget.shared; import java.io.Serializable; +import java.util.List; import java.util.Map; import org.gcube.datacatalogue.common.enums.Status; @@ -12,68 +13,75 @@ import org.gcube.datacatalogue.common.enums.Status; public class ManageProductBean implements Serializable{ private static final long serialVersionUID = -4882608487467259326L; - private String semanticId; // Stock id or Fishery id + private String semanticIdentifier; // Stock id or Fishery id private String catalogueIdentifier; // catalogue id private String knowledgeBaseIdentifier; // GRSF UUID private String grsfType; // Fishery or Stock type (e.g., Assessment_Unit, Marine Resource and so on) private String grsfDomain; // fishery/stock - private String sources; // sources for this record private String grsfName; // Fishery name or stock name + private String shortName; private boolean traceabilityFlag; //from false to true etc private Status currentStatus; private Status newStatus; private String annotation; // added by the administrator - private String shortName; private Map extrasIfAvailable; // read from GRSFManageEntries resource + private List sources; // sources for this record + private List similarGrsfRecords; public ManageProductBean() { super(); } - /** - * @param semanticId - * @param catalogueIdentifier - * @param knowledgeBaseIdentifier - * @param grsfType - * @param grsfDomain - * @param sources - * @param grsfName - * @param traceabilityFlag - * @param currentStatus - * @param newStatus - * @param annotation - * @param shortName - * @param extrasIfAvailable - */ - public ManageProductBean(String semanticId, String catalogueIdentifier, - String knowledgeBaseIdentifier, String grsfType, String grsfDomain, - String sources, String grsfName, boolean traceabilityFlag, - Status currentStatus, Status newStatus, String annotation, - String shortName, Map extrasIfAvailable) { + public ManageProductBean(String semanticIdentifier, + String catalogueIdentifier, String knowledgeBaseIdentifier, + String grsfType, String grsfDomain, String grsfName, + String shortName, boolean traceabilityFlag, Status currentStatus, + Status newStatus, String annotation, + Map extrasIfAvailable, List sources, + List similarGrsfRecords) { super(); - this.semanticId = semanticId; + this.semanticIdentifier = semanticIdentifier; this.catalogueIdentifier = catalogueIdentifier; this.knowledgeBaseIdentifier = knowledgeBaseIdentifier; this.grsfType = grsfType; this.grsfDomain = grsfDomain; - this.sources = sources; this.grsfName = grsfName; + this.shortName = shortName; this.traceabilityFlag = traceabilityFlag; this.currentStatus = currentStatus; this.newStatus = newStatus; this.annotation = annotation; - this.shortName = shortName; this.extrasIfAvailable = extrasIfAvailable; + this.sources = sources; + this.similarGrsfRecords = similarGrsfRecords; } - public String getSemanticId() { - return semanticId; + public String getSemanticIdentifier() { + return semanticIdentifier; } - public void setSemanticId(String semanticId) { - this.semanticId = semanticId; + public void setSemanticIdentifier(String semanticIdentifier) { + this.semanticIdentifier = semanticIdentifier; } + public List getSources() { + return sources; + } + + public void setSources(List sources) { + this.sources = sources; + } + + public List getSimilarGrsfRecords() { + return similarGrsfRecords; + } + + public void setSimilarGrsfRecords(List similarGrsfRecords) { + this.similarGrsfRecords = similarGrsfRecords; + } + + + public String getCatalogueIdentifier() { return catalogueIdentifier; } @@ -106,14 +114,6 @@ public class ManageProductBean implements Serializable{ this.grsfDomain = grsfDomain; } - public String getSources() { - return sources; - } - - public void setSources(String sources) { - this.sources = sources; - } - public String getGrsfName() { return grsfName; } @@ -153,7 +153,7 @@ public class ManageProductBean implements Serializable{ public void setAnnotation(String annotation) { this.annotation = annotation; } - + public boolean isTraceabilityFlag() { return traceabilityFlag; } @@ -172,15 +172,16 @@ public class ManageProductBean implements Serializable{ @Override public String toString() { - return "ManageProductBean [semanticId=" + semanticId + return "ManageProductBean [semanticIdentifier=" + semanticIdentifier + ", catalogueIdentifier=" + catalogueIdentifier + ", knowledgeBaseIdentifier=" + knowledgeBaseIdentifier + ", grsfType=" + grsfType + ", grsfDomain=" + grsfDomain - + ", sources=" + sources + ", grsfName=" + grsfName + + ", grsfName=" + grsfName + ", shortName=" + shortName + ", traceabilityFlag=" + traceabilityFlag + ", currentStatus=" + currentStatus + ", newStatus=" + newStatus + ", annotation=" - + annotation + ", shortName=" + shortName - + ", extrasIfAvailable=" + extrasIfAvailable + "]"; + + annotation + ", extrasIfAvailable=" + extrasIfAvailable + + ", sources=" + sources + ", similarGrsfRecords=" + + similarGrsfRecords + "]"; } } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java index 356f916..ea564d4 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java @@ -2,6 +2,11 @@ package org.gcube.datacatalogue.grsf_manage_widget.shared; import java.io.Serializable; +import org.gcube.datacatalogue.common.Constants; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; + /** * A similar grsf record @@ -64,5 +69,28 @@ public class SimilarGRSFRecord implements Serializable{ + ", semanticIdentifier=" + semanticIdentifier + ", shortName=" + shortName + ", url=" + url + "]"; } + + /** + * Get a {@link SimilarGRSFRecord} from a json string + * @param json + * @return {@link SimilarGRSFRecord} + * @throws ParseException + */ + public static SimilarGRSFRecord fromJson(String json) throws ParseException{ + + if(json == null) + return null; + + JSONParser parser = new JSONParser(); + JSONObject object = (JSONObject)parser.parse(json); + + return new SimilarGRSFRecord( + (String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_DESCRIPTION), + (String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_IDENTIFIER), + (String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_NAME), + (String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_URL) + ); + + } }