Scout/HowTo/3.8/Client notifications

From Eclipsepedia

< Scout‎ | HowTo‎ | 3.8
Revision as of 10:30, 6 March 2013 by Urs.beeli.sbb.ch (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search


Scout
Wiki Home
Website
DownloadGit
Community
ForumsBlogTwitter
Bugzilla
Bugzilla


This how-to describes how to implement client notifications as described on the Client Notification Concept page.

Contents

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:

shared

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 */);