branch feature/8145-2 updated (8a0f6ba -> 5df204e)
This is an automated email from the git hooks/post-receive script. New change to branch feature/8145-2 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git from 8a0f6ba Fixes #8145 Merge branch 'feature/8145' into develop new c9ac004 Ajout de nouvelles méthodes sur CaracteristicMap new 36c52ba Ajout d'un chargeur de cache + amélioration de l'API de cache sur les échantillons new 5df204e Revue du chargement du cache d'échantillon au niveau de l'ui et des actions d'édition des captures d'une campagne The 3 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Detailed log of new commits: commit 5df204ea979151aecb6b6ed5d631c1947f2331f6 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Mar 20 21:42:26 2016 +0100 Revue du chargement du cache d'échantillon au niveau de l'ui et des actions d'édition des captures d'une campagne commit 36c52ba34da0bab55db9f853213a7a482486147f Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Mar 20 21:41:47 2016 +0100 Ajout d'un chargeur de cache + amélioration de l'API de cache sur les échantillons commit c9ac004a84124845a9a9629a58e212455e6919d5 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Mar 20 21:40:57 2016 +0100 Ajout de nouvelles méthodes sur CaracteristicMap Summary of changes: .../persistence/entities/CaracteristicMap.java | 24 +++ .../fr/ifremer/tutti/service/TuttiDataContext.java | 78 ++++++-- .../service/samplingCache/CruiseSamplingCache.java | 222 ++++++++++++++++++--- .../samplingCache/CruiseSamplingCacheLoader.java | 84 ++++++++ .../samplingCache/CruiseSamplingInternalCache.java | 74 ++++++- .../actions/AbstractChangeScreenAction.java | 10 +- .../EditCatchesForSelectedCruiseAction.java | 55 +---- .../EditCatchesSupportAction.java} | 71 ++++++- .../content/home/actions/EditCatchesAction.java | 56 +----- .../frequency/IndividualObservationUICache.java | 20 +- .../species/frequency/SpeciesFrequencyUIModel.java | 2 +- 11 files changed, 508 insertions(+), 188 deletions(-) create mode 100644 tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCacheLoader.java copy tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/{home/actions/EditCatchesAction.java => actions/EditCatchesSupportAction.java} (55%) -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/8145-2 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit c9ac004a84124845a9a9629a58e212455e6919d5 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Mar 20 21:40:57 2016 +0100 Ajout de nouvelles méthodes sur CaracteristicMap --- .../persistence/entities/CaracteristicMap.java | 24 ++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/entities/CaracteristicMap.java b/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/entities/CaracteristicMap.java index ce5af9b..68a7c66 100644 --- a/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/entities/CaracteristicMap.java +++ b/tutti-persistence/src/main/java/fr/ifremer/tutti/persistence/entities/CaracteristicMap.java @@ -62,6 +62,30 @@ public class CaracteristicMap extends LinkedHashMap<Caracteristic, Serializable> .count() > 0; } + public CaracteristicQualitativeValue getQualitativeValue(Caracteristic caracteristic) { + Serializable value = get(caracteristic); + if (value != null && !(value instanceof CaracteristicQualitativeValue)) { + throw new IllegalArgumentException("caracteristic value for " + caracteristic + " is not qualitative: " + value); + } + return (CaracteristicQualitativeValue) value; + } + + public String getStringValue(Caracteristic caracteristic) { + Serializable value = get(caracteristic); + if (value != null && !(value instanceof String)) { + throw new IllegalArgumentException("caracteristic value for " + caracteristic + " is not text: " + value); + } + return (String) value; + } + + public Float getFloatValue(Caracteristic caracteristic) { + Serializable value = get(caracteristic); + if (value != null && !(value instanceof Float)) { + throw new IllegalArgumentException("caracteristic value for " + caracteristic + " is not float: " + value); + } + return (Float) value; + } + public CaracteristicQualitativeValue removeQualitativeValue(Caracteristic caracteristic) { Serializable remove = remove(caracteristic); if (remove != null && !(remove instanceof CaracteristicQualitativeValue)) { -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/8145-2 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit 36c52ba34da0bab55db9f853213a7a482486147f Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Mar 20 21:41:47 2016 +0100 Ajout d'un chargeur de cache + amélioration de l'API de cache sur les échantillons --- .../fr/ifremer/tutti/service/TuttiDataContext.java | 78 ++++++-- .../service/samplingCache/CruiseSamplingCache.java | 222 ++++++++++++++++++--- .../samplingCache/CruiseSamplingCacheLoader.java | 84 ++++++++ .../samplingCache/CruiseSamplingInternalCache.java | 74 ++++++- 4 files changed, 400 insertions(+), 58 deletions(-) diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java index 1306dae..5b59786 100644 --- a/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/TuttiDataContext.java @@ -26,7 +26,6 @@ import com.google.common.base.Preconditions; import fr.ifremer.tutti.TuttiConfiguration; import fr.ifremer.tutti.persistence.entities.data.Cruise; import fr.ifremer.tutti.persistence.entities.data.FishingOperation; -import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch; import fr.ifremer.tutti.persistence.entities.data.Program; import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModel; import fr.ifremer.tutti.persistence.entities.data.SampleCategoryModelEntry; @@ -42,6 +41,7 @@ import fr.ifremer.tutti.persistence.entities.referential.TaxonCache; import fr.ifremer.tutti.persistence.entities.referential.TaxonCaches; import fr.ifremer.tutti.persistence.entities.referential.Vessel; import fr.ifremer.tutti.service.samplingCache.CruiseSamplingCache; +import fr.ifremer.tutti.service.samplingCache.CruiseSamplingCacheLoader; import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -51,6 +51,7 @@ import java.io.Closeable; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -183,6 +184,16 @@ public class TuttiDataContext extends AbstractBean implements Closeable { fishingOperation = null; getValidationContext().resetExistingFishingOperations(); }); + // Pour supprimer le cache d'échantillons + addPropertyChangeListener(evt -> { + String propertyName = evt.getPropertyName(); + if (PROPERTY_CRUISE_ID.equals(propertyName) || PROPERTY_PROGRAM_ID.equals(propertyName)) { + + if (getOptionalCruiseSamplingCache().isPresent()) { + closeCruiseSamplingCache(); + } + } + }); } public void setPersistenceService(PersistenceService service) { @@ -422,10 +433,22 @@ public class TuttiDataContext extends AbstractBean implements Closeable { return fishingOperationId != null; } + public boolean isCanUseCruiseSamplingCache() { + return isProtocolFilled() + && isCruiseFilled() + && getProtocol().isUseCalcifiedPieceSampling(); + } + public boolean isCruiseSamplingCacheLoaded() { return cruiseSamplingCache != null; } + public boolean isCruiseSamplingCacheUpToDate() { + return isCruiseSamplingCacheLoaded() + && Objects.equals(getCruiseId(), cruiseSamplingCache.getCruiseId()) + && Objects.equals(getProtocolId(), cruiseSamplingCache.getProtocolId()); + } + public void setProgramId(String programId) { boolean oldProgramFilled = isProgramFilled(); boolean oldCruiseFilled = isCruiseFilled(); @@ -536,41 +559,52 @@ public class TuttiDataContext extends AbstractBean implements Closeable { return service.getProtocol(); } + public Optional<CruiseSamplingCache> getOptionalCruiseSamplingCache() { - return Optional.ofNullable(isCruiseSamplingCacheLoaded() ? cruiseSamplingCache : null); + return Optional.ofNullable(isCruiseSamplingCacheUpToDate() ? cruiseSamplingCache : null); } - public void loadCruiseSamplingCache() { + public void loadCruiseSamplingCache(CruiseSamplingCacheLoader cruiseSamplingCacheLoader) { checkOpened(); - if (!isCruiseSamplingCacheLoaded() && isProtocolFilled() && isCruiseFilled()) { - TuttiProtocol protocol = getProtocol(); + if (!isCanUseCruiseSamplingCache()) { + throw new IllegalStateException("Pas autorisé à charger le cache d'échantillons"); + } + if (isCruiseSamplingCacheLoaded() && !isCruiseSamplingCacheUpToDate()) { + closeCruiseSamplingCache(); + } - if (protocol.isUseCalcifiedPieceSampling()) { + if (log.isInfoEnabled()) { + log.info("Loading cruise sampling cache: {cruiseId:" + getCruiseId() + ", protocolId: " + getProtocolId() + "}"); + } - cruiseSamplingCache = new CruiseSamplingCache(protocol); + cruiseSamplingCache = cruiseSamplingCacheLoader.loadCruiseSamplingCache(getProtocol(), getCruiseId()); - service.getAllFishingOperationIds(getCruiseId()).stream().forEach(operationId -> { + if (log.isInfoEnabled()) { + log.info("cruise sampling cache loaded: " + cruiseSamplingCache); + } - FishingOperation operation = service.getFishingOperation(operationId); + } - List<IndividualObservationBatch> allIndividualObservationBatchsForFishingOperation = - service.getAllIndividualObservationBatchsForFishingOperation(operationId); + protected void closeCruiseSamplingCache() { + Objects.requireNonNull(cruiseSamplingCache); - allIndividualObservationBatchsForFishingOperation.forEach( - obs -> cruiseSamplingCache.increment(operation, - obs.getSpecies(), - (CaracteristicQualitativeValue) obs.getCaracteristics().get(service.getSexCaracteristic()), - null, - obs.getSize())); - }); + // on détruit le cache obsolète + if (log.isInfoEnabled()) { + log.info("Destroy obsolete cruise sampling cache: " + cruiseSamplingCache); + } - if (log.isInfoEnabled()) { - log.info("cruise sampling cache loaded"); - } - } + cruiseSamplingCache.close(); + ; + cruiseSamplingCache = null; + } + public List<Integer> getCruiseFishingOperationIds() { + checkOpened(); + if (!isCruiseFilled()) { + throw new IllegalStateException("Aucune campagne chargée, impossible de récupérer les identifiants de traits"); } + return service.getAllFishingOperationIds(getCruiseId()); } public FishingOperation getFishingOperation() { diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCache.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCache.java index 0d67031..c5ed6fc 100644 --- a/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCache.java +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCache.java @@ -24,13 +24,16 @@ package fr.ifremer.tutti.service.samplingCache; * #L% */ +import com.google.common.base.MoreObjects; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch; import fr.ifremer.tutti.persistence.entities.protocol.CalcifiedPiecesSamplingDefinition; import fr.ifremer.tutti.persistence.entities.protocol.SubStrata; import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol; import fr.ifremer.tutti.persistence.entities.protocol.Zone; +import fr.ifremer.tutti.persistence.entities.referential.Caracteristic; import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue; import fr.ifremer.tutti.persistence.entities.referential.Species; import fr.ifremer.tutti.persistence.entities.referential.TuttiLocation; @@ -45,6 +48,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; /** @@ -56,16 +60,56 @@ public class CruiseSamplingCache implements Closeable { /** Logger. */ private static final Log log = LogFactory.getLog(CruiseSamplingCache.class); - protected final CruiseSamplingInternalCache totalCruiseCache = new CruiseSamplingInternalCache(); - protected final CruiseSamplingInternalCache zoneCache = new CruiseSamplingInternalCache(); - protected final CruiseSamplingInternalCache operationCache = new CruiseSamplingInternalCache(); - - protected final Map<TuttiLocation, Zone> zonesByLocations = new HashMap<>(); - protected final Multimap<Integer, CalcifiedPiecesSamplingDefinition> cpsDefinitionsBySpecies = HashMultimap.create(); - - protected final EventListenerList listeners = new EventListenerList(); - - public CruiseSamplingCache(TuttiProtocol protocol) { + /** + * Le cache des échantillons au niveau de la campagne. + */ + private final CruiseSamplingInternalCache totalCruiseCache = new CruiseSamplingInternalCache(); + /** + * Le cache des échantillons au niveau de chaque zone. + */ + private final CruiseSamplingInternalCache zoneCache = new CruiseSamplingInternalCache(); + /** + * Le cache des échantillons au niveau de chaque opération. + */ + private final CruiseSamplingInternalCache operationCache = new CruiseSamplingInternalCache(); + + /** + * Le dictionnaire des zones du protocole indexés par location. + */ + private final Map<TuttiLocation, Zone> zonesByLocations = new HashMap<>(); + /** + * Le dictionnaire des définitions de l'algorithme de prélèvement des piècess calcifiées indexés par identifiant de taxon. + */ + private final Multimap<Integer, CalcifiedPiecesSamplingDefinition> cpsDefinitionsBySpecies = HashMultimap.create(); + + /** + * La caractéristic qui définie le sexe dans une observation individuelle. + */ + private final Caracteristic sexCaracteristic; + + /** + * La liste des listeners. + */ + private final EventListenerList listeners = new EventListenerList(); + + /** + * L'identifiant de la campagne associée à ce cache. + */ + private final Integer cruiseId; + /** + * L'identificant du protocol associé à ce cache. + */ + private final String protocolId; + + /** + * Un drapeau pour indiquer qu'on est en train de construire le cache et donc ne déclancher aucun listener. + */ + private boolean loading; + + public CruiseSamplingCache(Integer cruiseId, TuttiProtocol protocol, Caracteristic sexCaracteristic) { + this.cruiseId = cruiseId; + this.sexCaracteristic = sexCaracteristic; + this.protocolId = protocol.getId(); // fill the zones by location protocol.getZone().forEach(zone -> { @@ -89,6 +133,22 @@ public class CruiseSamplingCache implements Closeable { speciesProtocol.getCalcifiedPiecesSamplingDefinition())); } + public Integer getCruiseId() { + return cruiseId; + } + + public String getProtocolId() { + return protocolId; + } + + public boolean isLoading() { + return loading; + } + + public void setLoading(boolean loading) { + this.loading = loading; + } + @Override public void close() { if (log.isInfoEnabled()) { @@ -105,13 +165,56 @@ public class CruiseSamplingCache implements Closeable { } } - public void increment(FishingOperation operation, - Species species, - CaracteristicQualitativeValue gender, - Boolean maturity, - float lengthStep) { + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("cruiseId", cruiseId) + .add("protocolId", protocolId) + .add("totalCruiseCache", totalCruiseCache.size()) + .add("zoneCache", zoneCache.size()) + .add("operationCache", operationCache.size()) + .toString(); + } + + /** + * Ajout d'un échantillon dans le cache. + * + * @param fishingOperation l'opération de pêche contenant l'observation individuelle + * @param individualObservationBatch l'observation individuelle à ajouter au cache + */ + public void addIndividualObservation(FishingOperation fishingOperation, IndividualObservationBatch individualObservationBatch) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservationBatch); + + Species species = individualObservationBatch.getSpecies(); + Objects.requireNonNull(species); + + Boolean maturity = null; + Float lengthStep = individualObservationBatch.getSize(); + + CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic); + + addIndividualObservation(fishingOperation, species, gender, maturity, lengthStep); + + } - Objects.requireNonNull(operation); + /** + * Ajout d'un échantillon dans le cache. + * + * @param fishingOperation l'opération de pêche concernée + * @param species l'espèces concernée + * @param gender le sexe de l'échantillon (peut-être null) + * @param maturity la maturité de l'échantillon (peut-être null) + * @param lengthStep la classe de taille de l'échantillon + */ + public void addIndividualObservation(FishingOperation fishingOperation, + Species species, + CaracteristicQualitativeValue gender, + Boolean maturity, + float lengthStep) { + + Objects.requireNonNull(fishingOperation); Objects.requireNonNull(species); Optional<CalcifiedPiecesSamplingDefinition> cpsDefinitionOpt = getCalcifiedPiecesSamplingDefinition(species, maturity, lengthStep); @@ -133,7 +236,7 @@ public class CruiseSamplingCache implements Closeable { } CruiseSamplingInternalCache.CruiseSamplingInternalCacheKey samplingKey = CruiseSamplingInternalCache.newCruiseSamplingInternalCacheKey(species, gender, maturity, lengthStep); - Optional<Zone> zone = findZone(operation); + Optional<Zone> zone = findZone(fishingOperation); int totalValue = totalCruiseCache.increment(samplingKey); int zoneValue = 0; @@ -141,14 +244,14 @@ public class CruiseSamplingCache implements Closeable { CruiseSamplingInternalCache.ZoneCruiseSamplingInternalCacheKey zoneKey = samplingKey.toZoneKey(zone.get()); zoneValue = zoneCache.increment(zoneKey); } - CruiseSamplingInternalCache.FishingOperationCruiseSamplingInternalCacheKey operationKey = samplingKey.toFishingOperationKey(operation); + CruiseSamplingInternalCache.FishingOperationCruiseSamplingInternalCacheKey operationKey = samplingKey.toFishingOperationKey(fishingOperation); int operationValue = operationCache.increment(operationKey); if (log.isInfoEnabled()) { - log.info("increment " + samplingKey + " => op " + operationValue + " / zone " + zoneValue + " / cruise " + totalValue); + log.info("addIndividualObservation " + samplingKey + " => op " + operationValue + " / zone " + zoneValue + " / cruise " + totalValue); } - if (totalValue == 1 || totalValue % samplingInterval == 1) { + if (!isLoading() && (totalValue == 1 || totalValue % samplingInterval == 1)) { if (log.isInfoEnabled()) { log.info("-> needs sampling"); } @@ -159,13 +262,50 @@ public class CruiseSamplingCache implements Closeable { } } - public void decrement(FishingOperation operation, - Species species, - CaracteristicQualitativeValue gender, - Boolean maturity, - Float lengthStep) { + /** + * Suppression d'un échantillon du cache. + * + * @param fishingOperation l'opération de pêche concernée + * @param individualObservationBatches les observations individuelles à supprimer du cache + */ + public void removeIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservationBatches) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservationBatches); + + individualObservationBatches.forEach(individualObservationBatch -> { + + + Species species = individualObservationBatch.getSpecies(); + Objects.requireNonNull(species); + + Boolean maturity = null; + Float lengthStep = individualObservationBatch.getSize(); + CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic); - Objects.requireNonNull(operation); + removeIndividualObservation(fishingOperation, species, gender, maturity, lengthStep); + + }); + + + } + + /** + * Suppression d'un échantillon du cache. + * + * @param fishingOperation l'opération de pêche concernée + * @param species l'espèces concernée + * @param gender le sexe de l'échantillon (peut-être null) + * @param maturity la maturité de l'échantillon (peut-être null) + * @param lengthStep la classe de taille de l'échantillon + */ + public void removeIndividualObservation(FishingOperation fishingOperation, + Species species, + CaracteristicQualitativeValue gender, + Boolean maturity, + Float lengthStep) { + + Objects.requireNonNull(fishingOperation); Objects.requireNonNull(species); Objects.requireNonNull(lengthStep); @@ -188,7 +328,7 @@ public class CruiseSamplingCache implements Closeable { CruiseSamplingInternalCache.CruiseSamplingInternalCacheKey samplingKey = CruiseSamplingInternalCache.newCruiseSamplingInternalCacheKey(species, gender, maturity, lengthStep); - Optional<Zone> zone = findZone(operation); + Optional<Zone> zone = findZone(fishingOperation); int totalValue = totalCruiseCache.decrement(samplingKey); int zoneValue = 0; @@ -196,16 +336,39 @@ public class CruiseSamplingCache implements Closeable { CruiseSamplingInternalCache.ZoneCruiseSamplingInternalCacheKey zoneKey = samplingKey.toZoneKey(zone.get()); zoneValue = zoneCache.decrement(zoneKey); } - CruiseSamplingInternalCache.FishingOperationCruiseSamplingInternalCacheKey operationKey = samplingKey.toFishingOperationKey(operation); + CruiseSamplingInternalCache.FishingOperationCruiseSamplingInternalCacheKey operationKey = samplingKey.toFishingOperationKey(fishingOperation); int operationValue = operationCache.decrement(operationKey); if (log.isInfoEnabled()) { - log.info("decrement " + samplingKey + " => op " + operationValue + " / zone " + zoneValue + " / cruise " + totalValue); + log.info("removeIndividualObservation " + samplingKey + " => op " + operationValue + " / zone " + zoneValue + " / cruise " + totalValue); } } } } + /** + * Suppression de toutes les observations individuelles du cache. + * + * @param fishingOperation l'opération de pêche concernée + */ + public void removeFishingOperation(FishingOperation fishingOperation) { + + Objects.requireNonNull(fishingOperation); + + // suppression de toutes les entrées du cache des opérations (et récupération des clefs) + Set<String> removedKeys = operationCache.removeAllWhereKeyStartingWith(fishingOperation.getId()); + + removedKeys.forEach(totalCruiseCache::decrement); + + Optional<Zone> zone = findZone(fishingOperation); + + if (zone.isPresent()) { + String id = zone.get().getId(); + removedKeys.forEach(key -> zoneCache.decrementIfExist(CruiseSamplingInternalCache.addPrefixKey(id, key))); + } + + } + public void addSamplingListener(SamplingListener listener) { listeners.add(SamplingListener.class, listener); } @@ -266,5 +429,4 @@ public class CruiseSamplingCache implements Closeable { } } - } diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCacheLoader.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCacheLoader.java new file mode 100644 index 0000000..b7edd93 --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingCacheLoader.java @@ -0,0 +1,84 @@ +package fr.ifremer.tutti.service.samplingCache; + +import fr.ifremer.tutti.persistence.ProgressionModel; +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch; +import fr.ifremer.tutti.persistence.entities.protocol.TuttiProtocol; +import fr.ifremer.tutti.persistence.entities.referential.Caracteristic; +import fr.ifremer.tutti.service.DecoratorService; +import fr.ifremer.tutti.service.PersistenceService; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.decorator.Decorator; + +import java.util.List; + +/** + * Pour charger le cache. + * + * Created on 20/03/16. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 4.5 + */ +public class CruiseSamplingCacheLoader { + + /** Logger. */ + private static final Log log = LogFactory.getLog(CruiseSamplingCacheLoader.class); + + private final PersistenceService persistenceService; + private final DecoratorService decoratorService; + private final ProgressionModel progressionModel; + + public CruiseSamplingCacheLoader(PersistenceService persistenceService, + DecoratorService decoratorService, + ProgressionModel progressionModel) { + this.persistenceService = persistenceService; + this.decoratorService = decoratorService; + this.progressionModel = progressionModel; + } + + public CruiseSamplingCache loadCruiseSamplingCache(TuttiProtocol protocol, Integer cruiseId) { + + Caracteristic sexCaracteristic = persistenceService.getSexCaracteristic(); + + CruiseSamplingCache cruiseSamplingCache = new CruiseSamplingCache(cruiseId, protocol, sexCaracteristic); + + cruiseSamplingCache.setLoading(true); + + try { + if (log.isInfoEnabled()) { + log.info("Loading cruise sampling cache: " + cruiseSamplingCache); + } + + + Decorator<FishingOperation> fishingOperationDecorator = decoratorService.getDecoratorByType(FishingOperation.class); + + persistenceService.getAllFishingOperationIds(cruiseId).forEach(fishingOperationId -> { + + FishingOperation fishingOperation = persistenceService.getFishingOperation(fishingOperationId); + + progressionModel.increments("Chargement du cache d'échantillons pour le trait : " + fishingOperationDecorator.toString(fishingOperation)); + + List<IndividualObservationBatch> allIndividualObservationBatchsForFishingOperation = + persistenceService.getAllIndividualObservationBatchsForFishingOperation(fishingOperationId); + + allIndividualObservationBatchsForFishingOperation.forEach( + individualObservationBatch -> cruiseSamplingCache.addIndividualObservation(fishingOperation, individualObservationBatch)); + + }); + + if (log.isInfoEnabled()) { + log.info("cruise sampling cache loaded: " + cruiseSamplingCache); + } + + return cruiseSamplingCache; + + } finally { + + cruiseSamplingCache.setLoading(false); + + } + + } +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingInternalCache.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingInternalCache.java index 97f51c9..c12dda1 100644 --- a/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingInternalCache.java +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/samplingCache/CruiseSamplingInternalCache.java @@ -5,10 +5,15 @@ import fr.ifremer.tutti.persistence.entities.protocol.Zone; import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue; import fr.ifremer.tutti.persistence.entities.referential.Species; import org.apache.commons.lang3.mutable.MutableInt; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.io.Closeable; +import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.TreeMap; /** @@ -19,7 +24,20 @@ import java.util.TreeMap; */ class CruiseSamplingInternalCache implements Closeable { - protected final Map<String, MutableInt> data = new TreeMap<>(); + /** Logger. */ + private static final Log log = LogFactory.getLog(CruiseSamplingInternalCache.class); + + public static String addPrefixKey(String prefix, String key) { + return prefix + CruiseSamplingInternalCacheKey.KEY_SEPARATOR + key; + } + + private final Map<String, MutableInt> data = new TreeMap<>(); + + public static CruiseSamplingInternalCacheKey newCruiseSamplingInternalCacheKey(Species species, CaracteristicQualitativeValue gender, Boolean maturity, Float lengthStep) { + Objects.requireNonNull(species); + Objects.requireNonNull(lengthStep); + return new CruiseSamplingInternalCacheKey(species, gender, maturity, lengthStep); + } public int increment(CruiseSamplingInternalCacheKey samplingKey) { MutableInt value = data.computeIfAbsent(samplingKey.toString(), s -> new MutableInt(0)); @@ -28,20 +46,64 @@ class CruiseSamplingInternalCache implements Closeable { } public int decrement(CruiseSamplingInternalCacheKey samplingKey) { - MutableInt value = data.get(samplingKey.toString()); + return decrement(samplingKey.toString()); + } + + public int decrement(String samplingKey) { + MutableInt value = data.get(samplingKey); value.decrement(); return value.intValue(); } + public Integer decrementIfExist(String samplingKey) { + Integer result = null; + MutableInt value = data.get(samplingKey); + if (value != null) { + value.decrement(); + result = value.intValue(); + } + return result; + } + @Override public void close() { data.clear(); } - public static CruiseSamplingInternalCacheKey newCruiseSamplingInternalCacheKey(Species species, CaracteristicQualitativeValue gender, Boolean maturity, Float lengthStep) { - Objects.requireNonNull(species); - Objects.requireNonNull(lengthStep); - return new CruiseSamplingInternalCacheKey(species, gender, maturity, lengthStep); + public int size() { + return data.size(); + } + + /** + * Supprime du cache toutes les entrées dont la clef commence par l'identifiant donné (suivant du séparateur de clef) + * et retourne l'ensemble des clefs supprimées du cache. + * + * À noter que sur les clefs retournées, on a retirer le préfixe de concordance. + * + * @param id l'identifiant de début de clef à supprimer + * @return l'ensemble des clefs supprimées du cache (amputées du préfixe de concordance). + */ + public Set<String> removeAllWhereKeyStartingWith(String id) { + String keyPrefix = id + CruiseSamplingInternalCacheKey.KEY_SEPARATOR; + if (log.isDebugEnabled()) { + log.debug("Ask to remove all keys starting with: " + keyPrefix); + } + Set<String> result = new LinkedHashSet<>(); + Iterator<Map.Entry<String, MutableInt>> iterator = data.entrySet().iterator(); + int keyPrefixLength = keyPrefix.length(); + while (iterator.hasNext()) { + Map.Entry<String, MutableInt> entry = iterator.next(); + String key = entry.getKey(); + + if (key.startsWith(keyPrefix)) { + iterator.remove(); + if (log.isDebugEnabled()) { + log.debug("Removing key: " + key); + } + result.add(key.substring(keyPrefixLength)); + } + } + return result; } /** -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
This is an automated email from the git hooks/post-receive script. New commit to branch feature/8145-2 in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit 5df204ea979151aecb6b6ed5d631c1947f2331f6 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Mar 20 21:42:26 2016 +0100 Revue du chargement du cache d'échantillon au niveau de l'ui et des actions d'édition des captures d'une campagne --- .../actions/AbstractChangeScreenAction.java | 10 +-- .../EditCatchesForSelectedCruiseAction.java | 55 ++--------------- .../EditCatchesSupportAction.java} | 71 +++++++++++++++++++--- .../content/home/actions/EditCatchesAction.java | 56 ++--------------- .../frequency/IndividualObservationUICache.java | 20 +++--- .../species/frequency/SpeciesFrequencyUIModel.java | 2 +- 6 files changed, 84 insertions(+), 130 deletions(-) diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/AbstractChangeScreenAction.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/AbstractChangeScreenAction.java index 15e0c21..86b9819 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/AbstractChangeScreenAction.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/AbstractChangeScreenAction.java @@ -28,8 +28,6 @@ import fr.ifremer.tutti.ui.swing.TuttiUIContext; import fr.ifremer.tutti.ui.swing.content.MainUIHandler; import jaxx.runtime.SwingUtil; import jaxx.runtime.context.JAXXContextEntryDef; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import java.beans.PropertyVetoException; @@ -41,15 +39,11 @@ import static org.nuiton.i18n.I18n.t; * Will just check that the current screen can be quit via * the {@link MainUIHandler#quitCurrentScreen()}. * - * * @author Kevin Morin - kmorin@codelutin.com * @since 1.0 */ public abstract class AbstractChangeScreenAction extends AbstractMainUITuttiAction { - /** Logger. */ - private static final Log log = LogFactory.getLog(AbstractChangeScreenAction.class); - /** * Context entry to keep previous screen. * @@ -72,9 +66,7 @@ public abstract class AbstractChangeScreenAction extends AbstractMainUITuttiActi */ protected boolean skipCheckCurrentScreen; - protected AbstractChangeScreenAction(MainUIHandler handler, - boolean hideBody, - TuttiScreen screen) { + protected AbstractChangeScreenAction(MainUIHandler handler, boolean hideBody, TuttiScreen screen) { super(handler, hideBody); this.screen = screen; } diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesForSelectedCruiseAction.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesForSelectedCruiseAction.java index f0899fc..322aa3d 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesForSelectedCruiseAction.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesForSelectedCruiseAction.java @@ -22,18 +22,7 @@ package fr.ifremer.tutti.ui.swing.content.actions; * #L% */ -import com.google.common.base.Preconditions; -import fr.ifremer.tutti.persistence.entities.data.FishingOperation; -import fr.ifremer.tutti.service.ValidationService; -import fr.ifremer.tutti.ui.swing.TuttiScreen; import fr.ifremer.tutti.ui.swing.content.MainUIHandler; -import fr.ifremer.tutti.ui.swing.content.operation.EditFishingOperationUI; -import fr.ifremer.tutti.ui.swing.content.operation.FishingOperationsUI; -import jaxx.runtime.swing.editor.bean.BeanFilterableComboBox; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import javax.swing.*; /** * Opens the operations edition screen to edit the selected operations. @@ -41,51 +30,15 @@ import javax.swing.*; * @author Tony Chemit - chemit@codelutin.com * @since 1.0 */ -public class EditCatchesForSelectedCruiseAction extends AbstractChangeScreenAction { - - /** Logger. */ - private static final Log log = - LogFactory.getLog(EditCatchesForSelectedCruiseAction.class); +public class EditCatchesForSelectedCruiseAction extends EditCatchesSupportAction { public EditCatchesForSelectedCruiseAction(MainUIHandler handler) { - super(handler, true, TuttiScreen.EDIT_FISHING_OPERATION); - } - - @Override - public void doAction() throws Exception { - Preconditions.checkState(getContext().isCruiseFilled()); - if (log.isInfoEnabled()) { - log.info("Edit operations of cruise: " + getContext().getCruiseId()); - } - getContext().setValidationContext(ValidationService.VALIDATION_CONTEXT_EDIT); - loadReferantials(true); - getDataContext().loadCruiseSamplingCache(); - super.doAction(); + super(handler); } @Override - public void postSuccessAction() { - super.postSuccessAction(); - - SwingUtilities.invokeLater( - () -> { - - FishingOperationsUI currentBody = (FishingOperationsUI) getHandler().getCurrentBody(); - - BeanFilterableComboBox<FishingOperation> comboBox = currentBody.getFishingOperationComboBox(); - if (!comboBox.isEmpty()) { - FishingOperation selectedOperation = comboBox.getData().get(0); - currentBody.getModel().setSelectedFishingOperation(selectedOperation); - } - - EditFishingOperationUI fishingOperationTabContent = currentBody.getFishingOperationTabContent(); - - JComponent componentToFocus = fishingOperationTabContent.getHandler().getComponentToFocus(); - componentToFocus.requestFocusInWindow(); - - } - ); - + protected boolean isLoadReferential() { + return true; } } diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesSupportAction.java similarity index 55% copy from tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java copy to tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesSupportAction.java index c1c4712..b4a230d 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/actions/EditCatchesSupportAction.java @@ -1,4 +1,4 @@ -package fr.ifremer.tutti.ui.swing.content.home.actions; +package fr.ifremer.tutti.ui.swing.content.actions; /* * #%L @@ -23,11 +23,13 @@ package fr.ifremer.tutti.ui.swing.content.home.actions; */ import com.google.common.base.Preconditions; +import fr.ifremer.tutti.persistence.ProgressionModel; import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.service.TuttiDataContext; import fr.ifremer.tutti.service.ValidationService; +import fr.ifremer.tutti.service.samplingCache.CruiseSamplingCacheLoader; import fr.ifremer.tutti.ui.swing.TuttiScreen; import fr.ifremer.tutti.ui.swing.content.MainUIHandler; -import fr.ifremer.tutti.ui.swing.content.actions.AbstractChangeScreenAction; import fr.ifremer.tutti.ui.swing.content.operation.EditFishingOperationUI; import fr.ifremer.tutti.ui.swing.content.operation.FishingOperationsUI; import jaxx.runtime.swing.editor.bean.BeanFilterableComboBox; @@ -38,29 +40,81 @@ import javax.swing.JComponent; import javax.swing.SwingUtilities; /** - * Opens the operations edition screen. + * Opens the operations edition screen to edit the selected operations. * * @author Tony Chemit - chemit@codelutin.com * @since 1.0 */ -public class EditCatchesAction extends AbstractChangeScreenAction { +public abstract class EditCatchesSupportAction extends AbstractChangeScreenAction { /** Logger. */ - private static final Log log = LogFactory.getLog(EditCatchesAction.class); + private static final Log log = LogFactory.getLog(EditCatchesSupportAction.class); - public EditCatchesAction(MainUIHandler handler) { + public EditCatchesSupportAction(MainUIHandler handler) { super(handler, true, TuttiScreen.EDIT_FISHING_OPERATION); } + protected abstract boolean isLoadReferential(); + + protected boolean loadReferential; + protected boolean loadSamplingCache; + + @Override + public boolean prepareAction() throws Exception { + boolean doAction = super.prepareAction(); + + TuttiDataContext dataContext = getDataContext(); + if (doAction) { + + loadReferential = isLoadReferential(); + loadSamplingCache = dataContext.isCanUseCruiseSamplingCache() && + !(dataContext.isCruiseSamplingCacheLoaded() && dataContext.isCruiseSamplingCacheUpToDate()); + + int totalSteps = 1; + + if (loadReferential) { + totalSteps += 5; + } + + if (loadSamplingCache) { + + // Calcul des étapes (nb de traits dans la campagne) + long cruiseFishingOperationIds = getDataContext().getCruiseFishingOperationIds().stream().count(); + totalSteps += cruiseFishingOperationIds; + + if (log.isInfoEnabled()) { + log.info("Found " + cruiseFishingOperationIds + " fishing operations to load in sampling cache."); + } + } + + if (totalSteps > 1) { + ProgressionModel progressionModel = new ProgressionModel(); + progressionModel.setTotal(totalSteps); + setProgressionModel(progressionModel); + } + + } + return doAction; + } + @Override public void doAction() throws Exception { - Preconditions.checkState(getContext().isProgramFilled()); Preconditions.checkState(getContext().isCruiseFilled()); if (log.isInfoEnabled()) { log.info("Edit operations of cruise: " + getContext().getCruiseId()); } getContext().setValidationContext(ValidationService.VALIDATION_CONTEXT_EDIT); - getDataContext().loadCruiseSamplingCache(); + if (loadReferential) { + + loadReferantials(false); + + } + if (loadSamplingCache) { + + CruiseSamplingCacheLoader cruiseSamplingCacheLoader = new CruiseSamplingCacheLoader(getContext().getPersistenceService(), getContext().getDecoratorService(), getProgressionModel()); + getDataContext().loadCruiseSamplingCache(cruiseSamplingCacheLoader); + + } super.doAction(); } @@ -88,4 +142,5 @@ public class EditCatchesAction extends AbstractChangeScreenAction { ); } + } diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java index c1c4712..2552e45 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/home/actions/EditCatchesAction.java @@ -22,20 +22,8 @@ package fr.ifremer.tutti.ui.swing.content.home.actions; * #L% */ -import com.google.common.base.Preconditions; -import fr.ifremer.tutti.persistence.entities.data.FishingOperation; -import fr.ifremer.tutti.service.ValidationService; -import fr.ifremer.tutti.ui.swing.TuttiScreen; import fr.ifremer.tutti.ui.swing.content.MainUIHandler; -import fr.ifremer.tutti.ui.swing.content.actions.AbstractChangeScreenAction; -import fr.ifremer.tutti.ui.swing.content.operation.EditFishingOperationUI; -import fr.ifremer.tutti.ui.swing.content.operation.FishingOperationsUI; -import jaxx.runtime.swing.editor.bean.BeanFilterableComboBox; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import javax.swing.JComponent; -import javax.swing.SwingUtilities; +import fr.ifremer.tutti.ui.swing.content.actions.EditCatchesSupportAction; /** * Opens the operations edition screen. @@ -43,49 +31,15 @@ import javax.swing.SwingUtilities; * @author Tony Chemit - chemit@codelutin.com * @since 1.0 */ -public class EditCatchesAction extends AbstractChangeScreenAction { - - /** Logger. */ - private static final Log log = LogFactory.getLog(EditCatchesAction.class); +public class EditCatchesAction extends EditCatchesSupportAction { public EditCatchesAction(MainUIHandler handler) { - super(handler, true, TuttiScreen.EDIT_FISHING_OPERATION); + super(handler); } @Override - public void doAction() throws Exception { - Preconditions.checkState(getContext().isProgramFilled()); - Preconditions.checkState(getContext().isCruiseFilled()); - if (log.isInfoEnabled()) { - log.info("Edit operations of cruise: " + getContext().getCruiseId()); - } - getContext().setValidationContext(ValidationService.VALIDATION_CONTEXT_EDIT); - getDataContext().loadCruiseSamplingCache(); - super.doAction(); + protected boolean isLoadReferential() { + return false; } - @Override - public void postSuccessAction() { - super.postSuccessAction(); - - SwingUtilities.invokeLater( - () -> { - - FishingOperationsUI currentBody = (FishingOperationsUI) getHandler().getCurrentBody(); - - BeanFilterableComboBox<FishingOperation> comboBox = currentBody.getFishingOperationComboBox(); - if (!comboBox.isEmpty()) { - FishingOperation selectedOperation = comboBox.getData().get(0); - currentBody.getModel().setSelectedFishingOperation(selectedOperation); - } - - EditFishingOperationUI fishingOperationTabContent = currentBody.getFishingOperationTabContent(); - - JComponent componentToFocus = fishingOperationTabContent.getHandler().getComponentToFocus(); - componentToFocus.requestFocusInWindow(); - - } - ); - - } } diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/IndividualObservationUICache.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/IndividualObservationUICache.java index 7e57a8a..c5fec05 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/IndividualObservationUICache.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/IndividualObservationUICache.java @@ -211,11 +211,11 @@ public class IndividualObservationUICache implements Closeable { return; } - samplingCache.get().increment(fishingOperation, - species, - gender, - maturity, - uiModel.getLengthStep(lengthStep)); + samplingCache.get().addIndividualObservation(fishingOperation, + species, + gender, + maturity, + uiModel.getLengthStep(lengthStep)); } /** @@ -245,11 +245,11 @@ public class IndividualObservationUICache implements Closeable { return; } - samplingCache.get().decrement(fishingOperation, - species, - gender, - maturity, - uiModel.getLengthStep(lengthStep)); + samplingCache.get().removeIndividualObservation(fishingOperation, + species, + gender, + maturity, + uiModel.getLengthStep(lengthStep)); } diff --git a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/SpeciesFrequencyUIModel.java b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/SpeciesFrequencyUIModel.java index 1dd8fa7..16e331a 100644 --- a/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/SpeciesFrequencyUIModel.java +++ b/tutti-ui-swing/src/main/java/fr/ifremer/tutti/ui/swing/content/operation/catches/species/frequency/SpeciesFrequencyUIModel.java @@ -145,7 +145,7 @@ public class SpeciesFrequencyUIModel extends AbstractTuttiTableUIModel<SpeciesBa protected SpeciesBatchRowModel batch; /** - * Default step to increment length step. + * Default step to addIndividualObservation length step. * * @since 0.2 */ -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.
participants (1)
-
codelutin.com scm