diff --git a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharedsailingdata/SharedSailingData.java b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharedsailingdata/SharedSailingData.java index 9d158913c88..04203962ad8 100644 --- a/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharedsailingdata/SharedSailingData.java +++ b/java/com.sap.sailing.domain/src/com/sap/sailing/domain/sharedsailingdata/SharedSailingData.java @@ -61,11 +61,18 @@ public interface SharedSailingData { CourseTemplate getCourseTemplateById(UUID id); /** - * Records the fact that the {@code markProperties} were used to configure a mark that takes the role defined by the + * Records the fact that the {@code markProperties} were used to configure a mark based on a * {@code markTemplate}. Keeps the {@link MillisecondsTimePoint#now() current time} of this call which will be * returned for {@code markTemplate} when invoking {@link #getUsedMarkProperties(MarkTemplate)}. */ void recordUsage(MarkTemplate markTemplate, MarkProperties markProperties); + + /** + * Records the fact that the {@code markProperties} were used to configure a mark that takes the given role name. + * Keeps the {@link MillisecondsTimePoint#now() current time} of this call which will be returned for the role name + * when invoking {@link #getUsedMarkProperties(String)}. + */ + void recordUsage(MarkProperties markProperties, String roleName); /** * Returns the time points when {@link MarkProperties} objects were {@link #recordUsage(MarkTemplate, MarkProperties) last used} @@ -73,6 +80,12 @@ public interface SharedSailingData { */ Map getUsedMarkProperties(MarkTemplate markTemplate); + /** + * Returns the time points when {@link MarkProperties} objects were {@link #recordUsage(MarkProperties, String) last used} + * for the role name passed in the {@code roleName} parameter. + */ + Map getUsedMarkProperties(String roleName); + void deleteMarkProperties(MarkProperties markProperties); void deleteCourseTemplate(CourseTemplate courseTemplate); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/CourseAndMarkConfigurationFactoryImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/CourseAndMarkConfigurationFactoryImpl.java index a28fdd57e24..8d3150b8ebc 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/CourseAndMarkConfigurationFactoryImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/CourseAndMarkConfigurationFactoryImpl.java @@ -201,18 +201,6 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi .createMarkTemplate(markConfiguration.getEffectiveProperties()); } if (markConfiguration instanceof RegattaMarkConfiguration) { - final Mark mark = ((RegattaMarkConfiguration) markConfiguration).getMark(); - final UUID markPropertiesIdOrNull = mark.getOriginatingMarkPropertiesIdOrNull(); - try { - final MarkProperties markPropertiesOrNull = markPropertiesIdOrNull == null ? null - : sharedSailingData.getMarkPropertiesById(markPropertiesIdOrNull); - if (markPropertiesOrNull != null) { - sharedSailingData.recordUsage(effectiveMarkTemplate, markPropertiesOrNull); - } - } catch (Exception e) { - log.log(Level.WARNING, "Could not record usage for mark properties " + markPropertiesIdOrNull - + " an mark template " + effectiveMarkTemplate.getId(), e); - } // The configuration is used as is. We can't enrich the Mark with the newly created MarkTemplate. // In the UI, the regatta Mark still needs to be selected to ensure that all connections to regatta // Marks are unchanged when saving the course to a race afterwards. @@ -225,12 +213,10 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi effectiveConfiguration = new MarkPropertiesBasedMarkConfigurationImpl(markProperties, effectiveMarkTemplate, markConfiguration.getOptionalPositioning(), getPositioningIfAvailable(markProperties), /* storeToInventory */ false); - sharedSailingData.recordUsage(effectiveMarkTemplate, markProperties); } else if (markConfiguration instanceof FreestyleMarkConfiguration) { final MarkProperties markPropertiesOrNull = ((FreestyleMarkConfiguration) markConfiguration) .getOptionalMarkProperties(); if (markPropertiesOrNull != null) { - sharedSailingData.recordUsage(effectiveMarkTemplate, markPropertiesOrNull); if (markPropertiesOrNull.hasEqualAppeareanceWith(effectiveMarkTemplate)) { effectiveConfiguration = new MarkPropertiesBasedMarkConfigurationImpl(markPropertiesOrNull, effectiveMarkTemplate, markConfiguration.getOptionalPositioning(), getPositioningIfAvailable(markPropertiesOrNull), @@ -256,11 +242,11 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi } final MarkPairTemplateFactory markPairTemplateFactory = new MarkPairTemplateFactory(); - // TODO record usages for MarkProperties by role name final CourseConfigurationToCourseConfigurationMapper waypointConfigurationMapper = new CourseConfigurationToCourseConfigurationMapper( courseConfigurationAfterInventory.getWaypoints(), courseConfigurationAfterInventory.getAssociatedRoles(), marksConfigurationsMapping); + recordUsagesForMarkProperties(waypointConfigurationMapper.effectiveWaypoints, waypointConfigurationMapper.allAssociatedRoles); final CourseSequenceReplacementMapper waypointTemplateMapper = new CourseSequenceReplacementMapper( courseConfigurationAfterInventory.getWaypoints(), courseConfigurationAfterInventory.getAssociatedRoles(), @@ -288,6 +274,59 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi courseConfigurationAfterInventory.getNumberOfLaps(), courseConfigurationAfterInventory.getName()); } + + private void recordUsagesForMarkProperties(Iterable waypoints, + Map associatedRoles) { + for (MarkConfiguration markConfiguration : getAllMarkConfigurations(waypoints)) { + final MarkProperties markProperties = getAssociatedMarkPropertiesIfAvailable(markConfiguration); + if (markProperties != null) { + final String roleName = getExplicitOrImplicitRoleName(associatedRoles, markConfiguration); + try { + sharedSailingData.recordUsage(markProperties, roleName); + } catch (Exception e) { + log.log(Level.WARNING, + "Could not record usage for mark properties " + markProperties + " and role " + roleName, + e); + } + final MarkTemplate markTemplateOrNull = markConfiguration.getOptionalMarkTemplate(); + if (markTemplateOrNull != null) { + try { + sharedSailingData.recordUsage(markTemplateOrNull, markProperties); + } catch (Exception e) { + log.log(Level.WARNING, "Could not record usage for mark properties " + markProperties + + " and mark template " + markTemplateOrNull, e); + } + } + } + } + } + + private String getExplicitOrImplicitRoleName(Map associatedRoles, MarkConfiguration markConfiguration) { + String effectiveRole = associatedRoles.get(markConfiguration); + if (effectiveRole == null) { + markConfiguration.getEffectiveProperties().getName(); + } + return effectiveRole; + } + + private Iterable getAllMarkConfigurations(Iterable waypoints) { + final Set result = new HashSet<>(); + for (WaypointWithMarkConfiguration waypoint : waypoints) { + Util.addAll(waypoint.getControlPoint().getMarkConfigurations(), result); + } + return result; + } + + private MarkProperties getAssociatedMarkPropertiesIfAvailable(MarkConfiguration markConfiguration) { + if (markConfiguration instanceof MarkPropertiesBasedMarkConfiguration) { + return ((MarkPropertiesBasedMarkConfiguration) markConfiguration).getMarkProperties(); + } else if (markConfiguration instanceof RegattaMarkConfiguration) { + return ((RegattaMarkConfiguration) markConfiguration).getOptionalMarkProperties(); + } else if (markConfiguration instanceof FreestyleMarkConfiguration) { + return ((FreestyleMarkConfiguration) markConfiguration).getOptionalMarkProperties(); + } + return null; + } private void savePositioningToMark(Regatta regatta, Mark mark, Positioning optionalExplicitPositioning, MarkProperties optionalAssociatedMarkProperties, TimePoint timePointForDefinitionOfMarksAndDeviceMappings, @@ -351,6 +390,7 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi final CourseConfiguration courseConfiguration, TimePoint timePointForDefinitionOfMarksAndDeviceMappings, AbstractLogEventAuthor author) { final CourseConfiguration courseConfigurationAfterInventory = handleSaveToInventory(courseConfiguration); + recordUsagesForMarkProperties(courseConfiguration.getWaypoints(), courseConfiguration.getAssociatedRoles()); final Map marksByMarkConfigurations = new HashMap<>(); final RegattaLog regattaLog = regatta.getRegattaLog(); @@ -416,7 +456,6 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi }; courseSequenceMapper.effectiveWaypoints.forEach(wp -> course.addWaypoint(Util.size(course.getWaypoints()), wp)); courseSequenceMapper.explicitAssociatedRoles.forEach(course::addRoleMapping); - // TODO record usages for MarkProperties by role name return course; } @@ -1001,7 +1040,7 @@ public class CourseAndMarkConfigurationFactoryImpl implements CourseAndMarkConfi throw new IllegalStateException("Non declared mark found in waypoint sequence"); } // If an explicit role mapping isn't given -> default to the mark's name - allAssociatedRoles.computeIfAbsent(mark, m -> markConfiguration.getEffectiveProperties().getName()); + allAssociatedRoles.computeIfAbsent(mark, m -> getExplicitOrImplicitRoleName(existingRoleMapping, markConfiguration)); return mark; } diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ReplicatingSharedSailingData.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ReplicatingSharedSailingData.java index b7179c3b833..c515e1fe4c4 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ReplicatingSharedSailingData.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/ReplicatingSharedSailingData.java @@ -40,6 +40,8 @@ public interface ReplicatingSharedSailingData extends SharedSailingData, Void internalDeleteCourseTemplate(UUID courseTemplateUUID); Void internalRecordUsage(UUID markTemplateId, UUID markPropertiesId); + + Void internalRecordUsage(UUID markPropertiesId, String roleName); Void internalUpdateCourseTemplate(UUID uuid, String name, URL optionalImageURL, ArrayList tags); diff --git a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/SharedSailingDataImpl.java b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/SharedSailingDataImpl.java index 04e4feb725a..813c0d38477 100644 --- a/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/SharedSailingDataImpl.java +++ b/java/com.sap.sailing.server/src/com/sap/sailing/server/impl/SharedSailingDataImpl.java @@ -364,6 +364,22 @@ public class SharedSailingDataImpl implements ReplicatingSharedSailingData, Clea apply(s -> s.internalRecordUsage(markTemplateId, markPropertiesId)); } + + @Override + public Void internalRecordUsage(final UUID markPropertiesId, final String roleName) { + final MarkProperties markProperties = markPropertiesById.get(markPropertiesId); + markProperties.getLastUsedRole().put(roleName, new MillisecondsTimePoint(System.currentTimeMillis())); + mongoObjectFactory.storeMarkProperties(deviceIdentifierServiceFinder, markProperties); + return null; + } + + @Override + public void recordUsage(final MarkProperties markProperties, final String roleName) { + getSecurityService().checkCurrentUserUpdatePermission(markProperties); + final UUID markPropertiesId = markProperties.getId(); + + apply(s -> s.internalRecordUsage(markPropertiesId, roleName)); + } @Override public Map getUsedMarkProperties(MarkTemplate markTemplate) { @@ -375,6 +391,17 @@ public class SharedSailingDataImpl implements ReplicatingSharedSailingData, Clea } return recordedUsage; } + + @Override + public Map getUsedMarkProperties(String roleName) { + final Map recordedUsage = new HashMap<>(); + for (final MarkProperties mp : markPropertiesById.values()) { + if (mp.getLastUsedRole().containsKey(roleName)) { + recordedUsage.put(mp, mp.getLastUsedRole().get(roleName)); + } + } + return recordedUsage; + } @Override public void deleteMarkProperties(MarkProperties markProperties) {