Notifications Tutorial
XWiki supports notifications (a.k.a Observations) and it's possible to do some action when a document is modified, when a document's objects are modified, etc. See the full documentation in the Observation reference documentation.
This tutorial explains how to write a Groovy script in a wiki page that responds to document changes. More specifically whenever a wiki page is modified we log the event in the Main.Logger wiki page.
Writing the Event Listener
import org.xwiki.observation.*
import org.xwiki.observation.event.*
import com.xpn.xwiki.web.*
import com.xpn.xwiki.*
class LoggingEventListener implements EventListener
{
def xwiki
def context
LoggingEventListener(xwiki, context)
{
this.xwiki = xwiki
this.context = context
}
String getName()
{
// The unique name of this event listener
return "logging"
}
List<Event> getEvents()
{
// The list of events this listener listens to
return Arrays.asList(new DocumentUpdateEvent())
}
// Called by the Observation Manager when an event matches the list of events returned
// by getEvents()
void onEvent(Event event, Object source, Object data)
{
// Prevent infinite recursion since in this example we log to wiki page which
// triggers a document change... :)
if (source.fullName != "Main.Logger") {
def document = xwiki.getDocument("Main.Logger")
document.setContent("${document.getContent()}\n${source.fullName} has changed")
document.save("Logging event", true)
}
}
}
// Register against the Observation Manager
def observation = Utils.getComponent(ObservationManager.class)
observation.removeListener("logging")
def listener = new LoggingEventListener(xwiki, xcontext)
observation.addListener(listener)
{{/groovy}}
Add other events in list, to listen on other events. eg.
return Arrays.asList(new DocumentUpdateEvent(), new DocumentSaveEvent(), new DocumentDeleteEvent())
...
And here's the
.Older Notification Tutorial
This tutorial uses the old notification mechanism to listen to events (now deprecated in XWiki 2.0). You should follow it if you're using a version of XWiki Enterprise prior to 2.0.
In order to listen to events you need to write 2 pages:
- A page containing a Groovy class that registers against the XWiki Event Manager and that has the method to be called when the event happens.
- Another page that parses the Groovy page and loads it in the Groovy context.
Groovy Notification Class
Your Groovy needs to extend the com.xpn.xwiki.notify.XWikiDocChangeNotificationInterface as shown below.
import com.xpn.xwiki.api.*;
import com.xpn.xwiki.notify.*;
import com.xpn.xwiki.*;
import com.xpn.xwiki.doc.*;
public class MyGroovyClass implements XWikiDocChangeNotificationInterface
{
def xwiki;
def rule;
public MyGroovyClass()
{
this.rule = new DocChangeRule(this);
}
public void init(xwiki)
{
this.xwiki = xwiki;
xwiki.getXWiki().getNotificationManager().addGeneralRule(this.rule);
}
public void cleanup()
{
xwiki.getXWiki().getNotificationManager().removeGeneralRule(this.rule);
}
public void notify(XWikiNotificationRule rule, XWikiDocument newdoc, XWikiDocument olddoc,
int event, XWikiContext context)
{
// Do some action here.
}
}
/* *# */
In this example we've used a DocChangeRule rule. There are also other rules.
Calling the Groovy Class
$mygroovyclass.init($xwiki)
Example: IRC notification on document change
- Step 1: Groovy Class/* Groovy Class #* */
import org.jibble.pircbot.*;
import java.util.*;
import com.xpn.xwiki.api.*;
import com.xpn.xwiki.notify.*;
import com.xpn.xwiki.*;
import com.xpn.xwiki.doc.*;
public class XWikiBot extends PircBot implements XWikiDocChangeNotificationInterface
{
def xwiki;
def channel;
def rule;
public XWikiBot()
{
this.setName("xwikibot");
this.rule = new DocChangeRule(this);
}
public void init(xwiki, channel)
{
this.xwiki = xwiki;
this.channel = channel;
xwiki.getXWiki().getNotificationManager().addGeneralRule(this.rule);
}
public void cleanup()
{
xwiki.getXWiki().getNotificationManager().removeGeneralRule(this.rule);
}
public void notify(XWikiNotificationRule rule, XWikiDocument newdoc, XWikiDocument olddoc,
int event, XWikiContext context)
{
sendMessage(this.channel, newdoc.getFullName() + " was modified - " + newdoc.getExternalURL("view", context));
}
}
/* *# */ - Step 2: Add the PircBot JAR as an attachment to the MySpace.MyGroovyClass page created in step 1.
- Step 3: Calling page## Start by looking for a bot in the servlet context
#set ($sc = $context.getContext().getEngineContext().getServletContext())
## If the bot isn't in the servlet context, start the bot and put in the context
#set ($bot = $sc.getAttribute("ircbot"))
#if (!$bot)
Bot is not started, starting it...
#set($bot = $xwiki.parseGroovyFromPage("MySpace.MyGroovyClass", "MySpace.MyGroovyClass"))
#set ($channel = "#xwiki")
$bot.init($xwiki, $channel)
$bot.connect("irc.freenode.net")
$bot.joinChannel($channel)
$sc.setAttribute("ircbot", $bot)
Bot started!
## If the parameter passed is stop then stop the bot
#elseif ($request.action && $request.action == "stop")
$bot.cleanup()
$bot.disconnect()
$sc.setAttribute("ircbot", null)
Bot disconnected!
#else
Bot already started, doing nothing...
#end - Step 4: Creating a Scheduler job so that the Bot is restarted automatically if the server is restarted for example.
Create a Scheduler job, set it to run every 5 minutes for example and use the following Groovy script in the job:
// Start by looking for a bot in the servlet context
def sc = context.getEngineContext().getServletContext()
// If the bot isn't in the servlet context, start the bot and put in the context
def bot = sc.getAttribute("ircbot")
if (bot == null) {
// Bot is not started, starting it...
bot = xwiki.parseGroovyFromPage("MySpace.MyGroovyClass", "MySpace.MyGroovyClass")
def channel = "#xwiki"
bot.init(xwiki, channel)
bot.connect("irc.freenode.net")
bot.joinChannel(channel)
sc.setAttribute("ircbot", bot)
// Bot started!
}