Skip to content

Commit 91e09ed

Browse files
authored
fix: (2.39) notification trigger cause server halt [DHIS2-19452] (#20576)
1 parent a82ca26 commit 91e09ed

File tree

7 files changed

+133
-145
lines changed

7 files changed

+133
-145
lines changed

dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/notification/template/snapshot/NotificationTemplateMapper.java

Lines changed: 10 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,16 @@
2727
*/
2828
package org.hisp.dhis.program.notification.template.snapshot;
2929

30-
import static java.util.Collections.singleton;
31-
32-
import com.google.common.collect.ImmutableList;
3330
import java.util.Collection;
3431
import java.util.Collections;
3532
import java.util.HashSet;
33+
import java.util.List;
3634
import java.util.Optional;
3735
import java.util.Set;
3836
import java.util.function.Consumer;
3937
import java.util.function.Supplier;
4038
import org.hisp.dhis.common.BaseIdentifiableObject;
4139
import org.hisp.dhis.dataelement.DataElement;
42-
import org.hisp.dhis.organisationunit.OrganisationUnit;
4340
import org.hisp.dhis.program.notification.ProgramNotificationTemplate;
4441
import org.hisp.dhis.trackedentity.TrackedEntityAttribute;
4542
import org.hisp.dhis.user.User;
@@ -54,7 +51,7 @@ public ProgramNotificationTemplate toProgramNotificationTemplate(
5451
return toBaseIdentifiableObject(
5552
templateSnapshot,
5653
ProgramNotificationTemplate::new,
57-
ImmutableList.of(
54+
List.of(
5855
t -> t.setMessageTemplate(templateSnapshot.getMessageTemplate()),
5956
t -> t.setNotificationRecipient(templateSnapshot.getNotificationRecipient()),
6057
t ->
@@ -85,7 +82,7 @@ public ProgramNotificationTemplateSnapshot toProgramNotificationTemplateSnapshot
8582
return toIdentifiableObjectSnapshot(
8683
template,
8784
ProgramNotificationTemplateSnapshot::new,
88-
ImmutableList.of(
85+
List.of(
8986
t -> t.setMessageTemplate(template.getMessageTemplate()),
9087
t -> t.setNotificationRecipient(template.getNotificationRecipient()),
9188
t ->
@@ -115,14 +112,14 @@ private UserGroup toUserGroup(UserGroupSnapshot userGroupSnapshot) {
115112
return toBaseIdentifiableObject(
116113
userGroupSnapshot,
117114
UserGroup::new,
118-
ImmutableList.of(ug -> ug.setMembers(toUsers(userGroupSnapshot.getMembers()))));
115+
List.of(ug -> ug.setMembers(toUsers(userGroupSnapshot.getMembers()))));
119116
}
120117

121118
private UserGroupSnapshot toUserGroupSnapshot(UserGroup userGroup) {
122119
return toIdentifiableObjectSnapshot(
123120
userGroup,
124121
UserGroupSnapshot::new,
125-
ImmutableList.of(ug -> ug.setMembers(toUserSnapshot(userGroup.getMembers(), 0))));
122+
List.of(ug -> ug.setMembers(toUserSnapshot(userGroup.getMembers()))));
126123
}
127124

128125
private Set<User> toUsers(Set<UserSnapshot> userSnapshots) {
@@ -133,74 +130,32 @@ private Set<User> toUsers(Set<UserSnapshot> userSnapshots) {
133130
toBaseIdentifiableObject(
134131
userSnapshot,
135132
User::new,
136-
ImmutableList.of(
133+
List.of(
137134
u -> u.setName(userSnapshot.getName()),
138135
u -> u.setUsername(userSnapshot.getUsername()),
139136
u -> u.setEmail(userSnapshot.getEmail()),
140-
u -> u.setPhoneNumber(userSnapshot.getPhoneNumber()),
141-
u ->
142-
u.setOrganisationUnits(
143-
singleton(toOrganisationUnit(userSnapshot.getOrganisationUnit()))))));
137+
u -> u.setPhoneNumber(userSnapshot.getPhoneNumber()))));
144138
}
145139
return users;
146140
}
147141

148-
private Set<UserSnapshot> toUserSnapshot(Set<User> users, int ouLevel) {
142+
private Set<UserSnapshot> toUserSnapshot(Set<User> users) {
149143
Set<UserSnapshot> userSnapshots = new HashSet<>();
150144

151145
for (User user : users) {
152146
userSnapshots.add(
153147
toIdentifiableObjectSnapshot(
154148
user,
155149
UserSnapshot::new,
156-
ImmutableList.of(
150+
List.of(
157151
u -> u.setName(user.getName()),
158152
u -> u.setUsername(user.getUsername()),
159153
u -> u.setEmail(user.getEmail()),
160-
u -> u.setPhoneNumber(user.getPhoneNumber()),
161-
u ->
162-
u.setOrganisationUnit(
163-
toOrganisationUnitSnapshot(user.getOrganisationUnit(), ouLevel)))));
154+
u -> u.setPhoneNumber(user.getPhoneNumber()))));
164155
}
165156
return userSnapshots;
166157
}
167158

168-
private OrganisationUnit toOrganisationUnit(OrganisationUnitSnapshot organisationUnitSnapshot) {
169-
return toBaseIdentifiableObject(
170-
organisationUnitSnapshot,
171-
OrganisationUnit::new,
172-
ImmutableList.of(
173-
ou -> ou.setName(organisationUnitSnapshot.getName()),
174-
ou -> ou.setDescription(organisationUnitSnapshot.getDescription()),
175-
ou -> ou.setShortName(organisationUnitSnapshot.getShortName()),
176-
ou ->
177-
ou.setParent(
178-
organisationUnitSnapshot.getParent() != null
179-
? toOrganisationUnit(organisationUnitSnapshot.getParent())
180-
: null),
181-
ou -> ou.setUsers(toUsers(organisationUnitSnapshot.getUsers()))));
182-
}
183-
184-
private OrganisationUnitSnapshot toOrganisationUnitSnapshot(
185-
OrganisationUnit organisationUnit, int level) {
186-
if (level < 2) {
187-
return toIdentifiableObjectSnapshot(
188-
organisationUnit,
189-
OrganisationUnitSnapshot::new,
190-
ImmutableList.of(
191-
ou -> ou.setName(organisationUnit.getName()),
192-
ou -> ou.setDescription(organisationUnit.getDescription()),
193-
ou -> ou.setShortName(organisationUnit.getShortName()),
194-
ou ->
195-
ou.setParent(
196-
organisationUnit.getParent() != null
197-
? toOrganisationUnitSnapshot(organisationUnit.getParent(), level + 1)
198-
: null),
199-
ou -> ou.setUsers(toUserSnapshot(organisationUnit.getUsers(), level + 1))));
200-
}
201-
return null;
202-
}
203-
204159
private <T extends IdentifiableObjectSnapshot> T toIdentifiableObjectSnapshot(
205160
BaseIdentifiableObject from,
206161
Supplier<T> instanceSupplier,

dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/notification/template/snapshot/OrganisationUnitSnapshot.java

Lines changed: 0 additions & 46 deletions
This file was deleted.

dhis-2/dhis-api/src/main/java/org/hisp/dhis/program/notification/template/snapshot/UserSnapshot.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,4 @@ public class UserSnapshot extends IdentifiableObjectSnapshot {
4040
private String email;
4141

4242
private String phoneNumber;
43-
44-
private OrganisationUnitSnapshot organisationUnit;
4543
}

dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/notification/DefaultProgramNotificationService.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@
7575
import org.hisp.dhis.trackedentityattributevalue.TrackedEntityAttributeValue;
7676
import org.hisp.dhis.user.User;
7777
import org.hisp.dhis.user.UserGroup;
78-
import org.hisp.dhis.util.DateUtils;
7978
import org.springframework.stereotype.Service;
8079
import org.springframework.transaction.annotation.Transactional;
8180

@@ -89,9 +88,7 @@ public class DefaultProgramNotificationService implements ProgramNotificationSer
8988
private static final Predicate<NotificationInstanceWithTemplate> IS_SCHEDULED_BY_PROGRAM_RULE =
9089
(iwt) ->
9190
Objects.nonNull(iwt.getProgramNotificationInstance())
92-
&& PROGRAM_RULE.equals(iwt.getProgramNotificationTemplate().getNotificationTrigger())
93-
&& iwt.getProgramNotificationInstance().getScheduledAt() != null
94-
&& DateUtils.isToday(iwt.getProgramNotificationInstance().getScheduledAt());
91+
&& PROGRAM_RULE.equals(iwt.getProgramNotificationTemplate().getNotificationTrigger());
9592

9693
// -------------------------------------------------------------------------
9794
// Dependencies
@@ -107,6 +104,8 @@ public class DefaultProgramNotificationService implements ProgramNotificationSer
107104

108105
@NonNull private final IdentifiableObjectManager identifiableObjectManager;
109106

107+
@NonNull private final ProgramNotificationInstanceService notificationInstanceService;
108+
110109
@NonNull private final NotificationMessageRenderer<ProgramInstance> programNotificationRenderer;
111110

112111
@NonNull
@@ -148,11 +147,15 @@ public void sendScheduledNotificationsForDay(Date notificationDate, JobProgress
148147
public void sendScheduledNotifications(JobProgress progress) {
149148
progress.startingStage(
150149
"Fetching and filtering ProgramStageNotification messages scheduled by program rules");
150+
151+
ProgramNotificationInstanceParam param =
152+
ProgramNotificationInstanceParam.builder().scheduledAt(new Date()).build();
153+
151154
List<NotificationInstanceWithTemplate> instancesWithTemplates =
152155
progress.runStage(
153156
List.of(),
154157
() ->
155-
identifiableObjectManager.getAll(ProgramNotificationInstance.class).stream()
158+
notificationInstanceService.getProgramNotificationInstances(param).stream()
156159
.map(this::withTemplate)
157160
.filter(this::hasTemplate)
158161
.filter(IS_SCHEDULED_BY_PROGRAM_RULE)

dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/program/notification/HibernateProgramNotificationInstanceStore.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,18 @@
2727
*/
2828
package org.hisp.dhis.program.notification;
2929

30+
import java.time.Instant;
31+
import java.time.LocalDate;
32+
import java.time.ZoneId;
33+
import java.time.ZonedDateTime;
3034
import java.util.ArrayList;
35+
import java.util.Date;
3136
import java.util.List;
3237
import java.util.function.Function;
3338
import javax.persistence.criteria.CriteriaBuilder;
3439
import javax.persistence.criteria.Predicate;
3540
import javax.persistence.criteria.Root;
41+
import org.apache.commons.lang3.tuple.Pair;
3642
import org.hibernate.SessionFactory;
3743
import org.hisp.dhis.common.hibernate.HibernateIdentifiableObjectStore;
3844
import org.hisp.dhis.hibernate.JpaQueryParameters;
@@ -118,9 +124,30 @@ private List<Function<Root<ProgramNotificationInstance>, Predicate>> getPredicat
118124
}
119125

120126
if (params.hasScheduledAt()) {
121-
predicates.add(root -> builder.equal(root.get("scheduledAt"), params.getScheduledAt()));
127+
Pair<Date, Date> scheduledAt = getStartAndEndOfDay(params.getScheduledAt());
128+
129+
predicates.add(
130+
root ->
131+
builder.and(
132+
builder.greaterThanOrEqualTo(root.get("scheduledAt"), scheduledAt.getLeft()),
133+
builder.lessThan(root.get("scheduledAt"), scheduledAt.getRight())));
122134
}
123135

124136
return predicates;
125137
}
138+
139+
public Pair<Date, Date> getStartAndEndOfDay(Date scheduledAt) {
140+
ZoneId zoneId = ZoneId.systemDefault();
141+
Instant instant = scheduledAt.toInstant();
142+
LocalDate localDate = instant.atZone(zoneId).toLocalDate();
143+
144+
ZonedDateTime startOfDay = localDate.atStartOfDay(zoneId);
145+
146+
ZonedDateTime startOfNextDay = localDate.plusDays(1).atStartOfDay(zoneId);
147+
148+
Date start = Date.from(startOfDay.toInstant());
149+
Date end = Date.from(startOfNextDay.toInstant());
150+
151+
return Pair.of(start, end);
152+
}
126153
}

dhis-2/dhis-services/dhis-service-core/src/test/java/org/hisp/dhis/program/notification/ProgramNotificationServiceTest.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ class ProgramNotificationServiceTest extends DhisConvenienceTest {
120120

121121
@Mock private ProgramNotificationTemplateService notificationTemplateService;
122122

123+
@Mock private ProgramNotificationInstanceService notificationInstanceService;
124+
123125
private NotificationTemplateMapper notificationTemplateMapper = new NotificationTemplateMapper();
124126

125127
private DefaultProgramNotificationService programNotificationService;
@@ -197,6 +199,7 @@ public void initTest() {
197199
this.programInstanceStore,
198200
this.programStageInstanceStore,
199201
this.manager,
202+
this.notificationInstanceService,
200203
this.programNotificationRenderer,
201204
this.programStageNotificationRenderer,
202205
notificationTemplateService,
@@ -658,13 +661,13 @@ void testScheduledNotifications() {
658661
return new BatchResponseStatus(Collections.emptyList());
659662
});
660663

661-
when(manager.getAll(ProgramNotificationInstance.class))
662-
.thenReturn(Collections.singletonList(programNotificationInstaceForToday));
663-
664664
when(programNotificationRenderer.render(
665665
any(ProgramInstance.class), any(NotificationTemplate.class)))
666666
.thenReturn(notificationMessage);
667667

668+
when(notificationInstanceService.getProgramNotificationInstances(any()))
669+
.thenReturn(List.of(programNotificationInstaceForToday));
670+
668671
programNotificationService.sendScheduledNotifications(NoopJobProgress.INSTANCE);
669672

670673
assertEquals(1, sentProgramMessages.size());

0 commit comments

Comments
 (0)