server side revised

git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/widgets/grsf-manage-widget@162863 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
Costantino Perciante 2018-02-02 14:28:35 +00:00
parent b13f1eafc9
commit aee48d3ecd
11 changed files with 1075 additions and 495 deletions

View File

@ -3,11 +3,11 @@ org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.compiler.source=1.8

View File

@ -4,7 +4,7 @@
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<dependent-module archiveName="grsf-common-library-1.0.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/grsf-common-library/grsf-common-library">
<dependent-module archiveName="ckan-util-library-2.4.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/ckan-util-library/ckan-util-library">
<dependency-type>uses</dependency-type>
</dependent-module>
<property name="context-root" value="grsf-manage-widget"/>

View File

@ -27,22 +27,21 @@ public interface GRSFManageWidgetService extends RemoteService {
*/
String notifyProductUpdate(ManageProductBean bean) throws Exception;
/**
* Check that a record with such semantic identifier exists
* @param semanticIdentifier
* @return true or false
*/
boolean checkSemanticIdentifierExists(String semanticIdentifier) throws Exception;
/**
* Check that a record with such semantic identifier exists in a given domain
* @param semanticIdentifier
* @param domain
* @return
* @throws Exception
*/
boolean checkSemanticIdentifierExistsInDomain(String semanticIdentifier, String domain) throws Exception;
// /**
// * Check that a record with such semantic identifier exists
// * @param semanticIdentifier
// * @return true or false
// */
// boolean checkSemanticIdentifierExists(String semanticIdentifier) throws Exception;
//
// /**
// * Check that a record with such semantic identifier exists in a given domain
// * @param semanticIdentifier
// * @param domain
// * @return
// * @throws Exception
// */
// boolean checkSemanticIdentifierExistsInDomain(String semanticIdentifier, String domain) throws Exception;
/**
* Identifier of the record (UUID)
@ -61,4 +60,11 @@ public interface GRSFManageWidgetService extends RemoteService {
*/
String checkIdentifierExistsInDomain(String id, String domain) throws Exception;
/**
* Check if the given url for revertin the operation is valid and send the request to the knowledge base
* @param url
* @throws Exception
*/
void validateRevertOperation(String url) throws Exception;
}

View File

@ -21,11 +21,11 @@ public interface GRSFManageWidgetServiceAsync {
void isAdminUser(AsyncCallback<Boolean> callback);
void checkSemanticIdentifierExists(String semanticIdentifier,
AsyncCallback<Boolean> callback);
void checkSemanticIdentifierExistsInDomain(String semanticIdentifier,
String domain, AsyncCallback<Boolean> callback);
// void checkSemanticIdentifierExists(String semanticIdentifier,
// AsyncCallback<Boolean> callback);
//
// void checkSemanticIdentifierExistsInDomain(String semanticIdentifier,
// String domain, AsyncCallback<Boolean> callback);
void checkIdentifierExists(String id,
AsyncCallback<String> callback);
@ -33,4 +33,6 @@ public interface GRSFManageWidgetServiceAsync {
void checkIdentifierExistsInDomain(String id,
String domain, AsyncCallback<String> callback);
void validateRevertOperation(String url, AsyncCallback<Void> callback);
}

View File

@ -5,7 +5,12 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueFactory;
import org.gcube.datacatalogue.ckanutillibrary.server.utils.UtilMethods;
@ -22,11 +27,14 @@ import org.gcube.datacatalogue.grsf_manage_widget.shared.ex.NoGRSFRecordExceptio
import org.gcube.vomanagement.usermanagement.RoleManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager;
import org.gcube.vomanagement.usermanagement.model.GCubeTeam;
import org.gcube.vomanagement.usermanagement.model.GCubeUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
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.model.CkanDataset;
import eu.trentorise.opendata.jackan.model.CkanPair;
import eu.trentorise.opendata.jackan.model.CkanResource;
@ -52,7 +60,7 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
String currentScope = Utils.getCurrentContext(getThreadLocalRequest(), true);
DataCatalogue instance = null;
try{
String scopeInWhichDiscover = discoverScope != null && !discoverScope.isEmpty() ? discoverScope : currentScope;
String scopeInWhichDiscover = (discoverScope != null && !discoverScope.isEmpty()) ? discoverScope : currentScope;
logger.debug("Discovering ckan utils library into scope " + scopeInWhichDiscover);
instance = DataCatalogueFactory.getFactory().getUtilsPerScope(scopeInWhichDiscover);
}catch(Exception e){
@ -65,17 +73,29 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
@Override
public ManageProductBean getProductBeanById(String productIdentifier) throws Exception {
ManageProductBean toReturn = null;
// check into session first
HttpSession httpSession = getThreadLocalRequest().getSession();
String sessionProductKey = ScopeProvider.instance.get() + productIdentifier;
if(httpSession.getAttribute(sessionProductKey) != null)
return (ManageProductBean) httpSession.getAttribute(sessionProductKey);
if(!Utils.isIntoPortal()){
toReturn = new ManageProductBean();
toReturn.setCatalogueIdentifier(UUID.randomUUID().toString());
List<ConnectedBean> connectTo = new ArrayList<>();
connectTo.add(new ConnectedBean("91f1e413-dc9f-3b4e-b1c5-0e8560177253","Stock",
"aksldsam asd", "asdasjnk:fas", UUID.randomUUID().toString(), "http://data.d4science.org/ctlg/GRSF_Admin/91f1e413-dc9f-3b4e-b1c5-0e8560177253"));
toReturn.setConnectTo(connectTo);
connectTo.add(new ConnectedBean(
"91f1e413-dc9f-3b4e-b1c5-0e8560177253",
"Stock",
"http://data.d4science.org/ctlg/GRSF_Admin/91f1e413-dc9f-3b4e-b1c5-0e8560177253",
"89f1e413-dc9f-3b4e-b1c5-0e8560177254",
"Random title",
"http://data.d4science.org/ctlg/GRSF_Admin/89f1e413-dc9f-3b4e-b1c5-0e8560177254",
"Fishery"
));
toReturn.setCurrentConnections(connectTo);
toReturn.setGrsfDomain("Stock");
toReturn.setGrsfType("Assessment Unit");
toReturn.setKnowledgeBaseIdentifier("91f1e413-dc9f-3b4e-b1c5-0e8560177253");
@ -105,52 +125,63 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
}else{
// retrieve scope per current portlet url
String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest());
DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl);
String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
CkanDataset record = catalogue.getDataset(productIdentifier, catalogue.getApiKeyFromUsername(username));
String apiKey = catalogue.getApiKeyFromUsername(username);
CkanDataset record = catalogue.getDataset(productIdentifier, apiKey);
// it cannot be enabled in this case ...
if(record == null)
throw new Exception("Unable to retrieve information for the selected record, sorry");
else{
logger.debug("Trying to fetch record....");
logger.debug("Trying to fetch the 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 Record");
Map<String, String> extrasAsMap = record.getExtrasAsHashMap();
// get extras as hashmap and pairs
List<CkanPair> extrasAsPairs = record.getExtras();
String systemType = extrasAsMap.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 Record");
boolean isStock = record.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY).contains(Product_Type.STOCK.getOrigName());
// fetch map for namespaces
Map<String, String> fieldsNamespacesMap = Utils.getFieldToFieldNameSpaceMapping(getThreadLocalRequest().getSession(),
record.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY).contains(Product_Type.STOCK.getOrigName()) ? Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_STOCK
: Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_FISHERY);
Map<String, String> fieldsNamespacesMap =
Utils.getFieldToFieldNameSpaceMapping(httpSession, isStock ?
Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_STOCK : Constants.GENERIC_RESOURCE_NAME_MAP_KEY_NAMESPACES_FISHERY);
Map<String, List<String>> extrasWithoutNamespaces = Utils.replaceFieldsKey(extrasAsPairs, fieldsNamespacesMap);
// 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);
Status status = Status.fromString(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);
logger.debug(Constants.DOMAIN_CUSTOM_KEY + " is " + grsfDomain);
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);
if(status.equals(Status.To_be_Merged) || status.equals(Status.Rejected))
throw new Exception("Records under merging activity or rejected cannot be updated");
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.contains(Product_Type.STOCK.getOrigName()) ?
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");
String recordUrl = extrasWithoutNamespaces.get(Constants.ITEM_URL_FIELD).get(0);
String grsfName = extrasWithoutNamespaces.get(grsfDomain.contains(Product_Type.STOCK.getOrigName()) ? Constants.STOCK_NAME_CUSTOM_KEY : Constants.FISHERY_NAME_CUSTOM_KEY).get(0);
boolean traceabilityFlag = false;
try{
traceabilityFlag = extrasWithoutNamespaces.get(Constants.TRACEABILITY_FLAG_CUSTOM_KEY).get(0).equalsIgnoreCase("true");
}catch(Exception e){
logger.warn("Unable to fetch traceability flag", e);
}
// Get similar GRSF records, if any (each of which should have name, description, url and id(i.e semantic identifier))
List<String> similarGrsfRecordsAsStrings = extrasWithoutNamespaces.containsKey(Constants.SIMILAR_GRSF_RECORDS_CUSTOM_KEY) ? extrasWithoutNamespaces.get(Constants.SIMILAR_GRSF_RECORDS_CUSTOM_KEY): null;
@ -160,87 +191,87 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
for (String similarGRSFRecord : similarGrsfRecordsAsStrings) {
if(similarGRSFRecord.equals(Constants.NO_SIMILAR_GRSF_RECORDS)) // stop here if there is a single element with this information
break;
similarRecords.add(Utils.similarGRSFRecordFromJson(similarGRSFRecord));
}
}
logger.debug("SimilarGRSFRecords are " + similarRecords);
// get connected records
List<String> connectedBeansAsStrings = extrasWithoutNamespaces.containsKey(Constants.CONNECTED_CUSTOM_KEY) ? extrasWithoutNamespaces.get(Constants.CONNECTED_CUSTOM_KEY): null;
// get connected records (and the proposed ones)
List<String> connectedBeanUrls =
extrasWithoutNamespaces.containsKey(Constants.CONNECTED_CUSTOM_KEY) ? extrasWithoutNamespaces.get(Constants.CONNECTED_CUSTOM_KEY): null;
List<ConnectedBean> connectedBeans = new ArrayList<ConnectedBean>(0);
if(connectedBeansAsStrings != null){
for (String connectedBean : connectedBeansAsStrings) {
if(connectedBean.equals(Constants.NO_CONNECTED_RECORDS)) // stop here if there is a single element with this information
break;
connectedBeans.add(Utils.connectedBeanRecordFromJson(connectedBean, uuidKB, grsfDomain, catalogue));
}
}
List<ConnectedBean> connectedBeans = new ArrayList<ConnectedBean>(0);
if(connectedBeanUrls != null){
for (String connectedBean : connectedBeanUrls) {
if(connectedBean.equals(Constants.NO_CONNECTED_RECORDS)) // stop here if there is a single element with this information
break;
ConnectedBean builtBean = Utils.connectedBeanRecordFromUrl(recordUrl, connectedBean, uuidKB, grsfDomain, catalogue, apiKey);
if(builtBean != null)
connectedBeans.add(builtBean);
}
}
logger.debug("Connected records are " + connectedBeans);
logger.debug("Already connected records are " + connectedBeans);
// Get sources
List<CkanResource> resources = record.getResources();
List<SourceRecord> sources = new ArrayList<SourceRecord>(3);
for (CkanResource ckanResource : resources) {
if(Sources.getListNames().contains(ckanResource.getName()))
sources.add(new SourceRecord(ckanResource.getName(), ckanResource.getUrl()));
}
// get the connections the knowledge base suggests
List<ConnectedBean> suggestedConnectionsByKnowledgeBase = new ArrayList<ConnectedBean>(0);
List<String> exploitedResourcesUrls = isStock ?
(extrasWithoutNamespaces.containsKey(Constants.EXPLOITING_FISHERY_JSON_KEY) ?
extrasWithoutNamespaces.get(Constants.EXPLOITING_FISHERY_JSON_KEY) : null):
(extrasWithoutNamespaces.containsKey(Constants.RESOURCES_EXPLOITED_JSON_KEY) ? extrasWithoutNamespaces.get(Constants.RESOURCES_EXPLOITED_JSON_KEY) : null);
// set the values
toReturn = new ManageProductBean(semanticId, catalogueIdentifier, uuidKB, grsfType,
grsfDomain, grsfName, shortName, traceabilityFlag, Status.fromString(status), null,
null, null, sources, similarRecords, connectedBeans, false);
if(exploitedResourcesUrls != null && !exploitedResourcesUrls.isEmpty()){
for (String exploited : exploitedResourcesUrls) {
ConnectedBean builtBean = Utils.connectedBeanRecordFromUrl(recordUrl, exploited, uuidKB, grsfDomain, catalogue, apiKey);
if(builtBean != null)
suggestedConnectionsByKnowledgeBase.add(builtBean);
}
}
logger.debug("Knowledge base suggests " + suggestedConnectionsByKnowledgeBase);
// Get sources
List<CkanResource> resources = record.getResources();
List<SourceRecord> sources = new ArrayList<SourceRecord>(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, recordUrl,
null, sources, similarRecords, connectedBeans, suggestedConnectionsByKnowledgeBase);
}
}
logger.info("Returning item bean " + toReturn);
httpSession.setAttribute(sessionProductKey, toReturn);
return toReturn;
}
@Override
public boolean isAdminUser() {
try{
Boolean inSession = (Boolean)getThreadLocalRequest().getSession().getAttribute(Constants.GRSF_ADMIN_SESSION_KEY);
if(inSession != null)
return inSession;
else{
if(!Utils.isIntoPortal()){
getThreadLocalRequest().getSession().setAttribute(Constants.GRSF_ADMIN_SESSION_KEY, true);
return true;
}
PortalContext pContext = PortalContext.getConfiguration();
RoleManager roleManager = new LiferayRoleManager();
String username = pContext.getCurrentUser(getThreadLocalRequest()).getUsername();
long userId = pContext.getCurrentUser(getThreadLocalRequest()).getUserId();
long groupId = pContext.getCurrentGroupId(getThreadLocalRequest());
// List<GCubeRole> vreRoles = roleManager.listRolesByUserAndGroup(userId, groupId);
List<GCubeTeam> teamRoles = roleManager.listTeamsByUserAndGroup(userId, groupId);
boolean toSetInSession = false;
for (GCubeTeam team : teamRoles) {
if(team.getTeamName().equals(Constants.GRSF_CATALOGUE_EDITOR_ROLE) || team.getTeamName().equals(Constants.GRSF_CATALOGUE_REVIEWER_ROLE)){
logger.info("User " + username + " is allowed to modify GRSF records");
toSetInSession = true;
break;
}
if(!Utils.isIntoPortal()){
toSetInSession = true;
}else{
PortalContext pContext = PortalContext.getConfiguration();
RoleManager roleManager = new LiferayRoleManager();
String username = pContext.getCurrentUser(getThreadLocalRequest()).getUsername();
long userId = pContext.getCurrentUser(getThreadLocalRequest()).getUserId();
long groupId = pContext.getCurrentGroupId(getThreadLocalRequest());
List<GCubeTeam> teamRoles = roleManager.listTeamsByUserAndGroup(userId, groupId);
toSetInSession = isEditor(username, teamRoles) | isReviewer(username, teamRoles);
}
// 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;
}
@ -251,42 +282,132 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
}
@Override
public boolean checkSemanticIdentifierExists(String semanticIdentifier)
throws Exception {
public String notifyProductUpdate(ManageProductBean bean) throws Exception{
return getDataset(semanticIdentifier) != null;
logger.info("Creating notification for the bean " + bean + " to send to the knowledge base");
try{
String context = Utils.getScopeFromClientUrl(getThreadLocalRequest());
String token = SecurityTokenProvider.instance.get();
DataCatalogue catalogue = getCatalogue(context);
String administratorFullName = Utils.getCurrentUser(getThreadLocalRequest()).getFullname();
String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
// check if the base url of the service is in session
String keyPerContext = UtilMethods.concatenateSessionKeyScope(Constants.GRSF_UPDATER_SERVICE, context);
HttpServletRequest threadRequest = getThreadLocalRequest();
String baseUrl = (String)threadRequest.getSession().getAttribute(keyPerContext);
if(baseUrl == null || baseUrl.isEmpty()){
baseUrl = GRSFUpdaterServiceClient.discoverEndPoint(context);
threadRequest.getSession().setAttribute(keyPerContext, baseUrl);
}
// remove it from the session
String sessionProductKey = ScopeProvider.instance.get() + bean.getCatalogueIdentifier();
threadRequest.getSession().removeAttribute(sessionProductKey);
return Utils.updateRecord(baseUrl, bean, catalogue, username, administratorFullName, threadRequest,
PortalContext.getConfiguration().getCurrentGroupId(threadRequest), context, token);
}catch(Exception e){
logger.error("Unable to update the product", e);
throw e;
}
}
@Override
public boolean checkSemanticIdentifierExistsInDomain(String semanticIdentifier, String domain)
throws Exception {
public void validateRevertOperation(String encryptedUrl) throws Exception {
PortalContext pContext = PortalContext.getConfiguration();
String context = Utils.getScopeFromClientUrl(getThreadLocalRequest());
RoleManager roleManager = new LiferayRoleManager();
GCubeUser user = pContext.getCurrentUser(getThreadLocalRequest());
String username = user.getUsername();
String fullName = user.getFullname();
long userId = pContext.getCurrentUser(getThreadLocalRequest()).getUserId();
long groupId = pContext.getCurrentGroupId(getThreadLocalRequest());
List<GCubeTeam> teamRoles = roleManager.listTeamsByUserAndGroup(userId, groupId);
CkanDataset dataset = getDataset(semanticIdentifier);
boolean isEditor = isEditor(username, teamRoles);
boolean isReviewer = isReviewer(username, teamRoles);
// look for the right domain this time
List<CkanPair> extrasAsPairs = dataset.getExtras();
if(!(isEditor | isReviewer))
throw new Exception("You are not allowed to perform this operation!");
for (CkanPair ckanPair : extrasAsPairs) {
if(ckanPair.getKey().contains(Constants.DOMAIN_CUSTOM_KEY)){
return ckanPair.getValue().equalsIgnoreCase(domain);
}
// decrypt the url
RevertOperationUrl decryptedUrl = new RevertOperationUrl(encryptedUrl);
String adminInUrl = decryptedUrl.getAdmin();
String uuid = decryptedUrl.getUuid();
logger.info("User " + username + " has requested to invert an operation on record with id " + uuid + " and admin in url was " + adminInUrl);
// we need to check the timestamp (it has 24h validity)
boolean isValidTimestamp = decryptedUrl.isTimestampValid();
if(!isValidTimestamp)
throw new Exception("This operation can no longer be reverted (link expired)!");
String keyPerContext = UtilMethods.concatenateSessionKeyScope(Constants.GRSF_UPDATER_SERVICE, context);
String baseUrl = (String)getThreadLocalRequest().getSession().getAttribute(keyPerContext);
if(baseUrl == null || baseUrl.isEmpty()){
baseUrl = GRSFUpdaterServiceClient.discoverEndPoint(context);
getThreadLocalRequest().getSession().setAttribute(keyPerContext, baseUrl);
}
if(baseUrl == null || baseUrl.isEmpty())
throw new Exception("Unable to discover grsf-updater service!");
// check if it is a reviewer, than he can do what he wants (no matter the admin)
try(CloseableHttpClient httpClient = HttpClientBuilder.create().build();){
if(isReviewer){
GRSFUpdaterServiceClient.revertOperation(httpClient, baseUrl, fullName, uuid);
}else{
if(!username.equals(adminInUrl))
throw new Exception("You are not the editor allowed to perform this operation!");
else
GRSFUpdaterServiceClient.revertOperation(httpClient, baseUrl, fullName, uuid);
}
}catch(Exception e){
logger.error("Unable to update this Item ", e);
throw e;
}
}
/**
* Check if the current user is an editor
* @param username
* @param teamRoles
* @return true if he/she is an editor, false otherwise
*/
private boolean isEditor(String username, List<GCubeTeam> teamRoles){
for (GCubeTeam team : teamRoles) {
if(team.getTeamName().equals(Constants.GRSF_CATALOGUE_EDITOR_ROLE)){
logger.info("User " + username + " is allowed to modify GRSF records as editor");
return true;
}
}
return false;
}
private CkanDataset getDataset(String semanticIdentifier) throws Exception{
String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest());
DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl);
String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
CkanDataset dataset = Utils.getRecordBySemanticIdentifier(semanticIdentifier, catalogue, catalogue.getApiKeyFromUsername(username));
return dataset;
/**
* Check if the current user is a reviewer
* @param username
* @param teamRoles
* @return true if he/she is an reviewer, false otherwise
*/
private boolean isReviewer(String username, List<GCubeTeam> teamRoles){
for (GCubeTeam team : teamRoles) {
if(team.getTeamName().equals(team.getTeamName().equals(Constants.GRSF_CATALOGUE_REVIEWER_ROLE))){
logger.info("User " + username + " is allowed to modify GRSF records as reviewer");
return true;
}
}
return false;
}
@Override
public String checkIdentifierExists(String id)
throws Exception {
@ -295,8 +416,7 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
CkanDataset dataset = catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username));
if(dataset == null)
throw new Exception("This record doesn't exist");
throw new Exception("A record with id " + id + " doesn't exist");
return dataset.getExtrasAsHashMap().get(Constants.ITEM_URL_FIELD);
}
@ -308,7 +428,7 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
CkanDataset dataset = catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username));
if(dataset == null)
throw new Exception("This record doesn't exist");
throw new Exception("A record with id " + id + " doesn't exist");
List<CkanPair> extrasAsPairs = dataset.getExtras();
@ -319,33 +439,39 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
}
}
throw new Exception("This record doesn't exist in the specified domain");
throw new Exception("A record with id " + id + " doesn't exist in domain " + domain);
}
@Override
public String notifyProductUpdate(ManageProductBean bean) throws Exception{
// @Override
// public boolean checkSemanticIdentifierExists(String semanticIdentifier)
// throws Exception {
//
// return getDataset(semanticIdentifier) != null;
// }
//
// @Override
// public boolean checkSemanticIdentifierExistsInDomain(String semanticIdentifier, String domain)
// throws Exception {
// CkanDataset dataset = getDataset(semanticIdentifier);
//
// // look for the right domain this time
// List<CkanPair> extrasAsPairs = dataset.getExtras();
//
// for (CkanPair ckanPair : extrasAsPairs) {
// if(ckanPair.getKey().contains(Constants.DOMAIN_CUSTOM_KEY)){
// return ckanPair.getValue().equalsIgnoreCase(domain);
// }
// }
//
// return false;
// }
logger.info("Creating notification for the bean " + bean + " to send to the knowledge base");
try{
String context = Utils.getScopeFromClientUrl(getThreadLocalRequest());
DataCatalogue catalogue = getCatalogue(context);
String administratorFullName = Utils.getCurrentUser(getThreadLocalRequest()).getFullname();
String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
// 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 = Utils.discoverEndPoint(context);
getThreadLocalRequest().getSession().setAttribute(keyPerContext, baseUrl);
}
return Utils.updateRecord(baseUrl, bean, catalogue, username, administratorFullName, getThreadLocalRequest(),
PortalContext.getConfiguration().getCurrentGroupId(getThreadLocalRequest()));
}catch(Exception e){
logger.error("Unable to update the product.." + e.getMessage());
throw e;
}
}
// private CkanDataset getDataset(String semanticIdentifier) throws Exception{
// String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest());
// DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl);
// String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername();
// CkanDataset dataset = Utils.getRecordBySemanticIdentifier(semanticIdentifier, catalogue, catalogue.getApiKeyFromUsername(username));
// return dataset;
// }
}

View File

@ -0,0 +1,214 @@
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.util.Iterator;
import java.util.List;
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.DataCatalogue;
import org.gcube.datacatalogue.common.Constants;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ConnectedBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
import org.gcube.resources.discovery.client.queries.api.SimpleQuery;
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 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.util.EntityUtils;
/**
* Exploits the grsf-services-updater service's methods https://app.swaggerhub.com/apis/ymark/grsf-services-updater/1.1.0
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class GRSFUpdaterServiceClient {
private static final Logger logger = LoggerFactory.getLogger(GRSFUpdaterServiceClient.class);
/**
* Discover the service endpoint of the GRSF Updater service and return its url
* @param context
* @return
* @throws Exception
*/
public static String discoverEndPoint(String context) throws Exception{
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<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> 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<AccessPoint> 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);
throw e;
}finally{
if(oldContext != null && !oldContext.equals(context))
ScopeProvider.instance.set(oldContext);
}
return toReturn;
}
/**
* Send updates to the knowledge base
* @param httpClient
* @param serviceUrl
* @param bean
* @param catalogue
* @param username
* @param fullName
*/
@SuppressWarnings("unchecked")
public static void updateKB(CloseableHttpClient httpClient, String serviceUrl, ManageProductBean bean,
DataCatalogue catalogue, String username, String fullName) throws Exception{
JSONObject obj = new JSONObject();
obj.put(Constants.ADMINISTRATOR_FULLNAME, fullName);
obj.put(Constants.CATALOGUE_ID, bean.getCatalogueIdentifier());
obj.put(Constants.KB_ID, bean.getKnowledgeBaseIdentifier());
obj.put(Constants.NEW_STATUS, bean.getNewStatus().toString().toLowerCase());
obj.put(Constants.OLD_STATUS, bean.getCurrentStatus().toString().toLowerCase());
obj.put(Constants.TRACEABILITY_FLAG, bean.isTraceabilityFlag());
String annotation = bean.getAnnotation();
if(annotation != null)
obj.put(Constants.ANNOTATION, annotation.replaceAll("\"", ""));
obj.put(Constants.SHORT_NAME_OLD, bean.getShortName());
if(bean.getShortNameUpdated() == null || bean.getShortNameUpdated().isEmpty())
bean.setShortNameUpdated(bean.getShortName());
obj.put(Constants.SHORT_NAME_NEW, bean.getShortNameUpdated());
obj.put(Constants.OLD_STATUS, bean.getCurrentStatus().toString().toLowerCase());
// prepare connections
List<ConnectedBean> connections = bean.getConnections();
JSONArray connectionsJson = new JSONArray();
for(ConnectedBean c: connections){
JSONObject cc = new JSONObject();
if(c.isRemove() || (c.isConnect() && !c.isRemove())){ // do not send it if it needs to be unconnected but not removed
cc.put(Constants.SOURCE_KNOWLEDGE_BASE_ID, c.getSourceKnowledgeBaseId());
cc.put(Constants.DEST_KNOWLEDGE_BASE_ID, c.getDestKnowledgeBaseId());
cc.put(Constants.SOURCE_DOMAIN, c.getSourceDomain());
cc.put(Constants.CONNECTION_TO_REMOVE, c.isRemove());
}
connectionsJson.add(cc);
}
obj.put(Constants.CONNECTIONS, connectionsJson);
// prepare similar grsf records
List<SimilarGRSFRecord> similarRecords = bean.getSimilarGrsfRecords();
JSONArray similarRecordsJson = new JSONArray();
for(SimilarGRSFRecord s: similarRecords){
JSONObject ss = new JSONObject();
ss.put(Constants.KB_ID, s.getKnowledgeBaseId());
ss.put(Constants.MERGE, s.isSuggestedMerge());
similarRecordsJson.add(ss);
}
obj.put(Constants.SIMILAR_GRSF_RECORDS, similarRecordsJson);
logger.info("Update request looks like " + obj.toJSONString());
HttpPost request = new HttpPost(serviceUrl + Constants.SERVICE_POST_UPDATER_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(parsedJSON == null)
throw new Exception("There was a problem while performing this operation at knowledge base side");
if(response.getStatusLine().getStatusCode() == 200){
logger.info("Record updated " + bean);
}else if(!(boolean) parsedJSON.get(Constants.UPDATE_RESULT))
throw new IllegalArgumentException(
"Update failed for the following reason " + parsedJSON.get(Constants.ERROR_MESSAGE));
}
/**
* Send updates to the knowledge base
* @param httpClient
* @param serviceUrl
* @param bean
* @param catalogue
* @param username
* @param fullName
*/
@SuppressWarnings("unchecked")
public static void revertOperation(CloseableHttpClient httpClient, String serviceUrl, String fullName, String uuid) throws Exception{
JSONObject obj = new JSONObject();
obj.put(Constants.ADMINISTRATOR_FULLNAME, fullName);
obj.put(Constants.KB_ID, uuid);
logger.info("Update request looks like " + obj.toJSONString());
HttpPost request = new HttpPost(serviceUrl + Constants.SERVICE_POST_REVERT_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(parsedJSON == null)
throw new Exception("There was a problem while performing this operation at knowledge base side");
if(response.getStatusLine().getStatusCode() == 200){
logger.info("Request has been submitted");
}else if(!(boolean) parsedJSON.get(Constants.UPDATE_RESULT))
throw new IllegalArgumentException(
"Request failed for the following reason " + parsedJSON.get(Constants.ERROR_MESSAGE));
}
}

View File

@ -1,4 +1,4 @@
package org.gcube.datacatalogue.grsf_manage_widget.shared;
package org.gcube.datacatalogue.grsf_manage_widget.server.manage;
import java.net.URLDecoder;
import java.net.URLEncoder;
@ -22,11 +22,16 @@ public class RevertOperationUrl {
public static final String TIMESTAMP_QUERY_PARAM = "t";
public static final String UUID_QUERY_PARAM = "uuid";
public static final String OPERATION_REVERT_QUERY_PARAM = "operation_revert";
public static final long TTL = 1000 * 60 * 60 * 24;
/**
* For now only Merge can be reverted
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public enum Operation {
MERGE("merge"),
DISSECT("dissect");
MERGE("merge");
// DISSECT("dissect");
private String name;
private Operation(String name) {
@ -45,7 +50,6 @@ public class RevertOperationUrl {
private long timestamp;
private String uuid;
private Operation operation;
private Operation op;
/**
* @param admin
@ -55,17 +59,20 @@ public class RevertOperationUrl {
* @param op
*/
public RevertOperationUrl(String baseUrl, String admin, long timestamp, String uuid,
Operation operation, Operation op) {
Operation operation) {
super();
this.baseUrl = baseUrl;
this.admin = admin;
this.timestamp = timestamp;
this.uuid = uuid;
this.operation = operation;
this.op = op;
}
/**
* Build a crypted, encoded and shortened url
* @return
* @throws Exception
*/
public String getShortUrl() throws Exception{
String query = ADMIN_QUERY_PARAM + "=" + admin + "&" + TIMESTAMP_QUERY_PARAM + "=" + timestamp +"&" + UUID_QUERY_PARAM + "=" + uuid + "&" + OPERATION_REVERT_QUERY_PARAM + "=" + operation;
@ -131,13 +138,16 @@ public class RevertOperationUrl {
default:
break;
}
}
}catch(Exception e){
logger.error("Failed to parse url", e);
}
}
public boolean isTimestampValid() {
return TTL + this.timestamp < System.currentTimeMillis();
}
public String getBaseUrl() {
return baseUrl;
@ -188,58 +198,11 @@ public class RevertOperationUrl {
this.operation = operation;
}
public Operation getOp() {
return op;
}
public void setOp(Operation op) {
this.op = op;
}
@Override
public String toString() {
return "RevertOperationUrl [baseUrl=" + baseUrl + ", admin=" + admin
+ ", timestamp=" + timestamp + ", uuid=" + uuid
+ ", operation=" + operation + ", op=" + op + "]";
+ ", operation=" + operation + "]";
}
// public static void main(String[] args) throws Exception {
//
// ScopeProvider.instance.set("/gcube/devNext/NextNext");
// String url = "https://bluebridge.d4science.org/group/grsf_admin/data-catalogue?";
//
// // try encrypt + encode
// String query = "admin=costantino.perciante&t="+ System.currentTimeMillis() +"&uuid=" + UUID.randomUUID().toString() + "&operation_revert=merge";
// String encrypted = StringEncrypter.getEncrypter().encrypt(query);
// encrypted = URLEncoder.encode(encrypted, "UTF-8");
//
//
// String encryptedUrl = url + encrypted;
// System.out.println("Encrypted is " + encryptedUrl);
//
// UrlShortener shortener = new UrlShortener();
// String shortUrl = null;
// try{
// if(shortener!=null && shortener.isAvailable())
// shortUrl = shortener.shorten(encryptedUrl);
// }catch (Exception e) {
// e.printStackTrace();
// shortUrl = encryptedUrl;
// }
//
// System.out.println("Encrypted is " + shortUrl);
//
//
// // try decode + decrypt
// String params = encryptedUrl.split("\\?")[1];
// System.out.println("Params encrypted are " + params);
// String decoded = URLDecoder.decode(encrypted, "UTF-8");
// String decrypted = StringEncrypter.getEncrypter().decrypt(decoded);
//
// System.out.println("Decrypted is " + decrypted);
//}
}

View File

@ -0,0 +1,400 @@
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.queryFor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.resources.gcore.GCoreEndpoint;
import org.gcube.common.scope.api.ScopeProvider;
import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogue;
import org.gcube.datacatalogue.common.Constants;
import org.gcube.datacatalogue.grsf_manage_widget.server.manage.RevertOperationUrl.Operation;
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.SimpleQuery;
import org.gcube.vomanagement.usermanagement.RoleManager;
import org.gcube.vomanagement.usermanagement.UserManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayRoleManager;
import org.gcube.vomanagement.usermanagement.impl.LiferayUserManager;
import org.gcube.vomanagement.usermanagement.model.GCubeTeam;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import eu.trentorise.opendata.jackan.internal.org.apache.http.HttpEntity;
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.impl.client.LaxRedirectStrategy;
import eu.trentorise.opendata.jackan.internal.org.apache.http.util.EntityUtils;
/**
* For managing the different interactions with social channels (posts and mails)
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class SocialCommunications {
private static final Logger logger = LoggerFactory.getLogger(SocialCommunications.class);
// for discovering social networking service
private static final String resource = "jersey-servlet";
private static final String serviceName = "SocialNetworking";
private static final String serviceClass = "Portal";
// social operations
private static final String SOCIAL_SERVICE_APPLICATION_TOKEN = "/2/tokens/generate-application-token/";
private static final String SOCIAL_SERVICE_WRITE_APPLICATION_POST = "/2/posts/write-post-app/";
private static final String SOCIAL_SEND_EMAIL = "/2/messages/write-message/";
private static final String MEDIATYPE_JSON = "application/json";
// for writing a post in the GRSF admin context
private static final String APPLICATION_ID_CATALOGUE_MANAGER = "org.gcube.datacatalogue.GRSFNotifier";
// emails to be sent to editors and reviewers and post to be written into the grsf admin vre
private static final String POST_MESSAGE = "Dear members,"
+ "<br>The record 'PRODUCT_TITLE' has been just updated by USER_FULLNAME."
+ "<br>You can inspect it here: PRODUCT_URL<br>";
private static final String EMAIL_MESSAGE_REVIEWER = "Dear GRSF Reviewer,"
+ "<br>an update on the record named 'PRODUCT_TITLE' has been requested by USER_FULLNAME."
+ "<br>It is available here LINK_RECORD.";
private static final String EMAIL_MESSAGE_EDITOR = "Dear USER_FULLNAME,"
+ "<br>your request for the record 'PRODUCT_TITLE' has been accepted."
+ "<br>It is available here LINK_RECORD.";
private static final String REVERT_LINK_PIECE = "<br>The request involves a merge operation. You can reject the merge by exploiting this link LINK in the following 24 hours.";
/**
*
* @param context
* @return
*/
private static String getBaseUrlSocialService(String context){
if(context == null || context.isEmpty())
throw new IllegalArgumentException("A valid context is needed to discover the service");
String oldContext = ScopeProvider.instance.get();
ScopeProvider.instance.set(context);
String basePath = null;
try{
SimpleQuery query = queryFor(GCoreEndpoint.class);
query.addCondition(String.format("$resource/Profile/ServiceClass/text() eq '%s'",serviceClass));
query.addCondition("$resource/Profile/DeploymentData/Status/text() eq 'ready'");
query.addCondition(String.format("$resource/Profile/ServiceName/text() eq '%s'",serviceName));
query.setResult("$resource/Profile/AccessPoint/RunningInstanceInterfaces//Endpoint[@EntryName/string() eq \""+resource+"\"]/text()");
DiscoveryClient<String> client = client();
List<String> endpoints = client.submit(query);
if (endpoints == null || endpoints.isEmpty())
throw new Exception("Cannot retrieve the GCoreEndpoint serviceName: "+serviceName +", serviceClass: " +serviceClass +", in scope: "+context);
basePath = endpoints.get(0);
if(basePath==null)
throw new Exception("Endpoint:"+resource+", is null for serviceName: "+serviceName +", serviceClass: " +serviceClass +", in scope: "+context);
}catch(Exception e){
logger.error("Unable to retrieve such service endpoint information!", e);
}finally{
if(oldContext != null && !oldContext.equals(context))
ScopeProvider.instance.set(oldContext);
}
logger.info("Found base path " + basePath + " for the service");
return basePath;
}
/**
* Notify the users about the required changes.
* @param bean
* @param url
* @param username
* @param fullName
* @param hashtags
* @param enablePostNotification
*/
@SuppressWarnings("unchecked")
public static void writeProductPost(ManageProductBean bean, String username, String fullName, List<String> hashtags, boolean enablePostNotification){
// discover service endpoint for the social networking library
String currentScope = ScopeProvider.instance.get();
String tokenUser = SecurityTokenProvider.instance.get();
logger.info("Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************");
String basePath = getBaseUrlSocialService(currentScope);
if(basePath == null){
logger.error("Unable to write a post because there is no social networking service available");
}else{
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
try(CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();){
// ask token application
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
StringEntity input = new StringEntity("{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}");
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
HttpResponse response = client.execute(postRequest);
logger.debug("Url is " + basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed to retrieve application token : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}else{
Map<String, Object> mapResponseGeneratedToken = getResponseEntityAsJSON(response);
boolean successGeneratedToken = (boolean)mapResponseGeneratedToken.get("success");
if(!successGeneratedToken){
throw new RuntimeException("Failed to generate the token for the application!"
+ " Error message is " + mapResponseGeneratedToken.get("message"));
}else{
String applicationToken = (String)mapResponseGeneratedToken.get("result");
// replace
String message = POST_MESSAGE.replace("PRODUCT_TITLE", bean.getGrsfName()).replace("PRODUCT_URL", bean.getRecordUrl()).replace("USER_FULLNAME", fullName);
if(hashtags != null && !hashtags.isEmpty())
for (String hashtag : hashtags) {
String modifiedHashtag = hashtag.replaceAll(" ", "_").replace("_+", "_"); // no empty spaces allowed
if(modifiedHashtag.endsWith("_"))
modifiedHashtag = modifiedHashtag.substring(0, modifiedHashtag.length() - 1);
message += " #" + modifiedHashtag;
}
logger.info("The post that is going to be written is -> " + message);
postRequest = new HttpPost(basePath + SOCIAL_SERVICE_WRITE_APPLICATION_POST + "?gcube-token=" + applicationToken);
JSONObject object = new JSONObject();
object.put("text", message);
object.put("enable_notification", enablePostNotification);
input = new StringEntity(object.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201)
throw new RuntimeException("Failed to write application post : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}
}catch(Exception e){
logger.error("Failed to create a post", e);
}
}
}
/**
* Send an email to the administrator as well as the
* @param bean
* @param catalogue
* @param username
* @param fullName
* @param isMergeInvolved
* @param httpSession
* @throws Exceptio
*/
@SuppressWarnings("unchecked")
public static void sendEmailAdministrators(
ManageProductBean bean,
DataCatalogue catalogue,
String username,
String fullName,
long groupId,
HttpServletRequest httpServletRequest,
boolean isMergeInvolved) throws Exception {
// get the list of GRSF Reviewers to alert them as well
RoleManager roleManager = new LiferayRoleManager();
List<GCubeTeam> teamRoles = roleManager.listTeamsByGroup(groupId);
List<String> reviewers = new ArrayList<>();
UserManager um = new LiferayUserManager();
for(GCubeTeam tr: teamRoles){
if(tr.getTeamName().equals(Constants.GRSF_CATALOGUE_REVIEWER_ROLE))
reviewers.add(um.getUserById(tr.getUserId()).getUsername());
}
// if the user is a reviewer, then send the email just once
reviewers.remove(username);
logger.info("List of " + Constants.GRSF_CATALOGUE_REVIEWER_ROLE + " is " + reviewers);
// build the url that allows to revert the operation
Operation operation = Operation.MERGE;
// discover service endpoint for the social networking library
String currentScope = ScopeProvider.instance.get();
String tokenUser = SecurityTokenProvider.instance.get();
logger.info("Current scope for writeProductPost is " + currentScope + " and token is " + tokenUser.substring(0, 10) + "***************");
String basePath = getBaseUrlSocialService(currentScope);
if(basePath == null){
logger.error("Unable to write a post because there is no social networking service available");
}else{
basePath = basePath.endsWith("/") ? basePath : basePath + "/";
try(CloseableHttpClient client = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();){
// ask token application
HttpPost postRequest = new HttpPost(basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
StringEntity input = new StringEntity("{\"app_id\":\"" + APPLICATION_ID_CATALOGUE_MANAGER + "\"}");
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
HttpResponse response = client.execute(postRequest);
logger.debug("Url is " + basePath + SOCIAL_SERVICE_APPLICATION_TOKEN + "?gcube-token=" + tokenUser);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeException("Failed to retrieve application token : HTTP error code : "
+ response.getStatusLine().getStatusCode());
}else{
Map<String, Object> mapResponseGeneratedToken = getResponseEntityAsJSON(response);
boolean successGeneratedToken = (boolean)mapResponseGeneratedToken.get("success");
if(!successGeneratedToken){
throw new RuntimeException("Failed to generate the token for the application!"
+ " Error message is " + mapResponseGeneratedToken.get("message"));
}else{
String applicationToken = (String)mapResponseGeneratedToken.get("result");
String revertUrl = getEncodedUrlManage(operation, username, System.currentTimeMillis(), bean.getKnowledgeBaseIdentifier(), httpServletRequest);
String messageToEditor = (EMAIL_MESSAGE_EDITOR +
(isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getGrsfName()).replace("LINK_RECORD", bean.getRecordUrl()).replace("LINK", revertUrl);
String messageToReviewer = (EMAIL_MESSAGE_REVIEWER+
(isMergeInvolved? REVERT_LINK_PIECE : "")).replace("USER_FULLNAME", fullName).replace("PRODUCT_TITLE", bean.getGrsfName()).replace("LINK_RECORD", bean.getRecordUrl()).replace("LINK", revertUrl);
String subject = "Update request on GRSF Record";
// send email to the editor
logger.info("The message that is going to be send to the editor is\n" + messageToEditor);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
JSONObject reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToEditor);
JSONArray recipients = new JSONArray();
JSONObject recipient = new JSONObject();
recipient.put("id", username);
recipients.add(recipient);
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
Map<String, Object> mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
// send email to the reviewers
logger.info("The message that is going to be send to the reviewers is\n" + messageToReviewer);
postRequest = new HttpPost(basePath + SOCIAL_SEND_EMAIL + "?gcube-token=" + applicationToken);
reqMessage = new JSONObject();
reqMessage.put("subject", subject);
reqMessage.put("body", messageToReviewer);
recipients = new JSONArray();
for(String reviewer: reviewers){
JSONObject recip = new JSONObject();
recip.put("id", reviewer);
recipients.add(recip);
}
reqMessage.put("recipients", recipients);
input = new StringEntity(reqMessage.toJSONString());
input.setContentType(MEDIATYPE_JSON);
postRequest.setEntity(input);
response = client.execute(postRequest);
mapResponseWritePost = getResponseEntityAsJSON(response);
if (response.getStatusLine().getStatusCode() != 201){
logger.error("Failed to send message to editor : HTTP error code : "
+ response.getStatusLine().getStatusCode() + mapResponseWritePost.get("message"));
}
}
}
}catch(Exception e){
logger.error("Failed to create a post", e);
}
}
}
/**
* Create the url to be send for reverting the operation
* @param httpSession
* @return
* @throws Exception
*/
public static String getEncodedUrlManage(Operation operation, String administrator, long timestamp, String uuid, HttpServletRequest httpServletRequest) throws Exception{
String clientUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other parameters
RevertOperationUrl operationUrl = new RevertOperationUrl(clientUrl, administrator, timestamp, uuid, operation);
String shortUrl = operationUrl.getShortUrl();
return shortUrl;
}
/**
* Convert the json response to a map
* @param response
* @return
*/
@SuppressWarnings("unchecked")
private static Map<String, Object> getResponseEntityAsJSON(HttpResponse response){
Map<String, Object> toReturn = null;
HttpEntity entity = response.getEntity();
if (entity != null) {
try {
toReturn = new HashMap<String, Object>();
String jsonString = EntityUtils.toString(response.getEntity());
logger.debug("Response as string is " + jsonString);
ObjectMapper objectMapper = new ObjectMapper();
toReturn = objectMapper.readValue(jsonString, HashMap.class);
logger.debug("Map is " + toReturn);
}catch(Exception e){
logger.error("Failed to read json object", e);
}
}
return toReturn;
}
}

View File

@ -22,6 +22,7 @@ import javax.servlet.http.HttpSession;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.gcube.common.authorization.library.provider.SecurityTokenProvider;
import org.gcube.common.encryption.StringEncrypter;
import org.gcube.common.portal.PortalContext;
import org.gcube.common.resources.gcore.ServiceEndpoint;
@ -34,10 +35,9 @@ import org.gcube.datacatalogue.ckanutillibrary.server.DataCatalogueRunningCluste
import org.gcube.datacatalogue.ckanutillibrary.shared.ex.ApplicationProfileNotFoundException;
import org.gcube.datacatalogue.common.Constants;
import org.gcube.datacatalogue.common.enums.Status;
import org.gcube.datacatalogue.grsf_manage_widget.server.manage.RevertOperationUrl.Operation;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ConnectedBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean;
import org.gcube.datacatalogue.grsf_manage_widget.shared.RevertOperationUrl;
import org.gcube.datacatalogue.grsf_manage_widget.shared.RevertOperationUrl.Operation;
import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord;
import org.gcube.portlets.user.urlshortener.UrlShortener;
import org.gcube.resources.discovery.client.api.DiscoveryClient;
@ -177,7 +177,9 @@ public class Utils {
}
}
logger.debug("Map is " + namespacesMap);
httpSession.setAttribute(sessionKey, namespacesMap);
// put them into session for speeding up the operations
httpSession.setAttribute(sessionKey, namespacesMap);
return namespacesMap;
} catch (Exception e) {
logger.error("Error while trying to fetch applicationProfile profile from the infrastructure", e);
@ -221,7 +223,7 @@ public class Utils {
* @param extrasAsPairs
* @return
*/
public static Map<String, List<String>> getExtras(List<CkanPair> extrasAsPairs){
public static Map<String, List<String>> getExtrasAsHashMap(List<CkanPair> extrasAsPairs){
Map<String, List<String>> toReturn = new HashMap<String, List<String>>();
@ -242,52 +244,6 @@ public class Utils {
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<ServiceEndpoint> client = clientFor(ServiceEndpoint.class);
List<ServiceEndpoint> 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<AccessPoint> 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
@ -297,7 +253,7 @@ public class Utils {
* @return true on success, false otherwise
*/
public static String updateRecord(String serviceUrl, ManageProductBean bean, DataCatalogue catalogue, String username,
String fullName, HttpServletRequest httpServletRequest, long groupId) throws Exception{
String fullName, HttpServletRequest httpServletRequest, long groupId, String context, String token) throws Exception{
if(serviceUrl == null)
throw new IllegalArgumentException("GRSF Updater service url cannot be null");
@ -312,14 +268,21 @@ public class Utils {
updateStatusInvolvedRecords(bean, catalogue);
// send update to the knowledge base
updateKB(httpClient, serviceUrl, bean, catalogue, username, fullName);
GRSFUpdaterServiceClient.updateKB(httpClient, serviceUrl, bean, catalogue, username, fullName);
// send email to Editors and Reviewers if merges are involved or the record was rejected (but the record was the result of a merge) TODO
if(bean.isMergesInvolved() || bean.getNewStatus().equals(Status.Rejected))
sendEmailAdministrators(bean, catalogue, username, fullName, groupId, httpServletRequest);
// manage interactions through a separated thread but set there security token and context
new Thread(()->{
ScopeProvider.instance.set(context);
SecurityTokenProvider.instance.set(token);
// send email to Editors and Reviewers
SocialCommunications.sendEmailAdministrators(bean, catalogue, username, fullName, groupId, httpServletRequest, bean.isMergesInvolved());
// create a post about the operation
createSocialPost(bean, catalogue, username, fullName);
// create a post about the operation
SocialCommunications.createSocialPost(bean, catalogue, username, fullName, hashtags);
}).start();
}catch(Exception e){
logger.error("Unable to update this Item ", e);
@ -343,7 +306,7 @@ public class Utils {
for(SimilarGRSFRecord s: bean.getSimilarGrsfRecords()){
if(s.isSuggestedMerge()){
String productId = s.getKnowledgeBaseId();
Map<String, List<String>> extrasMap = getExtras(catalogue.getDataset(productId, sysApi).getExtras());
Map<String, List<String>> extrasMap = getExtrasAsHashMap(catalogue.getDataset(productId, sysApi).getExtras());
extrasMap.put(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY, Arrays.asList(Status.To_be_Merged.getOrigName()));
catalogue.patchProductCustomFields(productId, sysApi, extrasMap);
}
@ -351,174 +314,12 @@ public class Utils {
// update the current status record
String productId = bean.getKnowledgeBaseIdentifier();
Map<String, List<String>> extrasMap = getExtras(catalogue.getDataset(productId, sysApi).getExtras());
Map<String, List<String>> extrasMap = getExtrasAsHashMap(catalogue.getDataset(productId, sysApi).getExtras());
extrasMap.put(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY, Arrays.asList(Status.To_be_Merged.getOrigName()));
catalogue.patchProductCustomFields(productId, sysApi, extrasMap);
}
/**
* Create a post with proper hashtags of the action taken by who and on which record
* @param bean
* @param catalogue
* @param username
* @param fullName
*/
private static void createSocialPost(ManageProductBean bean,
DataCatalogue catalogue, String username, String fullName) {
List<String> hashtags = getHashTagsFromActions(bean);
// TODO
}
/**
* Send an email to the administrator as well as the
* @param bean
* @param catalogue
* @param username
* @param fullName
* @param httpSession
* @throws Exceptio
*/
private static void sendEmailAdministrators(ManageProductBean bean,
DataCatalogue catalogue, String username, String fullName, long groupId, HttpServletRequest httpServletRequest) throws Exception {
// get the list of GRSF Reviewers to alert as well
RoleManager roleManager = new LiferayRoleManager();
List<GCubeTeam> teamRoles = roleManager.listTeamsByGroup(groupId);
List<GCubeUser> reviewers = new ArrayList<>();
UserManager um = new LiferayUserManager();
for(GCubeTeam tr: teamRoles){
if(tr.getTeamName().equals(Constants.GRSF_CATALOGUE_REVIEWER_ROLE))
reviewers.add(um.getUserById(tr.getUserId()));
}
logger.info("List of " + Constants.GRSF_CATALOGUE_REVIEWER_ROLE + " is " + reviewers);
// build the url that allows to revert the operation TODO
Operation operation = bean.isMergesInvolved() ? Operation.MERGE : Operation.DISSECT;
getEncodedUrlManage(operation, username, System.currentTimeMillis(), bean.getKnowledgeBaseIdentifier(), httpServletRequest);
String object = "A GRSF Record has been modified";
// send the emails reviewers
String messageReviewer = "";
// send email to the editor
String messageEditor = "";
// TODO
}
/**
* Create the url to be send for reverting the operation
* @param httpSession
* @return
* @throws Exception
*/
public static String getEncodedUrlManage(Operation operation, String administrator, long timestamp, String uuid, HttpServletRequest httpServletRequest) throws Exception{
String clientUrl = getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other parameters
RevertOperationUrl operationUrl = new RevertOperationUrl(clientUrl, administrator, timestamp, uuid, operation, operation);
String shortUrl = operationUrl.getShortUrl();
logger.info("Encrypted and shortened url " + shortUrl);
return shortUrl;
}
/**
* Get the list of hashtags from the actions taken onto the record
* @param bean
* @return
*/
private static List<String> getHashTagsFromActions(ManageProductBean bean) {
// TODO Auto-generated method stub
return null;
}
/**
* Send updates to the knowledge base
* @param httpClient
* @param serviceUrl
* @param bean
* @param catalogue
* @param username
* @param fullName
*/
@SuppressWarnings("unchecked")
private static void updateKB(CloseableHttpClient httpClient, String serviceUrl, ManageProductBean bean,
DataCatalogue catalogue, String username, String fullName) throws Exception{
JSONObject obj = new JSONObject();
obj.put(Constants.ADMINISTRATOR_FULLNAME, fullName);
obj.put(Constants.CATALOGUE_ID, bean.getCatalogueIdentifier());
obj.put(Constants.KB_ID, bean.getKnowledgeBaseIdentifier());
obj.put(Constants.NEW_STATUS, bean.getNewStatus().toString().toLowerCase());
obj.put(Constants.OLD_STATUS, bean.getCurrentStatus().toString().toLowerCase());
obj.put(Constants.TRACEABILITY_FLAG, bean.isTraceabilityFlag());
String annotation = bean.getAnnotation();
if(annotation != null)
obj.put(Constants.ANNOTATION, annotation.replaceAll("\"", ""));
obj.put(Constants.SHORT_NAME_OLD, bean.getShortName());
if(bean.getShortNameUpdated() == null || bean.getShortNameUpdated().isEmpty())
bean.setShortNameUpdated(bean.getShortName());
obj.put(Constants.SHORT_NAME_NEW, bean.getShortNameUpdated());
obj.put(Constants.OLD_STATUS, bean.getCurrentStatus().toString().toLowerCase());
// prepare connections
List<ConnectedBean> connections = bean.getConnectTo();
JSONArray connectionsJson = new JSONArray();
for(ConnectedBean c: connections){
JSONObject cc = new JSONObject();
if(c.isRemove() || (c.isConnect() && !c.isRemove())){ // do not send it if it needs to be unconnected but not removed
cc.put(Constants.SOURCE_KNOWLEDGE_BASE_ID, c.getSourceKnowledgeBaseId());
cc.put(Constants.DEST_KNOWLEDGE_BASE_ID, c.getDestKnowledgeBaseId());
cc.put(Constants.SOURCE_DOMAIN, c.getSourceDomain());
cc.put(Constants.CONNECTION_TO_REMOVE, c.isRemove());
}
connectionsJson.add(cc);
}
obj.put(Constants.CONNECTIONS, connectionsJson);
// prepare similar grsf records
List<SimilarGRSFRecord> similarRecords = bean.getSimilarGrsfRecords();
JSONArray similarRecordsJson = new JSONArray();
for(SimilarGRSFRecord s: similarRecords){
JSONObject ss = new JSONObject();
ss.put(Constants.KB_ID, s.getKnowledgeBaseId());
ss.put(Constants.MERGE, s.isSuggestedMerge());
similarRecordsJson.add(ss);
}
obj.put(Constants.SIMILAR_GRSF_RECORDS, similarRecordsJson);
logger.info("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 Exception("Update failed at knowledge base side!");
}else if(!(boolean) parsedJSON.get(Constants.UPDATE_RESULT))
throw new IllegalArgumentException(
"Update failed for the following reason " + parsedJSON.get(Constants.ERROR_MESSAGE));
}
/**
* Get the scope in which ckan information needs to be discovered from the url
* @param httpServletRequest
@ -649,8 +450,9 @@ public class Utils {
* @param url
* @param clg
* @return
* @throws Exception
*/
public static CkanDataset getDatasetFromUrl(String url, DataCatalogue clg, String apiKey){
public static CkanDataset getDatasetFromUrl(String url, DataCatalogue clg, String apiKey) throws Exception{
if(url == null || url.isEmpty())
return null;
@ -667,7 +469,7 @@ public class Utils {
return clg.getDataset(uuidFound, apiKey);
}
return null;
throw new Exception("No record exists with such url " + url);
}
/**
@ -768,27 +570,31 @@ public class Utils {
* @param json
* @param sourceIdentifier
* @param sourceDomain
* @param grsfDomain
* @return
* @throws ParseException
*/
public static ConnectedBean connectedBeanRecordFromJson(String json, String sourceIdentifier, String sourceDomain,
DataCatalogue clg) throws ParseException {
public static ConnectedBean connectedBeanRecordFromUrl(
String sourceIdentifier,
String sourceDomain,
String sourceUrl,
String destUrl,
DataCatalogue clg,
String apiKey) throws ParseException {
if(json == null)
if(destUrl == null)
return null;
JSONParser parser = new JSONParser();
JSONObject object = (JSONObject)parser.parse(json);
String uuidDest = (String)object.get(Constants.CONNECTED_RECORD_KNOWLEDGE_BASE_ID_JSON_KEY);
String url = clg.getUrlFromDatasetIdOrName(uuidDest);
String connectedBeanUuid = Utils.getDatasetKnowledgeBaseIdFromUrl(destUrl);
CkanDataset destDataset = clg.getDataset(connectedBeanUuid, apiKey);
return new ConnectedBean(
sourceIdentifier,
sourceDomain,
(String)object.get(Constants.CONNECTED_RECORD_SHORT_NAME_JSON_KEY),
(String)object.get(Constants.CONNECTED_RECORD_SEMANTIC_IDENTIFIER_JSON_KEY),
uuidDest,
url
sourceUrl,
connectedBeanUuid,
destDataset.getTitle(),
destUrl,
destDataset.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY)
);
}
@ -799,10 +605,8 @@ public class Utils {
* @throws Exception
*/
public static String fetchSysAPI(String context) throws Exception{
DataCatalogueRunningCluster catalogueRunningInstance = new DataCatalogueRunningCluster(context);
return catalogueRunningInstance.getSysAdminToken();
}
}

View File

@ -12,10 +12,11 @@ public class ConnectedBean implements Serializable{
private static final long serialVersionUID = -4863776727351488790L;
private String sourceKnowledgeBaseId;
private String sourceDomain; // i.e. Stock or Fishery
private String destShortName;
private String destSemanticIdentifier;
private String destKnowledgeBaseId; // the dest indentifier of a Fishery or Stock (the link is from a Stock to a Fishery and viceversa)
private String url;
private String sourceUrl;
private String destKnowledgeBaseId; // the dest identifier of a Fishery or Stock (the link is from a Stock to a Fishery and vice versa)
private String destName;
private String destUrl;
private String destDomain; // please note that this MUST be different from sourceDomain
private boolean remove;
private boolean connect;
@ -24,25 +25,26 @@ public class ConnectedBean implements Serializable{
}
/**
*
* @param sourceKnowledgeBaseId
* @param sourceDomain
* @param destShortName
* @param destSemanticIdentifier
* @param sourceUrl
* @param destKnowledgeBaseId
* @param url
* @param destTitle
* @param destUrl
* @param remove
* @param connect
*/
public ConnectedBean(String sourceKnowledgeBaseId, String sourceDomain,
String destShortName, String destSemanticIdentifier,
String destKnowledgeBaseId, String url) {
String sourceUrl, String destKnowledgeBaseId, String destName,
String destUrl, String destDomain) {
super();
this.sourceKnowledgeBaseId = sourceKnowledgeBaseId;
this.sourceDomain = sourceDomain;
this.destShortName = destShortName;
this.destSemanticIdentifier = destSemanticIdentifier;
this.sourceUrl = sourceUrl;
this.destKnowledgeBaseId = destKnowledgeBaseId;
this.url = url;
this.destName = destName;
this.destUrl = destUrl;
this.destDomain = destDomain;
}
public boolean isConnect() {
@ -53,21 +55,6 @@ public class ConnectedBean implements Serializable{
this.connect = connect;
}
public String getDestShortName() {
return destShortName;
}
public void setDestShortName(String destShortName) {
this.destShortName = destShortName;
}
public String getDestSemanticIdentifier() {
return destSemanticIdentifier;
}
public void setDestSemanticIdentifier(String destSemanticIdentifier) {
this.destSemanticIdentifier = destSemanticIdentifier;
}
public String getSourceKnowledgeBaseId() {
return sourceKnowledgeBaseId;
}
@ -99,20 +86,45 @@ public class ConnectedBean implements Serializable{
this.remove = remove;
}
public String getUrl() {
return url;
public String getSourceUrl() {
return sourceUrl;
}
public void setUrl(String url) {
this.url = url;
public void setSourceUrl(String sourceUrl) {
this.sourceUrl = sourceUrl;
}
public String getDestName() {
return destName;
}
public void setDestName(String destName) {
this.destName = destName;
}
public String getDestUrl() {
return destUrl;
}
public void setDestUrl(String destUrl) {
this.destUrl = destUrl;
}
public String getDestDomain() {
return destDomain;
}
public void setDestDomain(String destDomain) {
this.destDomain = destDomain;
}
@Override
public String toString() {
return "ConnectedBean [sourceKnowledgeBaseId=" + sourceKnowledgeBaseId
+ ", sourceDomain=" + sourceDomain + ", destShortName="
+ destShortName + ", destSemanticIdentifier="
+ destSemanticIdentifier + ", destKnowledgeBaseId="
+ destKnowledgeBaseId + ", url=" + url + ", remove=" + remove
+ ", sourceDomain=" + sourceDomain + ", sourceUrl=" + sourceUrl
+ ", destKnowledgeBaseId=" + destKnowledgeBaseId
+ ", destName=" + destName + ", destUrl=" + destUrl
+ ", destDomain=" + destDomain + ", remove=" + remove
+ ", connect=" + connect + "]";
}

View File

@ -1,6 +1,7 @@
package org.gcube.datacatalogue.grsf_manage_widget.shared;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -14,13 +15,13 @@ public class ManageProductBean implements Serializable{
private static final long serialVersionUID = -4882608487467259326L;
private String semanticIdentifier; // Stock id or Fishery id
private String catalogueIdentifier; // catalogue 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 grsfName; // Fishery name or Stock name
private String shortName; // it is editable ...
private String shortNameUpdated;
private String shortNameUpdated; // the updated one, if any
private boolean traceabilityFlag; //from false to true etc
private Status currentStatus;
private Status newStatus;
@ -28,20 +29,34 @@ public class ManageProductBean implements Serializable{
private Map<String, String> extrasIfAvailable; // read from GRSFManageEntries resource
private List<SourceRecord> sources; // sources for this record
private List<SimilarGRSFRecord> similarGrsfRecords;
private List<ConnectedBean> connectTo;
private boolean mergesInvolved;
private List<ConnectedBean> suggestedByKnowledgeBase;
private List<ConnectedBean> suggestdByAdministrator = new ArrayList<ConnectedBean>(0);
private List<ConnectedBean> currentConnections;
private List<ConnectedBean> connections; // the one to used eventually
private boolean mergesInvolved; // important: in this case an email must be sent to the editors/reviewers
private String recordUrl; // this record url
public ManageProductBean() {
super();
}
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<String, String> extrasIfAvailable, List<SourceRecord> sources,
List<SimilarGRSFRecord> similarGrsfRecords, List<ConnectedBean> connectedBeans, boolean mergesInvolved) {
public ManageProductBean(
String semanticIdentifier,
String catalogueIdentifier,
String knowledgeBaseIdentifier,
String grsfType,
String grsfDomain,
String grsfName,
String shortName,
boolean traceabilityFlag,
Status currentStatus,
String recordUrl,
Map<String, String> extrasIfAvailable,
List<SourceRecord> sources,
List<SimilarGRSFRecord> similarGrsfRecords,
List<ConnectedBean> currentConnections,
List<ConnectedBean> suggestedByKnowledgeBase
) {
super();
this.semanticIdentifier = semanticIdentifier;
this.catalogueIdentifier = catalogueIdentifier;
@ -53,13 +68,12 @@ public class ManageProductBean implements Serializable{
this.shortNameUpdated = shortName;
this.traceabilityFlag = traceabilityFlag;
this.currentStatus = currentStatus;
this.newStatus = newStatus;
this.annotation = annotation;
this.extrasIfAvailable = extrasIfAvailable;
this.sources = sources;
this.similarGrsfRecords = similarGrsfRecords;
this.connectTo = connectedBeans;
this.mergesInvolved = mergesInvolved;
this.currentConnections = currentConnections;
this.suggestedByKnowledgeBase = suggestedByKnowledgeBase;
this.recordUrl = recordUrl;
}
public String getSemanticIdentifier() {
@ -184,12 +198,30 @@ public class ManageProductBean implements Serializable{
this.shortNameUpdated = shortNameUpdated;
}
public List<ConnectedBean> getConnectTo() {
return connectTo;
public List<ConnectedBean> getSuggestedByKnowledgeBase() {
return suggestedByKnowledgeBase;
}
public void setConnectTo(List<ConnectedBean> connectTo) {
this.connectTo = connectTo;
public void setSuggestedByKnowledgeBase(
List<ConnectedBean> suggestedByKnowledgeBase) {
this.suggestedByKnowledgeBase = suggestedByKnowledgeBase;
}
public List<ConnectedBean> getSuggestdByAdministrator() {
return suggestdByAdministrator;
}
public void setSuggestdByAdministrator(
List<ConnectedBean> suggestdByAdministrator) {
this.suggestdByAdministrator = suggestdByAdministrator;
}
public List<ConnectedBean> getCurrentConnections() {
return currentConnections;
}
public void setCurrentConnections(List<ConnectedBean> currentConnections) {
this.currentConnections = currentConnections;
}
public boolean isMergesInvolved() {
@ -200,6 +232,22 @@ public class ManageProductBean implements Serializable{
this.mergesInvolved = mergesInvolved;
}
public String getRecordUrl() {
return recordUrl;
}
public void setRecordUrl(String recordUrl) {
this.recordUrl = recordUrl;
}
public List<ConnectedBean> getConnections() {
return connections;
}
public void setConnections(List<ConnectedBean> connections) {
this.connections = connections;
}
@Override
public String toString() {
return "ManageProductBean [semanticIdentifier=" + semanticIdentifier
@ -212,7 +260,12 @@ public class ManageProductBean implements Serializable{
+ currentStatus + ", newStatus=" + newStatus + ", annotation="
+ annotation + ", extrasIfAvailable=" + extrasIfAvailable
+ ", sources=" + sources + ", similarGrsfRecords="
+ similarGrsfRecords + ", connectTo=" + connectTo
+ ", mergesInvolved=" + mergesInvolved + "]";
+ similarGrsfRecords + ", suggestedByKnowledgeBase="
+ suggestedByKnowledgeBase + ", suggestdByAdministrator="
+ suggestdByAdministrator + ", currentConnections="
+ currentConnections + ", connections=" + connections
+ ", mergesInvolved=" + mergesInvolved + ", recordUrl="
+ recordUrl + "]";
}
}