1 package fr.ifremer.tutti.service.sampling;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
46
47
48
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
89
90
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
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
214
215 private int individualObservationCount;
216
217
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 }