Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "Scout/HowTo/4.0/Client notifications"

< Scout‎ | HowTo‎ | 4.0
(client)
(Replaced content with "The Scout documentation has been moved to https://eclipsescout.github.io/.")
 
Line 1: Line 1:
{{ScoutPage|cat=HowTo 4.0}}
+
The Scout documentation has been moved to https://eclipsescout.github.io/.
 
+
This how-to describes how to implement client notifications as described on the [[Scout/Concepts/Client Notification|Client Notification Concept page]].
+
 
+
= Summary<br>  =
+
 
+
The following classes need to be changed or added to support this:  
+
 
+
'''shared'''
+
 
+
    org.eclipsescout.demo.minicrm.shared\META-INF\MANIFEST.MF
+
  org.eclipsescout.demo.minicrm.shared.CreateNotificationPermission
+
  org.eclipsescout.demo.minicrm.shared.notification.XxxxNotification (one for each event, where Xxxx is the name of the event)
+
  org.eclipsescout.demo.minicrm.shared.services.process.INotificationService
+
 
+
'''server'''
+
 
+
  org.eclipsescout.demo.minicrm.server\plugin.xml
+
  org.eclipsescout.demo.minicrm.server.services.custom.security.AccessControlService
+
  org.eclipsescout.demo.minicrm.server.NotificationService
+
 
+
'''client'''
+
 
+
    org.eclipsescout.demo.minicrm.client\plugin.xml
+
  org.eclipsescout.demo.minicrm.client.ClientSession
+
  org.eclipsescout.demo.minicrm.client.ui.desktop.Desktop
+
  org.eclipsescout.demo.minicrm.client.services.IMyNotificationConsumerService
+
  org.eclipsescout.demo.minicrm.client.services.MyNotificationConsumerService
+
 
+
The changes in detail are as follows:<br>
+
 
+
= shared  =
+
 
+
'''org.eclipsescout.demo.minicrm.shared\META-INF\MANIFEST.MF'''
+
 
+
Add the notification package to the exported packages:
+
<pre>Export-Package: org.eclipsescout.demo.minicrm.shared,
+
  org.eclipsescout.demo.shared.notification,
+
  ... remaining packages ...
+
</pre>
+
'''org.eclipsescout.demo.minicrm.shared.CreateNotificationPermission'''
+
 
+
Create this file with the content as follows:
+
<pre>public class CreateNotificationPermission extends BasicPermission {
+
  private static final long serialVersionUID = 0L;
+
 
+
  public CreateNotificationPermission() {
+
  super(CreateNotificationPermission.class.getName());
+
  }
+
}
+
</pre>
+
<br> '''org.eclipsescout.demo.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:
+
<pre>public class XxxxNotification extends AbstractClientNotification {
+
  private static final long serialVersionUID = 1L;
+
  /* optional private members */
+
+
  /* optional constructor */
+
  public XxxxNotification(/* parameters as needed */) {
+
    super();
+
    /* assigning parameters to private members as needed */
+
  }
+
 
+
  @Override
+
  public boolean coalesce(IClientNotification existingNotification) {
+
    return false;
+
  }
+
}
+
</pre>
+
<br> '''org.eclipsescout.demo.minicrm.shared.services.process.INotificationService'''
+
 
+
Create the skeleton for this interface:
+
<pre>@InputValidation(IValidationStrategy.NO_CHECK.class)
+
public interface INotificationService extends IService {
+
}
+
</pre>
+
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;
+
 
+
= <br> server  =
+
 
+
'''org.eclipsescout.demo.minicrm.server\plugin.xml'''
+
 
+
In the extension section that contains the services, add the NotificationService:
+
 
+
      &lt;service
+
          factory="org.eclipse.scout.rt.server.services.ServerServiceFactory"
+
          class="org.eclipsescout.demo.minicrm.server.services.process.NotificationService"
+
          session="org.eclipsescout.demo.minicrm.server.ServerSession"&gt;
+
    &lt;/service&gt;
+
 
+
'''org.eclipsescout.demo.minicrm.server.services.common.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:
+
<source lang="java">
+
@Override
+
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 {
+
 
+
          // get simple class names from the databse
+
          StringArrayHolder permission = new StringArrayHolder();
+
          SQL.selectInto("" +
+
              "SELECT DISTINCT P.PERMISSION_NAME " +
+
              "FROM ROLE_PERMISSION P, USER_ROLE R " +
+
              "WHERE R.USER_NR = :personNr " +
+
              "AND R.ROLE_NR = P.ROLE_NR " +
+
              "INTO :permission ",
+
              new NVPair("permission", permission));
+
 
+
          // create a map from simple class names to qualified class names
+
          HashMap<String, String> map = new HashMap<String, String>();
+
          for (BundleClassDescriptor descriptor : SERVICES.getService(IPermissionService.class).getAllPermissionClasses()) {
+
            map.put(descriptor.getSimpleClassName(), descriptor.getClassName());
+
          }
+
 
+
          // instantiate the real permissions and assign them
+
          for (String simpleClass : permission.getValue()) {
+
            try {
+
              permissions.add((Permission) Class.forName(map.get(simpleClass)).newInstance());
+
            }
+
            catch (Exception e) {
+
              logger.error("cannot find permission " + simpleClass + ": " + e.getMessage());
+
            }
+
          }
+
        }
+
        catch (ProcessingException e) {
+
          logger.error("cannot read permissions: " + e.getStackTrace());
+
        }
+
      }
+
 
+
    }
+
    return permissions;
+
  }
+
</source>
+
'''org.eclipsescout.demo.minicrm.server.services.process.NotificationService'''
+
 
+
Create the skeleton of this class:
+
<pre>public class NotificationService extends AbstractService implements INotificationService {
+
  private static IScoutLogger logger = ScoutLogManager.getLogger(NotificationService.class);
+
  private final static long TIMEOUT = 1000 * 60 * 10; // 10min
+
}
+
</pre>
+
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(/* your parameters */), new AllUserFilter(TIMEOUT));
+
}
+
 
+
= <br> client  =
+
 
+
'''org.eclipsescout.demo.minicrm.client\plugin.xml'''
+
 
+
In the extension section that contains the services and proxies, add the service for the MyNotificationConsumerService and the proxy for the MyNotificationService interface:
+
 
+
      &lt;service
+
          factory="org.eclipse.scout.rt.client.services.ClientServiceFactory"
+
          class="org.eclipsescout.demo.minicrm.client.services.MyNotificationConsumerService"
+
          session="org.eclipsescout.demo.minicrm.client.ClientSession"&gt;
+
    &lt;/service&gt;
+
    &lt;proxy
+
          factory="org.eclipse.scout.rt.client.services.ClientProxyServiceFactory"
+
          class="org.eclipsescout.demo.minicrm.shared.services.process.INotificationService"&gt;
+
    &lt;/proxy&gt;
+
 
+
'''org.eclipsescout.demo.minicrm.client.ui.desktop.Desktop'''
+
 
+
Add the following method, allowing access to the Desktop object:
+
<source lang="java">
+
  public static Desktop get() {
+
  return (Desktop) ClientSyncJob.getCurrentSession().getDesktop();
+
}
+
</source>
+
Add other getters to objects you might need in your MyNotificationConsumerService.
+
 
+
'''org.eclipsescout.demo.minicrm.client.ClientSession'''
+
 
+
Modify the execLoadSession() method to enable client notifications:
+
<source lang="java">
+
  @Override
+
public void execLoadSession() throws ProcessingException {
+
  setServiceTunnel(new HttpServiceTunnel(this, getBundle().getBundleContext().getProperty("server.url")));
+
+
  //pre-load all known code types
+
  CODES.getAllCodeTypes(org.eclipsescout.demo.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());
+
}
+
</source>
+
 
+
Modify the execStoreSession() method to end client notification:
+
<source lang="java">
+
  @Override
+
public void execStoreSession() throws ProcessingException {
+
  ClientSession.get().getServiceTunnel().setClientNotificationPollInterval(-1);
+
}
+
</source>
+
'''org.eclipsescout.demo.minicrm.client.services.IMyNotificationConsumerService'''
+
 
+
Create this empty interface:
+
<source lang="java">
+
public interface IMyNotificationConsumerService extends IService, IClientNotificationConsumerListener {
+
}
+
</source>
+
'''org.eclipsescout.demo.minicrm.client.services.MyNotificationConsumerService'''
+
 
+
Create the MyNotification consumer class. Add a block for each event you have defined in the shared project:
+
<source lang="java">
+
public class MyNotificationConsumerService extends AbstractService implements IMyConsumerService {
+
  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();
+
    }
+
  }
+
}
+
</source>
+
<br>
+
 
+
= Triggering an event  =
+
 
+
In order to trigger a client notification (either from another client or from the server), use the following line:
+
<pre>  SERVICES.getService(INotificationService.class).sendXxxx(/* optional parameters */);
+
</pre>
+

Latest revision as of 07:36, 18 March 2024

The Scout documentation has been moved to https://eclipsescout.github.io/.

Back to the top