1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.watchlist.internal

File WatchListNotificationCacheListener.java

 

Coverage histogram

../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

16
41
5
1
227
119
19
0.46
8.2
5
3.8

Classes

Class Line # Actions
WatchListNotificationCacheListener 55 41 0% 19 6
0.903225890.3%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.watchlist.internal;
21   
22    import java.util.Arrays;
23    import java.util.List;
24   
25    import javax.inject.Inject;
26    import javax.inject.Named;
27    import javax.inject.Provider;
28    import javax.inject.Singleton;
29   
30    import org.slf4j.Logger;
31    import org.xwiki.bridge.event.DocumentCreatedEvent;
32    import org.xwiki.bridge.event.DocumentDeletedEvent;
33    import org.xwiki.bridge.event.DocumentUpdatedEvent;
34    import org.xwiki.component.annotation.Component;
35    import org.xwiki.observation.AbstractEventListener;
36    import org.xwiki.observation.event.Event;
37    import org.xwiki.watchlist.internal.documents.WatchListClassDocumentInitializer;
38    import org.xwiki.watchlist.internal.documents.WatchListJobClassDocumentInitializer;
39    import org.xwiki.wiki.descriptor.WikiDescriptorManager;
40   
41    import com.xpn.xwiki.XWikiContext;
42    import com.xpn.xwiki.XWikiException;
43    import com.xpn.xwiki.doc.MandatoryDocumentInitializer;
44    import com.xpn.xwiki.doc.XWikiDocument;
45    import com.xpn.xwiki.objects.BaseObject;
46   
47    /**
48    * Listener that maintains the {@link WatchListNotificationCache} up to date with the changes in the documents.
49    *
50    * @version $Id: 87da5f73dfe48eff5d9f69cb3f528ab790f9711c $
51    */
52    @Component
53    @Named(WatchListNotificationCacheListener.LISTENER_NAME)
54    @Singleton
 
55    public class WatchListNotificationCacheListener extends AbstractEventListener
56    {
57    /**
58    * The name of the listener.
59    */
60    public static final String LISTENER_NAME = "WatchListNotificationCacheListener";
61   
62    /**
63    * The events to match.
64    */
65    private static final List<Event> LISTENER_EVENTS = Arrays.<Event>asList(new DocumentCreatedEvent(),
66    new DocumentUpdatedEvent(), new DocumentDeletedEvent());
67   
68    /**
69    * The cache to maintain. Make sure we use a provider to do lazy instantiation/initialization so that we do not
70    * trigger an unwanted initialization of the cache when the listener is initialized by observation manager, as it
71    * would be too soon and the cache would not be able to access the db.
72    */
73    @Inject
74    private Provider<WatchListNotificationCache> notificationCacheProvider;
75   
76    /**
77    * Needed to reinitialize the watchlist class.
78    */
79    @Inject
80    @Named(WatchListClassDocumentInitializer.DOCUMENT_FULL_NAME)
81    private MandatoryDocumentInitializer watchListClassInitializer;
82   
83    /**
84    * Used to get the list of all wikis.
85    */
86    @Inject
87    private WikiDescriptorManager wikiDescriptorManager;
88   
89    /**
90    * Logging framework.
91    */
92    @Inject
93    private Logger logger;
94   
95    /**
96    * Default constructor.
97    */
 
98  1 toggle public WatchListNotificationCacheListener()
99    {
100  1 super(LISTENER_NAME, LISTENER_EVENTS);
101    }
102   
 
103  73 toggle @Override
104    public void onEvent(Event event, Object source, Object data)
105    {
106  73 XWikiDocument currentDoc = (XWikiDocument) source;
107  73 XWikiDocument originalDoc = currentDoc.getOriginalDocument();
108  73 XWikiContext context = (XWikiContext) data;
109   
110  73 watchListJobObjectsEventHandler(originalDoc, currentDoc, context);
111  73 watchListObjectsEventHandler(originalDoc, currentDoc, context);
112    }
113   
114    /**
115    * Manage events affecting watchlist job objects.
116    *
117    * @param originalDoc document version before the event occurred
118    * @param currentDoc document version after event occurred
119    * @param context the XWiki context
120    */
 
121  73 toggle private void watchListJobObjectsEventHandler(XWikiDocument originalDoc, XWikiDocument currentDoc,
122    XWikiContext context)
123    {
124  73 BaseObject originalJob = originalDoc.getXObject(WatchListJobClassDocumentInitializer.DOCUMENT_REFERENCE);
125  73 BaseObject currentJob = currentDoc.getXObject(WatchListJobClassDocumentInitializer.DOCUMENT_REFERENCE);
126   
127  73 boolean reinitWatchListClass = false;
128   
129    // WatchListJob deleted
130  73 if (originalJob != null && currentJob == null) {
131  0 String deletedJobDocument = originalDoc.getFullName();
132   
133  0 reinitWatchListClass |= notificationCacheProvider.get().removeInterval(deletedJobDocument);
134    }
135   
136    // WatchListJob created
137  73 if (originalJob == null && currentJob != null) {
138  3 String newJobDocument = currentDoc.getFullName();
139   
140  3 reinitWatchListClass |= notificationCacheProvider.get().addInterval(newJobDocument);
141    }
142   
143    // If the list of WatchListJob documents was altered, the WatchListClass "interval" property needs to be updated
144    // for all existing wikis.
145  73 if (reinitWatchListClass) {
146    // TODO: Maybe this can be moved inside WatchListNotificationCache.add/removeJobDocument(), since it would
147    // benefit from the synchronization done there.
148  3 reinitializeWatchListClass(context);
149    }
150    }
151   
152    /**
153    * @param context the context to use. Since everything happens in the same thread, it's safe to assume that this is
154    * the request's context and not a synthetic one.
155    */
 
156  3 toggle private void reinitializeWatchListClass(XWikiContext context)
157    {
158  3 String currentWikiId = context.getWikiId();
159  3 try {
160    // Reinitialize on all wikis.
161  3 for (String wikiId : wikiDescriptorManager.getAllIds()) {
162  3 try {
163  3 context.setWikiId(wikiId);
164   
165  3 XWikiDocument document =
166    context.getWiki().getDocument(watchListClassInitializer.getDocumentReference(), context);
167   
168  3 if (watchListClassInitializer.updateDocument(document)) {
169  3 context.getWiki().saveDocument(document, context);
170    }
171    } catch (XWikiException e) {
172  0 logger.error("Failed to re-initialize mandatory document [{}] on wiki [{}]",
173    WatchListClassDocumentInitializer.DOCUMENT_FULL_NAME, wikiId, e);
174    }
175    }
176    } catch (Exception e) {
177  0 logger.error("Failed to re-initialize mandatory document [{}]",
178    WatchListClassDocumentInitializer.DOCUMENT_FULL_NAME, e);
179    } finally {
180    // Restore the contex wiki.
181  3 context.setWikiId(currentWikiId);
182    }
183    }
184   
185    /**
186    * Manage events affecting watchlist objects.
187    *
188    * @param originalDoc document version before the event occurred
189    * @param currentDoc document version after event occurred
190    * @param context the XWiki context
191    */
 
192  73 toggle private void watchListObjectsEventHandler(XWikiDocument originalDoc, XWikiDocument currentDoc, XWikiContext context)
193    {
194  73 BaseObject originalWatchListObj = originalDoc.getXObject(WatchListClassDocumentInitializer.DOCUMENT_REFERENCE);
195  73 BaseObject currentWatchListObj = currentDoc.getXObject(WatchListClassDocumentInitializer.DOCUMENT_REFERENCE);
196   
197  73 if (originalWatchListObj != null) {
198    // Existing subscriber
199   
200  29 String oriInterval =
201    originalWatchListObj.getStringValue(WatchListClassDocumentInitializer.INTERVAL_PROPERTY);
202   
203    // If a subscriber has been deleted, remove it from our cache and exit
204  29 if (currentWatchListObj == null) {
205  2 notificationCacheProvider.get().removeSubscriber(oriInterval, originalDoc.getPrefixedFullName());
206  2 return;
207    }
208   
209    // Modification of the interval
210  27 String newInterval =
211    currentWatchListObj.getStringValue(WatchListClassDocumentInitializer.INTERVAL_PROPERTY);
212   
213  27 if (!newInterval.equals(oriInterval)) {
214  2 notificationCacheProvider.get().moveSubscriber(oriInterval, newInterval,
215    originalDoc.getPrefixedFullName());
216    }
217    }
218   
219  71 if ((originalWatchListObj == null || originalDoc == null) && currentWatchListObj != null) {
220    // New subscriber
221  6 String newInterval =
222    currentWatchListObj.getStringValue(WatchListClassDocumentInitializer.INTERVAL_PROPERTY);
223   
224  6 notificationCacheProvider.get().addSubscriber(newInterval, currentDoc.getPrefixedFullName());
225    }
226    }
227    }