View Javadoc
1   package fr.ifremer.tutti.persistence.service;
2   
3   /*
4    * #%L
5    * Tutti :: Persistence
6    * %%
7    * Copyright (C) 2012 - 2014 Ifremer
8    * %%
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU General Public License as
11   * published by the Free Software Foundation, either version 3 of the 
12   * License, or (at your option) any later version.
13   * 
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Public License for more details.
18   * 
19   * You should have received a copy of the GNU General Public 
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/gpl-3.0.html>.
22   * #L%
23   */
24  
25  import com.google.common.base.Preconditions;
26  import com.google.common.collect.Lists;
27  import com.google.common.collect.Maps;
28  import com.google.common.collect.Sets;
29  import fr.ifremer.adagio.core.dao.administration.programStrategy.ProgramDao;
30  import fr.ifremer.adagio.core.dao.administration.programStrategy.ProgramImpl;
31  import fr.ifremer.adagio.core.dao.administration.user.PersonDao;
32  import fr.ifremer.adagio.core.dao.administration.user.PersonId;
33  import fr.ifremer.adagio.core.dao.administration.user.PersonImpl;
34  import fr.ifremer.adagio.core.dao.data.measure.GearPhysicalMeasurement;
35  import fr.ifremer.adagio.core.dao.data.survey.fishingTrip.FishingTrip;
36  import fr.ifremer.adagio.core.dao.data.survey.fishingTrip.ObservedFishingTrip;
37  import fr.ifremer.adagio.core.dao.data.survey.scientificCruise.ScientificCruise;
38  import fr.ifremer.adagio.core.dao.data.survey.scientificCruise.ScientificCruiseDao;
39  import fr.ifremer.adagio.core.dao.data.vessel.VesselDao;
40  import fr.ifremer.adagio.core.dao.data.vessel.VesselImpl;
41  import fr.ifremer.adagio.core.dao.data.vessel.feature.person.VesselPersonFeatures;
42  import fr.ifremer.adagio.core.dao.data.vessel.feature.physical.GearPhysicalFeatures;
43  import fr.ifremer.adagio.core.dao.referential.QualityFlag;
44  import fr.ifremer.adagio.core.dao.referential.QualityFlagCode;
45  import fr.ifremer.adagio.core.dao.referential.QualityFlagDao;
46  import fr.ifremer.adagio.core.dao.referential.QualityFlagImpl;
47  import fr.ifremer.adagio.core.dao.referential.VesselPersonRole;
48  import fr.ifremer.adagio.core.dao.referential.VesselPersonRoleId;
49  import fr.ifremer.adagio.core.dao.referential.gear.GearDao;
50  import fr.ifremer.adagio.core.dao.referential.location.Location;
51  import fr.ifremer.adagio.core.dao.referential.location.LocationDao;
52  import fr.ifremer.adagio.core.dao.referential.location.LocationImpl;
53  import fr.ifremer.adagio.core.dao.referential.pmfm.PmfmDao;
54  import fr.ifremer.adagio.core.dao.referential.pmfm.PmfmId;
55  import fr.ifremer.adagio.core.dao.referential.pmfm.QualitativeValue;
56  import fr.ifremer.adagio.core.dao.referential.pmfm.QualitativeValueDao;
57  import fr.ifremer.tutti.persistence.dao.GearPhysicalFeaturesDaoTutti;
58  import fr.ifremer.tutti.persistence.entities.CaracteristicMap;
59  import fr.ifremer.tutti.persistence.entities.TuttiEntities;
60  import fr.ifremer.tutti.persistence.entities.data.Cruise;
61  import fr.ifremer.tutti.persistence.entities.data.Cruises;
62  import fr.ifremer.tutti.persistence.entities.data.Program;
63  import fr.ifremer.tutti.persistence.entities.referential.Caracteristic;
64  import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValue;
65  import fr.ifremer.tutti.persistence.entities.referential.CaracteristicQualitativeValues;
66  import fr.ifremer.tutti.persistence.entities.referential.Gear;
67  import fr.ifremer.tutti.persistence.entities.referential.GearWithOriginalRankOrder;
68  import fr.ifremer.tutti.persistence.entities.referential.GearWithOriginalRankOrders;
69  import fr.ifremer.tutti.persistence.entities.referential.Gears;
70  import fr.ifremer.tutti.persistence.entities.referential.Person;
71  import fr.ifremer.tutti.persistence.entities.referential.TuttiLocation;
72  import fr.ifremer.tutti.persistence.entities.referential.Vessel;
73  import fr.ifremer.tutti.persistence.service.referential.CaracteristicPersistenceService;
74  import fr.ifremer.tutti.persistence.service.referential.GearPersistenceService;
75  import fr.ifremer.tutti.persistence.service.referential.LocationPersistenceService;
76  import fr.ifremer.tutti.persistence.service.referential.PersonPersistenceService;
77  import fr.ifremer.tutti.persistence.service.referential.VesselPersistenceService;
78  import fr.ifremer.tutti.persistence.service.util.MeasurementPersistenceHelper;
79  import fr.ifremer.tutti.persistence.service.util.SynchronizationStatusHelper;
80  import fr.ifremer.tutti.persistence.service.util.VesselPersonFeaturesPersistenceHelper;
81  import org.apache.commons.collections4.CollectionUtils;
82  import org.apache.commons.lang3.ObjectUtils;
83  import org.apache.commons.lang3.StringUtils;
84  import org.apache.commons.logging.Log;
85  import org.apache.commons.logging.LogFactory;
86  import org.hibernate.type.IntegerType;
87  import org.hibernate.type.ShortType;
88  import org.hibernate.type.StringType;
89  import org.nuiton.jaxx.application.ApplicationBusinessException;
90  import org.springframework.dao.DataRetrievalFailureException;
91  import org.springframework.stereotype.Service;
92  
93  import javax.annotation.Resource;
94  import java.io.Serializable;
95  import java.text.MessageFormat;
96  import java.util.Collection;
97  import java.util.Collections;
98  import java.util.Date;
99  import java.util.Iterator;
100 import java.util.List;
101 import java.util.Map;
102 import java.util.Set;
103 
104 import static org.nuiton.i18n.I18n.t;
105 
106 /**
107  * @author Tony Chemit - chemit@codelutin.com
108  * @since 0.3
109  */
110 @Service("cruisePersistenceService")
111 public class CruisePersistenceServiceImpl extends AbstractPersistenceService implements CruisePersistenceService {
112 
113     /** Logger. */
114     private static final Log log =
115             LogFactory.getLog(CruisePersistenceServiceImpl.class);
116 
117 
118     @Resource(name = "caracteristicPersistenceService")
119     private CaracteristicPersistenceService caracteristicService;
120 
121     @Resource(name = "gearPersistenceService")
122     private GearPersistenceService gearService;
123 
124     @Resource(name = "locationPersistenceService")
125     private LocationPersistenceService locationService;
126 
127     @Resource(name = "personPersistenceService")
128     private PersonPersistenceService personService;
129 
130     @Resource(name = "vesselPersistenceService")
131     private VesselPersistenceService vesselService;
132 
133     @Resource(name = "programPersistenceService")
134     protected ProgramPersistenceService programService;
135 
136     @Resource(name = "fishingOperationPersistenceService")
137     protected FishingOperationPersistenceService fishingOperationService;
138 
139     @Resource(name = "vesselPersonFeaturesPersistenceHelper")
140     protected VesselPersonFeaturesPersistenceHelper vesselPersonFeaturesPersistenceHelper;
141 
142     @Resource(name = "scientificCruiseDao")
143     protected ScientificCruiseDao scientificCruiseDao;
144 
145     @Resource(name = "programDao")
146     protected ProgramDao programDao;
147 
148     @Resource(name = "personDao")
149     protected PersonDao personDao;
150 
151     @Resource(name = "vesselExtendDao")
152     protected VesselDao vesselDao;
153 
154     @Resource(name = "locationDao")
155     protected LocationDao locationDao;
156 
157     @Resource(name = "qualityFlagDao")
158     protected QualityFlagDao qualityFlagDao;
159 
160     @Resource(name = "pmfmDao")
161     protected PmfmDao pmfmDao;
162 
163     @Resource(name = "qualitativeValueDao")
164     protected QualitativeValueDao qualitativeValueDao;
165 
166     @Resource(name = "gearDao")
167     protected GearDao gearDao;
168 
169     @Resource(name = "gearPhysicalFeaturesDaoTutti")
170     protected GearPhysicalFeaturesDaoTutti gearPhysicalFeaturesDao;
171 
172     @Resource(name = "measurementPersistenceHelper")
173     protected MeasurementPersistenceHelper measurementPersistenceHelper;
174 
175     @Resource(name = "synchronizationStatusHelper")
176     protected SynchronizationStatusHelper synchronizationStatusHelper;
177 
178     @Override
179     public List<Integer> getAllCruiseId(String programId) {
180 
181         Preconditions.checkNotNull(programId);
182 
183         Iterator list = queryList(
184                 "allCruiseIds",
185                 "programCode", StringType.INSTANCE, programId);
186 
187         List<Integer> result = Lists.newArrayList();
188         while (list.hasNext()) {
189             Integer id = (Integer) list.next();
190             result.add(id);
191         }
192         return Collections.unmodifiableList(result);
193 
194     }
195 
196     @Override
197     public List<Cruise> getAllCruise(String programId) {
198 
199         Preconditions.checkNotNull(programId);
200 
201         Iterator<Object[]> list = queryList(
202                 "allCruises",
203                 "programCode", StringType.INSTANCE, programId);
204 
205         List<Cruise> result = Lists.newArrayList();
206         while (list.hasNext()) {
207             Object[] source = list.next();
208             Cruise target = Cruises.newCruise();
209             target.setId(String.valueOf(source[0]));
210             target.setName((String) source[1]);
211             target.setBeginDate((Date) source[2]);
212             target.setSynchronizationStatus((String) source[3]);
213             result.add(target);
214         }
215         return Collections.unmodifiableList(result);
216 
217     }
218 
219     @Override
220     public Cruise getCruise(Integer cruiseId) {
221 
222         Preconditions.checkNotNull(cruiseId);
223 
224         Object[] source = queryUnique(
225                 "cruise",
226                 "cruiseId", IntegerType.INSTANCE, cruiseId,
227                 "pmfmIdSurveyPart", IntegerType.INSTANCE, PmfmId.SURVEY_PART.getValue());
228 
229         if (source == null) {
230             throw new DataRetrievalFailureException("Could not retrieve cruise with id=" + cruiseId);
231         }
232         Cruise result = Cruises.newCruise();
233         result.setId(cruiseId);
234 
235         int index = 0;
236 
237         // departureLocation
238         Integer departureLocationId = (Integer) source[index++];
239         TuttiLocation departureLocation = locationService.getLocation(String.valueOf(departureLocationId));
240         result.setDepartureLocation(departureLocation);
241 
242         // returnLocation
243         Integer returnLocationId = (Integer) source[index++];
244         TuttiLocation returnLocation = locationService.getLocation(String.valueOf(returnLocationId));
245         result.setReturnLocation(returnLocation);
246 
247         // program
248         String programCode = (String) source[index++];
249         Program program = programService.getProgram(programCode);
250         result.setProgram(program);
251 
252         // name
253         result.setName((String) source[index++]);
254 
255         // begin Date
256         result.setBeginDate((Date) source[index++]);
257 
258         // end Date
259         result.setEndDate((Date) source[index++]);
260 
261         // vessel
262         String vesselCode = (String) source[index++];
263         Vessel vessel = vesselService.getVessel(vesselCode);
264         result.setVessel(vessel);
265 
266         // head of sort room
267         List<Person> headOfMissions = Lists.newArrayList();
268         result.setHeadOfMission(headOfMissions);
269         List<Person> headOfSortRoom = Lists.newArrayList();
270         result.setHeadOfSortRoom(headOfSortRoom);
271 
272         Integer managerId = (Integer) source[index++];
273         Person manager = personService.getPerson(managerId);
274         headOfMissions.add(manager);
275 
276         // comment
277         result.setComment((String) source[index++]);
278 
279         // synchronizationStatus
280         result.setSynchronizationStatus((String) source[index++]);
281 
282         // surverPart
283         result.setSurveyPart((String) source[index]);
284 
285         // get cruise gears
286         Iterator<Object[]> list = queryList(
287                 "allCruiseGears",
288                 "cruiseId", IntegerType.INSTANCE, cruiseId,
289                 "pmfmIdTrawlNet", IntegerType.INSTANCE, PmfmId.MULTIRIG_NUMBER.getValue());
290 
291         List<GearWithOriginalRankOrder> gears = Lists.newArrayList();
292         int maxMultirigNumberFound = 0;
293         while (list.hasNext()) {
294             Object[] gearRow = list.next();
295             Gear simpleGear = gearService.getGear((Integer) gearRow[0]);
296             GearWithOriginalRankOrder target = GearWithOriginalRankOrders.newGearWithOriginalRankOrder(simpleGear);
297             target.setRankOrder((Short) gearRow[1]);
298             Float multirigNumber = (Float) gearRow[2];
299             if (multirigNumber != null && multirigNumber.intValue() > maxMultirigNumberFound) {
300                 maxMultirigNumberFound = multirigNumber.intValue();
301             }
302             gears.add(target);
303         }
304         result.setGear(gears);
305         if (maxMultirigNumberFound > 0) {
306             result.setMultirigNumber(maxMultirigNumberFound);
307         }
308 
309         Iterator<Object[]> vesselPersonFeaturesList = queryList(
310                 "allCruiseVesselPersonFeatures",
311                 "cruiseId", IntegerType.INSTANCE, cruiseId);
312         while (vesselPersonFeaturesList.hasNext()) {
313             Object[] vesselPersonFeatures = vesselPersonFeaturesList.next();
314 
315             Integer personId = (Integer) vesselPersonFeatures[0];
316             Person person = personService.getPerson(personId);
317             Integer roleId = (Integer) vesselPersonFeatures[1];
318             if (VesselPersonRoleId.SCIENTIFIC_CRUISE_MANAGER.getValue().equals(roleId)) {
319                 headOfMissions.add(person);
320 
321             } else if (VesselPersonRoleId.SORT_ROOM_MANAGER.getValue().equals(roleId)) {
322                 headOfSortRoom.add(person);
323             }
324         }
325 
326         // Force initialization of multirigNumber to 1 initialization (need for UI)
327         if (result.getMultirigNumber() == null) {
328             log.warn(MessageFormat.format("Cruise with id={0} has been load with a default multirigNumber=1, beacause not multirigNumber were found in database.", cruiseId));
329             result.setMultirigNumber(1);
330         }
331         return result;
332 
333     }
334 
335     @Override
336     public Cruise createCruise(Cruise bean) {
337         Preconditions.checkNotNull(bean);
338         Preconditions.checkArgument(bean.getId() == null, "Cruise 'id' must be null to call createCruise().");
339         Preconditions.checkNotNull(bean.getProgram());
340         Preconditions.checkNotNull(bean.getBeginDate());
341         Preconditions.checkNotNull(bean.getEndDate());
342         Preconditions.checkNotNull(bean.getDepartureLocation());
343         Preconditions.checkNotNull(bean.getReturnLocation());
344         Preconditions.checkNotNull(bean.getVessel());
345         Preconditions.checkState(CollectionUtils.isNotEmpty(bean.getHeadOfMission()));
346 
347         ScientificCruise scientificCruise = ScientificCruise.Factory.newInstance();
348         cruiseToEntity(bean, scientificCruise);
349         scientificCruiseDao.create(scientificCruise);
350 
351         bean.setId(String.valueOf(scientificCruise.getId()));
352         bean.setSynchronizationStatus(scientificCruise.getSynchronizationStatus());
353         return bean;
354     }
355 
356     @Override
357     public Cruise saveCruise(Cruise bean,
358                              boolean updateVessel,
359                              boolean updateGear) {
360         Preconditions.checkNotNull(bean);
361         Preconditions.checkNotNull(bean.getId(), "Cruise 'id' must not be null or empty to be saved.");
362         Preconditions.checkNotNull(bean.getProgram());
363         Preconditions.checkNotNull(bean.getBeginDate());
364         Preconditions.checkNotNull(bean.getEndDate());
365         Preconditions.checkNotNull(bean.getDepartureLocation());
366         Preconditions.checkNotNull(bean.getReturnLocation());
367         Preconditions.checkNotNull(bean.getVessel());
368         Preconditions.checkState(CollectionUtils.isNotEmpty(bean.getHeadOfMission()));
369 
370         ScientificCruise scientificCruise = scientificCruiseDao.load(Integer.valueOf(bean.getId()));
371         if (scientificCruise == null) {
372             throw new DataRetrievalFailureException(
373                     "Could not retrieve cruise with id=" + bean.getId());
374         }
375 
376         cruiseToEntity(bean, scientificCruise);
377         scientificCruiseDao.update(scientificCruise);
378 
379         if (updateVessel) {
380             Vessel vessel = bean.getVessel();
381             if (log.isInfoEnabled()) {
382                 log.info("Change vessel to " + vessel.getId() +
383                          " for cruise: " + bean.getId());
384             }
385             queryUpdate("updateOperationsVessel",
386                         "cruiseId", IntegerType.INSTANCE, scientificCruise.getId(),
387                         "vesselId", StringType.INSTANCE, scientificCruise.getVessel().getCode());
388         }
389 
390         if (updateGear) {
391 
392             for (GearWithOriginalRankOrder gear : bean.getGear()) {
393 
394                 Short originalRankOrder = gear.getOriginalRankOrder();
395                 Short newRankOrder = gear.getRankOrder();
396 
397                 if (originalRankOrder != null && originalRankOrder != 0 &&
398                     ObjectUtils.notEqual(originalRankOrder, newRankOrder)) {
399 
400                     // gear was used, but the rank order has changed
401                     // must update all operation using it
402 
403                     if (log.isInfoEnabled()) {
404                         log.info("Change gear " + gear.getId() + ", old rankOrder:" +
405                                  originalRankOrder + " to " + newRankOrder +
406                                  " for cruise: " + bean.getId());
407                     }
408 
409                     queryUpdate("updateOperationsGear",
410                                 "cruiseId", IntegerType.INSTANCE, scientificCruise.getId(),
411                                 "gearId", IntegerType.INSTANCE, gear.getIdAsInt(),
412                                 "oldRankOrder", ShortType.INSTANCE, originalRankOrder,
413                                 "newRankOrder", ShortType.INSTANCE, newRankOrder
414                     );
415                 }
416             }
417         }
418 
419         bean.setSynchronizationStatus(scientificCruise.getSynchronizationStatus());
420         return bean;
421     }
422 
423     @Override
424     public void setCruiseReadyToSynch(Integer cruiseId) {
425         synchronizationStatusHelper.setCruiseReadyToSynch(cruiseId);
426     }
427 
428     @Override
429     public CaracteristicMap getGearCaracteristics(Integer cruiseId,
430                                                   Integer gearId,
431                                                   short rankOrder) {
432         Preconditions.checkNotNull(cruiseId, "Cruise 'id' must not be null or empty");
433         Preconditions.checkNotNull(gearId, "Gear 'id' must not be null or empty");
434 
435         if (log.isDebugEnabled()) {
436             log.debug("Get caracteristic for gear " + gearId + " - " + rankOrder);
437         }
438 
439         CaracteristicMap result = new CaracteristicMap();
440 
441         Iterator<GearPhysicalMeasurement> list = queryListTyped(
442                 "gearCaracteristics",
443                 "cruiseId", IntegerType.INSTANCE, cruiseId,
444                 "gearId", IntegerType.INSTANCE, gearId,
445                 "rankOrder", ShortType.INSTANCE, rankOrder);
446 
447         while (list.hasNext()) {
448             GearPhysicalMeasurement measurement = list.next();
449 
450             Integer pmfmId = measurement.getPmfm().getId();
451             if (!PmfmId.MULTIRIG_NUMBER.getValue().equals(pmfmId)) {
452                 Caracteristic caracteristic = caracteristicService.getCaracteristic(pmfmId);
453 
454                 Serializable value = null;
455                 switch (caracteristic.getCaracteristicType()) {
456                     case NUMBER:
457                         value = measurement.getNumericalValue();
458                         break;
459                     case QUALITATIVE:
460                         QualitativeValue qualitativeValue = measurement.getQualitativeValue();
461                         if (qualitativeValue != null) {
462                             value = CaracteristicQualitativeValues.getQualitativeValue(caracteristic,
463                                                                                        qualitativeValue.getId());
464                         }
465                         break;
466                     case TEXT:
467                         value = measurement.getAlphanumericalValue();
468                         break;
469                 }
470                 result.put(caracteristic, value);
471             }
472         }
473         return result;
474     }
475 
476     @Override
477     public void saveGearCaracteristics(Gear gear, Cruise cruise) {
478         Preconditions.checkNotNull(cruise);
479         Preconditions.checkNotNull(cruise.getId(), "Cruise 'id' must not be null or empty");
480         Preconditions.checkNotNull(gear);
481         Preconditions.checkNotNull(gear.getId(), "Gear 'id' must not be null or empty");
482 
483         short rankOrder;
484 
485         if (gear.getRankOrder() == null) {
486             rankOrder = 1;
487         } else {
488             rankOrder = gear.getRankOrder();
489         }
490 
491         ScientificCruise scientificCruise = scientificCruiseDao.load(cruise.getIdAsInt());
492         if (scientificCruise == null) {
493             throw new DataRetrievalFailureException("Could not retrieve cruise with id=" + cruise.getId());
494         }
495 
496         // Retrieve entities : FishingTrip
497         ObservedFishingTrip fishingTrip = (ObservedFishingTrip) scientificCruise.getFishingTrips().iterator().next();
498         Preconditions.checkNotNull(fishingTrip);
499 
500         List<Integer> measurementsToRemove = Lists.newArrayList();
501 
502         if (log.isDebugEnabled()) {
503             log.debug("Save caracteristic for gear " + gear.getIdAsInt() + " - " + rankOrder);
504         }
505         GearPhysicalFeatures gpf = gearPhysicalFeaturesDao.getGearPhysicalfeatures(
506                 fishingTrip,
507                 gear.getIdAsInt(),
508                 rankOrder,
509                 true);
510 
511         if (gpf.getGearPhysicalMeasurements() != null) {
512             for (GearPhysicalMeasurement measurement : gpf.getGearPhysicalMeasurements()) {
513                 Integer pmfmId = measurement.getPmfm().getId();
514                 if (!PmfmId.MULTIRIG_NUMBER.getValue().equals(pmfmId)) {
515                     measurementsToRemove.add(pmfmId);
516                 }
517             }
518         }
519 
520         CaracteristicMap caracteristicMap = gear.getCaracteristics();
521         if (caracteristicMap != null) {
522             for (Caracteristic caracteristic : caracteristicMap.keySet()) {
523 
524                 Float numericalValue = null;
525                 String alphanumericalValue = null;
526                 Integer qualitativeValue = null;
527                 Object value = caracteristicMap.get(caracteristic);
528 
529                 switch (caracteristic.getCaracteristicType()) {
530                     case NUMBER:
531                         numericalValue = (Float) value;
532                         break;
533 
534                     case QUALITATIVE:
535                         Integer qvId = null;
536                         if (value instanceof CaracteristicQualitativeValue) {
537                             qvId = Integer.valueOf(((CaracteristicQualitativeValue) value).getId());
538                         } else if (value instanceof Integer) {
539                             qvId = (Integer) value;
540                         }
541                         qualitativeValue = qvId;
542                         break;
543 
544                     case TEXT:
545                         alphanumericalValue = (String) value;
546                         break;
547                 }
548 
549                 GearPhysicalMeasurement gearPhysicalMeasurement =
550                         gearPhysicalFeaturesDao.setGearPhysicalMeasurement(scientificCruise,
551                                                                            gpf,
552                                                                            caracteristic.getIdAsInt(),
553                                                                            numericalValue,
554                                                                            alphanumericalValue,
555                                                                            qualitativeValue);
556 
557                 measurementsToRemove.remove(gearPhysicalMeasurement.getPmfm().getId());
558             }
559         }
560 
561         for (Integer pmfmId : measurementsToRemove) {
562             gearPhysicalFeaturesDao.removeGearPhysicalMeasurement(gpf, pmfmId);
563         }
564 
565         gearPhysicalFeaturesDao.update(gpf);
566     }
567 
568     @Override
569     public boolean isOperationUseGears(Integer cruiseId, Collection<Gear> gears) {
570 
571         Preconditions.checkNotNull(cruiseId);
572         Preconditions.checkNotNull(gears);
573 
574         boolean result = false;
575 
576         if (!gears.isEmpty()) {
577             // ---
578             // get all gears found in operations of the cruise
579             // ---
580 
581             List<Integer> gearIds = TuttiEntities.toIntegerIds(gears);
582             Iterator<Object[]> list = queryList(
583                     "allFishingOperationsWithGear",
584                     "cruiseId", IntegerType.INSTANCE, cruiseId,
585                     "gearIds", IntegerType.INSTANCE, gearIds
586             );
587 
588             while (list.hasNext()) {
589                 Object[] next = list.next();
590                 GearWithOriginalRankOrder g = GearWithOriginalRankOrders.newGearWithOriginalRankOrder(
591                         (Integer) next[0],
592                         (Short) next[1]
593                 );
594                 if (gears.contains(g)) {
595                     result = true;
596                     break;
597                 }
598             }
599         }
600         return result;
601     }
602 
603     protected void cruiseToEntity(Cruise source, ScientificCruise target) {
604 
605         QualityFlag qualityFlagNotQualified = load(
606                 QualityFlagImpl.class, QualityFlagCode.NOTQUALIFIED.getValue());
607 
608         // Retrieve entities : FishingTrip
609         ObservedFishingTrip fishingTrip;
610         if (CollectionUtils.isEmpty(target.getFishingTrips())) {
611             fishingTrip = ObservedFishingTrip.Factory.newInstance();
612             if (target.getFishingTrips() == null) {
613                 target.setFishingTrips(Lists.newArrayList((FishingTrip) fishingTrip));
614                 fishingTrip.setScientificCruise(target);
615             } else {
616                 target.getFishingTrips().add(fishingTrip);
617                 fishingTrip.setScientificCruise(target);
618             }
619         } else {
620             fishingTrip = (ObservedFishingTrip) target.getFishingTrips().iterator().next();
621         }
622 
623         // Name
624         target.setName(source.getName());
625 
626         // Program
627         ProgramImpl program = load(ProgramImpl.class, source.getProgram().getId());
628         target.setProgram(program);
629 
630         // Vessel
631         VesselImpl vessel = load(VesselImpl.class, source.getVessel().getId());
632         target.setVessel(vessel);
633 
634         // BeginDate
635         target.setDepartureDateTime(dateWithNoSecondAndMiliSecond(source.getBeginDate()));
636 
637         // EndDate
638         target.setReturnDateTime(dateWithNoSecondAndMiliSecond(source.getEndDate()));
639 
640         // Comment
641         target.setComments(source.getComment());
642 
643         // Optional values in UI, but mandatory in DB
644         if (target.getManagerPerson() == null) {
645             target.setManagerPerson(load(PersonImpl.class, PersonId.UNKNOWN_RECORDER_PERSON.getValue()));
646         }
647 
648         // Default values :
649         if (target.getCreationDate() == null) {
650             target.setCreationDate(newCreateDate());
651         }
652         if (target.getManagerPerson() != null) {
653             target.setRecorderPerson(target.getManagerPerson());
654             target.setRecorderDepartment(target.getManagerPerson().getDepartment());
655         }
656 
657         // Fill fishing trip with scientificCruise info:
658         fishingTrip.setDepartureDateTime(target.getDepartureDateTime());
659         fishingTrip.setReturnDateTime(target.getReturnDateTime());
660         fishingTrip.setVessel(target.getVessel());
661         fishingTrip.setProgram(target.getProgram());
662         fishingTrip.setRecorderPerson(target.getRecorderPerson());
663         fishingTrip.setRecorderDepartment(target.getRecorderDepartment());
664         fishingTrip.setCreationDate(target.getCreationDate());
665         fishingTrip.setQualityFlag(qualityFlagNotQualified);
666 
667         // SynchronizationStatus
668         synchronizationStatusHelper.setDirty(target);
669         synchronizationStatusHelper.setDirty(fishingTrip);
670 
671         // DepartureLocation
672         Location departureLocation = load(LocationImpl.class, Integer.valueOf(source.getDepartureLocation().getId()));
673         fishingTrip.setDepartureLocation(departureLocation);
674 
675         // ReturnLocation
676         Location returnLocation = load(LocationImpl.class, Integer.valueOf(source.getReturnLocation().getId()));
677         fishingTrip.setReturnLocation(returnLocation);
678 
679         if (StringUtils.isEmpty(source.getSurveyPart())) {
680 
681             // remove surveyMeasurement if exists
682             measurementPersistenceHelper.removeSurveyMeasurement(fishingTrip, PmfmId.SURVEY_PART.getValue());
683         } else {
684 
685             // update it or create it
686             measurementPersistenceHelper.setSurveyMeasurement(fishingTrip, PmfmId.SURVEY_PART.getValue(), null, source.getSurveyPart(), null);
687         }
688 
689         // Gear
690         if (source.isGearEmpty() && fishingTrip.getGearPhysicalFeatures() != null) {
691             fishingTrip.getGearPhysicalFeatures().clear();
692         } else if (!source.isGearEmpty()) {
693             // Create a list to trace not updated items, to be able to remove them later
694             Set<GearPhysicalFeatures> notChangedGearPhysicalFeatures = Sets.newHashSet();
695             if (fishingTrip.getGearPhysicalFeatures() != null) {
696                 notChangedGearPhysicalFeatures.addAll(fishingTrip.getGearPhysicalFeatures());
697             }
698 
699             short gearRankOrder = 1;
700             // Create or update a geaPhysicalFeatures for each gears in the cruise
701             for (GearWithOriginalRankOrder gear : source.getGear()) {
702 
703                 Short rankOrder = gear.getRankOrder();
704 
705                 GearPhysicalFeatures guf;
706 
707                 // try first to get the guf with originalRankOrder
708                 guf = gearPhysicalFeaturesDao.getGearPhysicalfeatures(fishingTrip, gear.getIdAsInt(), gear.getOriginalRankOrder(), false);
709 
710                 if (guf == null) {
711 
712                     // try with new rankOrder
713                     // in facts, only means create a new one
714                     guf = gearPhysicalFeaturesDao.getGearPhysicalfeatures(fishingTrip, gear.getIdAsInt(), rankOrder, true);
715                     if (log.isDebugEnabled()) {
716                         log.debug("Will create guf: " + guf.getId() + " for gear: " + gear.getId() + " - " + gear.getRankOrder());
717                     }
718                 } else {
719 
720                     // got an old guf to update
721                     if (log.isDebugEnabled()) {
722                         log.debug("Will update guf: " + guf.getId() + " for gear: " + gear.getId() + " - " + gear.getOriginalRankOrder() + ", new rankOrder: " + gear.getRankOrder());
723                     }
724                 }
725 
726                 notChangedGearPhysicalFeatures.remove(guf);
727 
728                 guf.setStartDate(fishingTrip.getDepartureDateTime());
729                 guf.setEndDate(fishingTrip.getReturnDateTime());
730                 guf.setVessel(fishingTrip.getVessel());
731                 guf.setProgram(fishingTrip.getProgram());
732                 guf.setCreationDate(target.getCreationDate());
733                 guf.setQualityFlag(qualityFlagNotQualified);
734 
735                 // realign the rankOrder using the order of the list of gears
736                 guf.setRankOrder(gearRankOrder++);
737 
738                 // Trawl net (store in Gear Physical features)
739                 if (source.getMultirigNumber() == null) {
740                     gearPhysicalFeaturesDao.removeGearPhysicalMeasurement(guf, PmfmId.MULTIRIG_NUMBER.getValue());
741                 } else {
742                     gearPhysicalFeaturesDao.setGearPhysicalMeasurement(target, guf, PmfmId.MULTIRIG_NUMBER.getValue(), Float.valueOf(source.getMultirigNumber()), null, null);
743                 }
744             }
745 
746             // Remove deleted gear physical features
747             if (fishingTrip.getGearPhysicalFeatures() != null && notChangedGearPhysicalFeatures.size() > 0) {
748                 List<Gear> gears = Lists.transform(Lists.newArrayList(notChangedGearPhysicalFeatures),
749                                                    input -> {
750                                                        Gear result = Gears.newGear();
751 
752                                                        if (input != null && input.getGear() != null) {
753                                                            result.setRankOrder(input.getRankOrder());
754                                                            result.setId(input.getGear().getId());
755                                                        }
756                                                        return result;
757                                                    }
758                 );
759 
760                 boolean gearRemoved = isOperationUseGears(target.getId(), gears);
761                 if (gearRemoved) {
762                     throw new ApplicationBusinessException(t("tutti.persistence.cruise.gearUsedInOperations.error"));
763                 }
764 
765                 for (GearPhysicalFeatures guf : notChangedGearPhysicalFeatures) {
766                     if (guf.getGearPhysicalMeasurements() != null) {
767                         guf.getGearPhysicalMeasurements().clear();
768                     }
769                     fishingTrip.getGearPhysicalFeatures().remove(guf);
770                 }
771             }
772         }
773 
774         VesselPersonRole scientificCruiseManagerRole =
775                 vesselPersonFeaturesPersistenceHelper.getScientificCruiseManagerRole();
776 
777         VesselPersonRole sortRoomManagerRole =
778                 vesselPersonFeaturesPersistenceHelper.getSortRoomManagerRole();
779 
780         Map<Integer, VesselPersonFeatures> vesselPersonFeaturesMap = Maps.newLinkedHashMap();
781 
782         short personRankOrder = 1;
783 
784         // Head of Mission Managers (act as rankOrder 0)
785         List<Person> persons = source.getHeadOfMission();
786         target.setManagerPerson(load(PersonImpl.class, persons.get(0).getIdAsInt()));
787 
788         for (int i = 1; i < persons.size(); i++) {
789             Integer personId = persons.get(i).getIdAsInt();
790             vesselPersonFeaturesPersistenceHelper.fillVesselPersonFeatures(
791                     vesselPersonFeaturesMap,
792                     personId,
793                     fishingTrip,
794                     scientificCruiseManagerRole,
795                     personRankOrder++);
796         }
797 
798         // Sort Room Managers
799         if (CollectionUtils.isNotEmpty(source.getHeadOfSortRoom())) {
800             for (Person person : source.getHeadOfSortRoom()) {
801                 Integer personId = person.getIdAsInt();
802                 vesselPersonFeaturesPersistenceHelper.fillVesselPersonFeatures(
803                         vesselPersonFeaturesMap,
804                         personId,
805                         fishingTrip,
806                         sortRoomManagerRole,
807                         personRankOrder++);
808             }
809         }
810 
811         if (fishingTrip.getVesselPersonFeatures() == null) {
812             fishingTrip.setVesselPersonFeatures(Sets.<VesselPersonFeatures>newHashSet());
813         }
814         fishingTrip.getVesselPersonFeatures().clear();
815         fishingTrip.getVesselPersonFeatures().addAll(vesselPersonFeaturesMap.values());
816     }
817 }