diff --git a/src/main/java/org/olat/notifications/NotificationsManagerImpl.java b/src/main/java/org/olat/notifications/NotificationsManagerImpl.java index dbc6286cb50e90acf01f354a0b5984f7e518577c..0571d13ecaec48bdccaeeca57a16a5111c37b65f 100644 --- a/src/main/java/org/olat/notifications/NotificationsManagerImpl.java +++ b/src/main/java/org/olat/notifications/NotificationsManagerImpl.java @@ -25,11 +25,13 @@ package org.olat.notifications; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -234,6 +236,22 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us .getResultList(); } + protected List<Subscriber> getAllValidSubscribers(int firstResult, int maxResults) { + StringBuilder q = new StringBuilder(); + q.append("select sub from ").append(SubscriberImpl.class.getName()).append(" sub") + .append(" inner join fetch sub.publisher as pub") + .append(" where pub.state=").append(PUB_STATE_OK).append(" order by sub.identity.name, sub.key"); + TypedQuery<Subscriber> query = DBFactory.getInstance().getCurrentEntityManager() + .createQuery(q.toString(), Subscriber.class); + if(firstResult >= 0) { + query.setFirstResult(firstResult); + } + if(maxResults > 0) { + query.setMaxResults(maxResults); + } + return query.getResultList(); + } + @Override public List<SubscriptionInfo> getSubscriptionInfos(Identity identity, String publisherType) { StringBuilder sb = new StringBuilder(); @@ -271,13 +289,9 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us public void notifyAllSubscribersByEmail() { logAudit("starting notification cronjob for email sending", null); WorkThreadInformations.setLongRunningTask("sendNotifications"); - List<Subscriber> subs = getAllValidSubscribers(); - // ordered by identity.name! - + List<SubscriptionItem> items = new ArrayList<SubscriptionItem>(); List<Subscriber> subsToUpdate = null; - StringBuilder mailLog = new StringBuilder(); - StringBuilder mailErrorLog = new StringBuilder(); boolean veto = false; Subscriber latestSub = null; @@ -288,16 +302,25 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us Date defaultCompareDate = getDefaultCompareDate(); long start = System.currentTimeMillis(); + Set<Long> subs = new HashSet<Long>(); + // loop all subscriptions, as its ordered by identity, they get collected for each identity - for(Subscriber sub : subs){ + for(AllSubscriberIterator subscriberIt= new AllSubscriberIterator(); subscriberIt.hasNext(); ){ try { + Subscriber sub = subscriberIt.next(); ident = sub.getIdentity(); + + if(subs.contains(sub.getKey())) { + System.out.println("ERROR"); + } else { + subs.add(sub.getKey()); + } if (latestSub == null || (!ident.equalsByPersistableKey(latestSub.getIdentity()))) { // first time or next identity => prepare for a new user and send old data. // send a mail - notifySubscribersByEmail(latestSub, items, subsToUpdate, translator, start, veto, mailLog, mailErrorLog); + notifySubscribersByEmail(latestSub, items, subsToUpdate, translator, start, veto); // prepare for new user start = System.currentTimeMillis(); @@ -368,20 +391,14 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us } // for // done, purge last entry - notifySubscribersByEmail(latestSub, items, subsToUpdate, translator, start, veto, mailLog, mailErrorLog); - - // purge logs - if (mailErrorLog.length() > 0) { - logAudit("error sending email to the following identities: "+mailErrorLog.toString(),null); - } - logAudit("sent email to the following identities: "+mailLog.toString(), null); + notifySubscribersByEmail(latestSub, items, subsToUpdate, translator, start, veto); WorkThreadInformations.unsetLongRunningTask("sendNotifications"); } - private void notifySubscribersByEmail(Subscriber latestSub, List<SubscriptionItem> items, List<Subscriber> subsToUpdate, Translator translator, long start, boolean veto, StringBuilder mailLog, StringBuilder mailErrorLog) { + private void notifySubscribersByEmail(Subscriber latestSub, List<SubscriptionItem> items, List<Subscriber> subsToUpdate, Translator translator, long start, boolean veto) { if(veto) { if(latestSub != null) { - mailLog.append(latestSub.getIdentity().getName()).append(" already received email within prefs interval, "); + logAudit(latestSub.getIdentity().getName() + " already received notification email within prefs interval"); } } else if (items.size() > 0) { Identity curIdent = latestSub.getIdentity(); @@ -397,12 +414,12 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us p.setLongValue(new Date().getTime()); pm.updateProperty(p); } - - mailLog.append(curIdent.getName()).append(' ') - .append(items.size()).append(' ') - .append((System.currentTimeMillis() - start)).append("ms, "); + + StringBuilder mailLog = new StringBuilder(); + mailLog.append("Notifications mailed for ").append(curIdent.getName()).append(' ').append(items.size()).append(' ').append((System.currentTimeMillis() - start)).append("ms"); + logAudit(mailLog.toString()); } else { - mailErrorLog.append(curIdent.getName()).append(", "); + logAudit("Error sending notification email to : " + curIdent.getName()); } } //collecting the SubscriptionItem can potentially make a lot of DB calls @@ -1147,5 +1164,46 @@ public class NotificationsManagerImpl extends NotificationsManager implements Us public List<String> getEnabledNotificationIntervals() { return notificationIntervals; } + + /** + * Iterate through the valid subscribers + * + * Initial date: 23.10.2013<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ + private class AllSubscriberIterator implements Iterator<Subscriber> { + private final static int BATCH_SIZE = 500; + + private int count = 0; + private Deque<Subscriber> subscribers = new ArrayDeque<Subscriber>(BATCH_SIZE + 25); + + public void fillTheStack() { + List<Subscriber> batch = getAllValidSubscribers(count, BATCH_SIZE); + subscribers.addAll(batch); + count += batch.size(); + } + + @Override + public boolean hasNext() { + if(subscribers.size() == 0) { + fillTheStack(); + } + return subscribers.size() > 0; + } + + @Override + public Subscriber next() { + if(subscribers.size() == 0) { + fillTheStack(); + } + return subscribers.pollFirst(); + } + + @Override + public void remove() { + //not implemented + } + } } diff --git a/src/test/java/org/olat/notifications/NotificationsManagerTest.java b/src/test/java/org/olat/notifications/NotificationsManagerTest.java index a1f9af536c11e641a53ebcfc235543190999e331..4de6263174f7c9927c1673158d19a17feb9858a0 100644 --- a/src/test/java/org/olat/notifications/NotificationsManagerTest.java +++ b/src/test/java/org/olat/notifications/NotificationsManagerTest.java @@ -304,6 +304,34 @@ public class NotificationsManagerTest extends OlatTestCase { Assert.assertTrue(allSubscribers.contains(thisSubscriber)); } + @Test + public void testGetAllValidSubscribers_paged() { + Identity id = JunitTestHelper.createAndPersistIdentityAsUser("valid1paged-" + UUID.randomUUID().toString()); + //create a publisher + for(int i=0; i<10; i++) { + String identifier = UUID.randomUUID().toString().replace("-", ""); + SubscriptionContext context = new SubscriptionContext("AllSubs", new Long(130 + i), identifier); + PublisherData publisherData = new PublisherData("testGetAllValidSubscribers", "e.g. forumdata=keyofforum", null); + Publisher publisher = notificationManager.getOrCreatePublisher(context, publisherData); + Assert.assertNotNull(publisher); + + dbInstance.commitAndCloseSession(); + //add subscriber + notificationManager.subscribe(id, context, publisherData); + dbInstance.commitAndCloseSession(); + } + + //get all subscribers + List<Subscriber> allSubscribers = ((NotificationsManagerImpl)notificationManager).getAllValidSubscribers(0, -1); + Assert.assertNotNull(allSubscribers); + Assert.assertFalse(allSubscribers.isEmpty()); + + //get all subcribers pages + List<Subscriber> partialSubscribers = ((NotificationsManagerImpl)notificationManager).getAllValidSubscribers(0, 8); + Assert.assertNotNull(partialSubscribers); + Assert.assertEquals(8, partialSubscribers.size()); + } + @Test public void testGetSubscriberIdentities() { Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("valid1b-" + UUID.randomUUID().toString());