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

File DefaultWatchListEventMatcher.java

 

Coverage histogram

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

Code metrics

8
44
7
1
223
131
13
0.3
6.29
7
1.86

Classes

Class Line # Actions
DefaultWatchListEventMatcher 57 44 0% 13 6
0.8983050689.8%
 

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.ArrayList;
23    import java.util.Collection;
24    import java.util.Collections;
25    import java.util.Date;
26    import java.util.List;
27   
28    import javax.inject.Inject;
29    import javax.inject.Provider;
30    import javax.inject.Singleton;
31   
32    import org.apache.commons.collections4.CollectionUtils;
33    import org.apache.commons.lang3.StringUtils;
34    import org.slf4j.Logger;
35    import org.xwiki.component.annotation.Component;
36    import org.xwiki.model.reference.DocumentReference;
37    import org.xwiki.model.reference.DocumentReferenceResolver;
38    import org.xwiki.security.authorization.AuthorizationManager;
39    import org.xwiki.security.authorization.Right;
40    import org.xwiki.watchlist.internal.api.WatchListEvent;
41    import org.xwiki.watchlist.internal.api.WatchListStore;
42    import org.xwiki.watchlist.internal.api.WatchedElementType;
43   
44    import com.xpn.xwiki.XWikiContext;
45    import com.xpn.xwiki.plugin.activitystream.api.ActivityEvent;
46    import com.xpn.xwiki.plugin.activitystream.api.ActivityEventType;
47    import com.xpn.xwiki.plugin.activitystream.api.ActivityStream;
48    import com.xpn.xwiki.plugin.activitystream.plugin.ActivityStreamPlugin;
49   
50    /**
51    * Default implementation for {@link WatchListEventMatcher}.
52    *
53    * @version $Id: a8c95bfc4bfd21c7cbd86cbf6a4d0f60a100a833 $
54    */
55    @Component
56    @Singleton
 
57    public class DefaultWatchListEventMatcher implements WatchListEventMatcher
58    {
59   
60    /**
61    * Events to match.
62    */
63    private static final List<String> MATCHING_EVENT_TYPES = new ArrayList<String>()
64    {
 
65  1 toggle {
66  1 add(ActivityEventType.CREATE);
67  1 add(ActivityEventType.UPDATE);
68  1 add(ActivityEventType.DELETE);
69    }
70    };
71   
72    /**
73    * Logging framework.
74    */
75    @Inject
76    private Logger logger;
77   
78    /**
79    * Used to access the user's watched elements.
80    */
81    @Inject
82    private WatchListStore store;
83   
84    /**
85    * Context provider.
86    */
87    @Inject
88    private Provider<XWikiContext> contextProvider;
89   
90    /**
91    * Used to check view rights on the matched events.
92    */
93    @Inject
94    private AuthorizationManager authorizationManager;
95   
96    /**
97    * Used to resolve string references.
98    */
99    @Inject
100    private DocumentReferenceResolver<String> resolver;
101   
102    /**
103    * Used to convert {@link ActivityEvent}s to {@link WatchListEvent}s.
104    */
105    @Inject
106    private WatchListEventConverter<ActivityEvent> eventConverter;
107   
 
108  1 toggle @Override
109    public List<WatchListEvent> getEventsSince(Date start)
110    {
111  1 List<WatchListEvent> events = new ArrayList<>();
112   
113  1 XWikiContext context = getXWikiContext();
114   
115  1 ActivityStream actStream =
116    ((ActivityStreamPlugin) context.getWiki().getPlugin(ActivityStreamPlugin.PLUGIN_NAME, context))
117    .getActivityStream();
118  1 List<Object> parameters = new ArrayList<Object>();
119  1 parameters.add(start);
120   
121  1 try {
122    // FIXME: Watch out for memory usage here, since the list of events could be huge in some cases.
123  1 List<ActivityEvent> rawEvents =
124    actStream.searchEvents(
125    "act.date > ? and act.type in ('" + StringUtils.join(MATCHING_EVENT_TYPES, "','") + "')", false,
126    true, 0, 0, parameters, context);
127   
128    // If the page has been modified several times we want to display only one diff, if the page has been
129    // delete after update events we want to discard the update events since we won't be able to display
130    // diff from a deleted document. See WatchListEvent#addEvent(WatchListEvent) and
131    // WatchListEvent#equals(WatchListEvent).
132  1 for (ActivityEvent rawEvent : rawEvents) {
133  25 WatchListEvent event = this.eventConverter.convert(rawEvent);
134   
135  25 int existingIndex = events.indexOf(event);
136  25 if (existingIndex == -1) {
137    // An event on a new document, add the new event.
138  10 events.add(event);
139    } else {
140    // An event on an existing document, add to the events of that document.
141  15 WatchListEvent existingCompositeEvent = events.get(existingIndex);
142  15 existingCompositeEvent.addEvent(event);
143    }
144    }
145    } catch (Exception e) {
146  0 logger.error("Failed to retrieve updated documents from activity stream since [{}]", start, e);
147    }
148   
149  1 return events;
150    }
151   
 
152  25 toggle @Override
153    public List<WatchListEvent> getMatchingVisibleEvents(List<WatchListEvent> events, String subscriber)
154    {
155  25 List<WatchListEvent> result = new ArrayList<WatchListEvent>();
156   
157  25 for (WatchListEvent event : events) {
158  34 if (isEventSkipped(event)) {
159    // Skip events that are on a blacklist for various reasons (performance, security, etc.)
160  0 continue;
161    }
162   
163  34 if (!isEventViewable(event, subscriber)) {
164    // Skip events on documents that are not visible to the subscriber.
165  0 continue;
166    }
167   
168  34 if (!isEventMatching(event, subscriber)) {
169    // Skip events that are not interesting to the subscriber.
170  31 continue;
171    }
172   
173  3 result.add(event);
174    }
175   
176    // Sort the matching events by document.
177  25 Collections.sort(result);
178   
179  25 return result;
180    }
181   
 
182  34 toggle @Override
183    public boolean isEventMatching(WatchListEvent event, String subscriber)
184    {
185  34 boolean isWatched = false;
186   
187  34 try {
188    // The subscriber's watched users, since each event can be a composite event.
189  34 Collection<String> watchedUsers = store.getWatchedElements(subscriber, WatchedElementType.USER);
190   
191  34 isWatched |= store.isWatched(event.getWiki(), subscriber, WatchedElementType.WIKI);
192  34 isWatched |= store.isWatched(event.getPrefixedSpace(), subscriber, WatchedElementType.SPACE);
193  34 isWatched |= store.isWatched(event.getPrefixedFullName(), subscriber, WatchedElementType.DOCUMENT);
194  34 isWatched |= CollectionUtils.intersection(watchedUsers, event.getAuthors()).size() > 0;
195    } catch (Exception e) {
196  0 logger.error("Failed to determine if an event for the document [{}] is interesting to [{}]",
197    event.getDocumentReference(), subscriber, e);
198    }
199   
200  34 return isWatched;
201    }
202   
 
203  95 toggle @Override
204    public boolean isEventSkipped(WatchListEvent event)
205    {
206    // We exclude watchlist jobs from notifications since they are modified each time they are fired,
207    // producing useless noise.
208  95 Collection<String> possibleIntervals = store.getIntervals();
209  95 return possibleIntervals.contains(event.getFullName());
210    }
211   
 
212  34 toggle @Override
213    public boolean isEventViewable(WatchListEvent event, String subscriber)
214    {
215  34 DocumentReference userReference = resolver.resolve(subscriber);
216  34 return authorizationManager.hasAccess(Right.VIEW, userReference, event.getDocumentReference());
217    }
218   
 
219  1 toggle private XWikiContext getXWikiContext()
220    {
221  1 return contextProvider.get();
222    }
223    }