Notifications API

Last modified by Admin on 2017/11/29 20:01

bellHandle notifications
TypeJAR
CategoryAPI
Developed by

XWiki Development Team

Rating
Rate!
0 Votes
LicenseGNU Lesser General Public License 2.1
Bundled With

XWiki Enterprise

Installable with the Extension Manager

Description

Module that get the notifications to display to a user and handle the notification statuses.

Script Service

This module introduces a script service available like this:

$services.notifications

See the code with the available methods.

Tutorial: How to send notifications

Principle

In XWiki, a notification is simply an event sent by some application, stored by the Event Stream Module and then displayed in the notifications menu.

Recordable Event

In order to indicate that the event you send through the Observation Manager must be stored by the Event Stream, the event must implement the RecordableEvent interface.

Example: 

package org.xwiki.platform.blog.events;

import org.xwiki.eventstream.RecordableEvent;

/**
 * Event sent when a blog post has been published.
 *
 * @version $Id: c89002f510111a9e9162394fa35fc811d50eb482 $
 * @since 9.2RC1
 */

public class BlogPostPublishedEvent implements RecordableEvent
{
   @Override
   public boolean matches(Object otherEvent)
   {
       return otherEvent != null && otherEvent instanceof BlogPostPublishedEvent;
   }
}

Targetable Event

If you want that only some users or some groups receive the notification (by default it is everybody), your event need to implement the TargetableEvent interface. Then, you can specify a list of targets which are the ids of the users or the groups.

Recordable Event Converter

You can customize the way an event is stored by the Event Stream by implementing your own RecordableEventConverter.

The role of this component is to convert an event from the Observation Module to an event from the Event Stream Module, that the event stream can store. If you want to store custom parameters, you need to create your own converter.

By default, the DefaultRecordableEventConverter is used.

Recordable Event Descriptor

In order to be see the notification, a user must enable the notification for the event type you have created. To be listed in the user notification settings, you must provide a RecordableEventDescriptor, which is a component that give some description about your event type to the users.

Example:

package org.xwiki.platform.blog.events;

import javax.inject.Named;
import javax.inject.Singleton;

import org.xwiki.component.annotation.Component;
import org.xwiki.eventstream.RecordableEventDescriptor;

/**
 * Descriptor for the event {@link BlogPostPublishedEvent}.
 *
 * @version $Id: 6f28643529fd7f1bb4477afa7c9117f75cc2b84c $
 * @since 9.2RC1
 */

@Component
@Singleton
@Named("BlogPostPublishedEvent")
public class BlogPostPublishedEventDescriptor implements RecordableEventDescriptor
{
   @Override
   public String getEventType()
   {
       return BlogPostPublishedEvent.class.getCanonicalName();
   }

   @Override
   public String getApplicationName()
   {
       return "blog.applicationName";
   }

   @Override
   public String getDescription()
   {
       return "blog.events.blogpostpublished.description";
   }

   @Override
   public String getApplicationIcon()
   {
       return "rss";
   }
}

Notification Displayer

By default, all notifications are displayed using the notification/default.vm template.

## Default renderer for any kind of notification.
## Each application should create its own.
## The variable "$event" contains the event to display.
## See: org.xwiki.notifications.CompositeEvent
#template('notification/macros.vm')
#set ($app  = "$!event.events.get(0).application")
#set ($icon = 'bell')
#if ($app == 'xwiki')
 #set ($app = $services.localization.render('core.events.appName'))
 #set ($icon = 'file')
#end
#displayNotificationEvent($icon, $app, $event)

You can override this template for your event type by creating a template called notification/{canonical name of your event class}.vm

Example: notification/org.xwiki.platform.blog.events.BlogPostPublishedEventDescriptor.vm.

An other way to provide a custom displayer is to create a component that implement the NotificationDisplayer role.

Example:

/**
 * Implement a {@link NotificationDisplayer} for the event type
 * {@link org.xwiki.platform.blog.events.BlogPostPublishedEvent}.
 *
 * @version $Id: ebf9735007f36e701c2ed07420bc972b56da7982 $
 * @since 9.2RC1
 */

@Component
@Singleton
@Named(BlogNotificationDisplayer.EVENT_TYPE)
public class BlogNotificationDisplayer implements NotificationDisplayer
{
   /**
     * Name of the event type that this displayer handle.
     */

   public static final String EVENT_TYPE = "org.xwiki.platform.blog.events.BlogPostPublishedEvent";

   private static final List<String> EVENTS = Arrays.asList(EVENT_TYPE);

   @Override
   public Block renderNotification(Event eventNotification) throws NotificationException
   {
       // custom code here
   }

   @Override
   public List<String> getSupportedEvents()
   {
       return EVENTS;
   }
}

Example of code to send a notification

observationManager.notify(new BlogPostPublishedEvent(), "org.xwiki.platform:xwiki-platform-blog-api", document);

Example of code that send a notification when a blog post is saved

package org.xwiki.platform.blog.internal;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

import org.xwiki.bridge.event.DocumentCreatedEvent;
import org.xwiki.bridge.event.DocumentUpdatedEvent;
import org.xwiki.component.annotation.Component;
import org.xwiki.model.reference.DocumentReference;
import org.xwiki.model.reference.SpaceReference;
import org.xwiki.observation.AbstractEventListener;
import org.xwiki.observation.ObservationManager;
import org.xwiki.observation.event.Event;
import org.xwiki.platform.blog.events.BlogPostPublishedEvent;

import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.objects.BaseObject;

/**
 * Send the {@link BlogPostPublishedEvent} when a blog post is published.
 *
 * @version $Id: 6a3f33b7e415f7d967865024087d755448db2dc9 $
 * @since 9.2RC1
 */

@Component
@Singleton
@Named(BlogDocumentSavedListener.NAME)
public class BlogDocumentSavedListener extends AbstractEventListener
{
   /**
     * Name of the listener.
     */

   public static final String NAME = "Blog Document Saved Listener";

   @Inject
   private ObservationManager observationManager;

   /**
     * Construct a BlogDocumentSavedListener.
     */

   public BlogDocumentSavedListener()
   {
       super(NAME, new DocumentCreatedEvent(), new DocumentUpdatedEvent());
   }

   @Override
   public void onEvent(Event event, Object source, Object data)
   {
        XWikiDocument document = (XWikiDocument) source;

       // Send a BlogPostPublishedEvent if the blog post is published but was not before
       final DocumentReference blogPostClass = new DocumentReference("BlogPostClass", new SpaceReference("Blog",
                document.getDocumentReference().getWikiReference()));

        BaseObject blogPost         = document.getXObject(blogPostClass);
        BaseObject previousBlogPost = document.getOriginalDocument().getXObject(blogPostClass);

       if (isPublished(blogPost) && !isPublished(previousBlogPost)) {
            observationManager.notify(new BlogPostPublishedEvent(), "org.xwiki.platform:xwiki-platform-blog-api",
                    document);
       }
   }

   private boolean isPublished(BaseObject blogPost)
   {
       return blogPost != null && blogPost.getIntValue("published") == 1 && blogPost.getIntValue("hidden") == 0;
   }
}

Notification Email Renderer

By default, all notifications are displayed using the notification/email/default.html.vm and notification/email/default.plain.vm templates.

You can override these templates for your event type by creating templates called notification/email/{canonical name of your event class}.html.vm and notification/email/{canonical name of your event class}.plain.vm, respectively for emails clients that handle HTML and emails clients that do not.

An other way to provide a custom email renderer is to create a component that implement the NotificationEmailRenderer role.

@Component
@Singleton
@Named("canonical name of your event class")
public class CustomNotificationEmailRenderer implements NotificationEmailRenderer
{
 @Override
 public String renderHTML(CompositeEvent compositeEvent) throws NotificationException
 {
   return "a string containing HTML code for email clients that handle HTML";
 }

 @Override
 public String renderPlainText(CompositeEvent compositeEvent) throws NotificationException
 {
   return "a plain text string for email clients that do not handle HTML";
 }

 @Override
 public String generateEmailSubject(CompositeEvent compositeEvent) throws NotificationException
 {
   // not used yet
   return "a plain text string for the email's subject, when a notification is sent on real-time";
 }
}

Tutorial: How to create your own notification filter

This part is still unstable and not heavily tested.

On the Java-side, you can implement your own component for the role org.xwiki.notifications.NotificationFilter.

On the wiki-side, you must also create an UI Extension with the Extension Point ID "notification.profile.filter" and the name should be the name of the event you want to filter.

Create custom notification templates

Since XWiki 9.6RC1, an administrator can create custom notifications templates directly through wiki pages. This is done by using the NotificationDisplayerClass XObject.

In order to demonstrate how this system works, we will use this very XObject to define a custom template for "update" notifications.

The NotificationDisplayerClass XObject takes two properties : 

  • Event Type : The type of event that should be overridden
  • Notification Template : The notification template that should be used instead of the default one

NotificationDisplayerClassXObjectExample.png

Currently, the Event type property of the NotificationDisplayerClass can be found in the descriptors of the events for which you want to override the notification template. For example, the event type of the event DocumentUpdatedEvent is defined in the DocumentUpdatedEventDescriptor class as "update".

With the object described above, here is the result in the notification center (the two images represent how the notifications are displayed before and after defining the XObject).

Prerequisites & Installation Instructions

We recommend using the Extension Manager to install this extension (Make sure that the text "Installable with the Extension Manager" is displayed at the top right location on this page to know if this extension can be installed with the Extension Manager). Note that installing Extensions when being offline is currently not supported and you'd need to use some complex manual method.

You can also use the manual method which involves dropping the JAR file and all its dependencies into the WEB-INF/lib folder and restarting XWiki.

Dependencies

Dependencies for this extension (org.xwiki.platform:xwiki-platform-notifications-api 9.10.1):

  • org.xwiki.platform:xwiki-platform-eventstream-api 9.10.1
Tags:
Created by Vincent Massol on 2017/03/16 19:14
    

Get Connected