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 java.util.ArrayList;
37 import java.util.Iterator;
38 import java.util.List;
39
40 import info.magnolia.cms.core.HierarchyManager;
41 import info.magnolia.context.LifeTimeJCRSessionUtil;
42
43 import javax.jcr.RepositoryException;
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.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53
54
55
56
57 public class ObservationUtil {
58 private final static Logger log = LoggerFactory.getLogger(ObservationUtil.class);
59 private static final int ALL_EVENT_TYPES_MASK = Event.NODE_ADDED | Event.NODE_REMOVED | Event.PROPERTY_ADDED | Event.PROPERTY_CHANGED | Event.PROPERTY_REMOVED;
60
61
62
63
64
65
66 public static void registerChangeListener(String repository, String observationPath, EventListener listener) {
67 registerChangeListener(repository, observationPath, true, listener);
68 }
69
70
71
72
73
74
75 public static void registerChangeListener(String repository, String observationPath, boolean includeSubnodes, EventListener listener) {
76 registerChangeListener(repository, observationPath, includeSubnodes, (String[]) null, listener);
77 }
78
79
80
81
82
83
84 public static void registerChangeListener(String repository, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener) {
85 registerChangeListener(repository, observationPath, includeSubnodes, new String[] { nodeType }, listener);
86 }
87
88
89
90
91
92
93 public static void registerChangeListener(String repository, String observationPath, boolean includeSubnodes, String nodeType, int eventTypesMask, EventListener listener) {
94 if (nodeType == null) {
95 registerChangeListener(repository, observationPath, includeSubnodes, (String[]) null, eventTypesMask, listener);
96 } else {
97 registerChangeListener(repository, observationPath, includeSubnodes, new String[] { nodeType }, eventTypesMask, listener);
98 }
99 }
100
101
102
103
104
105
106 public static void registerChangeListener(String repository, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener) {
107 registerChangeListener(repository, observationPath, includeSubnodes, nodeTypes, ALL_EVENT_TYPES_MASK, listener);
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public static void registerChangeListener(String repository, String observationPath, boolean includeSubnodes, String[] nodeTypes, int eventTypesMask, EventListener listener) {
125 log.debug("Registering event listener for path [{}]", observationPath);
126
127 try {
128 ObservationManager observationManager = getObservationManager(repository);
129 if (observationManager == null) {
130 log.error("Unable to add event listeners for " + observationPath);
131 throw new IllegalStateException("Observation manager can't be obtained due to invalid session.");
132 }
133
134 observationManager.addEventListener(listener, eventTypesMask, observationPath, includeSubnodes, null, nodeTypes, false);
135 } catch (RepositoryException e) {
136 log.error("Unable to add event listeners for " + observationPath, e);
137 }
138 }
139
140 public static void registerDeferredChangeListener(String repository, String observationPath, EventListener listener, long delay, long maxDelay) {
141 registerDeferredChangeListener(repository, observationPath, true, (String[]) null, listener, delay, maxDelay);
142 }
143
144 public static void registerDeferredChangeListener(String repository, String observationPath, boolean includeSubnodes, EventListener listener, long delay, long maxDelay) {
145 registerDeferredChangeListener(repository, observationPath, includeSubnodes, (String[]) null, listener, delay, maxDelay);
146 }
147
148 public static void registerDeferredChangeListener(String repository, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener, long delay, long maxDelay) {
149 registerDeferredChangeListener(repository, observationPath, includeSubnodes, new String[] { nodeType }, listener, delay, maxDelay);
150 }
151
152
153
154
155
156
157 public static void registerDeferredChangeListener(String repository, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener, long delay, long maxDelay) {
158 final EventListener deferedListener = instanciateDeferredEventListener(listener, delay, maxDelay);
159 registerChangeListener(repository, observationPath, includeSubnodes, nodeTypes, deferedListener);
160 }
161
162
163
164
165
166
167 public static EventListener instanciateDeferredEventListener(EventListener listener, long delay, long maxDelay) {
168 return new DeferringEventListener(listener, delay, maxDelay);
169 }
170
171 public static void unregisterChangeListener(String repository, EventListener listener) {
172 try {
173 ObservationManager om = getObservationManager(repository);
174 if (om == null) {
175
176 return;
177 }
178 om.removeEventListener(listener);
179 } catch (RepositoryException e) {
180 log.error("Unable to remove event listener [" + listener + "] from repository " + repository, e);
181 }
182 }
183
184 private static ObservationManager getObservationManager(String repository) throws RepositoryException {
185 Workspace wks = getHierarchyManager(repository).getWorkspace();
186 return wks.getSession().isLive() ? wks.getObservationManager() : null;
187 }
188
189 private static HierarchyManager getHierarchyManager(String repository) {
190 return LifeTimeJCRSessionUtil.getHierarchyManager(repository);
191 }
192
193 public static class DeferringEventListener implements EventListener {
194
195 private ObservationBasedDelayedExecutor executor;
196
197 private EventListener listener;
198
199 public DeferringEventListener(EventListener listener, long delay, long maxDelay) {
200 this.listener = listener;
201 executor = new ObservationBasedDelayedExecutor(listener, delay, maxDelay);
202 }
203
204 public void onEvent(EventIterator events) {
205 this.executor.consume(events);
206 }
207
208 public String toString() {
209 return super.toString() + ":" + this.listener;
210 }
211 }
212
213
214
215
216 public static class ObservationBasedDelayedExecutor {
217 private final DelayedExecutor delayedExecutor;
218 private final List eventsBuffer = new ArrayList();
219
220 public ObservationBasedDelayedExecutor(final EventListener listener, long delay, long maxDelay) {
221 delayedExecutor = new DelayedExecutor(new Runnable() {
222 public void run() {
223
224 synchronized (eventsBuffer) {
225 listener.onEvent(new ListBasedEventIterator(eventsBuffer));
226 eventsBuffer.clear();
227 }
228 }
229 }, delay, maxDelay);
230 }
231
232 protected void consume(EventIterator events) {
233 synchronized (this.eventsBuffer) {
234 while (events.hasNext()) {
235 this.eventsBuffer.add(events.next());
236 }
237 delayedExecutor.trigger();
238 }
239 }
240 }
241
242
243
244
245
246 public static class ListBasedEventIterator implements EventIterator {
247 private Iterator iterator;
248 private List events;
249 private int pos = 0;
250
251 public ListBasedEventIterator(List events) {
252 this.events = events;
253 this.iterator = events.iterator();
254 }
255
256 public boolean hasNext() {
257 return this.iterator.hasNext();
258 }
259
260 public Object next() {
261 pos++;
262 return this.iterator.next();
263 }
264
265 public void remove() {
266 this.iterator.remove();
267 }
268
269 public Event nextEvent() {
270 return (Event) next();
271 }
272
273 public long getPosition() {
274 return pos;
275 }
276
277 public long getSize() {
278 return events.size();
279 }
280
281 public void skip(long skipNum) {
282 for (int i = 0; i < skipNum; i++) {
283 next();
284 }
285 }
286 }
287
288 }