1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.notifications.notifiers.internal.email

File NotificationUserIterator.java

 

Coverage histogram

../../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

12
30
7
1
175
108
17
0.57
4.29
7
2.43

Classes

Class Line # Actions
NotificationUserIterator 53 30 0% 17 1
0.9795918598%
 

Contributing tests

This file is covered by 1 test. .

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.notifications.notifiers.internal.email;
21   
22    import java.util.ArrayDeque;
23    import java.util.Arrays;
24    import java.util.Iterator;
25    import java.util.Queue;
26   
27    import javax.inject.Inject;
28   
29    import org.apache.commons.lang3.StringUtils;
30    import org.slf4j.Logger;
31    import org.xwiki.bridge.DocumentAccessBridge;
32    import org.xwiki.component.annotation.Component;
33    import org.xwiki.component.annotation.InstantiationStrategy;
34    import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
35    import org.xwiki.model.reference.DocumentReference;
36    import org.xwiki.model.reference.DocumentReferenceResolver;
37    import org.xwiki.model.reference.WikiReference;
38    import org.xwiki.notifications.notifiers.email.NotificationEmailInterval;
39    import org.xwiki.query.Query;
40    import org.xwiki.query.QueryException;
41    import org.xwiki.query.QueryManager;
42    import org.xwiki.wiki.descriptor.WikiDescriptorManager;
43   
44    /**
45    * Iterator that retrieve all users of the current wiki interested in the notifications emails at the specified
46    * interval.
47    *
48    * @version $Id: 132408203105a572e405cd4280eaa9ab3b52c3c1 $
49    * @since 9.5RC1
50    */
51    @Component(roles = NotificationUserIterator.class)
52    @InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
 
53    public class NotificationUserIterator implements Iterator<DocumentReference>
54    {
55    private static final int BATCH_SIZE = 50;
56   
57    /**
58    * The query to perform to get all users having a not-empty email address.
59    *
60    * Here, we re using <code>length(objUser.email) > 0</code> instead of <code>objUser.email <> ''</code> because
61    * ORACLE stores NULL instead of empty strings.
62    *
63    * But if we do
64    * <code>objUser.email <> NULL AND objUser.email <> ''</code>, then we have wrong results with MySQL.
65    *
66    * This <code>length()</code> trick allows us to use the same query on every database we support, but a better
67    * solution would be to write a different query for ORACLE than for the others, because this length() may be bad for
68    * performances.
69    */
70    // TODO: try with the solution suggested by Sergiu Dumitriu there: https://jira.xwiki.org/browse/XWIKI-14914
71    private static final String XWQL_QUERY = "select distinct doc.fullName from Document doc, "
72    + "doc.object(XWiki.XWikiUsers) objUser where length(objUser.email) > 0 order by doc.fullName";
73   
74    @Inject
75    private QueryManager queryManager;
76   
77    @Inject
78    private DocumentReferenceResolver<String> resolver;
79   
80    @Inject
81    private WikiDescriptorManager wikiDescriptorManager;
82   
83    @Inject
84    private DocumentAccessBridge documentAccessBridge;
85   
86    @Inject
87    private Logger logger;
88   
89    private Queue<String> users = new ArrayDeque<>();
90   
91    private NotificationEmailInterval interval;
92   
93    private int offset;
94   
95    private DocumentReference nextUser;
96   
97    /**
98    * Initialize the user iterator.
99    * @param interval the interval that users must have configured
100    */
 
101  373 toggle public void initialize(NotificationEmailInterval interval)
102    {
103  373 this.interval = interval;
104  373 getNext();
105    }
106   
 
107  378 toggle private void getNext()
108    {
109  378 DocumentReference classReference = new DocumentReference(wikiDescriptorManager.getCurrentWikiId(),
110    Arrays.asList("XWiki", "Notifications", "Code"), "NotificationEmailPreferenceClass");
111   
112  378 try {
113  378 nextUser = null;
114  755 while (!hasNext()) {
115  750 if (users.isEmpty()) {
116  748 doQuery();
117  748 if (users.isEmpty()) {
118  373 return;
119    }
120    }
121  958 while (!hasNext() && !users.isEmpty()) {
122  581 DocumentReference user = resolver.resolve(users.poll(),
123    new WikiReference(wikiDescriptorManager.getCurrentWikiId()));
124  581 Object userInterval
125    = documentAccessBridge.getProperty(user, classReference, "interval");
126  581 if (isDefaultInterval(userInterval) || isSameInterval(userInterval)) {
127  5 nextUser = user;
128    }
129    }
130    }
131    } catch (Exception e) {
132  0 logger.error("Fail to get next user.", e);
133    }
134    }
135   
 
136  748 toggle private void doQuery() throws QueryException
137    {
138  748 Query query = queryManager.createQuery(XWQL_QUERY, Query.XWQL);
139  748 query.setLimit(BATCH_SIZE);
140  748 query.setOffset(offset);
141  748 users.addAll(query.execute());
142  748 offset += BATCH_SIZE;
143    }
144   
 
145  581 toggle private boolean isDefaultInterval(Object interval)
146    {
147  581 return (interval == null || StringUtils.isBlank((String) interval))
148    && this.interval == NotificationEmailInterval.DAILY;
149    }
150   
 
151  579 toggle private boolean isSameInterval(Object interval)
152    {
153  579 if (interval == null || !(interval instanceof String)) {
154  573 return false;
155    }
156   
157  6 String stringInterval = (String) interval;
158  6 return StringUtils.isNotBlank(stringInterval)
159    && this.interval.equals(NotificationEmailInterval.valueOf(StringUtils.upperCase(stringInterval)));
160    }
161   
 
162  2091 toggle @Override
163    public boolean hasNext()
164    {
165  2091 return nextUser != null;
166    }
167   
 
168  5 toggle @Override
169    public DocumentReference next()
170    {
171  5 DocumentReference userReference = this.nextUser;
172  5 getNext();
173  5 return userReference;
174    }
175    }