in progress on defining the configuration

This commit is contained in:
Francesco Mangiacrapa 2024-01-31 18:09:38 +01:00
parent fb5b527a13
commit 49f7b248fb
8 changed files with 605 additions and 25 deletions

View File

@ -0,0 +1,15 @@
package org.gcube.application.cms.notifications;
import java.util.List;
import org.gcube.application.cms.notifications.config.SubscribeNotificationEvent;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class NotificationEventsSubscribedConfig {
String context;
List<SubscribeNotificationEvent> listNotificationEventSubscribed;
}

View File

@ -1,44 +1,305 @@
package org.gcube.application.cms.notifications;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.bson.Document;
import org.gcube.application.cms.implementations.utils.UserUtils;
import org.gcube.application.cms.notifications.config.SubscribeNotificationEvent;
import org.gcube.application.cms.plugins.EventListenerPluginInterface;
import org.gcube.application.cms.plugins.events.EventListener;
import org.gcube.application.cms.plugins.events.EventManager;
import org.gcube.application.cms.plugins.events.EventManager.Event;
import org.gcube.application.cms.plugins.events.ItemObserved;
import org.gcube.application.cms.plugins.faults.InitializationException;
import org.gcube.application.cms.plugins.faults.MaterializationException;
import org.gcube.application.cms.plugins.faults.ShutDownException;
import org.gcube.application.cms.plugins.implementations.AbstractPlugin;
import org.gcube.application.cms.plugins.reports.InitializationReport;
import org.gcube.application.cms.plugins.reports.Report;
import org.gcube.application.cms.plugins.reports.Report.Status;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.geoportal.common.model.document.Project;
import org.gcube.application.geoportal.common.model.plugins.PluginDescriptor;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
import com.vdurmont.semver4j.Semver;
public class NotificationsPlugin extends AbstractPlugin {
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
public static final PluginDescriptor DESCRIPTOR = new PluginDescriptor(NotificationsPlugin.class.getName(),
"Notification");
/**
* The Class NotificationsPlugin.
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Jan 30, 2024
*/
@Slf4j
public class NotificationsPlugin extends AbstractPlugin implements EventListenerPluginInterface {
public static final String SUBSCRIBE_NOTIFICATIONS_CONFIG = "subscribeNotifications";
public static final String PLUGIN_ID = "Notifications-Plugin";
public static final String PLUGIN_TYPE = "EventListener";
public static final PluginDescriptor DESCRIPTOR = new PluginDescriptor(PLUGIN_ID, PLUGIN_TYPE);
static {
DESCRIPTOR.setVersion(new Semver("1.0.0"));
DESCRIPTOR.setDescription("Manage the notification from Geoportal engine");
}
/**
* Inits the.
*
* @return the initialization report
* @throws InitializationException the initialization exception
*/
@Override
public InitializationReport init() throws InitializationException {
log.debug("Called init");
InitializationReport report = null;
try {
// Creating all listeners
EventListener<ItemObserved<Project>> listenerCreated = new EventListener<ItemObserved<Project>>() {
@Override
public void updated(ItemObserved<Project> observerd) {
log.info("listenerCreated fired on item: {} " + observerd);
boolean subscribed = checkIfSubscribedEvent(observerd);
if (subscribed) {
doAction(observerd);
}
}
};
EventListener<ItemObserved<Project>> listenerUpdated = new EventListener<ItemObserved<Project>>() {
@Override
public void updated(ItemObserved<Project> observerd) {
log.info("listenerUpdated fired on item: {} " + observerd);
boolean subscribed = checkIfSubscribedEvent(observerd);
if (subscribed) {
doAction(observerd);
}
}
};
EventListener<ItemObserved<Project>> listenerDeleted = new EventListener<ItemObserved<Project>>() {
@Override
public void updated(ItemObserved<Project> observerd) {
log.info("listenerDeleted fired on item: {} " + observerd);
boolean subscribed = checkIfSubscribedEvent(observerd);
if (subscribed) {
doAction(observerd);
}
}
};
EventListener<ItemObserved<Project>> listenerLCStepPerformed = new EventListener<ItemObserved<Project>>() {
@Override
public void updated(ItemObserved<Project> observerd) {
log.info("listenerLCStepPerformed fired on item: {} " + observerd);
boolean subscribed = checkIfSubscribedEvent(observerd);
if (subscribed) {
doAction(observerd);
}
}
};
// Subscribing all events
EventManager eventMngInst = EventManager.getInstance();
eventMngInst.subscribe(Event.PROJECT_CREATED, listenerCreated);
eventMngInst.subscribe(Event.PROJECT_UPDATED, listenerUpdated);
eventMngInst.subscribe(Event.PROJECT_DELETED, listenerDeleted);
eventMngInst.subscribe(Event.LIFECYCLE_STEP_PERFORMED, listenerLCStepPerformed);
report = new InitializationReport(Status.OK, PLUGIN_ID + " init performed");
} catch (Exception e) {
InitializationException exc = new InitializationException("Unable to initialize " + DESCRIPTOR.getId(), e);
log.error("init error: {} ", exc);
throw exc;
}
return report;
}
/**
* Gets the descriptor.
*
* @return the descriptor
*/
@Override
public PluginDescriptor getDescriptor() {
/*
* Should basically perform something like curl --location --request POST
* 'https://api.dev.d4science.org/social-networking-library-ws/rest/2/
* notifications/catalogue' \ --header 'Content-Type: application/json' \
* --header 'Authorization: Bearer
* eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJSSklZNEpoNF9qdDdvNmREY0NlUDFfS1l0akcxVExXVW9oMkQ2Tzk1bFNBIn0
* .
* eyJleHAiOjE2NTEyMzY2MzgsImlhdCI6MTY1MTIzNjMzOCwiYXV0aF90aW1lIjoxNjUxMjM2MzM0LCJqdGkiOiI5OGE5NjliMy04N2EzLTRiZWYtOWQ1Yi0yYTUwMmM5YWNmZTEiLCJpc3MiOiJodHRwczovL2FjY291bnRzLmRldi5kNHNjaWVuY2Uub3JnL2F1dGgvcmVhbG1zL2Q0c2NpZW5jZSIsImF1ZCI6IiUyRmdjdWJlJTJGZGV2c2VjJTJGZGV2VlJFIiwic3ViIjoiNmE4MmY1ODctYzgwZS00OWUzLTg4YzYtYzExN2U5ZDhkM2Y3IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoibmV4dC5kNHNjaWVuY2Uub3JnIiwic2Vzc2lvbl9zdGF0ZSI6IjA2NzQ2ZDNkLTExNjYtNGVjMC1hZWZmLTBiY2Q2YTEzMTI0MiIsImFjciI6IjEiLCJhbGxvd2VkLW9yaWdpbnMiOlsiLyoiXSwicmVzb3VyY2VfYWNjZXNzIjp7ImNvbmR1Y3Rvci1zZXJ2ZXIiOnsicm9sZXMiOlsiY29uZHVjdG9yLW1hbmFnZXIiXX0sIiUyRmdjdWJlJTJGZGV2c2VjJTJGZGV2VlJFIjp7InJvbGVzIjpbIkRhdGEtTWFuYWdlciIsIlZSRS1NYW5hZ2VyIiwiTWVtYmVyIl19fSwiYXV0aG9yaXphdGlvbiI6eyJwZXJtaXNzaW9ucyI6W3sicnNpZCI6IjU3Mjg1NTEwLTM5MzktNGRlNy04ZmMxLWUzYTlkM2NjZTI4MSIsInJzbmFtZSI6IkRlZmF1bHQgUmVzb3VyY2UifV19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6Ik1hc3NpbWlsaWFuIEFzc2FudGUiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJtYXNzaW1pbGlhbm8uYXNzYW50ZSIsImdpdmVuX25hbWUiOiJNYXNzaW1pbGlhbiIsImxvY2FsZSI6ImVuIiwiZmFtaWx5X25hbWUiOiJBc3NhbnRlIiwiZW1haWwiOiJtYXNzaW1pbGlhbm8uYXNzYW50ZUBpc3RpLmNuci5pdCJ9
* .
* b7TBRgsW0__3kl2H_ljcL7fSI9I1QaIqQq0Y7S90bWHtkRvmPkPyzWuGq9hhyN1kRg52Ue_3tEEDEkGgtceBEoZ0RAbpppkum7AJvjX6tKHF79k7wpnbxl7ED65VZFk0EazfC2w_n0WvPHQsb67zdwFeZk97G0pbjsVxYUBrhmnEMtXNzmAWaC0cc_
* -
* DriE5BBn3DjuWnaxXDxp3DB74YZoJmYR9HYN94c7Y0IV1XZxGFXLZ8V7UTfcJrGqulhF7HU79jd8hccZniam3NEfTZV
* -knJ4uEnupRHfMLBhnn1MGzxYFPN1xPIPgwiLSvRef7lK2sjI_bi6GAcT0sg5zwA' \
* --data-raw ' { "idsToNotify" : ["leonardo.candela", "luca.frosini"], "itemId"
* : "Conversational search dataset with labels", "notifyText" :
* "published the test item '\''Conversational search dataset with labels'\''",
* "itemURL" :
* "https://data.d4science.org/ctlg/ResourceCatalogue/conversational_dataset_with_labels",
* "idsAsGroup" : false, "type" : "ITEM_PUBLISHED" }
*/
return DESCRIPTOR;
}
/**
* Inits the in context.
*
* @return the initialization report
* @throws InitializationException the initialization exception
*/
@Override
@Synchronized
public InitializationReport initInContext() throws InitializationException {
InitializationReport report = new InitializationReport();
try {
String context = UserUtils.getCurrent().getContext();
if (getNotificationBindingMapPerContext() == null) {
log.info("Initializing in " + context);
notificationEventsBindingMap.put(context, new NotificationEventsSubscribedConfig());
}
report.setStatus(Report.Status.OK);
report.putMessage("Initialized " + DESCRIPTOR.getId() + " in the " + context);
} catch (Exception e) {
InitializationException exc = new InitializationException("Unable to initialize " + DESCRIPTOR.getId(), e);
log.error("initInContext error: {} ", exc);
throw exc;
}
return report;
}
/**
* Check if subscribed event.
*
* @param observerd the observerd
* @return true, if successful
*/
public boolean checkIfSubscribedEvent(ItemObserved<Project> observerd) {
log.info("Checking if {} is an subscribed event", observerd.getEvent());
try {
NotificationEventsSubscribedConfig eventsSub = readNotificationsSubscribedFromConfigurationInTheUCD(
observerd.getUseCaseDescriptor());
List<SubscribeNotificationEvent> listEvents = eventsSub.getListNotificationEventSubscribed();
log.info("List events is {}", listEvents);
if (listEvents.contains(observerd.getEvent())) {
log.info("the event {} is subscribed from config ", observerd.getEvent());
return true;
}
log.info("the event {} is not subscribed from config ", observerd.getEvent());
return false;
} catch (Exception e) {
log.error("Exception, Error on checking subscribed events", e);
return false;
}
}
protected Map<String, NotificationEventsSubscribedConfig> notificationEventsBindingMap = null;
/**
* Gets the notification binding map per context.
*
* @return the notification binding map per context
*/
protected NotificationEventsSubscribedConfig getNotificationBindingMapPerContext() {
String context = UserUtils.getCurrent().getContext();
log.debug("Getting {} from cache map for context {}", NotificationsPlugin.PLUGIN_ID, context);
if (notificationEventsBindingMap == null)
notificationEventsBindingMap = new LinkedHashMap<String, NotificationEventsSubscribedConfig>();
return notificationEventsBindingMap.get(context);
}
/**
* Read notifications subscribed from configuration in the UCD.
*
* @param useCaseDescriptor the use case descriptor
* @return the notification events subscribed config
* @throws Exception the exception
*/
public NotificationEventsSubscribedConfig readNotificationsSubscribedFromConfigurationInTheUCD(
UseCaseDescriptor useCaseDescriptor) throws Exception {
log.debug("Reading subscribed events from UCD");
NotificationEventsSubscribedConfig eventsSubscrInTheUCD = new NotificationEventsSubscribedConfig();
if (useCaseDescriptor == null)
throw new Exception("Error reading UCD null found");
try {
String context = UserUtils.getCurrent().getContext();
eventsSubscrInTheUCD = getNotificationBindingMapPerContext();
List<SubscribeNotificationEvent> listNotificationEventsSubscribedPerUCD = new ArrayList<SubscribeNotificationEvent>();
if (eventsSubscrInTheUCD == null || listNotificationEventsSubscribedPerUCD.isEmpty()) {
Document profileConfiguration = getConfigurationFromProfile(useCaseDescriptor).getConfiguration();
log.debug("UseCaseDescriptor Configuration is {} ", profileConfiguration);
// JSONPathWrapper schemaNavigator = new
// JSONPathWrapper(useCaseDescriptor.getSchema().toJson());
for (Object fsConfigObj : profileConfiguration.get(SUBSCRIBE_NOTIFICATIONS_CONFIG, List.class)) {
log.debug("Managing {} ", fsConfigObj);
SubscribeNotificationEvent fsConfig = Serialization.read(fsConfigObj.toString(),
SubscribeNotificationEvent.class);
log.debug("Converted config {}", fsConfig);
String theEventSubsribed = fsConfig.getEvent();
if (theEventSubsribed == null || theEventSubsribed.isEmpty())
throw new MaterializationException(
"Invalid Field Definition path in configuration [NO MATCH] : " + fsConfig.getEvent());
SubscribeNotificationEvent event = Serialization.convert(theEventSubsribed,
SubscribeNotificationEvent.class);
log.debug("Added event {} to list ", event);
listNotificationEventsSubscribedPerUCD.add(event);
}
eventsSubscrInTheUCD = new NotificationEventsSubscribedConfig();
eventsSubscrInTheUCD.setContext(context);
eventsSubscrInTheUCD.setListNotificationEventSubscribed(listNotificationEventsSubscribedPerUCD);
notificationEventsBindingMap.put(context, eventsSubscrInTheUCD);
log.info("Events subscribed read from config {} ", eventsSubscrInTheUCD);
}
} catch (Exception e) {
log.error("Unable to read configuration for "+NotificationsPlugin.PLUGIN_ID, e);
} catch (Throwable t) {
log.error("Exception, Unable to read configuration ", t);
}
return eventsSubscrInTheUCD;
}
/**
* Shutdown.
*
* @throws ShutDownException the shut down exception
*/
@Override
public void shutdown() throws ShutDownException {
// TODO Auto-generated method stub
}
/**
* Do action.
*
* @param itemObserved the item observed
*/
@Override
public void doAction(ItemObserved<Project> itemObserved) {
// TODO Auto-generated method stub
}
}

View File

@ -0,0 +1,18 @@
package org.gcube.application.cms.notifications.config;
import java.util.List;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import org.gcube.com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class NotificationFor {
List<String> roles;
@JsonProperty("when")
List<NotificationWhen> when;
}

View File

@ -0,0 +1,19 @@
package org.gcube.application.cms.notifications.config;
import java.util.List;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
/**
* Instantiates a new notification when.
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class NotificationWhen {
List<String> target_phase;
Notify notify;
}

View File

@ -0,0 +1,29 @@
package org.gcube.application.cms.notifications.config;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
/**
* Instantiates a new notify.
*
*
{
"send_personal_nofitication": false,
"send_email": true,
"send_pdf_document": false,
"post_on_vre": false,
"message": "ID_MESSAGE_1"
}
*
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Notify {
Boolean send_personal_nofitication;
Boolean send_email;
Boolean send_pdf_document;
Boolean post_on_vre;
String message;
}

View File

@ -0,0 +1,64 @@
package org.gcube.application.cms.notifications.config;
import java.util.List;
import org.gcube.com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
/**
*
* @author Francesco Mangiacrapa at ISTI-CNR francesco.mangiacrapa@isti.cnr.it
*
* Jan 30, 2024
*/
/**
* Instantiates a new subscribe notification config.
*
* {
* "event": "EVENT_NAME",
* "for": [
* {
* "roles": [
* "USER_ROLE"
* ],
* "when": [
* {
* "target_phase": [
* "TARGET_PHASE"
* ],
* "notify": {
* "send_personal_nofitication": "true/false",
* "send_email": "true/false",
* "send_pdf_document": "true/false",
* "post_on_vre": "true/false",
* "message": "ID_MESSAGE_1"
* }
* },
* {
* "target_phase": [
* "TARGET_PHASE"
* ],
* "notify": {
* "send_personal_nofitication": "true/false",
* "send_email": "true/false",
* "send_pdf_document": "true/false",
* "post_on_vre": "true/false",
* "message": "ID_MESSAGE_2"
* }
* }
* ]
* }
* ]
* }
*
*/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class SubscribeNotificationEvent {
String event;
List<NotificationFor> notificationFor;
}

View File

@ -0,0 +1 @@
/resources/

View File

@ -0,0 +1,173 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.gcube.application.cms.notifications.NotificationEventsSubscribedConfig;
import org.gcube.application.cms.notifications.NotificationsPlugin;
import org.gcube.application.cms.notifications.config.NotificationFor;
import org.gcube.application.cms.notifications.config.NotificationWhen;
import org.gcube.application.cms.notifications.config.Notify;
import org.gcube.application.cms.notifications.config.SubscribeNotificationEvent;
import org.gcube.application.cms.plugins.faults.InitializationException;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.cms.tests.TestProfiles;
import org.gcube.application.cms.tests.plugins.BasicPluginTest;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
import org.gcube.application.geoportal.common.utils.tests.GCubeTest;
import org.junit.Test;
import com.fasterxml.jackson.core.JsonProcessingException;
public class CatalogueBindingPluginTest extends BasicPluginTest {
// @Test
public void checkPlugin() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
NotificationsPlugin plugin = (NotificationsPlugin) plugins.get(NotificationsPlugin.DESCRIPTOR.getId());
try {
plugin.init();
} catch (InitializationException e1) {
e1.printStackTrace();
}
try {
plugin.initInContext();
} catch (InitializationException e1) {
e1.printStackTrace();
}
System.out.println("Plugin check: " + plugin);
}
//@Test
public void checkPluginConfig() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
NotificationsPlugin plugin = (NotificationsPlugin) plugins.get(NotificationsPlugin.DESCRIPTOR.getId());
UseCaseDescriptor descriptor = TestProfiles.profiles.get("profiledConcessioni");
try {
plugin.init();
} catch (InitializationException e1) {
e1.printStackTrace();
}
try {
plugin.initInContext();
} catch (InitializationException e1) {
e1.printStackTrace();
}
NotificationEventsSubscribedConfig notificationEventsSubs;
try {
notificationEventsSubs = plugin.readNotificationsSubscribedFromConfigurationInTheUCD(descriptor);
System.out
.println(NotificationEventsSubscribedConfig.class.getSimpleName() + ": " + notificationEventsSubs);
} catch (Exception e) {
e.printStackTrace();
}
}
//@Test
public void checkDeserialize() {
org.junit.Assume.assumeTrue(GCubeTest.isTestInfrastructureEnabled());
SubscribeNotificationEvent sne = new SubscribeNotificationEvent();
sne.setEvent("LIFECYCLE_STEP_PERFORMED");
List<NotificationFor> listNotificationFor = new ArrayList<NotificationFor>();
NotificationFor notificatioFor = new NotificationFor();
notificatioFor.setRoles(Arrays.asList("Data-Manager"));
List<NotificationWhen> listWhen = new ArrayList<NotificationWhen>();
NotificationWhen notificationWhen = new NotificationWhen();
notificationWhen.setTarget_phase(Arrays.asList("Pending Approval"));
Notify notify = new Notify();
notify.setSend_personal_nofitication(false);
notify.setPost_on_vre(false);
notify.setSend_email(false);
notify.setSend_personal_nofitication(false);
notify.setMessage("message");
notificationWhen.setNotify(notify);
listWhen.add(notificationWhen);
notificatioFor.setWhen(listWhen);
listNotificationFor.add(notificatioFor);
sne.setNotificationFor(listNotificationFor);
try {
String serializeTOJSON = Serialization.write(sne);
System.out.println("Serialized toJSON :"+serializeTOJSON);
SubscribeNotificationEvent deserializeToJSON = Serialization.read(serializeTOJSON, SubscribeNotificationEvent.class);
System.out.println("Deserialized from JSON :"+deserializeToJSON);
//Test Notify
/*
String testNotify = " {\n"
+ " \"send_personal_nofitication\": false,\n"
+ " \"send_email\": true,\n"
+ " \"send_pdf_document\": false,\n"
+ " \"post_on_vre\": false,\n"
+ " \"message\": \"ID_MESSAGE_1\"\n"
+ " }";
System.out.println("String :"+testNotify);
Notify serialize = Serialization.read(testNotify, Notify.class);
System.out.println("Ser from JSON :"+serialize);
*/
//Test NotificationFor
/*
String testNotificationFor = "{ \"when\": [\n"
+ " {\n"
+ " \"target_phase\": [\n"
+ " \"Rejected\"\n"
+ " ],\n"
+ " \"notify\": {\n"
+ " \"send_personal_nofitication\": false,\n"
+ " \"send_email\": true,\n"
+ " \"send_pdf_document\": false,\n"
+ " \"post_on_vre\": false,\n"
+ " \"message\": \"The project ${project_name} has just been rejected. You are kindly requested to review it\"\n"
+ " }\n"
+ " },\n"
+ " {\n"
+ " \"target_phase\": [\n"
+ " \"Published\"\n"
+ " ],\n"
+ " \"notify\": {\n"
+ " \"send_personal_nofitication\": false,\n"
+ " \"send_email\": true,\n"
+ " \"send_pdf_document\": true,\n"
+ " \"post_on_vre\": true,\n"
+ " \"message\": \"The project ${project_name} has just been published. See it at @link\"\n"
+ " }\n"
+ " }\n"
+ " ]}";
System.out.println("String :"+testNotificationFor);
NotificationFor serializeNotificationWhen = Serialization.read(testNotificationFor, NotificationFor.class);
System.out.println("Ser from JSON :"+serializeNotificationWhen);
*/
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}