View Javadoc
1   package fr.ifremer.tutti.service.sampling;
2   
3   /*
4    * #%L
5    * Tutti :: Service
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2012 - 2016 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU General Public License as
13   * published by the Free Software Foundation, either version 3 of the
14   * License, or (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU General Public
22   * License along with this program.  If not, see
23   * <http://www.gnu.org/licenses/gpl-3.0.html>.
24   * #L%
25   */
26  
27  import com.google.common.base.MoreObjects;
28  import com.google.common.base.Preconditions;
29  import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue;
30  import fr.ifremer.tutti.persistence.entities.referential.Species;
31  import org.apache.commons.lang3.StringUtils;
32  
33  import java.io.Closeable;
34  import java.io.Serializable;
35  import java.util.Collections;
36  import java.util.Iterator;
37  import java.util.LinkedList;
38  import java.util.List;
39  import java.util.Map;
40  import java.util.Objects;
41  import java.util.Set;
42  import java.util.TreeMap;
43  
44  /**
45   * Created on 19/03/16.
46   *
47   * @author Tony Chemit - chemit@codelutin.com
48   * @since 4.5
49   */
50  class CruiseSamplingInternalCache implements Closeable {
51  
52      private static final String KEY_SEPARATOR = "#";
53  
54      public static String createSamplingKey(Species species, CaracteristicQualitativeValue gender, Boolean maturity, int lengthStep) {
55          Objects.requireNonNull(species);
56          return species.getReferenceTaxonId() + KEY_SEPARATOR + (gender == null ? "" : gender.getId()) +
57                  KEY_SEPARATOR + (maturity == null ? "" : maturity.toString()) + KEY_SEPARATOR + lengthStep;
58      }
59  
60      public static String addPrefixKey(Serializable prefix, String key) {
61          Objects.requireNonNull(prefix);
62          Objects.requireNonNull(key);
63          return prefix + KEY_SEPARATOR + key;
64      }
65  
66      private final Map<String, SamplingData> data = new TreeMap<>();
67  
68      public SamplingData getSamplingData(String samplingKey) {
69          Objects.requireNonNull(samplingKey);
70          return data.get(samplingKey);
71      }
72  
73      public SamplingData getOrCreateSamplingData(String samplingKey) {
74          Objects.requireNonNull(samplingKey);
75          return data.computeIfAbsent(samplingKey, s -> new SamplingData());
76      }
77  
78      @Override
79      public void close() {
80          data.clear();
81      }
82  
83      public int size() {
84          return data.size();
85      }
86  
87      /**
88       * Get the number of samplings by lengthstep for a species, maturity and gender, for the lengthsteps between min size and max size
89       *
90       * @return a map of the number of samplings for each lengthstep in millimeters
91       */
92      public List<CacheExtractedKey> getSamplingNumbers(Map<String, Species> speciesById, Map<Integer, CaracteristicQualitativeValue> sexQualitativeValues) {
93  
94          List<CacheExtractedKey> result = new LinkedList<>();
95  
96          for (Map.Entry<String, SamplingData> entry : data.entrySet()) {
97  
98              SamplingData samplingData = entry.getValue();
99  
100             if (samplingData.withSampling()) {
101 
102                 String[] keyTokens = entry.getKey().split(KEY_SEPARATOR);
103 
104                 CacheExtractedKey key = new CacheExtractedKey();
105 
106                 int i = 0;
107                 String nextToken = keyTokens[i++];
108 
109                 Species species = speciesById.get(nextToken);
110                 key.setSpecies(species);
111 
112                 nextToken = keyTokens[i++];
113                 if (!StringUtils.isEmpty(nextToken)) {
114                     Integer sexId = Integer.parseInt(nextToken);
115                     CaracteristicQualitativeValue sexQualitativeValue = sexQualitativeValues.get(sexId);
116                     key.setSex(sexQualitativeValue);
117                 }
118 
119                 nextToken = keyTokens[i++];
120                 if (!StringUtils.isEmpty(nextToken)) {
121                     Boolean maturity = Boolean.parseBoolean(nextToken);
122                     key.setMaturity(maturity);
123                 }
124 
125                 nextToken = keyTokens[i];
126                 if (!StringUtils.isEmpty(nextToken)) {
127                     int lengthStep = Integer.parseInt(nextToken);
128                     key.setLengthStep(lengthStep);
129                 }
130 
131                 key.setSamplingNb(samplingData.getSamplingCount());
132 
133                 result.add(key);
134             }
135 
136         }
137 
138         return result;
139 
140     }
141 
142     public SamplingData addOneIndividualObservation(String key) {
143         SamplingData samplingData = getOrCreateSamplingData(key);
144         samplingData.individualObservationCount++;
145         return samplingData;
146     }
147 
148     public SamplingData removeOneIndividualObservation(String key) {
149         SamplingData samplingData = getSamplingData(key);
150 
151         Objects.requireNonNull(samplingData, "[" + key + "] You cannot decrement a individual observation if the sampling data does not exist");
152         Preconditions.checkState(samplingData.withIndividualObservation(), "[" + key + "] You cannot decrement the observation count if there is no observation");
153         samplingData.individualObservationCount--;
154         return samplingData;
155     }
156 
157     public SamplingData addOneSampling(String key) {
158         //FIXME Normalement on ne doit pas créer ici car si on ajoute un prélèvement c'est qu'il y a déjà au préalable une observation
159         SamplingData samplingData = getOrCreateSamplingData(key);
160         samplingData.samplingCount++;
161         return samplingData;
162     }
163 
164     public SamplingData removeOneSampling(String key) {
165         SamplingData samplingData = getSamplingData(key);
166         Objects.requireNonNull(samplingData, "[" + key + "] You cannot decrement a sampling count if the sampling data does not exist");
167         Preconditions.checkState(samplingData.withSampling(), "[" + key + "] You cannot decrement a sampling count if there is no sampling");
168         samplingData.samplingCount--;
169         return samplingData;
170     }
171 
172     public Set<String> getKeys() {
173         return Collections.unmodifiableSet(data.keySet());
174     }
175 
176     public void remove(String key, int individualObservationCountToRemove, int samplingCountToRemove) {
177 
178         SamplingData samplingData = getSamplingData(key);
179         Objects.requireNonNull(samplingData, "[" + key + "] not found.");
180 
181         int individualObservationCount = samplingData.getIndividualObservationCount();
182         Preconditions.checkState(individualObservationCount >= individualObservationCountToRemove, "[" + key + "] You cannot decrement " + individualObservationCountToRemove + " individual observation(s), you just have " + individualObservationCount);
183         samplingData.individualObservationCount -= individualObservationCountToRemove;
184 
185         int samplingCount = samplingData.getSamplingCount();
186         Preconditions.checkState(samplingCount >= samplingCountToRemove, "[" + key + "] You cannot decrement " + samplingCountToRemove + " sampling(s), you just have " + samplingCount);
187         samplingData.samplingCount -= samplingCountToRemove;
188 
189     }
190 
191     public void cleanEmptyEntries() {
192         Iterator<Map.Entry<String, SamplingData>> iterator = data.entrySet().iterator();
193         while (iterator.hasNext()) {
194             Map.Entry<String, SamplingData> entry = iterator.next();
195             SamplingData samplingData = entry.getValue();
196             if (!(samplingData.withSampling() || samplingData.withIndividualObservation())) {
197                 iterator.remove();
198             }
199         }
200     }
201 
202     private static final String TO_STRING_VERBOSE_FORMAT = "\n%1$-40s → %2$s";
203 
204     public String toStringVerbose() {
205         StringBuilder stringBuilder = new StringBuilder(size() +" entries.");
206         data.entrySet().forEach(entry -> stringBuilder.append(String.format(TO_STRING_VERBOSE_FORMAT, entry.getKey(), entry.getValue())));
207         return stringBuilder.toString();
208     }
209 
210     class SamplingData {
211 
212         /**
213          * Nombre d'observations individuelles.
214          */
215         private int individualObservationCount;
216         /**
217          * Nombre de prélèvements.
218          */
219         private int samplingCount;
220 
221         public int getIndividualObservationCount() {
222             return individualObservationCount;
223         }
224 
225         public boolean withSampling() {
226             return samplingCount > 0;
227         }
228 
229         public boolean withIndividualObservation() {
230             return individualObservationCount > 0;
231         }
232 
233         public int getSamplingCount() {
234             return samplingCount;
235         }
236 
237         @Override
238         public String toString() {
239             return MoreObjects.toStringHelper(SamplingData.class)
240                               .add("individualObservationCount", individualObservationCount)
241                               .add("samplingCount", samplingCount)
242                               .toString();
243         }
244     }
245 
246 }