#23561 Fixing Merging Request throws a Null Pointer exception

This commit is contained in:
Francesco Mangiacrapa 2022-06-22 16:15:08 +02:00
parent 0335ac8b9c
commit 72fd24fc61
3 changed files with 165 additions and 153 deletions

View File

@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
#### Bug fixes
- [#23549] Fixed serialization issue on the GRSFRecordAlreadyManagedStatusException
- [#23561] Fixed Merging Request throws a Null Pointer exception
## [v1.6.0] - 2022-05-25

View File

@ -587,17 +587,17 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS
@Override
public String checkIdentifierExistsInDomain(String id, String acceptedDomain) throws Exception {
if (!Utils.isIntoPortal()) {
boolean throwException = Math.random() > 0.5;
// simulate some delay...
Thread.sleep(2500);
if (throwException)
throw new Exception("The suggested record is not a GRSF record");
return "http://data.d4science.org/catalogue/grsf_admin/" + id;
}
// if (!Utils.isIntoPortal()) {
// boolean throwException = Math.random() > 0.5;
//
// // simulate some delay...
// Thread.sleep(2500);
//
// if (throwException)
// throw new Exception("The suggested record is not a GRSF record");
//
// return "http://data.d4science.org/catalogue/grsf_admin/" + id;
// }
String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest());
DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl);

View File

@ -51,6 +51,7 @@ import com.liferay.portal.service.UserLocalServiceUtil;
/**
* Utility methods for GRSF Management panel widget.
*
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
*/
public class Utils {
@ -59,7 +60,9 @@ public class Utils {
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}";
/**
* Return a map for converting a key to a namespace:key format by reading a generic resource.
* Return a map for converting a key to a namespace:key format by reading a
* generic resource.
*
* @param httpSession
* @return a map
*/
@ -71,12 +74,12 @@ public class Utils {
if (httpSession.getAttribute(sessionKey) != null)
return (Map<String, String>) httpSession.getAttribute(sessionKey);
Map<String, String> namespacesMap = new HashMap<String, String>(); // e.g. fishery_identity:Short Title -> Short Title
Map<String, String> namespacesMap = new HashMap<String, String>(); // e.g. fishery_identity:Short Title -> Short
// Title
try {
Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource " +
"where $profile/Profile/SecondaryType/string() eq '"+ "ApplicationProfile" + "' and $profile/Profile/Name/string() " +
" eq '" + resourceName + "'" +
"return $profile");
Query q = new QueryBox("for $profile in collection('/db/Profiles/GenericResource')//Resource "
+ "where $profile/Profile/SecondaryType/string() eq '" + "ApplicationProfile"
+ "' and $profile/Profile/Name/string() " + " eq '" + resourceName + "'" + "return $profile");
DiscoveryClient<String> client = client();
List<String> appProfile = client.submit(q);
@ -98,7 +101,8 @@ public class Utils {
throw new Exception("Malformed XML");
logger.debug("Size is " + sizeKeys);
for (int i = 0; i < sizeKeys; i++) {
namespacesMap.put(nodeListModifiedKeys.item(i).getTextContent(), nodeListKeys.item(i).getTextContent());
namespacesMap.put(nodeListModifiedKeys.item(i).getTextContent(),
nodeListKeys.item(i).getTextContent());
}
}
logger.debug("Map is " + namespacesMap);
@ -113,7 +117,9 @@ public class Utils {
}
/**
* Replace the extras' keys if needed, e.g. fishery_identity:Short Title -> Short Title
* Replace the extras' keys if needed, e.g. fishery_identity:Short Title ->
* Short Title
*
* @param extrasAsPairs
* @param namespaces
* @return a map with replaced key value pairs
@ -143,6 +149,7 @@ public class Utils {
/**
* Get the extras of this dataset as hashmap
*
* @param extrasAsPairs
* @return
*/
@ -169,22 +176,16 @@ public class Utils {
/**
* Send an update for this bean
*
* @param baseUrl
* @param bean
* @param username
* @param catalogue
* @return true on success, false otherwise
*/
public static void updateRecord(
String serviceUrl,
final ManageProductBean bean,
final DataCatalogue catalogue,
final String username,
final String fullName,
final HttpServletRequest httpServletRequest,
final long groupId,
final String context,
final String token) throws Exception{
public static void updateRecord(String serviceUrl, final ManageProductBean bean, final DataCatalogue catalogue,
final String username, final String fullName, final HttpServletRequest httpServletRequest,
final long groupId, final String context, final String token) throws Exception {
if (serviceUrl == null)
throw new IllegalArgumentException("GRSF Updater service url cannot be null");
@ -202,7 +203,7 @@ public class Utils {
// if there are merges, update the status of the other involved records
if (bean.isMergesInvolved())
updateStatusInvolvedRecords(bean, catalogue);
updateStatusInvolvedRecords(bean, username, catalogue);
}
@ -210,9 +211,12 @@ public class Utils {
final String baseUrlSocial = SocialCommunications.getBaseUrlSocialService(httpServletRequest);
// and the user current browser url
final String currentBrowserUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other parameters
final String currentBrowserUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore
// other
// parameters
// manage interactions through a separated thread but set there security token and context (and then reset them)
// manage interactions through a separated thread but set there security token
// and context (and then reset them)
Thread t = new Thread(new Runnable() {
@Override
@ -226,7 +230,8 @@ public class Utils {
groupId, currentBrowserUrl, bean.isMergesInvolved());
// create a post about the operation
SocialCommunications.writeProductPost(baseUrlSocial, bean, username, fullName, false, currentBrowserUrl);
SocialCommunications.writeProductPost(baseUrlSocial, bean, username, fullName, false,
currentBrowserUrl);
} catch (Exception e) {
logger.error("Something failed while alerting editors/reviewers", e);
@ -246,14 +251,16 @@ public class Utils {
/**
* Revert operation and alert admins/vre users
*
* @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it)
* @param httpClient
* @param baseUrl
* @param fullName
* @param uuid
*/
public static void revertOperation(CloseableHttpClient httpClient, String baseUrl, HttpServletRequest httpServletRequest,
final RevertableOperationInfo rInfo, final String token, final String context, final long groupId) throws Exception{
public static void revertOperation(CloseableHttpClient httpClient, String baseUrl,
HttpServletRequest httpServletRequest, final RevertableOperationInfo rInfo, final String token,
final String context, final long groupId) throws Exception {
GRSFUpdaterServiceClient.revertOperation(httpClient, baseUrl, rInfo.getFullNameCurrentAdmin(), rInfo.getUuid());
@ -261,9 +268,11 @@ public class Utils {
final String baseUrlSocial = SocialCommunications.getBaseUrlSocialService(httpServletRequest);
// and the user current browser url
final String currentBrowserUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other parameters
final String currentBrowserUrl = Utils.getCurrentClientUrl(httpServletRequest).split("\\?")[0]; // ignore other
// parameters
// manage interactions through a separated thread but set there security token and context (and then reset them)
// manage interactions through a separated thread but set there security token
// and context (and then reset them)
Thread t = new Thread(new Runnable() {
@Override
@ -292,23 +301,26 @@ public class Utils {
}
/**
* Update the status of the involved records to "to be merged"
* @param bean
* @param catalogue
* @param username
* @param fullName
* @throws Exception
* Update the status of the involved records to "to be merged".
*
* @param bean the bean
* @param username the username
* @param catalogue the catalogue
* @throws Exception the exception
*/
private static void updateStatusInvolvedRecords(ManageProductBean bean, DataCatalogue catalogue) throws Exception {
private static void updateStatusInvolvedRecords(ManageProductBean bean, String username, DataCatalogue catalogue)
throws Exception {
String context = ScopeProvider.instance.get();
String sysApi = fetchSysAPI(context);
// String context = ScopeProvider.instance.get();
// String sysApi = fetchSysAPI(context);
for (SimilarGRSFRecord s : bean.getSimilarGrsfRecords()) {
if (s.isSuggestedMerge()) {
String productId = s.getKnowledgeBaseId();
Map<String, List<String>> updateStatus = new HashMap<String, List<String>>(1);
updateStatus.put(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY, Arrays.asList(Status.To_be_Merged.getOrigName()));
catalogue.patchProductCustomFields(productId, sysApi, updateStatus, true);
updateStatus.put(Constants.STATUS_OF_THE_GRSF_RECORD_CUSTOM_KEY,
Arrays.asList(Status.To_be_Merged.getOrigName()));
// Fixing bug #23561, passing username (instead of sysAPI)
catalogue.patchProductCustomFields(productId, username, updateStatus, true);
}
}
@ -316,6 +328,7 @@ public class Utils {
/**
* Get the scope in which ckan information needs to be discovered from the url
*
* @param httpServletRequest
* @return
*/
@ -342,13 +355,15 @@ public class Utils {
}
} catch (Exception e) {
scopeToReturn = getCurrentContext(httpServletRequest, true);
logger.warn("Failed to determine the scope from the client url, returning the current one: " + scopeToReturn);
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
@ -362,6 +377,7 @@ public class Utils {
/**
* Retrieve the current scope by using the portal manager
*
* @param b
* @return a GcubeUser object
*/
@ -382,6 +398,7 @@ public class Utils {
/**
* Retrieve the current user by using the portal manager
*
* @return a GcubeUser object
*/
public static GCubeUser getCurrentUser(HttpServletRequest request) {
@ -396,7 +413,8 @@ public class Utils {
}
/**
* Exploits the fact that in GRSF the url of a record contains the name (which is unique) of the record itself.
* Exploits the fact that in GRSF the url of a record contains the name (which
* is unique) of the record itself.
*
* @param url the url
* @param clg the clg
@ -425,7 +443,9 @@ public class Utils {
}
/**
* Exploits the fact that in GRSF the url of a record contains the name (which is unique) of the record itself
* 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
@ -450,14 +470,15 @@ public class Utils {
return null;
}
/**
* Get a {@link SimilarGRSFRecord} from a json string
*
* @param json
* @return {@link SimilarGRSFRecord}
* @throws ParseException
*/
public static SimilarGRSFRecord similarGRSFRecordFromJson(String json, DataCatalogue ctl, String username, HttpSession httpSession) throws ParseException{
public static SimilarGRSFRecord similarGRSFRecordFromJson(String json, DataCatalogue ctl, String username,
HttpSession httpSession) throws ParseException {
if (json == null)
return null;
@ -468,21 +489,19 @@ public class Utils {
String uuid = getDatasetKnowledgeBaseIdFromUrl((String) object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_URL));
CkanDataset dataset = ctl.getDataset(uuid, username);
boolean isStock = dataset.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY).contains(Product_Type.STOCK.getOrigName());
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(dataset.getExtras(), fieldsNamespacesMap);
boolean isStock = dataset.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY)
.contains(Product_Type.STOCK.getOrigName());
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(dataset.getExtras(),
fieldsNamespacesMap);
return new SimilarGRSFRecord(
uuid,
(String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_DESCRIPTION),
(String)object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_NAME),
dataset.getTitle(),
return new SimilarGRSFRecord(uuid, (String) object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_DESCRIPTION),
(String) object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_NAME), dataset.getTitle(),
(String) object.get(Constants.SIMILAR_RECORDS_BEAN_FIELD_URL),
extrasWithoutNamespaces.get(Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY).get(0),
extrasWithoutNamespaces.get(Constants.DOMAIN_CUSTOM_KEY).get(0)
);
extrasWithoutNamespaces.get(Constants.DOMAIN_CUSTOM_KEY).get(0));
}
@ -511,42 +530,34 @@ public class Utils {
* @return the connected bean
* @throws ParseException the parse exception
*/
public static ConnectedBean connectedBeanRecordFromUrl(
String destUrl,
DataCatalogue clg,
String username,
HttpSession httpSession
) throws ParseException {
public static ConnectedBean connectedBeanRecordFromUrl(String destUrl, DataCatalogue clg, String username,
HttpSession httpSession) throws ParseException {
if (destUrl == null)
return null;
String connectedBeanUuid = getDatasetKnowledgeBaseIdFromUrl(destUrl);
CkanDataset destDataset = clg.getDataset(connectedBeanUuid, username);
boolean isStock = destDataset.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY).contains(Product_Type.STOCK.getOrigName());
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(destDataset.getExtras(), fieldsNamespacesMap);
boolean isStock = destDataset.getExtrasAsHashMap().get(Constants.DOMAIN_CUSTOM_KEY)
.contains(Product_Type.STOCK.getOrigName());
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(destDataset.getExtras(),
fieldsNamespacesMap);
String semanticId = extrasWithoutNamespaces.get(Constants.GRSF_SEMANTIC_IDENTIFIER_CUSTOM_KEY).get(0);
String destDomain = extrasWithoutNamespaces.get(Constants.DOMAIN_CUSTOM_KEY).get(0);
String shortName = extrasWithoutNamespaces.get(Constants.SHORT_NAME_CUSTOM_KEY).get(0);
String description = destDataset.getNotes();
return new ConnectedBean(
connectedBeanUuid,
description,
shortName,
destDataset.getTitle(),
destUrl,
semanticId,
destDomain
);
return new ConnectedBean(connectedBeanUuid, description, shortName, destDataset.getTitle(), destUrl, semanticId,
destDomain);
}
/**
* Fetch the sysadmin key from the IS for this catalogue
*
* @return
* @throws Exception
*/