View Javadoc
1   package fr.ifremer.dali.decorator;
2   
3   /*
4    * #%L
5    * Dali :: Core
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (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 Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  import fr.ifremer.dali.config.DaliConfiguration;
27  import fr.ifremer.dali.dto.*;
28  import fr.ifremer.dali.dto.configuration.context.ContextDTO;
29  import fr.ifremer.dali.dto.configuration.control.RuleListDTO;
30  import fr.ifremer.dali.dto.configuration.filter.FilterDTO;
31  import fr.ifremer.dali.dto.configuration.programStrategy.ProgramDTO;
32  import fr.ifremer.dali.dto.configuration.programStrategy.StrategyDTO;
33  import fr.ifremer.dali.dto.data.sampling.SamplingOperationDTO;
34  import fr.ifremer.dali.dto.data.survey.OccasionDTO;
35  import fr.ifremer.dali.dto.referential.*;
36  import fr.ifremer.dali.dto.referential.pmfm.ParameterDTO;
37  import fr.ifremer.dali.dto.referential.pmfm.PmfmDTO;
38  import fr.ifremer.dali.dto.referential.pmfm.QualitativeValueDTO;
39  import fr.ifremer.dali.dto.system.extraction.ExtractionDTO;
40  import fr.ifremer.dali.dto.system.extraction.ExtractionPeriodDTO;
41  import fr.ifremer.dali.dto.system.extraction.FilterTypeDTO;
42  import fr.ifremer.dali.dto.system.synchronization.SynchroTableDTO;
43  import fr.ifremer.quadrige3.core.dao.technical.AlphanumericComparator;
44  import fr.ifremer.quadrige3.core.dao.technical.Assert;
45  import fr.ifremer.quadrige3.core.dao.technical.Dates;
46  import fr.ifremer.quadrige3.core.dao.technical.Times;
47  import fr.ifremer.quadrige3.core.dao.technical.decorator.Decorator;
48  import fr.ifremer.quadrige3.core.vo.administration.program.ProgramVO;
49  import fr.ifremer.quadrige3.core.vo.data.survey.LightSurveyVO;
50  import fr.ifremer.quadrige3.ui.core.dto.CodeOnly;
51  import fr.ifremer.quadrige3.ui.core.dto.MonthDTO;
52  import fr.ifremer.quadrige3.ui.core.dto.referential.BaseReferentialDTO;
53  import fr.ifremer.quadrige3.ui.core.dto.referential.StatusDTO;
54  import org.apache.commons.collections4.CollectionUtils;
55  import org.apache.commons.lang3.ArrayUtils;
56  import org.apache.commons.lang3.StringUtils;
57  
58  import java.io.File;
59  import java.util.concurrent.TimeUnit;
60  
61  import static org.nuiton.i18n.I18n.t;
62  
63  /**
64   * Dali decorator service.
65   *
66   * @author Lionel Touseau <lionel.touseau@e-is.pro>
67   * @since 1.0
68   */
69  public class DecoratorServiceImpl extends fr.ifremer.quadrige3.core.service.decorator.DecoratorServiceImpl
70          implements DecoratorService {
71  
72      /**
73       * {@inheritDoc}
74       */
75      @Override
76      protected void onLoadDecorators(fr.ifremer.quadrige3.core.dao.technical.decorator.DecoratorProvider provider) {
77  
78          // referential
79          provider.registerDecorator(AnalysisInstrumentDTO.class, CODE, "${id}$s", TOKEN_SEPARATOR, SEPARATOR);
80          provider.registerDecorator(AnalysisInstrumentDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
81          provider.registerDecorator(DepartmentDTO.class, "${code}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR);
82          provider.registerDecorator(DepartmentDTO.class, CODE, "${code}$s", TOKEN_SEPARATOR, SEPARATOR);
83          provider.registerDecorator(DepartmentDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
84          provider.registerDecorator(LocationDTO.class, "${label}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR);
85          provider.registerDecorator(LocationDTO.class, CODE, "${label}$s", TOKEN_SEPARATOR, SEPARATOR);
86          provider.registerDecorator(LocationDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
87          provider.registerDecorator(HarbourDTO.class, "${code}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR);
88          provider.registerDecorator(ParameterDTO.class, "${transcribedCode}$s", TOKEN_SEPARATOR, SEPARATOR); // use transcribed code (Mantis #47330)
89          provider.registerDecorator(ParameterDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
90          provider.registerDecorator(ParameterDTO.class, CODE_NAME, "${transcribedCode}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR); // use transcribed code (Mantis #47330)
91          provider.registerDecorator(PersonDTO.class, "${firstName}$s#${name}$s - ${department/name}$s", TOKEN_SEPARATOR, " ");
92          provider.registerDecorator(PrivilegeDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
93          provider.registerDecorator(new PMFMDecorator());
94          provider.registerDecorator(NAME, new PMFMNameDecorator());
95          provider.registerDecorator(NAME_WITH_UNIT, new PMFMNameWithUnitDecorator());
96          provider.registerDecorator(NAME_WITH_ID, new PMFMNameWithIdDecorator());
97          provider.registerDecorator(new SortedQualitativeValueDecorator());
98          provider.registerDecorator(UnitDTO.class, WITH_SYMBOL, "${name}$s (${symbol}$s)", TOKEN_SEPARATOR, SEPARATOR);
99          provider.registerDecorator(new TaxonDecorator());
100         provider.registerDecorator(TaxonDTO.class, CODE, "${id}$s", TOKEN_SEPARATOR, SEPARATOR); // TODO: where is it used ?
101         provider.registerDecorator(WITH_CITATION, new TaxonWithCitationDecorator());
102         provider.registerDecorator(WITH_REFERENT, new TaxonWithReferentDecorator());
103         provider.registerDecorator(WITH_CITATION_AND_REFERENT, new TaxonWithCitationAndReferentDecorator());
104         provider.registerDecorator(TaxonGroupDTO.class, "${label}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR);
105         provider.registerDecorator(TaxonGroupDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
106         provider.registerDecorator(SamplingEquipmentDTO.class, CODE, "${id}$s", TOKEN_SEPARATOR, SEPARATOR);
107         provider.registerDecorator(SamplingEquipmentDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
108         provider.registerDecorator(StatusDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
109         provider.registerDecorator(PositioningSystemDTO.class, CODE_NAME, "${code}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR);
110 
111         // extraction
112         provider.registerDecorator(ExtractionDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
113         provider.registerDecorator(FilterTypeDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
114         provider.registerDecorator(ExtractionPeriodDTO.class, "${startDate}$td/%1$tm/%1$tY#${endDate}$td/%2$tm/%2$tY", TOKEN_SEPARATOR, " => ");
115 
116         // configuration
117         provider.registerDecorator(ContextDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
118         provider.registerDecorator(FilterDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
119         provider.registerDecorator(ProgramDTO.class, "${code}$s#${name}$s", TOKEN_SEPARATOR, SEPARATOR);
120         provider.registerDecorator(ProgramDTO.class, NAME, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
121         provider.registerDecorator(ProgramDTO.class, CODE, "${code}$s", TOKEN_SEPARATOR, SEPARATOR);
122         provider.registerDecorator(StrategyDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
123 
124         // rules
125         provider.registerDecorator(RuleListDTO.class, "${code}$s", TOKEN_SEPARATOR, SEPARATOR);
126 
127         // Base decorator for object extending BaseReferentialDTO
128         provider.registerDecorator(BaseReferentialDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
129         // Base decorator for object extending CodeOnly
130         provider.registerDecorator(CodeOnly.class, "${code}$s", TOKEN_SEPARATOR, SEPARATOR);
131 
132         // data
133         provider.registerDecorator(OccasionDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
134         provider.registerDecorator(SamplingOperationDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
135         provider.registerDecorator(CONCAT, new SamplingOperationDecorator());
136         provider.registerDecorator(new LightSurveyVODecorator());
137 
138         // system
139         provider.registerDecorator(ParameterTypeDTO.class, "${keyLabel}$s", TOKEN_SEPARATOR, SEPARATOR);
140         provider.registerDecorator(StateDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
141         provider.registerDecorator(FunctionDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
142         provider.registerDecorator(SynchronizationStatusDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
143         provider.registerDecorator(SearchDateDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
144         provider.registerDecorator(MonthDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR);
145 
146         // synchro
147         provider.registerDecorator(new SynchroTableWithCountDecorator());
148         provider.registerDecorator(WITH_COUNT, new SynchroTableWithCountDecorator(WITH_COUNT));
149 
150         // misc
151         provider.registerDecorator(COLLECTION_SIZE, new CollectionSizeDecorator());
152         provider.registerDecorator(DURATION_IN_MINUTES, new DurationDecorator(DURATION_IN_MINUTES));
153         provider.registerDecorator(DURATION_IN_DECIMAL_HOURS, new DurationDecorator(DURATION_IN_DECIMAL_HOURS));
154         provider.registerDecorator(TIME_IN_HOURS_MINUTES, new TimeDecorator());
155         provider.registerDecorator(File.class, "${absolutePath}$s", TOKEN_SEPARATOR, SEPARATOR);
156     }
157 
158     private class TaxonDecorator extends Decorator<TaxonDTO> {
159 
160         TaxonDecorator() {
161             super(TaxonDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR, false);
162             setUseCache(true);
163         }
164     }
165 
166     private class TaxonWithCitationDecorator extends Decorator<TaxonDTO> {
167 
168         TaxonWithCitationDecorator() {
169             super(TaxonDTO.class, "${name}$s#${citation}$s", TOKEN_SEPARATOR, " ", false);
170             setUseCache(true);
171         }
172 
173         @Override
174         protected Object getValue(TaxonDTO bean, String token) {
175 
176             if ("citation".equals(token)) {
177                 if (bean.getCitation() == null) {
178                     return "";
179                 }
180                 String citation = bean.getCitation().getName();
181                 if (citation.startsWith("(")) {
182                     return citation;
183                 }
184                 return String.format("(%s)", citation);
185             }
186 
187             return super.getValue(bean, token);
188         }
189     }
190 
191     private class TaxonWithReferentDecorator extends Decorator<TaxonDTO> {
192 
193         TaxonWithReferentDecorator() {
194             super(TaxonDTO.class, "${name}$s#${referent}$s", TOKEN_SEPARATOR, "", false);
195             setUseCache(true);
196         }
197 
198         @Override
199         protected Object getValue(TaxonDTO bean, String token) {
200 
201             if ("referent".equals(token)) {
202 
203                 if (bean.isReferent()) {
204                     return "";
205                 }
206 
207                 return String.format(" = %s", bean.getReferenceTaxon() == null ? "[unknown referent]" : bean.getReferenceTaxon().getName());
208             }
209 
210             return super.getValue(bean, token);
211         }
212     }
213 
214     private class TaxonWithCitationAndReferentDecorator extends Decorator<TaxonDTO> {
215 
216         TaxonWithCitationAndReferentDecorator() {
217             super(TaxonDTO.class, "${name}$s#${citation}$s#${referent}$s", TOKEN_SEPARATOR, " ", false);
218             setUseCache(true);
219         }
220 
221         @Override
222         protected Object getValue(TaxonDTO bean, String token) {
223 
224             if ("citation".equals(token)) {
225                 if (bean.getCitation() == null) {
226                     return "";
227                 }
228                 String citation = bean.getCitation().getName();
229                 if (citation.startsWith("(")) {
230                     return citation;
231                 }
232                 return String.format("(%s)", citation);
233 
234             } else if ("referent".equals(token)) {
235 
236                 if (bean.isReferent()) {
237                     return "";
238                 }
239 
240                 return String.format("= %s", bean.getReferenceTaxon() == null ? "[unknown referent]" : bean.getReferenceTaxon().getName());
241             }
242 
243 
244             return super.getValue(bean, token);
245         }
246     }
247 
248     class PMFMNameDecorator extends Decorator<PmfmDTO> {
249 
250         static final String TOKEN_NAME = "name";
251 
252         PMFMNameDecorator() {
253             this("${" + TOKEN_NAME + "}$s");
254         }
255 
256         PMFMNameDecorator(String expression) {
257             this(expression, SEPARATOR);
258         }
259 
260         PMFMNameDecorator(String expression, String separatorReplacement) {
261             super(PmfmDTO.class, expression, TOKEN_SEPARATOR, separatorReplacement, true);
262         }
263 
264         @Override
265         protected Object getValue(PmfmDTO bean, String token) {
266 
267             if (TOKEN_NAME.equals(token)) {
268 
269                 // return parameter name if transcribed name is not set
270                 if (StringUtils.isBlank(bean.getName())) {
271                     return bean.getParameter() != null ? bean.getParameter().getName() : null;
272                 }
273 
274                 return bean.getName();
275             }
276 
277             return super.getValue(bean, token);
278         }
279     }
280 
281     private class PMFMDecorator extends PMFMNameDecorator {
282 
283         PMFMDecorator() {
284             super("${" + TOKEN_NAME + "}$s#${parameter/transcribedCode}$s#${matrix/name}$s#${fraction/name}$s#${method/name}$s#${unit/symbol}$s");
285         }
286     }
287 
288     private class PMFMNameWithIdDecorator extends PMFMNameDecorator {
289 
290         PMFMNameWithIdDecorator() {
291             // The id is put at the end of the string to preserve alphabetic order (Mantis #46672)
292             super("${" + TOKEN_NAME + "}$s#${parameter/transcribedCode}$s#${matrix/name}$s#${fraction/name}$s#${method/name}$s#${unit/symbol}$s#${id}$s");
293         }
294     }
295 
296     private class PMFMNameWithUnitDecorator extends PMFMNameDecorator {
297 
298         int noUnitId;
299         boolean checkConfig = false;
300 
301         PMFMNameWithUnitDecorator() {
302             super("${" + TOKEN_NAME + "}$s#${unit/symbol}$s", "");
303         }
304 
305         @Override
306         protected Object getValue(PmfmDTO bean, String token) {
307 
308             if ("unit/symbol".equals(token)) {
309 
310                 if (!checkConfig) {
311                     DaliConfiguration config = DaliConfiguration.getInstance();
312                     noUnitId = config.getNoUnitId();
313                     checkConfig = true;
314                 }
315 
316                 // check if unit is 'no unit'
317                 if (bean.getUnit() == null || bean.getUnit().getId() == noUnitId) {
318                     return "";
319                 }
320 
321                 return String.format(" (%s)", super.getValue(bean, token));
322             }
323 
324             return super.getValue(bean, token);
325         }
326     }
327 
328     /**
329      * QualitativeValue decorator with enhanced sorting comparator
330      * fixme maybe to deprecate ?
331      */
332     private class SortedQualitativeValueDecorator extends Decorator<QualitativeValueDTO> {
333 
334         SortedQualitativeValueDecorator() {
335             super(QualitativeValueDTO.class, "${name}$s", TOKEN_SEPARATOR, SEPARATOR, false);
336 
337             context.setComparator((o1, o2) ->
338                     AlphanumericComparator.instance().compare(
339                             SortedQualitativeValueDecorator.this.toString(o1),
340                             SortedQualitativeValueDecorator.this.toString(o2)
341                     ));
342         }
343     }
344 
345     /**
346      * Survey decorator.
347      */
348     private class LightSurveyVODecorator extends Decorator<LightSurveyVO> {
349 
350         private static final String SEPARATOR = " - ";
351 
352         /**
353          * Constructor.
354          */
355         LightSurveyVODecorator() {
356             super(LightSurveyVO.class, "${surveyId}$s", "", "", false);
357         }
358 
359         @Override
360         protected Object getValue(final LightSurveyVO bean, final String token) {
361             final StringBuilder result = new StringBuilder(20);
362 
363             // Add location
364             if (bean.getMonitoringLocation() != null) {
365                 result.append(bean.getMonitoringLocation().getLabel());
366                 result.append(SEPARATOR);
367                 result.append(bean.getMonitoringLocation().getName());
368                 result.append(SEPARATOR);
369             }
370 
371             // Add survey date
372             String dateStr = Dates.formatDate(bean.getSurveyDt(), DaliConfiguration.getInstance().getDateFormat());
373             result.append(dateStr);
374 
375             // Add programs
376             if (ArrayUtils.isNotEmpty(bean.getPrograms())) {
377                 for (ProgramVO program : bean.getPrograms()) {
378                     result.append(SEPARATOR);
379                     result.append(program.getProgCd());
380                 }
381             }
382 
383             return result.toString();
384         }
385     }
386 
387     /**
388      * Sampling Operation decorator.
389      */
390     private class SamplingOperationDecorator extends Decorator<SamplingOperationDTO> {
391 
392         private static final String SEPARATOR = " - ";
393 
394         /**
395          * Constructor.
396          */
397         SamplingOperationDecorator() {
398             super(SamplingOperationDTO.class, "${name}$s", "", "", false);
399         }
400 
401         @Override
402         protected Object getValue(final SamplingOperationDTO bean, final String token) {
403 
404             return bean.getName() +
405                     SEPARATOR +
406                     Times.secondsToString(bean.getTime()) +
407                     SEPARATOR +
408                     bean.getSamplingEquipment().getName();
409         }
410     }
411 
412     /**
413      * Time decoration.
414      */
415     private class TimeDecorator extends Decorator<Integer> {
416 
417         TimeDecorator() {
418             super(Integer.class, "${time}$s", "", "", false);
419         }
420 
421         @Override
422         protected Object getValue(final Integer bean, final String token) {
423             return Times.secondsToString(bean);
424         }
425     }
426 
427     /**
428      * Decorator display duration (Integer representing number of minutes) to days/hours/minutes readable format
429      */
430     private class DurationDecorator extends Decorator<Number> {
431 
432         private final String type;
433 
434         DurationDecorator(String type) {
435             super(Number.class, "${duration}$s", "", "", false);
436             this.type = type;
437         }
438 
439         @Override
440         protected Object getValue(final Number number, final String token) {
441             // return string representation of a duration
442             if (number == null) {
443                 return "null";
444             }
445             // convert the bean vale to the correct number of minutes
446             int duration = 0;
447             switch (type) {
448                 case DURATION_IN_MINUTES:
449                     // standard case (number should be an Integer)
450                     duration = number.intValue();
451                     break;
452 
453                 case DURATION_IN_DECIMAL_HOURS:
454                     // convert decimal hours in minutes (number can be a Double)
455                     duration = (int) Math.round(number.doubleValue() * 60);
456                     break;
457 
458                 default:
459                     break;
460             }
461 
462             if (duration < 0) {
463                 return "< 0";
464             }
465             long days = TimeUnit.MINUTES.toDays(duration);
466             duration -= TimeUnit.DAYS.toMinutes(days);
467             long hours = TimeUnit.MINUTES.toHours(duration);
468             duration -= TimeUnit.HOURS.toMinutes(hours);
469             long minutes = TimeUnit.MINUTES.toMinutes(duration);
470 
471             StringBuilder sb = new StringBuilder(64);
472             if (days > 0) {
473                 sb.append(days);
474                 sb.append("j ");
475             }
476             if (hours > 0) {
477                 sb.append(hours);
478                 sb.append("h ");
479             } else if (minutes > 0) {
480                 sb.append("0h ");
481             }
482             sb.append(minutes);
483             sb.append("m");
484             return sb.toString();
485         }
486     }
487 
488     private class SynchroTableWithCountDecorator extends Decorator<SynchroTableDTO> {
489 
490         private final String type;
491 
492         SynchroTableWithCountDecorator(String type) {
493             super(SynchroTableDTO.class, "${name}$s", "", "", false);
494             this.type = type;
495             Assert.isTrue(type == null || type.equals(WITH_COUNT), "unknown type for this decorator. Expected: null or 'withCount'");
496         }
497 
498         SynchroTableWithCountDecorator() {
499             super(SynchroTableDTO.class, "${name}$s", "", "", false);
500             this.type = null;
501         }
502 
503         @Override
504         protected Object getValue(SynchroTableDTO bean, String token) {
505 
506             // Translate table name
507             String decoratedTableName = t("quadrige3.table." + bean.getName());
508             if (decoratedTableName.startsWith("quadrige3.table")) {
509                 // Use table name as default translation
510                 decoratedTableName = bean.getName();
511             }
512 
513             if (type == null) {
514                 return decoratedTableName;
515             }
516 
517             // Count nb rows and nb resolve rows
518             int nbTotal = bean.sizeRows();
519 
520             return String.format("%s (%s)",
521                     decoratedTableName,
522                     nbTotal);
523         }
524 
525     }
526 
527     // Decorator for collection of BaseReferentialDTO
528     private class CollectionSizeDecorator extends Decorator<BaseReferentialDTO> {
529 
530         CollectionSizeDecorator() {
531             super(BaseReferentialDTO.class, "${size}$s", "", "", false);
532         }
533 
534         @Override
535         public String toString(Object object) {
536             // return directly the collection size
537             return String.valueOf(CollectionUtils.size(object));
538         }
539 
540         @Override
541         protected Object onNullValue(BaseReferentialDTO bean, String token) {
542             return "0";
543         }
544     }
545 
546 }