View Javadoc
1   /**
2    * This file Copyright (c) 2003-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
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   * Util to register JCR observations. Supports delayed execution of the listener to handle event bursts.
57   *
58   * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration} instead
59   */
60  @Deprecated
61  public class ObservationUtil {
62  
63      private final static Logger log = LoggerFactory.getLogger(ObservationUtil.class);
64  
65      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;
66  
67  
68      /**
69       * Unregisters all EventListeners for the given workspace.
70       *
71       * @deprecated since 5.4.6 without replacement
72       */
73      @Deprecated
74      public static void dispose(String workspace) {
75          try {
76              ObservationManager om = getObservationManager(workspace);
77  
78              if (om instanceof ObservationManagerImpl) {
79                  ((ObservationManagerImpl) om).dispose();
80              } else {
81                  log.warn("Observation can not be disposed ");
82              }
83          } catch (RepositoryException e) {
84              log.error("Unable to Unregisters all EventListeners for the following workspace {}", workspace, e);
85          }
86      }
87  
88      /**
89       * Registers an EventListener for any node type.
90       *
91       * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
92       * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
93       */
94      @Deprecated
95      public static void registerChangeListener(String workspace, String observationPath, EventListener listener) {
96          registerChangeListener(workspace, observationPath, true, listener);
97      }
98  
99      /**
100      * Registers an EventListener for any node type.
101      *
102      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
103      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
104      */
105     @Deprecated
106     public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, EventListener listener) {
107         registerChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, listener);
108     }
109 
110     /**
111      * Registers an EventListener for a specific node type.
112      *
113      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
114      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
115      */
116     @Deprecated
117     public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener) {
118         registerChangeListener(workspace, observationPath, includeSubnodes, new String[]{nodeType}, listener);
119     }
120 
121     /**
122      * Registers an EventListener for a specific node type and event types.
123      *
124      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
125      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
126      */
127     @Deprecated
128     public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, int eventTypesMask, EventListener listener) {
129         if (nodeType == null) {
130             registerChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, eventTypesMask, listener);
131         } else {
132             registerChangeListener(workspace, observationPath, includeSubnodes, new String[]{nodeType}, eventTypesMask, listener);
133         }
134     }
135 
136     /**
137      * Registers an EventListener for a specific set of node types and event types.
138      *
139      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
140      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
141      */
142     @Deprecated
143     public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener) {
144         registerChangeListener(workspace, observationPath, includeSubnodes, nodeTypes, ALL_EVENT_TYPES_MASK, listener);
145     }
146 
147     /**
148      * Register a single event listener, bound to the given path.
149      *
150      * <p><strong>
151      * Be careful that if you observe "/", events may be generated for jcr:system,
152      * which is "shared" across all workspaces.
153      * </strong></p>
154      * <p>Use {@link FilteredEventListener} and {@link FilteredEventListener#JCR_SYSTEM_EXCLUDING_PREDICATE JCR_SYSTEM_EXCLUDING_PREDICATE} wherever appropriate.</p>
155      *
156      * <p>Finally, consider using {@link ObservationManager#addEventListener(EventListener, int, String, boolean, String[], String[], boolean) ObservationManager} directly,
157      * as {@link ObservationUtil} may become mostly deprecated in the near future.</p>
158      *
159      * @param observationPath the absPath parameter of {@link ObservationManager#addEventListener}
160      * @param includeSubnodes the isDeep parameter of {@link ObservationManager#addEventListener}
161      * @param nodeTypes the nodeTypeName parameter of {@link ObservationManager#addEventListener}
162      * @param eventTypesMask the eventTypes parameter of {@link ObservationManager#addEventListener}
163      * @param listener the listener parameter of {@link ObservationManager#addEventListener}
164      *
165      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
166      * @see ObservationManager#addEventListener(EventListener, int, String, boolean, String[], String[], boolean)
167      * @see Event
168      * @see FilteredEventListener
169      */
170     @Deprecated
171     public static void registerChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, int eventTypesMask, EventListener listener) {
172         log.debug("Registering event listener for path [{}]", observationPath);
173 
174         try {
175             ObservationManager observationManager = getObservationManager(workspace);
176             if (observationManager == null) {
177                 log.error("Unable to add event listeners for {}", observationPath);
178                 throw new IllegalStateException("Observation manager can't be obtained due to invalid session.");
179             }
180 
181             observationManager.addEventListener(listener, eventTypesMask, observationPath, includeSubnodes, null, nodeTypes, false);
182         } catch (RepositoryException e) {
183             log.error("Unable to add event listeners for {}", observationPath, e);
184         }
185     }
186 
187     /**
188      * The event firing is deferred in case there is a series of fired events.
189      *
190      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
191      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
192      */
193     @Deprecated
194     public static void registerDeferredChangeListener(String workspace, String observationPath, EventListener listener, long delay, long maxDelay) {
195         registerDeferredChangeListener(workspace, observationPath, true, (String[]) null, listener, delay, maxDelay);
196     }
197 
198     /**
199      * The event firing is deferred in case there is a series of fired events.
200      *
201      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
202      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
203      */
204     @Deprecated
205     public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, EventListener listener, long delay, long maxDelay) {
206         registerDeferredChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, listener, delay, maxDelay);
207     }
208 
209     /**
210      * The event firing is deferred in case there is a series of fired events.
211      *
212      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
213      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
214      */
215     @Deprecated
216     public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener, long delay, long maxDelay) {
217         registerDeferredChangeListener(workspace, observationPath, includeSubnodes, new String[] { nodeType }, listener, delay, maxDelay);
218     }
219 
220     /**
221      * The event firing is deferred in case there is a series of fired events.
222      *
223      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
224      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
225      */
226     @Deprecated
227     public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener, long delay, long maxDelay) {
228         final EventListener deferredListener = instanciateDeferredEventListener(listener, delay, maxDelay);
229         registerChangeListener(workspace, observationPath, includeSubnodes, nodeTypes, deferredListener);
230     }
231 
232     /**
233      * Use this and register the returned EventListener with the
234      * registerChangeListener() methods, if you need to be able to later
235      * unregister your EventListener.
236      *
237      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
238      */
239     @Deprecated
240     public static EventListener instanciateDeferredEventListener(EventListener listener, long delay, long maxDelay) {
241         return new DeferringEventListener(listener, delay, maxDelay);
242     }
243 
244     /**
245      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Handle#unregister()} to unregister listeners
246      */
247     @Deprecated
248     public static void unregisterChangeListener(String workspace, EventListener listener) {
249         try {
250             ObservationManager om = getObservationManager(workspace);
251             if (om == null) {
252                 // session have been invalidated and Observation manager is disconnected. Nothing to unregister. Bail out.
253                 return;
254             }
255             om.removeEventListener(listener);
256         } catch (RepositoryException e) {
257             log.error("Unable to remove event listener [{}] from workspace {}", listener, workspace, e);
258         }
259     }
260 
261     private static ObservationManager getObservationManager(String workspace) throws RepositoryException {
262         Workspace wks = getSession(workspace).getWorkspace();
263         return wks.getSession().isLive() ? wks.getObservationManager() : null;
264     }
265 
266     private static Session getSession(String workspace) throws RepositoryException {
267         return LifeTimeJCRSessionUtil.getSession(workspace);
268     }
269 
270     /**
271      * A listener using an {@link ObservationBasedDelayedExecutor}.
272      *
273      * @deprecated since 5.4.6 use {@link info.magnolia.observation.DeferringEventListener} instead
274      */
275     @Deprecated
276     public static class DeferringEventListener implements EventListener {
277 
278         private ObservationBasedDelayedExecutor executor;
279 
280         private EventListener listener;
281 
282         public DeferringEventListener(EventListener listener, long delay, long maxDelay) {
283             this.listener = listener;
284             executor = new ObservationBasedDelayedExecutor(listener, delay, maxDelay);
285         }
286 
287         @Override
288         public void onEvent(EventIterator events) {
289             this.executor.consume(events);
290         }
291 
292         @Override
293         public String toString() {
294             return super.toString() + ":" + this.listener;
295         }
296     }
297 
298     /**
299      * Deferred event handling. Uses the DelayedExecutor class.
300      *
301      * @deprecated since 5.4.6 use {@link info.magnolia.observation.DeferringEventListener.ObservationBasedDelayedExecutor} instead
302      */
303     @Deprecated
304     public static class ObservationBasedDelayedExecutor {
305 
306         private final DelayedExecutor delayedExecutor;
307         private final List eventsBuffer = new ArrayList();
308 
309         public ObservationBasedDelayedExecutor(final EventListener listener, long delay, long maxDelay) {
310             delayedExecutor = new DelayedExecutor(new Runnable() {
311                 @Override
312                 public void run() {
313                     // during execution consume is blocked
314                     synchronized (eventsBuffer) {
315                         listener.onEvent(new ListBasedEventIterator(eventsBuffer));
316                         eventsBuffer.clear();
317                     }
318                 }
319             }, delay, maxDelay);
320         }
321 
322         protected void consume(EventIterator events) {
323             synchronized (this.eventsBuffer) {
324                 while (events.hasNext()) {
325                     this.eventsBuffer.add(events.next());
326                 }
327                 delayedExecutor.trigger();
328             }
329         }
330     }
331 
332     /**
333      * List based event iterator. Used to collect events in a list which are
334      * later on passed to the listener.
335      *
336      * @deprecated since 5.4.6 use {@link info.magnolia.observation.DeferringEventListener.ListBasedEventIterator} instead
337      */
338     @Deprecated
339     public static class ListBasedEventIterator implements EventIterator {
340 
341         private Iterator iterator;
342         private List events;
343         private int pos = 0;
344 
345         public ListBasedEventIterator(List events) {
346             this.events = events;
347             this.iterator = events.iterator();
348         }
349 
350         @Override
351         public boolean hasNext() {
352             return this.iterator.hasNext();
353         }
354 
355         @Override
356         public Object next() {
357             pos++;
358             return this.iterator.next();
359         }
360 
361         @Override
362         public void remove() {
363             this.iterator.remove();
364         }
365 
366         @Override
367         public Event nextEvent() {
368             return (Event) next();
369         }
370 
371         @Override
372         public long getPosition() {
373             return pos;
374         }
375 
376         @Override
377         public long getSize() {
378             return events.size();
379         }
380 
381         @Override
382         public void skip(long skipNum) {
383             for (int i = 0; i < skipNum; i++) {
384                 next();
385             }
386         }
387     }
388 
389 }