1 package fr.ifremer.quadrige3.ui.core.dto;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import fr.ifremer.quadrige3.core.dao.referential.Status;
25 import fr.ifremer.quadrige3.core.dao.referential.StatusCode;
26 import fr.ifremer.quadrige3.core.dao.referential.UnitId;
27 import fr.ifremer.quadrige3.core.dao.technical.Assert;
28 import fr.ifremer.quadrige3.core.dao.technical.Beans;
29 import fr.ifremer.quadrige3.core.exception.QuadrigeTechnicalException;
30 import fr.ifremer.quadrige3.ui.core.dto.referential.BaseReferentialDTO;
31 import fr.ifremer.quadrige3.ui.core.dto.referential.StatusDTO;
32 import org.apache.commons.beanutils.BeanUtils;
33 import org.apache.commons.collections4.CollectionUtils;
34 import org.apache.commons.lang3.ArrayUtils;
35 import org.apache.commons.lang3.StringUtils;
36
37 import java.lang.reflect.InvocationTargetException;
38 import java.math.BigDecimal;
39 import java.math.RoundingMode;
40 import java.sql.Array;
41 import java.sql.SQLException;
42 import java.text.DecimalFormat;
43 import java.text.DecimalFormatSymbols;
44 import java.util.*;
45 import java.util.function.Function;
46 import java.util.stream.Collectors;
47
48 import static org.nuiton.i18n.I18n.t;
49
50
51
52
53
54
55
56
57 public class QuadrigeBeans extends Beans {
58
59
60
61
62 public static final Function<QuadrigeBean, String> GET_ID_STRING = input -> (input == null) ? null : input.getId().toString();
63
64
65
66 public static final Function<String, Integer> ID_MAPPER = id -> (id == null || id.isEmpty()) ? null : Integer.valueOf(id);
67
68
69
70 public static final Function<QuadrigeBean, String> GET_CODE = p -> (p == null) ? null : (String) getProperty(p, "code");
71
72
73
74 public static final String DEFAULT_DATE_FORMAT = "dd/MM/yyyy";
75
76
77
78 public static final String DEFAULT_STRING_SEPARATOR = " - ";
79 private static DecimalFormatSymbols symbols;
80 private static DecimalFormat decimalFormat;
81
82
83
84
85 protected QuadrigeBeans() {
86
87 }
88
89
90
91
92
93
94
95
96 public static <B extends QuadrigeBean> List<Integer> collectIds(Collection<B> collection) {
97 if (CollectionUtils.isEmpty(collection)) return new ArrayList<>();
98 return collection.stream().filter(Objects::nonNull).map(QuadrigeBean::getId).filter(Objects::nonNull).collect(Collectors.toList());
99 }
100
101 public static <B extends QuadrigeBean> List<String> collectStringIds(Collection<B> collection) {
102 if (CollectionUtils.isEmpty(collection)) return new ArrayList<>();
103 return collection.stream().filter(Objects::nonNull)
104 .map(bean -> bean instanceof CodeOnly ? ((CodeOnly) bean).getCode() : bean.getId().toString())
105 .filter(Objects::nonNull).collect(Collectors.toList());
106 }
107
108 public static <B extends QuadrigeBean> String joinIds(Collection<B> collection, String separator) {
109 return String.join(separator, collectStringIds(collection));
110 }
111
112
113
114
115
116
117
118 public static <B extends QuadrigeBean> Map<Integer, B> mapById(Collection<B> beans) {
119 return CollectionUtils.isNotEmpty(beans)
120 ?
121 beans.stream().collect(Collectors.toMap(
122 QuadrigeBean::getId,
123 o -> o,
124 (k1, k2) -> {
125 throw new IllegalStateException(String.format("Duplicate key %s", k1));
126 },
127 HashMap::new))
128 : new HashMap<>();
129
130
131
132 }
133
134
135
136
137
138
139
140
141
142 public static <B extends QuadrigeBean> B findById(Collection<B> beans, Integer id) {
143 if (CollectionUtils.isEmpty(beans) || id == null) return null;
144 return beans.stream().filter(Objects::nonNull).filter(b -> id.equals(b.getId())).findFirst().orElse(null);
145 }
146
147
148
149
150
151
152 public static DecimalFormatSymbols getDecimalFormatSymbols() {
153 if (symbols == null) {
154 symbols = new DecimalFormatSymbols();
155 symbols.setDecimalSeparator('.');
156 symbols.setGroupingSeparator(' ');
157 }
158 return symbols;
159 }
160
161
162
163
164
165
166
167
168 public static DecimalFormat getDecimalFormat(int minDecimal, int maxDecimal) {
169 if (decimalFormat == null) {
170 decimalFormat = new DecimalFormat();
171 decimalFormat.setDecimalFormatSymbols(getDecimalFormatSymbols());
172 decimalFormat.setGroupingUsed(false);
173 }
174 decimalFormat.setMinimumFractionDigits(minDecimal);
175 decimalFormat.setMaximumFractionDigits(maxDecimal);
176 return decimalFormat;
177 }
178
179
180
181
182
183
184
185
186
187 public static String toSecuredString(String text) {
188 if (text == null) return null;
189
190 String result = text.trim().replaceAll("[.,:;'\"()\\[\\]{}?!^=+/\\\\#~%²&|`¨@$£€¤µ*§]+", "");
191
192 return StringUtils.stripAccents(result);
193 }
194
195
196
197
198
199
200
201
202
203
204
205 public static String toFullySecuredString(String text) {
206 if (text == null) return null;
207
208 String result = text.replaceAll("[a-zA-Z]'", "");
209
210 result = toSecuredString(result);
211
212 return result != null ? result.replaceAll(" ", "_") : null;
213 }
214
215
216
217
218
219
220
221
222
223 @SuppressWarnings("unchecked")
224 public static <B extends QuadrigeBean> B clone(final B bean) throws QuadrigeTechnicalException {
225 if (bean == null) return null;
226 try {
227
228 return (B) BeanUtils.cloneBean(bean);
229 } catch (final IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) {
230 throw new QuadrigeTechnicalException(t("quadrige.error.exception.duplicateBean"), e);
231 }
232 }
233
234 public static <B extends QuadrigeBean> List<B> clone(final Collection<B> beans) {
235 if (beans == null) return null;
236 return beans.stream().map(QuadrigeBeans::clone).collect(Collectors.toList());
237 }
238
239 public static <B extends QuadrigeBean> Set<B> clone(final Set<B> beans) {
240 if (beans == null) return null;
241 return beans.stream().map(QuadrigeBeans::clone).collect(Collectors.toSet());
242 }
243
244 public static BigDecimal convertLengthValue(BigDecimal length, int fromUnitId, int toUnitId) {
245
246 if (length == null) {
247 return null;
248 }
249 if (length.intValue() == 0) {
250 return BigDecimal.valueOf(0);
251 }
252 if (fromUnitId == toUnitId) {
253 return length;
254 }
255
256 UnitId[] availableUnits = new UnitId[]{UnitId.METER, UnitId.CENTIMENTER, UnitId.MILLIMETER, UnitId.MICROMETER};
257 UnitId fromUnit;
258 UnitId toUnit;
259 try {
260 fromUnit = UnitId.fromValue(fromUnitId);
261 if (!ArrayUtils.contains(availableUnits, fromUnit)) {
262 throw new IllegalArgumentException();
263 }
264 } catch (IllegalArgumentException e) {
265 throw new QuadrigeTechnicalException(t("quadrige.error.length.conversion", fromUnitId));
266 }
267 try {
268 toUnit = UnitId.fromValue(toUnitId);
269 if (!ArrayUtils.contains(availableUnits, toUnit)) {
270 throw new IllegalArgumentException();
271 }
272 } catch (IllegalArgumentException e) {
273 throw new QuadrigeTechnicalException(t("quadrige.error.length.conversion", toUnitId));
274 }
275
276 Map<UnitId, BigDecimal> conversionMap = new HashMap<>();
277 conversionMap.put(UnitId.METER, BigDecimal.valueOf(1));
278 conversionMap.put(UnitId.CENTIMENTER, BigDecimal.valueOf(100));
279 conversionMap.put(UnitId.MILLIMETER, BigDecimal.valueOf(1000));
280 conversionMap.put(UnitId.MICROMETER, BigDecimal.valueOf(1000L * 1000));
281
282 return length.multiply(conversionMap.get(toUnit)).divide(conversionMap.get(fromUnit), RoundingMode.FLOOR);
283 }
284
285 public static Integer toInteger(BigDecimal bigDecimal) {
286 return bigDecimal != null ? bigDecimal.intValue() : null;
287 }
288
289 public static Double toDouble(BigDecimal bigDecimal) {
290 return bigDecimal != null ? bigDecimal.doubleValue() : null;
291 }
292
293
294
295
296
297
298
299
300
301 @SuppressWarnings(value = "unused")
302 public static String getUnifiedSQLString(Array array, String separator) {
303
304 try {
305
306 return getUnifiedString(
307 Arrays.stream((Object[]) array.getArray())
308 .filter(Objects::nonNull)
309 .map(Object::toString)
310 .collect(Collectors.toList()),
311 separator);
312
313 } catch (SQLException e) {
314
315 return "";
316 }
317 }
318
319
320
321
322
323
324
325
326
327
328
329 public static String getUnifiedString(List<String> strings, String separator) {
330
331 Set<String> stringSet = new LinkedHashSet<>();
332
333 for (String string : strings) {
334 if (StringUtils.isNotBlank(string)) {
335
336
337 if (string.contains(separator)) {
338 List<String> subComments = split(string, separator);
339 stringSet.addAll(subComments);
340 } else {
341 stringSet.add(string);
342 }
343 }
344 }
345
346 return stringSet.stream().filter(Objects::nonNull).collect(Collectors.joining(separator));
347
348 }
349
350
351
352
353
354
355
356 public static boolean hasNoBlockingError(ErrorAware bean) {
357 if (bean != null && CollectionUtils.isNotEmpty(bean.getErrors())) {
358 for (ErrorDTO error : bean.getErrors()) {
359 if (error.isError() && !error.isControl()) {
360 return false;
361 }
362 }
363 }
364 return true;
365 }
366
367
368
369
370
371
372 public static void removeBlockingErrors(ErrorAware bean) {
373 bean.getErrors().removeIf(error -> !error.isControl());
374 }
375
376
377
378
379
380
381
382
383 public static List<ErrorDTO> getErrors(ErrorAware bean, final Boolean controlOnly) {
384 if (bean == null || CollectionUtils.isEmpty(bean.getErrors())) {
385 return new ArrayList<>();
386 }
387 return filterCollection(bean.getErrors(), error -> error.isError() && (controlOnly == null || (controlOnly == error.isControl())));
388 }
389
390
391
392
393
394
395
396 public static List<String> getErrorMessages(ErrorAware bean) {
397 return collectProperties(getErrors(bean, null), ErrorDTO.PROPERTY_MESSAGE);
398 }
399
400
401
402
403
404
405
406
407
408
409 public static List<ErrorDTO> getErrors(ErrorAware bean, final String propertyName, final Integer pmfmId, final Boolean controlOnly) {
410 if (bean == null || CollectionUtils.isEmpty(bean.getErrors())) {
411 return new ArrayList<>();
412 }
413 return filterCollection(bean.getErrors(), error -> error.isError()
414 && (controlOnly == null || (controlOnly == error.isControl()))
415 && error.containsPropertyName(propertyName)
416 && (pmfmId == null || pmfmId.equals(error.getPmfmId()))
417 );
418 }
419
420
421
422
423
424
425
426
427
428 public static List<String> getErrorMessages(ErrorAware bean, String propertyName, Integer pmfmId) {
429 return collectProperties(getErrors(bean, propertyName, pmfmId, null), ErrorDTO.PROPERTY_MESSAGE);
430 }
431
432
433
434
435
436
437
438
439 public static List<ErrorDTO> getWarnings(ErrorAware bean, final Boolean controlOnly) {
440 if (bean == null || CollectionUtils.isEmpty(bean.getErrors())) {
441 return new ArrayList<>();
442 }
443 return filterCollection(bean.getErrors(), error -> error.isWarning() && (controlOnly == null || (controlOnly == error.isControl())));
444 }
445
446
447
448
449
450
451
452 public static List<String> getWarningMessages(ErrorAware bean) {
453 return collectProperties(getWarnings(bean, null), ErrorDTO.PROPERTY_MESSAGE);
454 }
455
456
457
458
459
460
461
462
463
464
465 public static List<ErrorDTO> getWarnings(ErrorAware bean, final String propertyName, final Integer pmfmId, final Boolean controlOnly) {
466 if (bean == null || CollectionUtils.isEmpty(bean.getErrors())
467
468 || !getErrors(bean, propertyName, pmfmId, controlOnly).isEmpty()) {
469 return new ArrayList<>();
470 }
471 return filterCollection(bean.getErrors(), error -> error.isWarning()
472 && (controlOnly == null || (controlOnly == error.isControl()))
473 && error.containsPropertyName(propertyName)
474 && (pmfmId == null || pmfmId.equals(error.getPmfmId())));
475 }
476
477
478
479
480
481
482
483
484
485 public static List<String> getWarningMessages(ErrorAware bean, String propertyName, Integer pmfmId) {
486 return collectProperties(getWarnings(bean, propertyName, pmfmId, null), ErrorDTO.PROPERTY_MESSAGE);
487 }
488
489
490
491
492
493
494
495
496 public static void addError(ErrorAware bean, String message, String... properties) {
497 addError(bean, message, null, properties);
498 }
499
500
501
502
503
504
505
506
507
508 public static void addError(ErrorAware bean, String message, Integer pmfmId, String... properties) {
509 addErrorDTOToBean(bean, false, message, pmfmId, properties);
510 }
511
512
513
514
515
516
517
518
519 public static void addWarning(ErrorAware bean, String message, String... properties) {
520 addWarning(bean, message, null, properties);
521 }
522
523
524
525
526
527
528
529
530
531 public static void addWarning(ErrorAware bean, String message, Integer pmfmId, String... properties) {
532 addErrorDTOToBean(bean, true, message, pmfmId, properties);
533 }
534
535 private static void addErrorDTOToBean(ErrorAware bean, boolean warning, String message, Integer pmfmId, String... properties) {
536 ErrorDTO error = QuadrigeBeanFactory.newErrorDTO();
537 error.setError(!warning);
538 error.setWarning(warning);
539 error.setMessage(message);
540 error.setPropertyName(properties != null ? Arrays.asList(properties) : null);
541 error.setPmfmId(pmfmId);
542 bean.getErrors().add(error);
543 }
544
545
546
547
548
549
550
551 public static void addUniqueErrors(ErrorAware bean, Collection<ErrorDTO> errors) {
552
553 if (CollectionUtils.isNotEmpty(errors)) {
554 for (ErrorDTO errorToAdd : errors) {
555 boolean canAdd = true;
556 for (ErrorDTO existingError : bean.getErrors()) {
557 if (isErrorEquals(errorToAdd, existingError)) {
558 canAdd = false;
559 break;
560 }
561 }
562 if (canAdd) {
563 bean.getErrors().add(errorToAdd);
564 }
565 }
566 }
567
568 }
569
570 private static boolean isErrorEquals(ErrorDTO error1, ErrorDTO error2) {
571 return error1.isError() == error2.isError()
572 && error1.isWarning() == error2.isWarning()
573 && error1.isControl() == error2.isControl()
574 && Objects.equals(error1.getControlElementCode(), error2.getControlElementCode())
575 && Objects.deepEquals(error1.getPropertyName().toArray(), error2.getPropertyName().toArray())
576 && Objects.equals(error1.getPmfmId(), error2.getPmfmId())
577 && Objects.equals(error1.getIndividualId(), error2.getIndividualId())
578 && Objects.equals(error1.getMessage(), error2.getMessage());
579 }
580
581
582
583
584
585
586
587 public static BaseReferentialDTO newDummyBaseReferentialBean(int id) {
588 BaseReferentialDTO bean = QuadrigeBeanFactory.newBaseReferentialDTO();
589 bean.setId(id);
590 return bean;
591 }
592
593
594
595
596
597
598
599
600 public static <E extends BaseReferentialDTO> List<E> filterLocalReferential(List<E> list) {
601 return filterReferential(list, true);
602 }
603
604
605
606
607
608
609
610
611 public static <E extends BaseReferentialDTO> List<E> filterNationalReferential(List<E> list) {
612 return filterReferential(list, false);
613 }
614
615
616
617
618
619
620
621
622
623 public static <E extends BaseReferentialDTO> List<E> filterReferential(List<E> list, final boolean local) {
624 if (CollectionUtils.isNotEmpty(list)) {
625 return filterCollection(list, input -> isLocalReferential(input) == local);
626 }
627 return new ArrayList<>();
628 }
629
630 public static boolean isLocalReferential(BaseReferentialDTO dto) {
631 return (dto.getStatus() != null && isLocalStatus(dto.getStatus())) || (dto.getId() != null && dto.getId() < 0);
632 }
633
634
635
636
637
638
639
640 public static boolean isLocalStatus(StatusDTO statusDTO) {
641 Assert.notNull(statusDTO);
642 return isLocalStatus(statusDTO.getCode());
643 }
644
645
646
647
648
649
650
651 public static boolean isLocalStatus(Status status) {
652 Assert.notNull(status);
653 return isLocalStatus(status.getStatusCd());
654 }
655
656
657
658
659
660
661
662 public static boolean isLocalStatus(String statusCode) {
663 Assert.notBlank(statusCode);
664 return StatusCode.LOCAL_DISABLE.value().equals(statusCode)
665 || StatusCode.LOCAL_ENABLE.value().equals(statusCode);
666 }
667
668
669 public static boolean isDisabledReferential(BaseReferentialDTO dto) {
670 return dto.getStatus() != null && isDisabledStatus(dto.getStatus());
671 }
672
673 public static boolean isDisabledStatus(StatusDTO statusDTO) {
674 Assert.notNull(statusDTO);
675 return isDisabledStatus(statusDTO.getCode());
676 }
677
678 public static boolean isDisabledStatus(String statusCode) {
679 Assert.notBlank(statusCode);
680 return StatusCode.LOCAL_DISABLE.value().equals(statusCode) || StatusCode.DISABLE.value().equals(statusCode);
681 }
682
683 }