java/com.sap.sailing.server.test/src/com/sap/sailing/server/test/LeagueEventHierarchyOwnershipChangeTest.java
... ...
@@ -2,6 +2,7 @@ package com.sap.sailing.server.test;
2 2
3 3
import static org.junit.jupiter.api.Assertions.assertNull;
4 4
import static org.junit.jupiter.api.Assertions.assertSame;
5
+import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
5 6
6 7
import java.util.Collections;
7 8
import java.util.Locale;
... ...
@@ -142,6 +143,48 @@ public class LeagueEventHierarchyOwnershipChangeTest {
142 143
final OwnershipAnnotation eventOwnership = securityService.getOwnership(event.getIdentifier());
143 144
assertSame(eventOwnership.getAnnotation().getTenantOwner(), lg2Ownership.getAnnotation().getTenantOwner());
144 145
}
146
+
147
+ @Test
148
+ public void testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminatesWithNewCourseArea() {
149
+ final CourseArea otherCourseArea = new CourseAreaImpl("Other", UUID.randomUUID(), /* centerPosition */ null, /* radius */ null);
150
+ testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminates(otherCourseArea);
151
+ }
152
+
153
+ @Test
154
+ public void testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminatesWithSharedCourseArea() {
155
+ testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminates(defaultCourseArea);
156
+ }
157
+
158
+ private void testCyclicLeagueHierarchyOwnershipChangeStartingAtEventTerminates(CourseArea courseAreaForSharedLeaderboard) {
159
+ final Event otherEvent = service.addEvent("Test2", "Test Event 2", TimePoint.now(), TimePoint.now().plus(Duration.ONE_WEEK), "There",
160
+ /* isPublic */ true, UUID.randomUUID());
161
+ otherEvent.getVenue().addCourseArea(courseAreaForSharedLeaderboard);
162
+ try {
163
+ final LeaderboardGroup sharedLeaderboardGroup = new LeaderboardGroupImpl("LG-shared", "LGDesc-shared",
164
+ "The shared LG", /* displayGroupsInReverseOrder */ false, Collections.emptyList());
165
+ final Leaderboard sharedOverallLeaderboard = new LeaderboardGroupMetaLeaderboard(sharedLeaderboardGroup, new LowPoint(),
166
+ new ThresholdBasedResultDiscardingRuleImpl(new int[0]));
167
+ sharedLeaderboardGroup.setOverallLeaderboard(sharedOverallLeaderboard);
168
+ sharedLeaderboardGroup.addLeaderboard(new FlexibleLeaderboardImpl("SharedFlexibleLeaderboard",
169
+ new ThresholdBasedResultDiscardingRuleImpl(new int[0]), new LowPoint(), defaultCourseArea));
170
+ event.addLeaderboardGroup(sharedLeaderboardGroup);
171
+ otherEvent.addLeaderboardGroup(sharedLeaderboardGroup);
172
+ assertTimeoutPreemptively(java.time.Duration.ofSeconds(5), () -> SailingHierarchyOwnershipUpdater
173
+ .createOwnershipUpdater(/* createNewGroup */ true, /* existingGroupIdOrNull */ null,
174
+ THE_NEW_OWNING_GROUP_NAME, /* migrateCompetitors */ true, /* migrateBoats */ true,
175
+ /* copyMembersAndRoles */ true, service)
176
+ .updateGroupOwnershipForEventHierarchy(event));
177
+ final OwnershipAnnotation eventOwnership = securityService.getOwnership(event.getIdentifier());
178
+ final OwnershipAnnotation otherEventOwnership = securityService.getOwnership(otherEvent.getIdentifier());
179
+ assertSame(eventOwnership.getAnnotation().getTenantOwner(), otherEventOwnership.getAnnotation().getTenantOwner());
180
+ final OwnershipAnnotation overallLeaderboardOwnership = securityService.getOwnership(overallLeaderboard.getIdentifier());
181
+ assertSame(eventOwnership.getAnnotation().getTenantOwner(), overallLeaderboardOwnership.getAnnotation().getTenantOwner());
182
+ final OwnershipAnnotation sharedOverallLeaderboardOwnership = securityService.getOwnership(sharedOverallLeaderboard.getIdentifier());
183
+ assertSame(eventOwnership.getAnnotation().getTenantOwner(), sharedOverallLeaderboardOwnership.getAnnotation().getTenantOwner());
184
+ } finally {
185
+ service.removeEvent(otherEvent.getId());
186
+ }
187
+ }
145 188
146 189
@AfterEach
147 190
public void tearDown() {
java/com.sap.sailing.server/src/com/sap/sailing/server/hierarchy/SailingHierarchyOwnershipUpdater.java
... ...
@@ -65,6 +65,9 @@ public class SailingHierarchyOwnershipUpdater {
65 65
private final boolean updateCompetitors;
66 66
private final boolean updateBoats;
67 67
private final Set<QualifiedObjectIdentifier> objectsToUpdateOwnershipsFor;
68
+ private final Set<Event> visitedEvents;
69
+ private final Set<LeaderboardGroup> visitedLeaderboardGroups;
70
+ private final Set<Leaderboard> visitedLeaderboards;
68 71
69 72
private SailingHierarchyOwnershipUpdater(final RacingEventService service, SecurityService securityService,
70 73
final GroupOwnerUpdateStrategy updateStrategy, final boolean updateCompetitors, final boolean updateBoats) {
... ...
@@ -74,6 +77,9 @@ public class SailingHierarchyOwnershipUpdater {
74 77
this.updateCompetitors = updateCompetitors;
75 78
this.updateBoats = updateBoats;
76 79
objectsToUpdateOwnershipsFor = new HashSet<>();
80
+ visitedEvents = new HashSet<>();
81
+ visitedLeaderboardGroups = new HashSet<>();
82
+ visitedLeaderboards = new HashSet<>();
77 83
}
78 84
79 85
public void updateGroupOwnershipForEventHierarchy(Event event) {
... ...
@@ -82,48 +88,48 @@ public class SailingHierarchyOwnershipUpdater {
82 88
}
83 89
84 90
private void updateGroupOwnershipForEventHierarchyInternal(Event event) {
85
- updateGroupOwner(event.getIdentifier());
86
- SailingHierarchyWalker.walkFromEvent(event, /* includeLeaderboardGroupsWithOverallLeaderboard */ false,
87
- new EventHierarchyVisitor() {
88
- @Override
89
- public void visit(Leaderboard leaderboard, Set<LeaderboardGroup> leaderboardGroups) {
90
- updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard);
91
- }
92
-
93
- @Override
94
- public void visit(LeaderboardGroup leaderboardGroup) {
95
- // leaderboard groups with overall leaderboard may be visited if all their leaderboards belong
96
- // to the "event", but the process won't recurse back into "event" as we pass it explicitly as
97
- // an event not to visit
98
- updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup, /* exclude */ event);
99
- }
100
- });
91
+ if (visitedEvents.add(event)) {
92
+ updateGroupOwner(event.getIdentifier());
93
+ SailingHierarchyWalker.walkFromEvent(event, /* includeLeaderboardGroupsWithOverallLeaderboard */ false,
94
+ new EventHierarchyVisitor() {
95
+ @Override
96
+ public void visit(Leaderboard leaderboard, Set<LeaderboardGroup> leaderboardGroups) {
97
+ updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard);
98
+ }
99
+
100
+ @Override
101
+ public void visit(LeaderboardGroup leaderboardGroup) {
102
+ // leaderboard groups with overall leaderboard may be visited if all their leaderboards belong
103
+ // to the "event", but the process won't recurse back into "event" as we pass it explicitly as
104
+ // an event not to visit
105
+ updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup);
106
+ }
107
+ });
108
+ }
101 109
}
102 110
103 111
public void updateGroupOwnershipForLeaderboardGroupHierarchy(LeaderboardGroup leaderboardGroup) {
104
- updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup, /* eventToExclude */ null);
112
+ updateGroupOwnershipForLeaderboardGroupHierarchyInternal(leaderboardGroup);
105 113
commitChanges();
106 114
}
107 115
108
- private void updateGroupOwnershipForLeaderboardGroupHierarchyInternal(LeaderboardGroup leaderboardGroup, Event eventToExclude) {
109
- updateGroupOwner(leaderboardGroup.getIdentifier());
110
- SailingHierarchyWalker.walkFromLeaderboardGroup(service, leaderboardGroup,
111
- /* includeEventsIfLeaderboardGroupHasOverallLeaderboard */ true,
112
- new LeaderboardGroupHierarchyVisitor() {
113
- @Override
114
- public void visit(Leaderboard leaderboard) {
115
- updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard);
116
- }
117
-
118
- @Override
119
- public void visit(Event event) {
120
- if (event != eventToExclude) {
121
- // Only events of LeaderboardGroups with overall leaderboard are visited -> no infinite
122
- // recursion occurs
116
+ private void updateGroupOwnershipForLeaderboardGroupHierarchyInternal(LeaderboardGroup leaderboardGroup) {
117
+ if (visitedLeaderboardGroups.add(leaderboardGroup)) {
118
+ updateGroupOwner(leaderboardGroup.getIdentifier());
119
+ SailingHierarchyWalker.walkFromLeaderboardGroup(service, leaderboardGroup,
120
+ /* includeEventsIfLeaderboardGroupHasOverallLeaderboard */ true,
121
+ new LeaderboardGroupHierarchyVisitor() {
122
+ @Override
123
+ public void visit(Leaderboard leaderboard) {
124
+ updateGroupOwnershipForLeaderboardHierarchyInternal(leaderboard);
125
+ }
126
+
127
+ @Override
128
+ public void visit(Event event) {
123 129
updateGroupOwnershipForEventHierarchyInternal(event);
124 130
}
125
- }
126
- });
131
+ });
132
+ }
127 133
}
128 134
129 135
public void updateGroupOwnershipForLeaderboardHierarchy(Leaderboard leaderboard) {
... ...
@@ -132,31 +138,33 @@ public class SailingHierarchyOwnershipUpdater {
132 138
}
133 139
134 140
private void updateGroupOwnershipForLeaderboardHierarchyInternal(Leaderboard leaderboard) {
135
- updateGroupOwner(leaderboard.getIdentifier());
136
- if (leaderboard instanceof RegattaLeaderboard) {
137
- RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard;
138
- updateGroupOwner(regattaLeaderboard.getRegatta().getIdentifier());
139
- }
140
- SailingHierarchyWalker.walkFromLeaderboard(leaderboard, new LeaderboardHierarchyVisitor() {
141
- @Override
142
- public void visit(TrackedRace race) {
143
- updateGroupOwner(race.getIdentifier());
141
+ if (visitedLeaderboards.add(leaderboard)) {
142
+ updateGroupOwner(leaderboard.getIdentifier());
143
+ if (leaderboard instanceof RegattaLeaderboard) {
144
+ RegattaLeaderboard regattaLeaderboard = (RegattaLeaderboard) leaderboard;
145
+ updateGroupOwner(regattaLeaderboard.getRegatta().getIdentifier());
144 146
}
145
-
146
- @Override
147
- public void visit(Boat boat) {
148
- if (updateBoats) {
149
- updateGroupOwner(boat.getIdentifier());
147
+ SailingHierarchyWalker.walkFromLeaderboard(leaderboard, new LeaderboardHierarchyVisitor() {
148
+ @Override
149
+ public void visit(TrackedRace race) {
150
+ updateGroupOwner(race.getIdentifier());
150 151
}
151
- }
152
-
153
- @Override
154
- public void visit(Competitor competitor) {
155
- if (updateCompetitors) {
156
- updateGroupOwner(competitor.getIdentifier());
152
+
153
+ @Override
154
+ public void visit(Boat boat) {
155
+ if (updateBoats) {
156
+ updateGroupOwner(boat.getIdentifier());
157
+ }
157 158
}
158
- }
159
- });
159
+
160
+ @Override
161
+ public void visit(Competitor competitor) {
162
+ if (updateCompetitors) {
163
+ updateGroupOwner(competitor.getIdentifier());
164
+ }
165
+ }
166
+ });
167
+ }
160 168
}
161 169
162 170
private void updateGroupOwner(QualifiedObjectIdentifier id) {