This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository tutti. See https://gitlab.nuiton.org/codelutin/tutti.git commit c0998d61c99c033888bb6fca3c0131d10c7a9fd0 Author: Tony CHEMIT <chemit@codelutin.com> Date: Sun Apr 17 07:35:26 2016 +0200 Revue de l'API de cache pour avoir un cache de haut niveau sur les cruise puis des caches dédiés --- .../tutti/service/sampling/CruiseCache.java | 141 +++++++ .../tutti/service/sampling/CruiseCacheAble.java | 46 +++ .../tutti/service/sampling/CruiseCacheLoader.java | 149 +++++++ .../service/sampling/CruiseSamplingCache.java | 451 ++++++++++----------- .../sampling/CruiseSamplingCacheLoader.java | 156 ------- .../tutti/service/sampling/SamplingCodeCache.java | 113 ++++++ 6 files changed, 652 insertions(+), 404 deletions(-) diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCache.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCache.java new file mode 100644 index 0000000..98bf67f --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCache.java @@ -0,0 +1,141 @@ +package fr.ifremer.tutti.service.sampling; + +import com.google.common.base.MoreObjects; +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; + +/** + * Le cache de données pour une campagne. Ce cache contient tous les caches plus spécifiques + * (codes de prélèvement, algorithme de prélèvement de pièces calcifiées,...). + * + * Created on 16/04/16. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 4.5 + */ +public class CruiseCache implements CruiseCacheAble { + + /** Logger. */ + private static final Log log = LogFactory.getLog(CruiseCache.class); + /** + * L'identifiant de la campagne associée à ce cache. + */ + private final int cruiseId; + /** + * L'identificant du protocol associé à ce cache. + */ + private final String protocolId; + /** + * Le cache optioanel lié à l'algorithme de prélèvement des pièces calcifiées. + */ + private final CruiseSamplingCache cruiseSamplingCache; + /** + * Le cache des codes de prélèvement disponibles. + */ + private final SamplingCodeCache samplingCodeCache; + + public CruiseCache(Integer cruiseId, String protocolId, CruiseSamplingCache cruiseSamplingCache, SamplingCodeCache samplingCodeCache) { + Objects.requireNonNull(cruiseId); + Objects.requireNonNull(samplingCodeCache); + this.cruiseId = cruiseId; + this.protocolId = protocolId; + this.cruiseSamplingCache = cruiseSamplingCache; + this.samplingCodeCache = samplingCodeCache; + } + + public boolean isCacheUpToDate(Integer cruiseId, String protocolId) { + return Objects.equals(this.cruiseId, cruiseId) && Objects.equals(this.protocolId, protocolId); + } + + public boolean useSamplingCache() { + return cruiseSamplingCache != null; + } + + public Integer getCruiseId() { + return cruiseId; + } + + public String getProtocolId() { + return protocolId; + } + + public Optional<CruiseSamplingCache> getSamplingCruiseCache() { + return Optional.ofNullable(cruiseSamplingCache); + } + + public SamplingCodeCache getSamplingCodeCache() { + return samplingCodeCache; + } + + @Override + public void addIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + if (useSamplingCache()) { + cruiseSamplingCache.addIndividualObservations(fishingOperation, individualObservations); + } + + samplingCodeCache.addIndividualObservations(fishingOperation, individualObservations); + + } + + @Override + public void removeIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + if (useSamplingCache()) { + cruiseSamplingCache.removeIndividualObservations(fishingOperation, individualObservations); + } + + samplingCodeCache.removeIndividualObservations(fishingOperation, individualObservations); + + } + + @Override + public void addFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + if (useSamplingCache()) { + cruiseSamplingCache.addFishingOperation(fishingOperation, individualObservations); + } + + samplingCodeCache.addFishingOperation(fishingOperation, individualObservations); + + } + + @Override + public void removeFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + if (useSamplingCache()) { + cruiseSamplingCache.removeFishingOperation(fishingOperation, individualObservations); + } + + samplingCodeCache.removeFishingOperation(fishingOperation, individualObservations); + + } + + @Override + public void close() { + + if (log.isInfoEnabled()) { + log.info("Closing cruise cache: " + this); + } + if (useSamplingCache()) { + IOUtils.closeQuietly(cruiseSamplingCache); + } + IOUtils.closeQuietly(samplingCodeCache); + } + + @Override + public String toString() { + MoreObjects.ToStringHelper toStringHelper = MoreObjects.toStringHelper(this); + if (cruiseSamplingCache != null) { + toStringHelper.add("cruiseSamplingCache", cruiseSamplingCache); + } + return toStringHelper.add("samplingCodeCache", samplingCodeCache).toString(); + } +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCacheAble.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCacheAble.java new file mode 100644 index 0000000..88e2015 --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCacheAble.java @@ -0,0 +1,46 @@ +package fr.ifremer.tutti.service.sampling; + +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch; + +import java.io.Closeable; +import java.util.Collection; + +/** + * Created on 17/04/16. + * + * @author Tony Chemit - chemit@codelutin.com + */ +public interface CruiseCacheAble extends Closeable { + + /** + * Ajout de toutes les observations individuelles de l'opération de pêche dans le cache. + * + * @param fishingOperation l'opération de pêche concernée + */ + void addFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations); + + /** + * Suppression de toutes les observations individuelles du cache. + * + * @param fishingOperation l'opération de pêche concernée + */ + void removeFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations); + + /** + * Ajout des plusieurs échantillons qui sont sur la m$eme opération de pêche dans le cache. + * + * @param fishingOperation l'opération de pêche concernée + * @param individualObservations les observations à ajouter au cache + */ + void addIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations); + + /** + * Suppression de plusieurs échantillons qui sont sur la même opération de pêche du cache. + * + * @param fishingOperation l'opération de pêche concernée + * @param individualObservations les observations individuelles à supprimer du cache + */ + void removeIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations); + +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCacheLoader.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCacheLoader.java new file mode 100644 index 0000000..db4c529 --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseCacheLoader.java @@ -0,0 +1,149 @@ +package fr.ifremer.tutti.service.sampling; + +/* + * #%L + * Tutti :: Service + * $Id:$ + * $HeadURL:$ + * %% + * Copyright (C) 2012 - 2016 Ifremer + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +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.Collection; +import java.util.List; + +import static org.nuiton.i18n.I18n.t; + +/** + * Pour charger le cache de données de campagnes. + * + * Created on 20/03/16. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 4.5 + */ +public class CruiseCacheLoader { + + /** Logger. */ + private static final Log log = LogFactory.getLog(CruiseCacheLoader.class); + + private final PersistenceService persistenceService; + private final DecoratorService decoratorService; + private final ProgressionModel progressionModel; + private final CruiseCache cruiseCache; + + public static CruiseCacheLoader newCacheLoader(PersistenceService persistenceService, + DecoratorService decoratorService, + ProgressionModel progressionModel, + TuttiProtocol protocol, + Integer cruiseId) { + + boolean loadSamplingCache = protocol != null && protocol.isUseCalcifiedPieceSampling(); + + CruiseSamplingCache cruiseSamplingCache; + + if (loadSamplingCache) { + + Caracteristic sexCaracteristic = persistenceService.getSexCaracteristic(); + + Collection<Caracteristic> maturityCaracteristics = persistenceService.getMaturityCaracteristics(persistenceService.getAllCaracteristic()); + cruiseSamplingCache = new CruiseSamplingCache(protocol, sexCaracteristic, maturityCaracteristics); + + } else { + + cruiseSamplingCache = null; + + } + + CruiseCache cruiseCache = new CruiseCache(cruiseId, protocol == null ? null : protocol.getId(), cruiseSamplingCache, new SamplingCodeCache()); + return new CruiseCacheLoader(persistenceService, decoratorService, progressionModel, cruiseCache); + } + + public static CruiseCacheLoader newCacheLoader(PersistenceService persistenceService, + DecoratorService decoratorService, + ProgressionModel progressionModel, + CruiseCache cruiseCache) { + return new CruiseCacheLoader(persistenceService, decoratorService, progressionModel, cruiseCache); + } + + public CruiseCache loadCruiseCache() { + + if (log.isInfoEnabled()) { + log.info("Loading cruise cache: " + cruiseCache); + } + + Decorator<FishingOperation> fishingOperationDecorator = decoratorService.getDecoratorByType(FishingOperation.class); + + persistenceService.getAllFishingOperationIds(cruiseCache.getCruiseId()).forEach(fishingOperationId -> { + + FishingOperation fishingOperation = persistenceService.getFishingOperation(fishingOperationId); + + progressionModel.increments(t("tutti.cruise.cacheLoader.loading.fishingOperation", fishingOperationDecorator.toString(fishingOperation))); + + loadCruiseCacheForFishingOperation(fishingOperation); + + }); + + if (log.isInfoEnabled()) { + log.info("Cruise cache loaded: " + cruiseCache); + } + + return cruiseCache; + } + + public CruiseCache loadCruiseCacheForFishingOperation(FishingOperation fishingOperation) { + + if (log.isInfoEnabled()) { + log.info("Loading cruise cache for fishing operation: " + fishingOperation + " → " + cruiseCache); + } + + List<IndividualObservationBatch> individualObservations = + persistenceService.getAllIndividualObservationBatchsForFishingOperation(fishingOperation.getIdAsInt()); + + cruiseCache.addFishingOperation(fishingOperation, individualObservations); + + if (log.isInfoEnabled()) { + log.info("Cruise cache loaded for fishing operation: " + fishingOperation + " → " + cruiseCache); + } + + return cruiseCache; + + } + + private CruiseCacheLoader(PersistenceService persistenceService, + DecoratorService decoratorService, + ProgressionModel progressionModel, + CruiseCache cruiseCache) { + this.persistenceService = persistenceService; + this.decoratorService = decoratorService; + this.progressionModel = progressionModel; + this.cruiseCache = cruiseCache; + } + +} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCache.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCache.java index 6ce0fd0..ad39cb7 100644 --- a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCache.java +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCache.java @@ -26,7 +26,6 @@ package fr.ifremer.tutti.service.sampling; import com.google.common.base.MoreObjects; import com.google.common.collect.HashMultimap; -import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import fr.ifremer.tutti.persistence.entities.TuttiEntities; import fr.ifremer.tutti.persistence.entities.data.FishingOperation; @@ -40,12 +39,10 @@ import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativ import fr.ifremer.tutti.persistence.entities.referential.Species; import fr.ifremer.tutti.persistence.entities.referential.TuttiLocation; import fr.ifremer.tutti.util.Numbers; -import org.apache.commons.lang3.mutable.MutableInt; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.swing.event.EventListenerList; -import java.io.Closeable; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -58,7 +55,7 @@ import java.util.Set; * @author Kevin Morin (Code Lutin) * @since 4.5 */ -public class CruiseSamplingCache implements Closeable { +public class CruiseSamplingCache implements CruiseCacheAble { /** Logger. */ private static final Log log = LogFactory.getLog(CruiseSamplingCache.class); @@ -104,27 +101,13 @@ public class CruiseSamplingCache implements Closeable { */ 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; - /** - * Le code prélèvement le plus grand pour chaque espèce. - */ - private final Map<Integer, MutableInt> highestSamplingCodeBySpecies = new HashMap<>(); - public CruiseSamplingCache(int cruiseId, TuttiProtocol protocol, Caracteristic sexCaracteristic, Collection<Caracteristic> maturityCaracteristics) { - this.cruiseId = cruiseId; + public CruiseSamplingCache(TuttiProtocol protocol, Caracteristic sexCaracteristic, Collection<Caracteristic> maturityCaracteristics) { this.sexCaracteristic = sexCaracteristic; - this.sexQualitativeValues = Maps.uniqueIndex(sexCaracteristic.getQualitativeValue(), TuttiEntities.GET_ID_AS_INT); - this.protocolId = protocol.getId(); + this.sexQualitativeValues = TuttiEntities.splitByIdAsInt(sexCaracteristic.getQualitativeValue()); locationIdsPerZone = HashMultimap.create(); protocol.getZone().forEach(zone -> locationIdsPerZone.putAll(zone, Zones.getAllLocationIds(zone))); @@ -141,14 +124,6 @@ public class CruiseSamplingCache implements Closeable { protocol.getMaturityCaracteristics().forEach(mc -> matureStatesByMaturityCracteristic.putAll(mc.getId(), mc.getMatureStateIds())); } - public int getCruiseId() { - return cruiseId; - } - - public String getProtocolId() { - return protocolId; - } - public boolean isLoading() { return loading; } @@ -158,89 +133,207 @@ public class CruiseSamplingCache implements Closeable { } @Override - public void close() { - if (log.isInfoEnabled()) { - log.info("Closing cruise sampling cache."); - } - totalCruiseCache.close(); - zoneCache.close(); - operationCache.close(); - locationIdsPerZone.clear(); - cpsDefinitionsBySpecies.clear(); - maturityCaracteristicBySpecies.clear(); - sexQualitativeValues.clear(); - matureStatesByMaturityCracteristic.clear(); - SamplingListener[] samplingListeners = listeners.getListeners(SamplingListener.class); - for (SamplingListener listener : samplingListeners) { - removeSamplingListener(listener); - } + public void addFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + addIndividualObservations(fishingOperation, individualObservations); + } @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(); + public void addIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); + + setLoading(true); + + try { + + + Zone optionalZone = tryFindZone(fishingOperation).orElse(null); + int fishingOperationId = fishingOperation.getIdAsInt(); + + for (IndividualObservationBatch individualObservationBatch : individualObservations) { + + Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition = + tryToFindCalcifiedPiecesSamplingDefinition(individualObservationBatch); + + if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) { + + // pas dans l'algorithme, one ne tient pas compte de cette observation + continue; + } + + Species species = individualObservationBatch.getSpecies(); + Objects.requireNonNull(species); + + // l'observation a forcement une taille + Float lengthStep = individualObservationBatch.getSize(); + Objects.requireNonNull(lengthStep); + + Boolean maturity = getMaturity(individualObservationBatch); + + int lengthStepInMm = Numbers.convertToMm(lengthStep, individualObservationBatch.getLengthStepCaracteristic().getUnit()); + + CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic); + + CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition = optionalCalcifiedPiecesSamplingDefinition.get(); + + addIndividualObservation(calcifiedPiecesSamplingDefinition, fishingOperationId, optionalZone, species, gender, maturity, lengthStepInMm); + + String samplingCode = individualObservationBatch.getSamplingCode(); + if (samplingCode != null) { + + addSampling(calcifiedPiecesSamplingDefinition, fishingOperationId, optionalZone, species, gender, maturity, lengthStepInMm); + + } + + } + + } finally { + + setLoading(false); + + } + } - /** - * Ajout d'un échantillon dans le cache. - * - * @param fishingOperationId l'identifiant de l'opération de pêche concernée - * @param optionalZone la zone (facultative) de l'opération de pêche concernée - * @param individualObservationBatchs les observations à ajouter au cache - */ - public void addIndividualObservations(int fishingOperationId, - Zone optionalZone, - List<IndividualObservationBatch> individualObservationBatchs) { + @Override + public void removeIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { - Objects.requireNonNull(fishingOperationId); -// Objects.requireNonNull(optionalZone); - Objects.requireNonNull(individualObservationBatchs); + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); + + setLoading(true); + + try { + + Zone optionalZone = tryFindZone(fishingOperation).orElse(null); + int fishingOperationId = fishingOperation.getIdAsInt(); + + for (IndividualObservationBatch individualObservationBatch : individualObservations) { + + Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition = + tryToFindCalcifiedPiecesSamplingDefinition(individualObservationBatch); + + if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) { + + // pas dans l'algorithme, one ne tient pas compte de cette observation + continue; + } - for (IndividualObservationBatch individualObservationBatch : individualObservationBatchs) { + Species species = individualObservationBatch.getSpecies(); + Objects.requireNonNull(species); - Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition = - tryToFindCalcifiedPiecesSamplingDefinition(individualObservationBatch); + Boolean maturity = getMaturity(individualObservationBatch); - if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) { + float lengthStep = individualObservationBatch.getSize(); + int lengthStepInMm = Numbers.convertToMm(lengthStep, individualObservationBatch.getLengthStepCaracteristic().getUnit()); + + CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic); + + CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition = optionalCalcifiedPiecesSamplingDefinition.get(); + + String samplingCode = individualObservationBatch.getSamplingCode(); + if (samplingCode != null) { + + removeSampling(calcifiedPiecesSamplingDefinition, fishingOperationId, optionalZone, species, gender, maturity, lengthStepInMm); + + } + + removeIndividualObservation(calcifiedPiecesSamplingDefinition, fishingOperationId, optionalZone, species, gender, maturity, lengthStepInMm); - // pas dans l'algorithme, one ne tient pas compte de cette observation - continue; } - Species species = individualObservationBatch.getSpecies(); - Objects.requireNonNull(species); + } finally { - // l'observation a forcement une taille - Float lengthStep = individualObservationBatch.getSize(); - Objects.requireNonNull(lengthStep); + setLoading(false); - Boolean maturity = getMaturity(individualObservationBatch); + } - int lengthStepInMm = Numbers.convertToMm(lengthStep, individualObservationBatch.getLengthStepCaracteristic().getUnit()); + } - CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic); + @Override + public void removeFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { - CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition = optionalCalcifiedPiecesSamplingDefinition.get(); + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); - addIndividualObservation(calcifiedPiecesSamplingDefinition, fishingOperationId, optionalZone, species, gender, maturity, lengthStepInMm); + setLoading(true); - String samplingCode = individualObservationBatch.getSamplingCode(); - if (samplingCode != null) { + try { - addSampling(calcifiedPiecesSamplingDefinition, fishingOperationId, optionalZone, species, gender, maturity, lengthStepInMm, samplingCode); + String fishingOperationId = fishingOperation.getId(); + if (log.isInfoEnabled()) { + log.info("Removing fishing operation: " + fishingOperation + " from " + this); + } + + // suppression de toutes les entrées du cache des opérations (et récupération des clefs) + Set<String> removedKeys = operationCache.removeAllWhereKeyStartingWith(fishingOperationId); + + if (log.isInfoEnabled()) { + log.info("Fishing operation: " + fishingOperation + " removed from operationCache: " + operationCache.size()); + } + + removedKeys.forEach(totalCruiseCache::decrementObservationNb); + + if (log.isInfoEnabled()) { + log.info("Fishing operation: " + fishingOperation + " removed from totalCruiseCache: " + totalCruiseCache.size()); + } + + Optional<Zone> optionalZone = tryFindZone(fishingOperation); + + if (optionalZone.isPresent()) { + String zoneId = optionalZone.get().getId(); + removedKeys.forEach(key -> zoneCache.decrementObservationNbIfExist(CruiseSamplingInternalCache.addPrefixKey(zoneId, key))); + + if (log.isInfoEnabled()) { + log.info("Fishing operation: " + fishingOperation + " removed from zoneCache: " + zoneCache.size()); + } + } + + if (log.isInfoEnabled()) { + log.info("Fishing operation: " + fishingOperation + " removed from " + this); } + } finally { + + setLoading(false); + } } + @Override + public void close() { + + if (log.isInfoEnabled()) { + log.info("Closing cruise sampling cache."); + } + totalCruiseCache.close(); + zoneCache.close(); + operationCache.close(); + locationIdsPerZone.clear(); + cpsDefinitionsBySpecies.clear(); + maturityCaracteristicBySpecies.clear(); + matureStatesByMaturityCracteristic.clear(); + SamplingListener[] samplingListeners = listeners.getListeners(SamplingListener.class); + for (SamplingListener listener : samplingListeners) { + removeSamplingListener(listener); + } + + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("totalCruiseCache", totalCruiseCache.size()) + .add("zoneCache", zoneCache.size()) + .add("operationCache", operationCache.size()) + .toString(); + } + /** * Ajout d'un observation dans le cache. * @@ -279,57 +372,6 @@ public class CruiseSamplingCache implements Closeable { /** * Suppression d'un échantillon du cache. * - * @param fishingOperationId l'identifiant de l'opération de pêche concernée - * @param zone la zone (facultative) de l'opération de pêche concernée - * @param individualObservationBatches les observations individuelles à supprimer du cache - */ - public void removeIndividualObservations(int fishingOperationId, - Zone zone, - Collection<IndividualObservationBatch> individualObservationBatches) { - - Objects.requireNonNull(fishingOperationId); - Objects.requireNonNull(zone); - Objects.requireNonNull(individualObservationBatches); - - for (IndividualObservationBatch individualObservationBatch : individualObservationBatches) { - - Optional<CalcifiedPiecesSamplingDefinition> optionalCalcifiedPiecesSamplingDefinition = - tryToFindCalcifiedPiecesSamplingDefinition(individualObservationBatch); - - if (!optionalCalcifiedPiecesSamplingDefinition.isPresent()) { - - // pas dans l'algorithme, one ne tient pas compte de cette observation - continue; - } - - Species species = individualObservationBatch.getSpecies(); - Objects.requireNonNull(species); - - Boolean maturity = getMaturity(individualObservationBatch); - - float lengthStep = individualObservationBatch.getSize(); - int lengthStepInMm = Numbers.convertToMm(lengthStep, individualObservationBatch.getLengthStepCaracteristic().getUnit()); - - CaracteristicQualitativeValue gender = individualObservationBatch.getCaracteristics().getQualitativeValue(sexCaracteristic); - - CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition = optionalCalcifiedPiecesSamplingDefinition.get(); - - String samplingCode = individualObservationBatch.getSamplingCode(); - if (samplingCode != null) { - - removeSampling(calcifiedPiecesSamplingDefinition, fishingOperationId, zone, species, gender, maturity, lengthStepInMm, samplingCode); - - } - - removeIndividualObservation(calcifiedPiecesSamplingDefinition, fishingOperationId, zone, species, gender, maturity, lengthStepInMm); - - } - - } - - /** - * 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) @@ -368,14 +410,12 @@ public class CruiseSamplingCache implements Closeable { * @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 (en mm) - * @param samplingCode le code de prélèvement ajouté */ public void addSampling(FishingOperation fishingOperation, Species species, CaracteristicQualitativeValue gender, Boolean maturity, - int lengthStep, - String samplingCode) { + int lengthStep) { Objects.requireNonNull(fishingOperation); Objects.requireNonNull(species); @@ -395,7 +435,8 @@ public class CruiseSamplingCache implements Closeable { CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition = optionalCalcifiedPiecesSamplingDefinition.get(); - addSampling(calcifiedPiecesSamplingDefinition, fishingOperation.getIdAsInt(), optionalZone.orElse(null), species, gender, maturity, lengthStep, samplingCode); + addSampling(calcifiedPiecesSamplingDefinition, fishingOperation.getIdAsInt(), optionalZone.orElse(null), species, gender, maturity, lengthStep); + } /** @@ -406,14 +447,12 @@ public class CruiseSamplingCache implements Closeable { * @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 (en mm) - * @param samplingCode le code de prélèvement supprimé */ public void removeSampling(FishingOperation fishingOperation, Species species, CaracteristicQualitativeValue gender, Boolean maturity, - int lengthStep, - String samplingCode) { + int lengthStep) { Objects.requireNonNull(fishingOperation); Objects.requireNonNull(species); @@ -428,52 +467,7 @@ public class CruiseSamplingCache implements Closeable { CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition = optionalCalcifiedPiecesSamplingDefinition.get(); - removeSampling(calcifiedPiecesSamplingDefinition, fishingOperation.getIdAsInt(), optionalZone.orElse(null), species, gender, maturity, lengthStep, samplingCode); - - } - - /** - * 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); - - String fishingOperationId = fishingOperation.getId(); - - if (log.isInfoEnabled()) { - log.info("Remove fishing operation: " + fishingOperationId + " from CruiseSamplingCache: " + this); - } - - // suppression de toutes les entrées du cache des opérations (et récupération des clefs) - Set<String> removedKeys = operationCache.removeAllWhereKeyStartingWith(fishingOperationId); - - if (log.isInfoEnabled()) { - log.info("Fishing operation: " + fishingOperationId + " removed from operationCache: " + operationCache.size()); - } - - removedKeys.forEach(totalCruiseCache::decrementObservationNb); - - if (log.isInfoEnabled()) { - log.info("Fishing operation: " + fishingOperationId + " removed from totalCruiseCache: " + totalCruiseCache.size()); - } - - Optional<Zone> optionalZone = tryFindZone(fishingOperation); - - if (optionalZone.isPresent()) { - String zoneId = optionalZone.get().getId(); - removedKeys.forEach(key -> zoneCache.decrementObservationNbIfExist(CruiseSamplingInternalCache.addPrefixKey(zoneId, key))); - - if (log.isInfoEnabled()) { - log.info("Fishing operation: " + fishingOperationId + " removed from zoneCache: " + zoneCache.size()); - } - } - - if (log.isInfoEnabled()) { - log.info("Fishing operation: " + fishingOperationId + " removed from CruiseSamplingCache: " + this); - } + removeSampling(calcifiedPiecesSamplingDefinition, fishingOperation.getIdAsInt(), optionalZone.orElse(null), species, gender, maturity, lengthStep); } @@ -533,16 +527,12 @@ public class CruiseSamplingCache implements Closeable { } - public Optional<Zone> tryFindZone(FishingOperation operation) { - Optional<Zone> result; - if (operation.getSubStrata() != null) { - result = tryFindZone(operation.getSubStrata()); - } else if (operation.getStrata() != null) { - result = tryFindZone(operation.getStrata()); - } else { - result = Optional.empty(); - } - return result; + public boolean isZoneChanged(FishingOperation operation1, FishingOperation operation2) { + + Optional<Zone> optionalZone1 = tryFindZone(operation1); + Optional<Zone> optionalZone2 = tryFindZone(operation2); + return !Objects.equals(optionalZone1, optionalZone2); + } public Boolean getMaturity(int speciesId, CaracteristicQualitativeValue maturityQualitativeValue) { @@ -554,12 +544,6 @@ public class CruiseSamplingCache implements Closeable { return maturity; } - public int getNextSamplingCodeId(int speciesId) { - MutableInt samplingCode = highestSamplingCodeBySpecies.get(speciesId); - return (samplingCode == null ? 0 : samplingCode.intValue()) + 1; -// return highestSamplingCodeBySpecies.getOrDefault(speciesId, 0) + 1; - } - public void addSamplingListener(SamplingListener listener) { listeners.add(SamplingListener.class, listener); } @@ -568,6 +552,18 @@ public class CruiseSamplingCache implements Closeable { listeners.remove(SamplingListener.class, listener); } + private Optional<Zone> tryFindZone(FishingOperation operation) { + Optional<Zone> result; + if (operation.getSubStrata() != null) { + result = tryFindZone(operation.getSubStrata()); + } else if (operation.getStrata() != null) { + result = tryFindZone(operation.getStrata()); + } else { + result = Optional.empty(); + } + return result; + } + private void fireSamplingNeeded(SamplingEvent event) { SamplingListener[] samplingListeners = listeners.getListeners(SamplingListener.class); @@ -746,7 +742,6 @@ public class CruiseSamplingCache implements Closeable { * @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 (en mm) - * @param samplingCode le code de prélèvement ajouté */ private void addSampling(CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition, int fishingOperationId, @@ -754,8 +749,7 @@ public class CruiseSamplingCache implements Closeable { Species species, CaracteristicQualitativeValue gender, Boolean maturity, - int lengthStep, - String samplingCode) { + int lengthStep) { Objects.requireNonNull(calcifiedPiecesSamplingDefinition); Objects.requireNonNull(fishingOperationId); @@ -784,27 +778,6 @@ public class CruiseSamplingCache implements Closeable { SamplingEvent event = new SamplingEvent(this, lengthStep, gender, maturity, calcifiedPiecesSamplingDefinition, zone, totalSamplingNb, zoneSamplingNb, operationSamplingNb); fireSummaryUpdated(event); - addSamplingCode(species.getReferenceTaxonId(), samplingCode); - - } - - private int addSamplingCode(int speciesId, String samplingCode) { - int code = SamplingCodePrefix.extractSamplingCodeIdFromSamplingCode(samplingCode); - - // increment the highest sampling code if it is this code -// return highestSamplingCodeBySpecies.compute(speciesId, -// (key, highestSamplingCode) -> highestSamplingCode == null ? code : Math.max(highestSamplingCode, code)); - - return highestSamplingCodeBySpecies.compute(speciesId, - (key, highestSamplingCode) -> { - if (highestSamplingCode == null) { - highestSamplingCode = new MutableInt(code); - } else { - int nexValue = Math.max(highestSamplingCode.intValue(), code); - highestSamplingCode.setValue(nexValue); - } - return highestSamplingCode; - }).intValue(); } /** @@ -816,7 +789,6 @@ public class CruiseSamplingCache implements Closeable { * @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 (en mm) - * @param samplingCode le code de prélèvement supprimé */ private void removeSampling(CalcifiedPiecesSamplingDefinition calcifiedPiecesSamplingDefinition, int fishingOperationId, @@ -824,8 +796,7 @@ public class CruiseSamplingCache implements Closeable { Species species, CaracteristicQualitativeValue gender, Boolean maturity, - int lengthStep, - String samplingCode) { + int lengthStep) { Objects.requireNonNull(calcifiedPiecesSamplingDefinition); Objects.requireNonNull(fishingOperationId); @@ -855,21 +826,6 @@ public class CruiseSamplingCache implements Closeable { SamplingEvent event = new SamplingEvent(this, lengthStep, gender, maturity, calcifiedPiecesSamplingDefinition, zone, totalSamplingNb, zoneSamplingNb, operationSamplingNb); fireSummaryUpdated(event); - removeSamplingCode(species.getReferenceTaxonId(), samplingCode); - - } - - - private void removeSamplingCode(int speciesId, String samplingCode) { - int code = SamplingCodePrefix.extractSamplingCodeIdFromSamplingCode(samplingCode); - - // decrement the highest sampling code if it is this code - MutableInt samplingCodeFound = highestSamplingCodeBySpecies.get(speciesId); - if (samplingCodeFound != null && code == samplingCodeFound.intValue()) { - samplingCodeFound.decrement(); - } -// return highestSamplingCodeBySpecies.computeIfPresent(speciesId, -// (key, highestSamplingCode) -> code.equals(highestSamplingCode) ? code - 1 : highestSamplingCode); } private Optional<CalcifiedPiecesSamplingDefinition> tryToFindCalcifiedPiecesSamplingDefinition(IndividualObservationBatch individualObservationBatch) { @@ -897,11 +853,10 @@ public class CruiseSamplingCache implements Closeable { } - return result; } - + private Optional<CalcifiedPiecesSamplingDefinition> tryToFindCalcifiedPiecesSamplingDefinition(Species species, Boolean maturity, int lengthStep, CaracteristicQualitativeValue gender) { Collection<CalcifiedPiecesSamplingDefinition> cpsDefinitions = cpsDefinitionsBySpecies.get(species.getReferenceTaxonId()); diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCacheLoader.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCacheLoader.java deleted file mode 100644 index ebe3107..0000000 --- a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/CruiseSamplingCacheLoader.java +++ /dev/null @@ -1,156 +0,0 @@ -package fr.ifremer.tutti.service.sampling; - -/* - * #%L - * Tutti :: Service - * $Id:$ - * $HeadURL:$ - * %% - * Copyright (C) 2012 - 2016 Ifremer - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -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.protocol.Zone; -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.Collection; -import java.util.List; - -import static org.nuiton.i18n.I18n.t; - -/** - * 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(); - - Collection<Caracteristic> maturityCaracteristics = persistenceService.getMaturityCaracteristics(persistenceService.getAllCaracteristic()); - - CruiseSamplingCache cruiseSamplingCache = new CruiseSamplingCache(cruiseId, protocol, sexCaracteristic, maturityCaracteristics); - - 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(t("tutti.cruise.cacheLoader.loading.fishingOperation", fishingOperationDecorator.toString(fishingOperation))); - - List<IndividualObservationBatch> allIndividualObservationBatchsForFishingOperation = - persistenceService.getAllIndividualObservationBatchsForFishingOperation(fishingOperationId); - - Zone optionalZone = cruiseSamplingCache.tryFindZone(fishingOperation).orElse(null); - - cruiseSamplingCache.addIndividualObservations(fishingOperationId, - optionalZone, - allIndividualObservationBatchsForFishingOperation); - -// allIndividualObservationBatchsForFishingOperation.stream().filter(obs -> obs.getSize() != null).forEach( -// individualObservationBatch -> cruiseSamplingCache.addIndividualObservation(fishingOperationId, optionalZone, individualObservationBatch)); - - }); - - if (log.isInfoEnabled()) { - log.info("cruise sampling cache loaded: " + cruiseSamplingCache); - } - - return cruiseSamplingCache; - - } finally { - - cruiseSamplingCache.setLoading(false); - - } - - } - - public void loadCruiseSamplingCacheForFishingOperation(CruiseSamplingCache cruiseSamplingCache, FishingOperation fishingOperation) { - - cruiseSamplingCache.setLoading(true); - - try { - - Integer fishingOperationId = fishingOperation.getIdAsInt(); - - Zone optionalZone = cruiseSamplingCache.tryFindZone(fishingOperation).orElse(null); - - if (log.isInfoEnabled()) { - log.info("Loading cruise sampling cache for fishing operation: " + fishingOperationId + " - " + cruiseSamplingCache); - } - - List<IndividualObservationBatch> allIndividualObservationBatchsForFishingOperation = - persistenceService.getAllIndividualObservationBatchsForFishingOperation(fishingOperationId); - - cruiseSamplingCache.addIndividualObservations(fishingOperationId, - optionalZone, - allIndividualObservationBatchsForFishingOperation); - -// allIndividualObservationBatchsForFishingOperation.forEach( -// individualObservationBatch -> cruiseSamplingCache.addIndividualObservation(fishingOperationId, optionalZone, individualObservationBatch)); - - if (log.isInfoEnabled()) { - log.info("Cruise sampling cache loaded for fishing operation: " + fishingOperationId + " - " + cruiseSamplingCache); - } - - } finally { - - cruiseSamplingCache.setLoading(false); - - } - - } - -} diff --git a/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/SamplingCodeCache.java b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/SamplingCodeCache.java new file mode 100644 index 0000000..149f8d2 --- /dev/null +++ b/tutti-service/src/main/java/fr/ifremer/tutti/service/sampling/SamplingCodeCache.java @@ -0,0 +1,113 @@ +package fr.ifremer.tutti.service.sampling; + +import fr.ifremer.tutti.persistence.entities.data.FishingOperation; +import fr.ifremer.tutti.persistence.entities.data.IndividualObservationBatch; +import org.apache.commons.lang3.mutable.MutableInt; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Objects; +import java.util.TreeMap; + +/** + * Contient le cache des codes de prélèvement disponibles. + * + * Created on 16/04/16. + * + * @author Tony Chemit - chemit@codelutin.com + * @since 4.5 + */ +public class SamplingCodeCache implements CruiseCacheAble { + + /** + * Le code prélèvement le plus grand pour chaque espèce. + */ + private final Map<Integer, MutableInt> highestSamplingCodeBySpecies; + + public SamplingCodeCache() { + this.highestSamplingCodeBySpecies = new TreeMap<>(); + } + + @Override + public void addFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); + addIndividualObservations(fishingOperation, individualObservations); + + } + + @Override + public void removeFishingOperation(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); + removeIndividualObservations(fishingOperation, individualObservations); + + } + + @Override + public void addIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); + + individualObservations + .stream() + .filter(batch -> batch.getSamplingCode() != null) + .forEach(batch -> addSamplingCode(batch.getSpecies().getReferenceTaxonId(), batch.getSamplingCode())); + + } + + @Override + public void removeIndividualObservations(FishingOperation fishingOperation, Collection<IndividualObservationBatch> individualObservations) { + + Objects.requireNonNull(fishingOperation); + Objects.requireNonNull(individualObservations); + + individualObservations + .stream() + .filter(batch -> batch.getSamplingCode() != null) + .forEach(batch -> removeSamplingCode(batch.getSpecies().getReferenceTaxonId(), batch.getSamplingCode())); + + } + + @Override + public void close() throws IOException { + highestSamplingCodeBySpecies.clear(); + } + + public int getNextSamplingCodeId(int speciesId) { + MutableInt samplingCode = highestSamplingCodeBySpecies.get(speciesId); + return (samplingCode == null ? 0 : samplingCode.intValue()) + 1; + } + + public int addSamplingCode(int speciesId, String samplingCode) { + int code = SamplingCodePrefix.extractSamplingCodeIdFromSamplingCode(samplingCode); + + return highestSamplingCodeBySpecies.compute(speciesId, + (key, highestSamplingCode) -> { + if (highestSamplingCode == null) { + highestSamplingCode = new MutableInt(code); + } else { + int nexValue = Math.max(highestSamplingCode.intValue(), code); + highestSamplingCode.setValue(nexValue); + } + return highestSamplingCode; + }).intValue(); + } + + public void removeSamplingCode(int speciesId, String samplingCode) { + + int code = SamplingCodePrefix.extractSamplingCodeIdFromSamplingCode(samplingCode); + + // decrement the highest sampling code if it is this code + MutableInt samplingCodeFound = highestSamplingCodeBySpecies.get(speciesId); + if (samplingCodeFound != null && code == samplingCodeFound.intValue()) { + samplingCodeFound.decrement(); + } + + } + +} -- To stop receiving notification emails like this one, please contact codelutin.com SCM administrator <admin+scm@codelutin.com>.