1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.util;
35
36 import info.magnolia.context.LifeTimeJCRSessionUtil;
37
38 import java.util.ArrayList;
39 import java.util.Iterator;
40 import java.util.List;
41
42 import javax.jcr.RepositoryException;
43 import javax.jcr.Session;
44 import javax.jcr.Workspace;
45 import javax.jcr.observation.Event;
46 import javax.jcr.observation.EventIterator;
47 import javax.jcr.observation.EventListener;
48 import javax.jcr.observation.ObservationManager;
49
50 import org.apache.jackrabbit.core.observation.ObservationManagerImpl;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54
55
56
57
58
59
60 public class ObservationUtil {
61
62 private final static Logger log = LoggerFactory.getLogger(ObservationUtil.class);
63
64 private static final int ALL_EVENT_TYPES_MASK = Event.NODE_ADDED | Event.NODE_REMOVED | Event.NODE_MOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
65
66
67
68
69
70 public static void dispose(String workspace) {
71 try {
72 ObservationManager om = getObservationManager(workspace);
73
74 if(om instanceof ObservationManagerImpl) {
75 ((ObservationManagerImpl)om).dispose();
76 } else {
77 log.warn("Observation can not be disposed ");
78 }
79 } catch (RepositoryException e) {
80 log.error("Unable to Unregisters all EventListeners for the following workspace "+workspace, e);
81 }
82 }
83
84
85
86
87
88
89
90 public static void registerChangeListener(String workspace, String observationPath, EventListener listener) {
91 registerChangeListener(workspace, observationPath, true, listener);
92 }
93
94
95
96
97
98
99 public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, EventListener listener) {
100 registerChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, listener);
101 }
102
103
104
105
106
107
108 public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener) {
109 registerChangeListener(workspace, observationPath, includeSubnodes, new String[] { nodeType }, listener);
110 }
111
112
113
114
115
116
117 public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, int eventTypesMask, EventListener listener) {
118 if (nodeType == null) {
119 registerChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, eventTypesMask, listener);
120 } else {
121 registerChangeListener(workspace, observationPath, includeSubnodes, new String[] { nodeType }, eventTypesMask, listener);
122 }
123 }
124
125
126
127
128
129
130 public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener) {
131 registerChangeListener(workspace, observationPath, includeSubnodes, nodeTypes, ALL_EVENT_TYPES_MASK, listener);
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, int eventTypesMask, EventListener listener) {
149 log.debug("Registering event listener for path [{}]", observationPath);
150
151 try {
152 ObservationManager observationManager = getObservationManager(workspace);
153 if (observationManager == null) {
154 log.error("Unable to add event listeners for " + observationPath);
155 throw new IllegalStateException("Observation manager can't be obtained due to invalid session.");
156 }
157
158 observationManager.addEventListener(listener, eventTypesMask, observationPath, includeSubnodes, null, nodeTypes, false);
159 } catch (RepositoryException e) {
160 log.error("Unable to add event listeners for " + observationPath, e);
161 }
162 }
163
164 public static void registerDeferredChangeListener(String workspace, String observationPath, EventListener listener, long delay, long maxDelay) {
165 registerDeferredChangeListener(workspace, observationPath, true, (String[]) null, listener, delay, maxDelay);
166 }
167
168 public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, EventListener listener, long delay, long maxDelay) {
169 registerDeferredChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, listener, delay, maxDelay);
170 }
171
172 public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener, long delay, long maxDelay) {
173 registerDeferredChangeListener(workspace, observationPath, includeSubnodes, new String[] { nodeType }, listener, delay, maxDelay);
174 }
175
176
177
178
179
180
181 public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener, long delay, long maxDelay) {
182 final EventListener deferredListener = instanciateDeferredEventListener(listener, delay, maxDelay);
183 registerChangeListener(workspace, observationPath, includeSubnodes, nodeTypes, deferredListener);
184 }
185
186
187
188
189
190
191 public static EventListener instanciateDeferredEventListener(EventListener listener, long delay, long maxDelay) {
192 return new DeferringEventListener(listener, delay, maxDelay);
193 }
194
195 public static void unregisterChangeListener(String workspace, EventListener listener) {
196 try {
197 ObservationManager om = getObservationManager(workspace);
198 if (om == null) {
199
200 return;
201 }
202 om.removeEventListener(listener);
203 } catch (RepositoryException e) {
204 log.error("Unable to remove event listener [" + listener + "] from workspace " + workspace, e);
205 }
206 }
207
208 private static ObservationManager getObservationManager(String workspace) throws RepositoryException {
209 Workspace wks = getSession(workspace).getWorkspace();
210 return wks.getSession().isLive() ? wks.getObservationManager() : null;
211 }
212
213 private static Session getSession(String workspace) throws RepositoryException {
214 return LifeTimeJCRSessionUtil.getSession(workspace);
215 }
216
217
218
219
220 public static class DeferringEventListener implements EventListener {
221
222 private ObservationBasedDelayedExecutor executor;
223
224 private EventListener listener;
225
226 public DeferringEventListener(EventListener listener, long delay, long maxDelay) {
227 this.listener = listener;
228 executor = new ObservationBasedDelayedExecutor(listener, delay, maxDelay);
229 }
230
231 @Override
232 public void onEvent(EventIterator events) {
233 this.executor.consume(events);
234 }
235
236 @Override
237 public String toString() {
238 return super.toString() + ":" + this.listener;
239 }
240 }
241
242
243
244
245 public static class ObservationBasedDelayedExecutor {
246
247 private final DelayedExecutor delayedExecutor;
248 private final List eventsBuffer = new ArrayList();
249
250 public ObservationBasedDelayedExecutor(final EventListener listener, long delay, long maxDelay) {
251 delayedExecutor = new DelayedExecutor(new Runnable() {
252 @Override
253 public void run() {
254
255 synchronized (eventsBuffer) {
256 listener.onEvent(new ListBasedEventIterator(eventsBuffer));
257 eventsBuffer.clear();
258 }
259 }
260 }, delay, maxDelay);
261 }
262
263 protected void consume(EventIterator events) {
264 synchronized (this.eventsBuffer) {
265 while (events.hasNext()) {
266 this.eventsBuffer.add(events.next());
267 }
268 delayedExecutor.trigger();
269 }
270 }
271 }
272
273
274
275
276
277 public static class ListBasedEventIterator implements EventIterator {
278
279 private Iterator iterator;
280 private List events;
281 private int pos = 0;
282
283 public ListBasedEventIterator(List events) {
284 this.events = events;
285 this.iterator = events.iterator();
286 }
287
288 @Override
289 public boolean hasNext() {
290 return this.iterator.hasNext();
291 }
292
293 @Override
294 public Object next() {
295 pos++;
296 return this.iterator.next();
297 }
298
299 @Override
300 public void remove() {
301 this.iterator.remove();
302 }
303
304 @Override
305 public Event nextEvent() {
306 return (Event) next();
307 }
308
309 @Override
310 public long getPosition() {
311 return pos;
312 }
313
314 @Override
315 public long getSize() {
316 return events.size();
317 }
318
319 @Override
320 public void skip(long skipNum) {
321 for (int i = 0; i < skipNum; i++) {
322 next();
323 }
324 }
325 }
326
327 }