Skip to content
Snippets Groups Projects
Unverified Commit cc63a7a6 authored by Simon Urli's avatar Simon Urli Committed by GitHub
Browse files

XWIKI-17034: Allow to define different grouping strategy for notifications (#2203)


Previous work was about introducing strategies to group events for creating
composite events. This work is about strategies for chosing how many
mails should be sent for each composite event to notify by email.
Historically the strategy was hardcoded and consisted in putting all
composite events in the same email. Here we provide different
strategies: the previous one, but also a strategy allowing to send one
email per composite event, and another one allowing to send a separate
email specifically for mentions.

That work also improves previous API to use a clear UserReference
instead of a String which is vague.

Co-authored-by: default avatarManuel Leduc <manuel.leduc@xwiki.com>
Co-authored-by: default avatarThomas Mortagne <thomas.mortagne@xwiki.com>
parent 0bbe4d73
No related branches found
No related tags found
No related merge requests found
Showing
with 543 additions and 31 deletions
......@@ -24,6 +24,7 @@
import org.xwiki.component.annotation.Role;
import org.xwiki.eventstream.Event;
import org.xwiki.stability.Unstable;
import org.xwiki.user.UserReference;
/**
* Component responsible to perform the grouping based on the available {@link GroupingEventStrategy}, on the targeted
......@@ -41,13 +42,14 @@ public interface GroupingEventManager
* it to group the given events.
*
* @param events the list of events to group
* @param userId the identifier of the user for whom the grouping is performed
* @param userReference the user for whom the grouping is performed (or {@code null} if it's not for a specific
* user)
* @param target the output target (e.g. email or alert)
* @return a list of composite events as computed by {@link GroupingEventStrategy#group(List)}
* @throws NotificationException in case of problem when performing the grouping
*/
List<CompositeEvent> getCompositeEvents(List<Event> events, String userId, String target) throws
NotificationException;
List<CompositeEvent> getCompositeEvents(List<Event> events, UserReference userReference, String target)
throws NotificationException;
/**
* Add new events to an already existing list of composite events, using the {@link GroupingEventStrategy}
......@@ -56,10 +58,11 @@ List<CompositeEvent> getCompositeEvents(List<Event> events, String userId, Strin
*
* @param compositeEvents a list of composite events (might be empty)
* @param newEvents the new events to group along with the given list of composite events
* @param userId the identifier of the user for whom the grouping is performed
* @param userReference the user for whom the grouping is performed (or {@code null} if it's not for a specific
* user)
* @param target the output target (e.g. email or alert)
* @throws NotificationException in case of problem when performing the grouping
*/
void augmentCompositeEvents(List<CompositeEvent> compositeEvents, List<Event> newEvents, String userId,
String target) throws NotificationException;
void augmentCompositeEvents(List<CompositeEvent> compositeEvents, List<Event> newEvents,
UserReference userReference, String target) throws NotificationException;
}
......@@ -20,6 +20,7 @@
package org.xwiki.notifications;
import org.xwiki.component.annotation.Role;
import org.xwiki.stability.Unstable;
/**
* Get the configuration options concerning the Notification module.
......@@ -85,4 +86,14 @@ default int getAsyncPoolSize()
{
return 2;
}
/**
* @return the hint of the component to be used for the email grouping strategy.
* @since 15.5RC1
*/
@Unstable
default String getEmailGroupingStrategyHint()
{
return "default";
}
}
......@@ -84,4 +84,10 @@ public int getAsyncPoolSize()
{
return configurationSource.getProperty(CONFIGURATION_PREFIX + "async.poolSize", 2);
}
@Override
public String getEmailGroupingStrategyHint()
{
return configurationSource.getProperty(CONFIGURATION_PREFIX + "emailGroupingStrategyHint", "default");
}
}
......@@ -31,7 +31,7 @@
<name>XWiki Platform - Notifications - Notifiers - API</name>
<description>Handle how notifications are transmitted to a user</description>
<properties>
<xwiki.jacoco.instructionRatio>0.70</xwiki.jacoco.instructionRatio>
<xwiki.jacoco.instructionRatio>0.75</xwiki.jacoco.instructionRatio>
</properties>
<dependencies>
<dependency>
......
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.email;
import org.xwiki.component.annotation.Role;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.stability.Unstable;
import java.util.List;
/**
* Defines how the events should be grouped to be sent in individual emails.
* Contrarily to {@link org.xwiki.notifications.GroupingEventStrategy} the goal here is not to group individual
* {@link org.xwiki.eventstream.Event} in {@link CompositeEvent} but to group a list of {@link CompositeEvent} that has
* been already computed based on the {@link org.xwiki.notifications.GroupingEventStrategy} and decide how many mails
* should be sent for those {@link CompositeEvent}.
*
* @version $Id$
* @since 15.5RC1
*/
@Unstable
@Role
public interface NotificationEmailGroupingStrategy
{
/**
* Group the given list of {@link CompositeEvent} in sub-lists, where each list represent an email to be sent.
* Hence, if that method returns a single list containing all {@link CompositeEvent} a single email with all the
* events will be sent. On the contrary, if it returns as many list as there is events, then there will be as many
* emails as there is events.
*
* @param compositeEvents the list of composite events that should be sent by email
* @return a list of list of events where each list of events represents an email
* @throws NotificationException in case of problem to compute the sub-lists
*/
List<List<CompositeEvent>> groupEventsPerMail(List<CompositeEvent> compositeEvents) throws NotificationException;
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.internal.email.grouping;
import org.xwiki.component.annotation.Component;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.notifications.notifiers.email.NotificationEmailGroupingStrategy;
import javax.inject.Singleton;
import java.util.List;
/**
* Default implementation of {@link NotificationEmailGroupingStrategy}.
* This implementation considers that all events should be returned in a single email.
*
* @version $Id$
* @since 15.5RC1
*/
@Component
@Singleton
public class DefaultNotificationEmailGroupingStrategy implements NotificationEmailGroupingStrategy
{
@Override
public List<List<CompositeEvent>> groupEventsPerMail(List<CompositeEvent> compositeEvents)
throws NotificationException
{
// TODO: Maybe the default component should systematically paginate?
return List.of(compositeEvents);
}
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.internal.email.grouping;
import org.xwiki.component.annotation.Component;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.notifications.notifiers.email.NotificationEmailGroupingStrategy;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.List;
import java.util.stream.Collectors;
/**
* This component offers a strategy for sending one email per composite event to notify to the user.
* This strategy can be used in combination with
* {@link org.xwiki.notifications.internal.ApplicationTypeGroupingStrategy} to send as many emails as there is type of
* events to notify the users. It could also be used with the default event grouping strategy so that users received as
* many emails as there is group of events.
*
* @version $Id$
* @since 15.5RC1
*/
@Component
@Singleton
@Named("emailperevent")
public class OneMailPerCompositeEmailGroupingStrategy implements NotificationEmailGroupingStrategy
{
@Override
public List<List<CompositeEvent>> groupEventsPerMail(List<CompositeEvent> compositeEvents)
throws NotificationException
{
return compositeEvents.stream().map(List::of).collect(Collectors.toList());
}
}
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.internal.email.grouping;
import org.apache.commons.lang.StringUtils;
import org.xwiki.component.annotation.Component;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.notifications.notifiers.email.NotificationEmailGroupingStrategy;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
/**
* This component offers a strategy where the notifications related to mentions are sent in a separated email than all
* others notifications. So two emails are sent in case of mentions: one for the mentions, and another one for other
* events.
*
* @version $Id$
* @since 15.5RC1
*/
@Component
@Singleton
@Named("separatedmention")
public class SeparatedMentionEmailGroupingStrategy implements NotificationEmailGroupingStrategy
{
@Override
public List<List<CompositeEvent>> groupEventsPerMail(List<CompositeEvent> compositeEvents)
throws NotificationException
{
List<CompositeEvent> otherEvents = new ArrayList<>();
List<CompositeEvent> mention = new ArrayList<>();
List<List<CompositeEvent>> result = new ArrayList<>();
for (CompositeEvent compositeEvent : compositeEvents) {
if (StringUtils.equals("mention", compositeEvent.getType())) {
mention.add(compositeEvent);
} else {
otherEvents.add(compositeEvent);
}
}
if (!otherEvents.isEmpty()) {
result.add(otherEvents);
}
if (!mention.isEmpty()) {
result.add(mention);
}
return result;
}
}
......@@ -42,12 +42,14 @@
/**
* This listener is responsible of starting triggers when specific events occurs in the wiki.
*
* @since 9.6-RC1
* @since 9.6RC1
* @version $Id$
* @deprecated This component is only used in case of post-filtering events. We stopped supporting those.
*/
@Component
@Singleton
@Named(LiveNotificationEmailListener.NAME)
@Deprecated(since = "15.5RC1")
public class LiveNotificationEmailListener extends AbstractEventListener
{
/**
......
......@@ -42,9 +42,11 @@
*
* @since 9.6RC1
* @version $Id$
* @deprecated This component is only used in case of post-filtering events. We stopped supporting those.
*/
@Component(roles = LiveNotificationEmailManager.class)
@Singleton
@Deprecated(since = "15.5RC1")
public class LiveNotificationEmailManager implements Initializable
{
@Inject
......@@ -91,7 +93,6 @@ public void addEvent(Event event)
Iterator<QueueElement> it = queue.iterator();
while (it.hasNext()) {
QueueElement element = it.next();
// Compute the similarity between the event and the composite event in the map
int similarity = similarityCalculator.computeSimilarity(event, element.event.getEvents().get(0));
......
......@@ -46,9 +46,11 @@
*
* @since 9.6RC1
* @version $Id$
* @deprecated This component is only used in case of post-filtering events. We stopped supporting those.
*/
@Component(roles = LiveNotificationEmailSender.class)
@InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
@Deprecated(since = "15.5RC1")
public class LiveNotificationEmailSender
{
@Inject
......
......@@ -164,6 +164,7 @@ private void prepare(QueueEntry entry, Map<DocumentReference, CompositeEvent> ev
entry.entities.forEach(entity -> {
CompositeEvent composite = eventsToSend.get(entity);
// FIXME: This should use the grouping strategy
if (composite != null) {
// Compute the similarity between the event and the composite event in the map
int similarity = similarityCalculator.computeSimilarity(composite.getEvents().get(0), entry.event);
......
......@@ -4,6 +4,9 @@ org.xwiki.notifications.notifiers.internal.DefaultNotificationCacheManager
org.xwiki.notifications.notifiers.internal.DefaultNotificationDisplayer
org.xwiki.notifications.notifiers.internal.DefaultNotificationRenderer
org.xwiki.notifications.notifiers.internal.InternalHtmlNotificationRenderer
org.xwiki.notifications.notifiers.internal.email.grouping.DefaultNotificationEmailGroupingStrategy
org.xwiki.notifications.notifiers.internal.email.grouping.OneMailPerCompositeEmailGroupingStrategy
org.xwiki.notifications.notifiers.internal.email.grouping.SeparatedMentionEmailGroupingStrategy
org.xwiki.notifications.notifiers.internal.email.IntervalUsersManager
org.xwiki.notifications.notifiers.internal.email.IntervalUsersManagerInvalidator
org.xwiki.notifications.notifiers.internal.email.live.LiveNotificationEmailListener
......
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.internal.email.grouping;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.test.junit5.mockito.ComponentTest;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link DefaultNotificationEmailGroupingStrategy}.
*
* @version $Id$
* @since 15.5RC1
*/
@ComponentTest
class DefaultNotificationEmailGroupingStrategyTest
{
@InjectMockComponents
private DefaultNotificationEmailGroupingStrategy groupingStrategy;
@Test
void groupEventsPerMail() throws NotificationException
{
CompositeEvent event1 = mock(CompositeEvent.class, "event1");
CompositeEvent event2 = mock(CompositeEvent.class, "event2");
CompositeEvent event3 = mock(CompositeEvent.class, "event3");
CompositeEvent event4 = mock(CompositeEvent.class, "event4");
List<CompositeEvent> input = List.of(event1, event2, event3, event4);
assertEquals(List.of(input), this.groupingStrategy.groupEventsPerMail(input));
}
}
\ No newline at end of file
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.internal.email.grouping;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.test.junit5.mockito.ComponentTest;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link OneMailPerCompositeEmailGroupingStrategy}.
*
* @version $Id$
* @since 15.5RC1
*/
@ComponentTest
class OneMailPerCompositeEmailGroupingStrategyTest
{
@InjectMockComponents
private OneMailPerCompositeEmailGroupingStrategy groupingStrategy;
@Test
void groupEventsPerMail() throws NotificationException
{
CompositeEvent event1 = mock(CompositeEvent.class, "event1");
CompositeEvent event2 = mock(CompositeEvent.class, "event2");
CompositeEvent event3 = mock(CompositeEvent.class, "event3");
CompositeEvent event4 = mock(CompositeEvent.class, "event4");
List<CompositeEvent> input = List.of(event1, event2, event3, event4);
assertEquals(List.of(
List.of(event1),
List.of(event2),
List.of(event3),
List.of(event4)
), this.groupingStrategy.groupEventsPerMail(input));
}
}
\ No newline at end of file
/*
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.xwiki.notifications.notifiers.internal.email.grouping;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationException;
import org.xwiki.test.junit5.mockito.ComponentTest;
import org.xwiki.test.junit5.mockito.InjectMockComponents;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Tests for {@link SeparatedMentionEmailGroupingStrategy}.
*
* @version $Id$
* @since 15.5RC1
*/
@ComponentTest
class SeparatedMentionEmailGroupingStrategyTest
{
@InjectMockComponents
private SeparatedMentionEmailGroupingStrategy groupingStrategy;
@Test
void groupEventsPerMail() throws NotificationException
{
CompositeEvent event1 = mock(CompositeEvent.class, "event1");
CompositeEvent event2 = mock(CompositeEvent.class, "event2");
CompositeEvent event3 = mock(CompositeEvent.class, "event3");
CompositeEvent event4 = mock(CompositeEvent.class, "event4");
List<CompositeEvent> input = List.of(event1, event2, event3, event4);
assertEquals(List.of(input), this.groupingStrategy.groupEventsPerMail(input));
when(event1.getType()).thenReturn("update");
when(event2.getType()).thenReturn("mention");
when(event3.getType()).thenReturn("create");
when(event4.getType()).thenReturn("mention");
assertEquals(List.of(
List.of(event1, event3),
List.of(event2, event4)
), this.groupingStrategy.groupEventsPerMail(input));
when(event1.getType()).thenReturn("mention");
when(event2.getType()).thenReturn("mention");
when(event3.getType()).thenReturn("mention");
when(event4.getType()).thenReturn("mention");
assertEquals(List.of(input), this.groupingStrategy.groupEventsPerMail(input));
when(event1.getType()).thenReturn("update");
when(event2.getType()).thenReturn("create");
when(event3.getType()).thenReturn("delete");
when(event4.getType()).thenReturn("other");
assertEquals(List.of(input), this.groupingStrategy.groupEventsPerMail(input));
when(event1.getType()).thenReturn("update");
when(event2.getType()).thenReturn("create");
when(event3.getType()).thenReturn("delete");
when(event4.getType()).thenReturn("mention");
assertEquals(List.of(
List.of(event1, event2, event3),
List.of(event4)
), this.groupingStrategy.groupEventsPerMail(input));
}
}
\ No newline at end of file
......@@ -31,7 +31,7 @@
<name>XWiki Platform - Notifications - Notifiers - Default bridge</name>
<description>Default bridge to oldcore for the notifications notifiers API module.</description>
<properties>
<xwiki.jacoco.instructionRatio>0.32</xwiki.jacoco.instructionRatio>
<xwiki.jacoco.instructionRatio>0.33</xwiki.jacoco.instructionRatio>
<xwiki.extension.namespaces>{root}</xwiki.extension.namespaces>
<checkstyle.suppressions.location>${basedir}/src/checkstyle/checkstyle-suppressions.xml</checkstyle.suppressions.location>
</properties>
......
......@@ -37,8 +37,11 @@
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.xwiki.bridge.DocumentAccessBridge;
import org.xwiki.component.manager.ComponentLookupException;
import org.xwiki.component.manager.ComponentManager;
import org.xwiki.eventstream.EntityEvent;
import org.xwiki.eventstream.EventStore;
import org.xwiki.eventstream.internal.DefaultEntityEvent;
......@@ -53,7 +56,9 @@
import org.xwiki.model.reference.EntityReferenceSerializer;
import org.xwiki.model.reference.WikiReference;
import org.xwiki.notifications.CompositeEvent;
import org.xwiki.notifications.NotificationConfiguration;
import org.xwiki.notifications.NotificationException;
import org.xwiki.notifications.notifiers.email.NotificationEmailGroupingStrategy;
import org.xwiki.notifications.notifiers.email.NotificationEmailRenderer;
import com.xpn.xwiki.XWikiContext;
......@@ -126,6 +131,16 @@ public abstract class AbstractMimeMessageIterator implements Iterator<MimeMessag
@Inject
private Provider<XWikiContext> xcontextProvider;
@Inject
@Named("context")
private ComponentManager componentManager;
@Inject
private NotificationConfiguration notificationConfiguration;
@Inject
private NotificationEmailGroupingStrategy fallbackNotificationEmailGroupingStrategy;
private final MailListener listener = new VoidMailListener()
{
@Override
......@@ -153,6 +168,8 @@ public void onPrepareMessageError(ExtendedMimeMessage message, Exception e, Map<
private EntityReference templateReference;
private Iterator<List<CompositeEvent>> processingEvents = null;
private List<CompositeEvent> currentEvents = Collections.emptyList();
private DocumentReference currentUser;
......@@ -198,32 +215,59 @@ private void onPrepare(ExtendedMimeMessage message, boolean delete)
protected abstract List<CompositeEvent> retrieveCompositeEventList(DocumentReference user)
throws NotificationException;
private NotificationEmailGroupingStrategy getEmailGroupingStrategy()
{
NotificationEmailGroupingStrategy strategy = this.fallbackNotificationEmailGroupingStrategy;
String emailGroupingStrategyHint = this.notificationConfiguration.getEmailGroupingStrategyHint();
if (this.componentManager.hasComponent(NotificationEmailGroupingStrategy.class, emailGroupingStrategyHint)) {
try {
strategy = this.componentManager
.getInstance(NotificationEmailGroupingStrategy.class, emailGroupingStrategyHint);
} catch (ComponentLookupException e) {
this.logger.warn("Error while loading NotificationEmailGroupingStrategy with hint [{}]. " +
"Fallback on default strategy. Root cause: [{}]",
emailGroupingStrategyHint, ExceptionUtils.getRootCauseMessage(e));
this.logger.debug("Root cause of the error was: ", e);
}
} else {
this.logger.warn("Cannot find a NotificationEmailGroupingStrategy with hint [{}]. " +
"Fallback on default strategy.", emailGroupingStrategyHint);
}
return strategy;
}
/**
* Compute the message that will be sent to the next user in the iterator.
*/
protected void computeNext()
{
this.currentEvents = Collections.emptyList();
this.currentUserEmail = null;
while ((this.currentEvents.isEmpty() || this.currentUserEmail == null) && this.userIterator.hasNext()) {
this.currentUser = this.userIterator.next();
try {
this.currentUserEmail = new InternetAddress(getUserEmail(this.currentUser));
} catch (AddressException e) {
// The user has not written a valid email
continue;
}
try {
// TODO: in a next version, it will be important to paginate these results and to send several emails
// if there is too much content
this.currentEvents = retrieveCompositeEventList(this.currentUser);
} catch (NotificationException e) {
logger.error(ERROR_MESSAGE, this.currentUser, e);
if (this.processingEvents == null || !this.processingEvents.hasNext()) {
this.currentEvents = Collections.emptyList();
this.currentUserEmail = null;
while ((this.currentEvents.isEmpty() || this.currentUserEmail == null) && this.userIterator.hasNext()) {
this.currentUser = this.userIterator.next();
try {
this.currentUserEmail = new InternetAddress(getUserEmail(this.currentUser));
} catch (AddressException e) {
// The user has not written a valid email
continue;
}
try {
List<CompositeEvent> compositeEvents = retrieveCompositeEventList(this.currentUser);
if (!compositeEvents.isEmpty()) {
this.processingEvents =
getEmailGroupingStrategy().groupEventsPerMail(compositeEvents).iterator();
this.currentEvents = this.processingEvents.next();
}
} catch (NotificationException e) {
logger.error(ERROR_MESSAGE, this.currentUser, e);
}
}
this.currentUsedId = this.serializer.serialize(this.currentUser);
} else {
this.currentEvents = this.processingEvents.next();
}
this.currentUsedId = this.serializer.serialize(this.currentUser);
this.hasNext = this.currentUserEmail != null && !this.currentEvents.isEmpty();
}
......
......@@ -24,6 +24,7 @@
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Named;
import org.xwiki.component.annotation.Component;
import org.xwiki.component.annotation.InstantiationStrategy;
......@@ -37,6 +38,8 @@
import org.xwiki.notifications.sources.NotificationParameters;
import org.xwiki.notifications.sources.ParametrizedNotificationManager;
import org.xwiki.notifications.sources.internal.DefaultNotificationParametersFactory;
import org.xwiki.user.UserReference;
import org.xwiki.user.UserReferenceResolver;
/**
* Default implementation of {@link PeriodicMimeMessageIterator}.
......@@ -58,6 +61,10 @@ public class DefaultPeriodicMimeMessageIterator extends AbstractMimeMessageItera
@Inject
private GroupingEventManager groupingEventManager;
@Inject
@Named("document")
private UserReferenceResolver<DocumentReference> userReferenceResolver;
private Date lastTrigger;
@Override
......@@ -72,7 +79,6 @@ public void initialize(NotificationUserIterator userIterator, Map<String, Object
@Override
protected List<CompositeEvent> retrieveCompositeEventList(DocumentReference user) throws NotificationException
{
String serializedUser = this.serializer.serialize(user);
NotificationParameters notificationParameters = new NotificationParameters();
notificationParameters.user = user;
notificationParameters.format = NotificationFormat.EMAIL;
......@@ -80,8 +86,9 @@ protected List<CompositeEvent> retrieveCompositeEventList(DocumentReference user
notificationParameters.fromDate = this.lastTrigger;
notificationParameters.endDateIncluded = false;
notificationParametersFactory.useUserPreferences(notificationParameters);
UserReference userReference = this.userReferenceResolver.resolve(user);
List<Event> rawEvents = this.notificationManager.getRawEvents(notificationParameters);
return this.groupingEventManager.getCompositeEvents(rawEvents, serializedUser, NotificationFormat.EMAIL.name());
return this.groupingEventManager.getCompositeEvents(rawEvents, userReference, NotificationFormat.EMAIL.name());
}
}
......@@ -44,9 +44,11 @@
*
* @since 9.10RC1
* @version $Id$
* @deprecated This component is only used in case of post-filtering events. We stopped supporting those.
*/
@Component
@InstantiationStrategy(ComponentInstantiationStrategy.PER_LOOKUP)
@Deprecated(since = "15.5RC1")
public class DefaultLiveMimeMessageIterator extends AbstractMimeMessageIterator
implements LiveMimeMessageIterator
{
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment