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         DeprecationUtil.isDeprecated("use info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar instead");
173 
174         log.debug("Registering event listener for path [{}] in workspace [{}]", observationPath, workspace);
175 
176         try {
177             ObservationManager observationManager = getObservationManager(workspace);
178             if (observationManager == null) {
179                 log.error("Unable to add event listeners for {}", observationPath);
180                 throw new IllegalStateException("Observation manager can't be obtained due to invalid session.");
181             }
182 
183             observationManager.addEventListener(listener, eventTypesMask, observationPath, includeSubnodes, null, nodeTypes, false);
184         } catch (RepositoryException e) {
185             log.error("Unable to add event listeners for {}", observationPath, e);
186         }
187     }
188 
189     /**
190      * The event firing is deferred in case there is a series of fired events.
191      *
192      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
193      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
194      */
195     @Deprecated
196     public static void registerDeferredChangeListener(String workspace, String observationPath, EventListener listener, long delay, long maxDelay) {
197         registerDeferredChangeListener(workspace, observationPath, true, (String[]) null, listener, delay, maxDelay);
198     }
199 
200     /**
201      * The event firing is deferred in case there is a series of fired events.
202      *
203      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
204      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
205      */
206     @Deprecated
207     public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, EventListener listener, long delay, long maxDelay) {
208         registerDeferredChangeListener(workspace, observationPath, includeSubnodes, (String[]) null, listener, delay, maxDelay);
209     }
210 
211     /**
212      * The event firing is deferred in case there is a series of fired events.
213      *
214      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
215      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
216      */
217     @Deprecated
218     public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, String nodeType, EventListener listener, long delay, long maxDelay) {
219         registerDeferredChangeListener(workspace, observationPath, includeSubnodes, new String[] { nodeType }, listener, delay, maxDelay);
220     }
221 
222     /**
223      * The event firing is deferred in case there is a series of fired events.
224      *
225      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
226      * @see #registerChangeListener(String, String, boolean, String[], int, EventListener)
227      */
228     @Deprecated
229     public static void registerDeferredChangeListener(String workspace, String observationPath, boolean includeSubnodes, String[] nodeTypes, EventListener listener, long delay, long maxDelay) {
230         final EventListener deferredListener = instanciateDeferredEventListener(listener, delay, maxDelay);
231         registerChangeListener(workspace, observationPath, includeSubnodes, nodeTypes, deferredListener);
232     }
233 
234     /**
235      * Use this and register the returned EventListener with the
236      * registerChangeListener() methods, if you need to be able to later
237      * unregister your EventListener.
238      *
239      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Registrar} instead to register listeners
240      */
241     @Deprecated
242     public static EventListener instanciateDeferredEventListener(EventListener listener, long delay, long maxDelay) {
243         return new DeferringEventListener(listener, delay, maxDelay);
244     }
245 
246     /**
247      * @deprecated since 5.4.6 use {@link info.magnolia.observation.WorkspaceEventListenerRegistration.Handle#unregister()} to unregister listeners
248      */
249     @Deprecated
250     public static void unregisterChangeListener(String workspace, EventListener listener) {
251         try {
252             ObservationManager om = getObservationManager(workspace);
253             if (om == null) {
254                 // session have been invalidated and Observation manager is disconnected. Nothing to unregister. Bail out.
255                 return;
256             }
257             om.removeEventListener(listener);
258         } catch (RepositoryException e) {
259             log.error("Unable to remove event listener [{}] from workspace {}", listener, workspace, e);
260         }
261     }
262 
263     private static ObservationManager getObservationManager(String workspace) throws RepositoryException {
264         Workspace wks = getSession(workspace).getWorkspace();
265         return wks.getSession().isLive() ? wks.getObservationManager() : null;
266     }
267 
268     private static Session getSession(String workspace) throws RepositoryException {
269         return LifeTimeJCRSessionUtil.getSession(workspace);
270     }
271 
272     /**
273      * A listener using an {@link ObservationBasedDelayedExecutor}.
274      *
275      * @deprecated since 5.4.6 use {@link info.magnolia.observation.DeferringEventListener} instead
276      */
277     @Deprecated
278     public static class DeferringEventListener implements EventListener {
279 
280         private ObservationBasedDelayedExecutor executor;
281 
282         private EventListener listener;
283 
284         public DeferringEventListener(EventListener listener, long delay, long maxDelay) {
285             this.listener = listener;
286             executor = new ObservationBasedDelayedExecutor(listener, delay, maxDelay);
287         }
288 
289         @Override
290         public void onEvent(EventIterator events) {
291             this.executor.consume(events);
292         }
293 
294         @Override
295         public String toString() {
296             return super.toString() + ":" + this.listener;
297         }
298     }
299 
300     /**
301      * Deferred event handling. Uses the DelayedExecutor class.
302      *
303      * @deprecated since 5.4.6 use {@link info.magnolia.observation.DeferringEventListener.ObservationBasedDelayedExecutor} instead
304      */
305     @Deprecated
306     public static class ObservationBasedDelayedExecutor {
307 
308         private final DelayedExecutor delayedExecutor;
309         private final List eventsBuffer = new ArrayList();
310 
311         public ObservationBasedDelayedExecutor(final EventListener listener, long delay, long maxDelay) {
312             delayedExecutor = new DelayedExecutor(new Runnable() {
313                 @Override
314                 public void run() {
315                     // during execution consume is blocked
316                     synchronized (eventsBuffer) {
317                         listener.onEvent(new ListBasedEventIterator(eventsBuffer));
318                         eventsBuffer.clear();
319                     }
320                 }
321             }, delay, maxDelay);
322         }
323 
324         protected void consume(EventIterator events) {
325             synchronized (this.eventsBuffer) {
326                 while (events.hasNext()) {
327                     this.eventsBuffer.add(events.next());
328                 }
329                 delayedExecutor.trigger();
330             }
331         }
332     }
333 
334     /**
335      * List based event iterator. Used to collect events in a list which are
336      * later on passed to the listener.
337      *
338      * @deprecated since 5.4.6 use {@link info.magnolia.observation.DeferringEventListener.ListBasedEventIterator} instead
339      */
340     @Deprecated
341     public static class ListBasedEventIterator implements EventIterator {
342 
343         private Iterator iterator;
344         private List events;
345         private int pos = 0;
346 
347         public ListBasedEventIterator(List events) {
348             this.events = events;
349             this.iterator = events.iterator();
350         }
351 
352         @Override
353         public boolean hasNext() {
354             return this.iterator.hasNext();
355         }
356 
357         @Override
358         public Object next() {
359             pos++;
360             return this.iterator.next();
361         }
362 
363         @Override
364         public void remove() {
365             this.iterator.remove();
366         }
367 
368         @Override
369         public Event nextEvent() {
370             return (Event) next();
371         }
372 
373         @Override
374         public long getPosition() {
375             return pos;
376         }
377 
378         @Override
379         public long getSize() {
380             return events.size();
381         }
382 
383         @Override
384         public void skip(long skipNum) {
385             for (int i = 0; i < skipNum; i++) {
386                 next();
387             }
388         }
389     }
390 
391 }