Wiki source code of Notifications Tutorial

Version 7.7 by LSu on 2013/11/27

Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}{{toc/}}{{/box}}
2
3 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>>extensions:Extension.Observation Module]].
4
5 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.
6
7 {{warning}}This tutorial is slightly deprecated and needs a bit of clean up to comply with the current XWiki best practices.{{/warning}}
8
9 = Writing the Event Listener =
10
11 {{code language="java"}}
12 {{groovy}}
13 import org.xwiki.observation.*
14 import org.xwiki.observation.event.*
15 import com.xpn.xwiki.web.*
16 import com.xpn.xwiki.*
17
18 class LoggingEventListener implements EventListener
19 {
20 def xwiki
21 def context
22
23 LoggingEventListener(xwiki, context)
24 {
25 this.xwiki = xwiki
26 this.context = context
27 }
28
29 String getName()
30 {
31 // The unique name of this event listener
32 return "logging"
33 }
34
35 List<Event> getEvents()
36 {
37 // The list of events this listener listens to
38 return Arrays.asList(new DocumentUpdateEvent())
39 }
40
41 // Called by the Observation Manager when an event matches the list of events returned
42 // by getEvents()
43 void onEvent(Event event, Object source, Object data)
44 {
45 // Prevent infinite recursion since in this example we log to wiki page which
46 // triggers a document change... :)
47 if (source.fullName != "Main.Logger") {
48 def document = xwiki.getDocument("Main.Logger")
49 document.setContent("${document.getContent()}\n${source.fullName} has changed")
50 document.save("Logging event", true)
51 }
52 }
53 }
54
55 // Register against the Observation Manager
56 def observation = Utils.getComponent(ObservationManager.class)
57 observation.removeListener("logging")
58 def listener = new LoggingEventListener(xwiki, xcontext)
59 observation.addListener(listener)
60
61 {{/groovy}}
62 {{/code}}
63
64 Add other events in list, to listen on other events. eg.
65
66 {{code}}
67 ...
68 return Arrays.asList(new DocumentUpdateEvent(), new DocumentSaveEvent(), new DocumentDeleteEvent())
69 ...
70 {{/code}}
71
72 And here's the [[full code with nice pretty-printing and a register button>>attach:groovynotifier.txt]].
73
74 = Older Notification Tutorial =
75
76 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.
77
78 In order to listen to events you need to write 2 pages:
79
80 * 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.
81 * Another page that parses the Groovy page and loads it in the Groovy context.
82
83 == Groovy Notification Class ==
84
85 Your Groovy needs to extend the ##com.xpn.xwiki.notify.XWikiDocChangeNotificationInterface## as shown below.
86
87 {{code language="java"}}
88 /* Groovy Class #* */
89
90 import com.xpn.xwiki.api.*;
91 import com.xpn.xwiki.notify.*;
92 import com.xpn.xwiki.*;
93 import com.xpn.xwiki.doc.*;
94
95 public class MyGroovyClass implements XWikiDocChangeNotificationInterface
96 {
97 def xwiki;
98 def rule;
99
100 public MyGroovyClass()
101 {
102 this.rule = new DocChangeRule(this);
103 }
104
105 public void init(xwiki)
106 {
107 this.xwiki = xwiki;
108 xwiki.getXWiki().getNotificationManager().addGeneralRule(this.rule);
109 }
110
111 public void cleanup()
112 {
113 xwiki.getXWiki().getNotificationManager().removeGeneralRule(this.rule);
114 }
115
116 public void notify(XWikiNotificationRule rule, XWikiDocument newdoc, XWikiDocument olddoc,
117 int event, XWikiContext context)
118 {
119 // Do some action here.
120 }
121 }
122
123 /* *# */
124 {{/code}}
125
126 In this example we've used a ##DocChangeRule## rule. There are also {{scm path="xwiki-platform-core/xwiki-platform-legacy/xwiki-platform-legacy-oldcore/src/main/java/com/xpn/xwiki/notify"}}other rules{{/scm}}.
127
128 == Calling the Groovy Class ==
129
130 {{code}}
131 #set($mygroovyclass = $xwiki.parseGroovyFromPage("MySpace.MyGroovyClass"))
132 $mygroovyclass.init($xwiki)
133 {{/code}}
134
135 == Example: IRC notification on document change ==
136
137 {{warning}}
138 The code below uses the parseGroovyFromPage method which takes 2 parameters. The second one is the name of page containing JARS as attachments. These JARs are put in the classloader used by Groovy when parsing the page. This feature is only working in XWiki Core 1.3 and later.
139 {{/warning}}
140
141 * **Step 1**: Groovy Class(((
142 {{code language="java"}}
143 /* Groovy Class #* */
144
145 import org.jibble.pircbot.*;
146 import java.util.*;
147 import com.xpn.xwiki.api.*;
148 import com.xpn.xwiki.notify.*;
149 import com.xpn.xwiki.*;
150 import com.xpn.xwiki.doc.*;
151
152 public class XWikiBot extends PircBot implements XWikiDocChangeNotificationInterface
153 {
154 def xwiki;
155 def channel;
156 def rule;
157
158 public XWikiBot()
159 {
160 this.setName("xwikibot");
161 this.rule = new DocChangeRule(this);
162 }
163
164 public void init(xwiki, channel)
165 {
166 this.xwiki = xwiki;
167 this.channel = channel;
168 xwiki.getXWiki().getNotificationManager().addGeneralRule(this.rule);
169 }
170
171 public void cleanup()
172 {
173 xwiki.getXWiki().getNotificationManager().removeGeneralRule(this.rule);
174 }
175
176 public void notify(XWikiNotificationRule rule, XWikiDocument newdoc, XWikiDocument olddoc,
177 int event, XWikiContext context)
178 {
179 sendMessage(this.channel, newdoc.getFullName() + " was modified - " + newdoc.getExternalURL("view", context));
180 }
181 }
182
183 /* *# */
184 {{/code}}
185 )))
186 * **Step 2**: Add the PircBot JAR as an attachment to the ##MySpace.MyGroovyClass## page created in step 1.
187 * **Step 3**: Calling page(((
188 {{code}}
189 ## Start by looking for a bot in the servlet context
190 #set ($sc = $context.getContext().getEngineContext().getServletContext())
191
192 ## If the bot isn't in the servlet context, start the bot and put in the context
193 #set ($bot = $sc.getAttribute("ircbot"))
194 #if (!$bot)
195 Bot is not started, starting it...
196 #set($bot = $xwiki.parseGroovyFromPage("MySpace.MyGroovyClass", "MySpace.MyGroovyClass"))
197 #set ($channel = "#xwiki")
198 $bot.init($xwiki, $channel)
199 $bot.connect("irc.freenode.net")
200 $bot.joinChannel($channel)
201 $sc.setAttribute("ircbot", $bot)
202 Bot started!
203
204 ## If the parameter passed is stop then stop the bot
205 #elseif ($request.action && $request.action == "stop")
206 $bot.cleanup()
207 $bot.disconnect()
208 $sc.setAttribute("ircbot", null)
209 Bot disconnected!
210
211 #else
212 Bot already started, doing nothing...
213
214 #end
215 {{/code}}
216 )))
217 * **Step 4**: Creating a Scheduler job so that the Bot is restarted automatically if the server is restarted for example.(((
218 Create a Scheduler job, set it to run every 5 minutes for example and use the following Groovy script in the job:
219
220 {{code language="java"}}
221 // Start by looking for a bot in the servlet context
222 def sc = context.getEngineContext().getServletContext()
223
224 // If the bot isn't in the servlet context, start the bot and put in the context
225 def bot = sc.getAttribute("ircbot")
226 if (bot == null) {
227 // Bot is not started, starting it...
228 bot = xwiki.parseGroovyFromPage("MySpace.MyGroovyClass", "MySpace.MyGroovyClass")
229 def channel = "#xwiki"
230 bot.init(xwiki, channel)
231 bot.connect("irc.freenode.net")
232 bot.joinChannel(channel)
233 sc.setAttribute("ircbot", bot)
234 // Bot started!
235 }
236 {{/code}}
237 )))

Get Connected