Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Scout/HowTo/3.8/Client notifications
The Scout documentation has been moved to https://eclipsescout.github.io/.
This how-to describes how to implement client notifications as described on the Client Notification Concept page.
Summary
The following classes need to be changed or added to support this:
shared
org.eclipse.minicrm.shared\META-INF\MANIFEST.MF org.eclipse.minicrm.shared.CreateNotificationPermission org.eclipse.minicrm.shared.notification.XxxxNotification (one for each event, where Xxxx is the name of the event) org.eclipse.minicrm.shared.services.process.INotificationProcessService
server
org.eclipse.minicrm.server\plugin.xml org.eclipse.minicrm.server.services.custom.security.AccessControlService org.eclipse.minicrm.server.NotificationProcessService
client
org.eclipse.minicrm.client\plugin.xml org.eclipse.minicrm.client.ClientSession org.eclipse.minicrm.client.ui.desktop.Desktop org.eclipse.minicrm.client.services.IMyNotificationConsumerService org.eclipse.minicrm.client.services.MyNotificationConsumerService
The changes in detail are as follows:
org.eclipse.minicrm.shared\META-INF\MANIFEST.MF
Add the notification package to the exported packages:
Export-Package: org.eclipse.minicrm.shared, org.eclipse.minicrm.shared.notification, ... remaining packages ...
org.eclipse.minicrm.shared.CreateNotificationPermission
Create this file with the content as follows:
public class CreateNotificationPermission extends BasicPermission { private static final long serialVersionUID = 0L; public CreateNotificationPermission() { super(CreateNotificationPermission.class.getName()); } }
org.eclipse.minicrm.shared.notification.XxxxNotification
Create a notification class for each distinct event you want to be able to signal. Optionally, add members and a constructor if you need to pass information with the notification:
public class MessageNotification extends AbstractClientNotification { private static final long serialVersionUID = 1L; /* optional private members */ /* optional constructor */ public MessageNotification(/* parameters as needed */) { super(); /* assigning parameters to private members as needed */ } @Override public boolean coalesce(IClientNotification existingNotification) { return false; } }
org.eclipse.minicrm.shared.services.process.INotificationProcessService
Create the skeleton for this interface:
@InputValidation(IValidationStrategy.NO_CHECK.class) public interface INotificationProcessService extends IService { }
For each event that you want to notify independently, add a method (corresponding to the notifications above; add parameters if needed):
public void sendXxxx(/* optional parameters */) throws ProcessingException;
server
org.eclipse.minicrm.server\plugin.xml
In the extension section that contains the services, add the NotificationProcessService:
<service factory="org.eclipse.scout.rt.server.services.ServerServiceFactory" class="org.eclipse.minicrm.server.services.process.NotificationProcessService" session="org.eclipse.minicrm.server.ServerSession"> </service>
org.eclipse.minicrm.server.services.custom.security.AccessControlService
In the method execLoadPermissions() add the permission to create notifications and wrap the whole remainder of the class (defining user based permissions) in a check for null:
protected Permissions execLoadPermissions() { Permissions permissions = new Permissions(); permissions.add(new RemoteServiceAccessPermission("*.shared.*", "*")); permissions.add(new CreateNotificationPermission()); if (ServerSession.get().getPersonNr() != null) { // backdoor: the first user may do everything? if (ServerSession.get().getPersonNr().equals(1L)) { logger.warn("backdoor used: person nr 1 was granted all permissions"); permissions.add(new AllPermission()); } else { try { ... remaining code ... } } } return permissions; }
org.eclipse.minicrm.server.NotificationProcessService
Create the skeleton of this class:
public class NotificationProcessService extends AbstractService implements INotificationProcessService { private static IScoutLogger logger = ScoutLogManager.getLogger(NotificationProcessService.class); private final static long TIMEOUT = 1000 * 60 * 10; // 10min }
For each method that was added to the interface, add the implementation:
@Override public void sendXxxx(/* parameters as needed */) throws ProcessingException { if (!ACCESS.check(new CreateNotificationPermission())) { throw new VetoException(TEXTS.get("AuthorizationFailed")); } logger.info("queue 'Xxxx' notification on server"); IClientNotificationService service = SERVICES.getService(IClientNotificationService.class); service.putNotification(new XxxxNotification(/* parameters as needed */), new AllUserFilter(TIMEOUT)); }
client
org.eclipse.minicrm.client\plugin.xml
In the extension section that contains the services and proxies, add the service for the notification consumer service and the proxy for the NotificationProcessService interface:
<service factory="org.eclipse.scout.rt.client.services.ClientServiceFactory" class="org.eclipse.minicrm.client.services.MyNotificationConsumerService" session="org.eclipse.minicrm.client.ClientSession"> </service> <proxy factory="org.eclipse.scout.rt.client.services.ClientProxyServiceFactory" class="org.eclipse.minicrm.shared.services.process.INotificationProcessService"> </proxy>
org.eclipse.minicrm.client.ui.desktop.Desktop
Add the following method, allowing access to the Desktop object:
public static Desktop get() { return (Desktop) ClientSyncJob.getCurrentSession().getDesktop(); }
Add other getters to objects you might need in your NotificationConsumerService.
org.eclipse.minicrm.client.ClientSession
Modify the execLoadSession() method to enable client notifications:
@Override public void execLoadSession() throws ProcessingException { setServiceTunnel(new HttpServiceTunnel(this, getBundle().getBundleContext().getProperty("server.url"))); //pre-load all known code types CODES.getAllCodeTypes(org.eclipse.minicrm.shared.Activator.PLUGIN_ID); // turn client notification polling on getServiceTunnel().setClientNotificationPollInterval(2000L); IMyNotificationConsumerService notificationHandlerService = SERVICES.getService(IMyNotificationConsumerService.class); SERVICES.getService(IClientNotificationConsumerService.class).addClientNotificationConsumerListener(this, notificationHandlerService); setDesktop(new Desktop()); }
Modify the execStoreSession() method to end client notifiaction:
@Override public void execStoreSession() throws ProcessingException { ClientSession.get().getServiceTunnel().setClientNotificationPollInterval(-1); }
org.eclipse.minicrm.client.services.IMyNotificationConsumerService
Create this empty interface:
public interface IMyNotificationConsumerService extends IService, IClientNotificationConsumerListener { }
org.eclipse.minicrm.client.services.MyNotificationConsumerService
Create the notification consumer class. Add a block for each event you have defined in the shared project:
public class MyNotificationConsumerService extends AbstractService implements IMyNotificationConsumerService { private static IScoutLogger logger = ScoutLogManager.getLogger(MyNotificationConsumerService.class); @Override public void handleEvent(ClientNotificationConsumerEvent e, boolean sync) { logger.info("received client notification event for user '" + ClientSyncJob.getCurrentSession().getUserId() + "'"); final IClientNotification notification = e.getClientNotification(); final IClientSession session = ClientSyncJob.getCurrentSession(); // deal with notification in async jobs to prevent blocking of the model thread if (notification instanceof XxxxNotification) { new ClientAsyncJob("async wrapper (Xxxx)", session) { @Override protected void runVoid(IProgressMonitor monitor) throws Throwable { new ClientSyncJob("Xxxx", session) { @Override protected void runVoid(IProgressMonitor monitor1) throws Throwable { Desktop desktop = Desktop.get(); if (desktop != null) { /* do whatever is needed to react to this event */ } } }.schedule(); } }.schedule(); } else if (notification instanceof XxxxNotification) { new ClientAsyncJob("async wrapper (Xxxx)", session) { @Override protected void runVoid(IProgressMonitor monitor) throws Throwable { new ClientSyncJob("Xxxx", session) { @Override protected void runVoid(IProgressMonitor monitor1) throws Throwable { Desktop desktop = Desktop.get(); if (desktop != null) { /* do whatever is needed to react to this event */ } } }.schedule(); } }.schedule(); } } }
Triggering an event
In order to trigger a client notification (either from another client or from the server), use the following line:
SERVICES.getService(INotificationProcessService.class).sendXxxx(/* optional parameters */);