1 package fr.ifremer.reefdb.dao.referential.taxon;
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 import com.google.common.collect.*;
27 import fr.ifremer.quadrige3.core.dao.referential.StatusCode;
28 import fr.ifremer.quadrige3.core.dao.referential.StatusImpl;
29 import fr.ifremer.quadrige3.core.dao.referential.TaxonGroupTypeCode;
30 import fr.ifremer.quadrige3.core.dao.referential.TaxonGroupTypeImpl;
31 import fr.ifremer.quadrige3.core.dao.referential.taxon.TaxonGroup;
32 import fr.ifremer.quadrige3.core.dao.referential.taxon.TaxonGroupDaoImpl;
33 import fr.ifremer.quadrige3.core.dao.referential.taxon.TaxonGroupHistoricalRecord;
34 import fr.ifremer.quadrige3.core.dao.referential.taxon.TaxonNameImpl;
35 import fr.ifremer.quadrige3.core.dao.technical.Assert;
36 import fr.ifremer.quadrige3.core.dao.technical.hibernate.TemporaryDataHelper;
37 import fr.ifremer.quadrige3.core.service.technical.CacheService;
38 import fr.ifremer.reefdb.dao.technical.Daos;
39 import fr.ifremer.reefdb.dto.ReefDbBeanFactory;
40 import fr.ifremer.reefdb.dto.ReefDbBeans;
41 import fr.ifremer.reefdb.dto.referential.TaxonDTO;
42 import fr.ifremer.reefdb.dto.referential.TaxonGroupDTO;
43 import org.apache.commons.collections4.CollectionUtils;
44 import org.hibernate.Query;
45 import org.hibernate.SessionFactory;
46 import org.hibernate.type.IntegerType;
47 import org.hibernate.type.StringType;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.cache.Cache;
50 import org.springframework.cache.interceptor.SimpleKey;
51 import org.springframework.dao.DataRetrievalFailureException;
52 import org.springframework.stereotype.Repository;
53
54 import javax.annotation.Resource;
55 import java.time.LocalDate;
56 import java.util.*;
57 import java.util.stream.Collectors;
58
59
60
61
62
63 @Repository("reefDbTaxonGroupDao")
64 public class ReefDbTaxonGroupDaoImpl extends TaxonGroupDaoImpl implements ReefDbTaxonGroupDao {
65
66
67
68 private static final Multimap<String, String> columnNamesByReferentialTableNames = ImmutableListMultimap.<String, String>builder()
69 .put("TAXON_GROUP", "PARENT_TAXON_GROUP_ID")
70 .put("TAXON_GROUP_HISTORICAL_RECORD", "TAXON_GROUP_ID").build();
71
72 private static final Multimap<String, String> columnNamesByDataTableNames = ImmutableListMultimap.<String, String>builder()
73 .put("TAXON_MEASUREMENT", "TAXON_GROUP_ID").build();
74
75 private static final Map<String, String> validationDateColumnNameByDataTableNames = ImmutableMap.<String, String>builder()
76 .put("TAXON_MEASUREMENT", "TAXON_MEAS_VALID_DT").build();
77
78 @Resource
79 protected CacheService cacheService;
80
81 @Resource(name = "reefDbTaxonGroupDao")
82 protected ReefDbTaxonGroupDao loopbackTaxonGroupDao;
83 @Resource(name = "reefDbTaxonNameDao")
84 protected ReefDbTaxonNameDao taxonNameDao;
85
86
87
88
89
90
91 @Autowired
92 public ReefDbTaxonGroupDaoImpl(SessionFactory sessionFactory) {
93 super(sessionFactory);
94 }
95
96
97 @Override
98 public List<TaxonGroupDTO> getAllTaxonGroups() {
99
100
101 Cache cacheById = cacheService.getCache(TAXON_GROUP_BY_ID_CACHE);
102 Cache allTaxonNamesCache = cacheService.getCache(ReefDbTaxonNameDao.ALL_TAXON_NAMES_CACHE);
103 Cache taxonCache = cacheService.getCache(ReefDbTaxonNameDao.TAXON_NAME_BY_ID_CACHE);
104 Cache referenceTaxonCache = cacheService.getCache(ReefDbTaxonNameDao.TAXON_NAME_BY_REFERENCE_ID_CACHE);
105 Cache taxonNameByTaxonGroupIdCache = cacheService.getCache(ReefDbTaxonNameDao.TAXON_NAME_BY_TAXON_GROUP_ID_CACHE);
106
107
108 List<TaxonDTO> allTaxonNames = taxonNameDao.getAllTaxonNames();
109
110 LocalDate taxonRefDate = LocalDate.now();
111 Multimap<Integer, TaxonDTO> taxonMap = taxonNameDao.getAllTaxonNamesMapByTaxonGroupId(taxonRefDate);
112
113 Query query = createQuery("allTaxonGroup",
114 "taxonGroupTypeCode", StringType.INSTANCE, TaxonGroupTypeCode.IDENTIFICATION.getValue());
115 Iterator<Object[]> it = Daos.queryIteratorWithStatus(query,
116 ImmutableList.of(StatusCode.ENABLE.getValue(), StatusCode.TEMPORARY.getValue(), StatusCode.LOCAL_ENABLE.getValue()));
117
118
119 List<TaxonGroupDTO> result = Lists.newArrayList();
120 while (it.hasNext()) {
121 Object[] source = it.next();
122 TaxonGroupDTO taxonGroup = toTaxonGroupDTO(Arrays.asList(source).iterator());
123
124
125 TaxonGroupDTO lightTaxonGroup = getLightTaxonGroup(taxonGroup);
126
127
128 Collection<TaxonDTO> taxons = taxonMap.get(taxonGroup.getId());
129 for (TaxonDTO taxon : taxons) {
130
131
132 if (!taxon.containsTaxonGroups(lightTaxonGroup)) {
133 taxon.addTaxonGroups(lightTaxonGroup);
134 }
135
136
137 {
138 TaxonDTO cachedTaxon = taxonCache.get(taxon.getId(), TaxonDTO.class);
139 if (cachedTaxon != null && !cachedTaxon.containsTaxonGroups(lightTaxonGroup)) {
140 cachedTaxon.addTaxonGroups(lightTaxonGroup);
141 taxonCache.evict(taxon.getId());
142 taxonCache.put(taxon.getId(), cachedTaxon);
143 }
144 }
145
146
147 {
148 TaxonDTO cachedReferenceTaxon = referenceTaxonCache.get(taxon.getReferenceTaxonId(), TaxonDTO.class);
149 if (cachedReferenceTaxon != null && !cachedReferenceTaxon.containsTaxonGroups(lightTaxonGroup)) {
150 cachedReferenceTaxon.addTaxonGroups(lightTaxonGroup);
151 referenceTaxonCache.evict(taxon.getReferenceTaxonId());
152 referenceTaxonCache.put(taxon.getReferenceTaxonId(), cachedReferenceTaxon);
153 }
154 }
155
156
157 {
158 TaxonDTO cachedTaxon = ReefDbBeans.findById(allTaxonNames, taxon.getId());
159 if (!cachedTaxon.containsTaxonGroups(lightTaxonGroup)) {
160 cachedTaxon.addTaxonGroups(lightTaxonGroup);
161 }
162 }
163
164
165 taxonNameDao.fillParentAndReferent(taxon);
166 }
167
168
169 taxonGroup.addAllTaxons(taxons);
170
171
172 cacheById.put(taxonGroup.getId(), taxonGroup);
173
174 result.add(taxonGroup);
175 }
176
177
178 taxonNameByTaxonGroupIdCache.clear();
179 taxonNameByTaxonGroupIdCache.put(taxonRefDate, taxonMap);
180
181
182 allTaxonNamesCache.put(SimpleKey.EMPTY, allTaxonNames);
183
184 return ImmutableList.copyOf(result);
185 }
186
187
188 @Override
189 public TaxonGroupDTO getTaxonGroupById(int taxonGroupId) {
190
191
192 Object[] source = queryUnique("taxonGroupById", "taxonGroupId", IntegerType.INSTANCE, taxonGroupId);
193
194 if (source == null) {
195 throw new DataRetrievalFailureException("can't load taxon group with id = " + taxonGroupId);
196 }
197
198 TaxonGroupDTO taxonGroup = toTaxonGroupDTO(Arrays.asList(source).iterator());
199
200
201 TaxonGroupDTO lightTaxonGroup = getLightTaxonGroup(taxonGroup);
202
203 Collection<TaxonDTO> taxons = taxonNameDao.getAllTaxonNamesMapByTaxonGroupId(LocalDate.now()).get(taxonGroupId);
204 for (TaxonDTO taxon : taxons) {
205 if (!taxon.containsTaxonGroups(lightTaxonGroup)) {
206 taxon.addTaxonGroups(lightTaxonGroup);
207 }
208 }
209
210
211 taxonGroup.addAllTaxons(taxons);
212 return taxonGroup;
213 }
214
215
216
217 @Override
218 public List<TaxonGroupDTO> getTaxonGroupsByIds(Collection<Integer> taxonGroupIds) {
219
220 if (CollectionUtils.isEmpty(taxonGroupIds)) return new ArrayList<>();
221
222 return loopbackTaxonGroupDao.getAllTaxonGroups().stream().filter(taxonGroup -> taxonGroupIds.contains(taxonGroup.getId())).collect(Collectors.toList());
223 }
224
225
226 @Override
227 public List<TaxonGroupDTO> findTaxonGroups(Integer parentTaxonGroupId, String label, String name, boolean isStrictName, List<String> statusCodes) {
228
229 Multimap<Integer, TaxonDTO> taxonMap = taxonNameDao.getAllTaxonNamesMapByTaxonGroupId(LocalDate.now());
230
231 Query query = createQuery("taxonGroupsByCriteria",
232 "parentTaxonGroupId", IntegerType.INSTANCE, parentTaxonGroupId,
233 "label", StringType.INSTANCE, label,
234 "name", StringType.INSTANCE, isStrictName ? null : name,
235 "strictName", StringType.INSTANCE, isStrictName ? name : null,
236 "taxonGroupTypeCode", StringType.INSTANCE, TaxonGroupTypeCode.IDENTIFICATION.getValue());
237
238 Iterator<Object[]> it = Daos.queryIteratorWithStatus(query, statusCodes);
239
240 List<TaxonGroupDTO> result = Lists.newArrayList();
241 while (it.hasNext()) {
242 Object[] source = it.next();
243 TaxonGroupDTO taxonGroup = toTaxonGroupDTO(Arrays.asList(source).iterator());
244 TaxonGroupDTO lightTaxonGroup = getLightTaxonGroup(taxonGroup);
245
246
247 Collection<TaxonDTO> taxons = taxonMap.get(taxonGroup.getId());
248 for (TaxonDTO taxon : taxons) {
249 if (!taxon.containsTaxonGroups(lightTaxonGroup)) {
250 taxon.addTaxonGroups(lightTaxonGroup);
251 }
252 }
253
254 taxonGroup.addAllTaxons(taxons);
255 result.add(taxonGroup);
256 }
257
258
259 if (CollectionUtils.isNotEmpty(result) && parentTaxonGroupId != null) {
260 Set<TaxonGroupDTO> subTaxonGroups = Sets.newHashSet();
261 for (TaxonGroupDTO taxonGroup : result) {
262
263 subTaxonGroups.addAll(findTaxonGroups(taxonGroup.getId(), label, name, isStrictName, statusCodes));
264 }
265 result.addAll(subTaxonGroups);
266 }
267
268 return ImmutableList.copyOf(result);
269 }
270
271
272 @Override
273 public void saveTaxonGroups(List<? extends TaxonGroupDTO> taxonGroups) {
274 if (CollectionUtils.isEmpty(taxonGroups)) {
275 return;
276 }
277
278 for (TaxonGroupDTO taxonGroup : taxonGroups) {
279 if (taxonGroup.isDirty()) {
280 saveTaxonGroup(taxonGroup);
281 taxonGroup.setDirty(false);
282 }
283 }
284 getSession().flush();
285 getSession().clear();
286 }
287
288
289 @Override
290 public void deleteTaxonGroups(List<Integer> taxonGroupIds) {
291 if (taxonGroupIds == null) return;
292 taxonGroupIds.stream().filter(Objects::nonNull).distinct().forEach(this::remove);
293 getSession().flush();
294 getSession().clear();
295 }
296
297
298 @Override
299 public void replaceTemporaryTaxonGroup(Integer sourceId, Integer targetId, boolean delete) {
300 Assert.notNull(sourceId);
301 Assert.notNull(targetId);
302
303 executeMultipleUpdate(columnNamesByReferentialTableNames, sourceId, targetId);
304 executeMultipleUpdateWithNullCondition(columnNamesByDataTableNames, validationDateColumnNameByDataTableNames, sourceId, targetId);
305
306 if (delete) {
307
308 remove(sourceId);
309 }
310
311 getSession().flush();
312 getSession().clear();
313 }
314
315
316 @Override
317 public boolean isTaxonGroupUsedInReferential(int taxonGroupId) {
318
319 return executeMultipleCount(columnNamesByReferentialTableNames, taxonGroupId);
320 }
321
322
323 @Override
324 public boolean isTaxonGroupUsedInData(int taxonGroupId) {
325
326 return executeMultipleCount(columnNamesByDataTableNames, taxonGroupId);
327 }
328
329
330 @Override
331 public boolean isTaxonGroupUsedInValidatedData(int taxonGroupId) {
332
333 return executeMultipleCountWithNotNullCondition(columnNamesByDataTableNames, validationDateColumnNameByDataTableNames, taxonGroupId);
334 }
335
336
337 private void saveTaxonGroup(TaxonGroupDTO taxonGroup) {
338 Assert.notNull(taxonGroup);
339 Assert.notBlank(taxonGroup.getName());
340
341 if (taxonGroup.getStatus() == null) {
342 taxonGroup.setStatus(Daos.getStatus(StatusCode.LOCAL_ENABLE));
343 }
344 Assert.isTrue(ReefDbBeans.isLocalStatus(taxonGroup.getStatus()), "source must have local status");
345
346 TaxonGroup target;
347 if (taxonGroup.getId() == null) {
348 target = TaxonGroup.Factory.newInstance();
349 target.setTaxonGroupId(TemporaryDataHelper.getNewNegativeIdForTemporaryData(getSession(), target.getClass()));
350 } else {
351 target = get(taxonGroup.getId());
352 Assert.isTrue(ReefDbBeans.isLocalStatus(target.getStatus()), "target must have local status");
353 }
354
355 target.setTaxonGroupNm(taxonGroup.getName());
356 target.setStatus(load(StatusImpl.class, taxonGroup.getStatus().getCode()));
357 target.setTaxonGroupType(load(TaxonGroupTypeImpl.class, "1"));
358 target.setTaxonGroupUpdate(Daos.convertToString(true));
359 target.setTaxonGroupExclus(Daos.convertToString(false));
360
361 target.setTaxonGroupLb(taxonGroup.getLabel());
362 if (taxonGroup.getParentTaxonGroup() != null) {
363 target.setParentTaxonGroup(load(taxonGroup.getParentTaxonGroup().getId()));
364 } else {
365 target.setParentTaxonGroup(null);
366 }
367 target.setTaxonGroupCm(taxonGroup.getComment());
368 if (target.getTaxonGroupCreationDt() == null) {
369 target.setTaxonGroupCreationDt(newCreateDate());
370 }
371 target.setUpdateDt(newUpdateTimestamp());
372
373 getSession().save(target);
374 taxonGroup.setId(target.getTaxonGroupId());
375
376
377 saveTaxonsInTaxonGroup(taxonGroup, target);
378
379
380 }
381
382 private void saveTaxonsInTaxonGroup(TaxonGroupDTO source, TaxonGroup target) {
383
384 Collection<TaxonGroupHistoricalRecord> existingTaxonGroupHistoricalRecords = target.getTaxonGroupHistoricalRecords();
385 Map<Integer, TaxonGroupHistoricalRecord> tghrByTaxonId = ReefDbBeans.mapByProperty(existingTaxonGroupHistoricalRecords, "taxonName.taxonNameId");
386 boolean needUpdate = false;
387
388 for (TaxonDTO taxon : source.getTaxons()) {
389 TaxonGroupHistoricalRecord tghr = tghrByTaxonId.remove(taxon.getId());
390
391 if (tghr == null) {
392 tghr = TaxonGroupHistoricalRecord.Factory.newInstance();
393 tghr.setTaxonGroupHistRecordId((Integer) TemporaryDataHelper.getNewNegativeIdForTemporaryData(getSession(), TaxonGroupHistoricalRecord.class));
394 tghr.setTaxonName(load(TaxonNameImpl.class, taxon.getId()));
395 tghr.setTaxonGroup(target);
396 getSession().save(tghr);
397 target.addTaxonGroupHistoricalRecords(tghr);
398 needUpdate = true;
399 }
400 }
401
402 if (!tghrByTaxonId.isEmpty()) {
403
404 for (TaxonGroupHistoricalRecord tghrToRemove : tghrByTaxonId.values()) {
405 target.removeTaxonGroupHistoricalRecords(tghrToRemove);
406 getSession().delete(tghrToRemove);
407 }
408 needUpdate = true;
409 }
410
411 if (needUpdate) {
412
413 update(target);
414
415
416 Multimap<Integer, TaxonDTO> taxonMap = taxonNameDao.getAllTaxonNamesMapByTaxonGroupId(LocalDate.now());
417 taxonMap.replaceValues(source.getId(), source.getTaxons());
418
419
420 Cache taxonNameByTaxonGroupIdCache = cacheService.getCache(ReefDbTaxonNameDao.TAXON_NAME_BY_TAXON_GROUP_ID_CACHE);
421 taxonNameByTaxonGroupIdCache.evict(null);
422 taxonNameByTaxonGroupIdCache.put(null, taxonMap);
423 }
424 }
425
426 private TaxonGroupDTO toTaxonGroupDTO(Iterator<Object> source) {
427 TaxonGroupDTO result = ReefDbBeanFactory.newTaxonGroupDTO();
428 result.setId((Integer) source.next());
429 result.setLabel((String) source.next());
430 result.setName((String) source.next());
431 result.setComment((String) source.next());
432 result.setExclusive(Daos.safeConvertToBoolean(source.next()));
433 result.setUpdate(Daos.safeConvertToBoolean(source.next()));
434 result.setType((String) source.next());
435
436
437 Integer parentId = (Integer) source.next();
438 String parentLabel = (String) source.next();
439 String parentName = (String) source.next();
440
441 if (parentId != null) {
442 TaxonGroupDTO parent = ReefDbBeanFactory.newTaxonGroupDTO();
443 parent.setId(parentId);
444 parent.setLabel(parentLabel);
445 parent.setName(parentName);
446
447 result.setParentTaxonGroup(parent);
448 }
449
450 result.setStatus(Daos.getStatus((String) source.next()));
451 result.setCreationDate(Daos.convertToDate(source.next()));
452 result.setUpdateDate(Daos.convertToDate(source.next()));
453
454 return result;
455 }
456
457 private TaxonGroupDTO getLightTaxonGroup(TaxonGroupDTO taxonGroup) {
458 TaxonGroupDTO result = ReefDbBeans.clone(taxonGroup);
459 result.setTaxons(null);
460 result.setParentTaxonGroup(null);
461 return result;
462 }
463
464 }