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.9/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.INotificationService
server
org.eclipse.minicrm.server\plugin.xml org.eclipse.minicrm.server.services.custom.security.AccessControlService org.eclipse.minicrm.server.NotificationService
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.INotificationService
Create the skeleton for this interface:
@InputValidation(IValidationStrategy.NO_CHECK.class)
public interface INotificationService 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 NotificationService:
<service
factory="org.eclipse.scout.rt.server.services.ServerServiceFactory"
class="org.eclipse.minicrm.server.services.process.NotificationService"
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.NotificationService
Create the skeleton of this class:
public class NotificationService extends AbstractService implements INotificationService {
private static IScoutLogger logger = ScoutLogManager.getLogger(NotificationService.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 NotificationService 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.INotificationService">
</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(INotificationService.class).sendXxxx(/* optional parameters */);