View Javadoc
1   package fr.ifremer.tutti.persistence.service.referential;
2   
3   /*
4    * #%L
5    * Tutti :: Persistence
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2012 - 2014 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU General Public License as
13   * published by the Free Software Foundation, either version 3 of the
14   * License, or (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 General Public
22   * License along with this program.  If not, see
23   * <http://www.gnu.org/licenses/gpl-3.0.html>.
24   * #L%
25   */
26  
27  import com.google.common.base.Preconditions;
28  import com.google.common.collect.Lists;
29  import fr.ifremer.adagio.core.dao.data.vessel.VesselExtendDao;
30  import fr.ifremer.adagio.core.dao.referential.StatusCode;
31  import fr.ifremer.adagio.core.dao.referential.VesselTypeId;
32  import fr.ifremer.adagio.core.dao.referential.location.LocationExtendDao;
33  import fr.ifremer.adagio.core.dao.referential.location.LocationLabel;
34  import fr.ifremer.adagio.core.dao.referential.location.LocationLevelId;
35  import fr.ifremer.adagio.core.dao.technical.hibernate.TemporaryDataHelper;
36  import fr.ifremer.tutti.persistence.entities.referential.Vessel;
37  import fr.ifremer.tutti.persistence.entities.referential.Vessels;
38  import org.apache.commons.lang3.StringUtils;
39  import org.apache.commons.logging.Log;
40  import org.apache.commons.logging.LogFactory;
41  import org.hibernate.type.DateType;
42  import org.hibernate.type.IntegerType;
43  import org.hibernate.type.StringType;
44  import org.nuiton.jaxx.application.ApplicationBusinessException;
45  import org.nuiton.jaxx.application.ApplicationTechnicalException;
46  import org.springframework.cache.Cache;
47  import org.springframework.dao.DataIntegrityViolationException;
48  import org.springframework.stereotype.Service;
49  
50  import javax.annotation.Resource;
51  import java.util.Collection;
52  import java.util.Collections;
53  import java.util.Date;
54  import java.util.Iterator;
55  import java.util.List;
56  
57  /**
58   * Created on 11/3/14.
59   *
60   * @author Tony Chemit - chemit@codelutin.com
61   * @since 3.8
62   */
63  @Service("vesselPersistenceService")
64  public class VesselPersistenceServiceImpl extends ReferentialPersistenceServiceSupport implements VesselPersistenceService {
65  
66      /** Logger. */
67      private static final Log log = LogFactory.getLog(VesselPersistenceServiceImpl.class);
68  
69      @Resource(name = "vesselExtendDao")
70      protected VesselExtendDao vesselExtendDao;
71  
72      @Resource(name = "locationDao")
73      protected LocationExtendDao locationDao;
74  
75      @Override
76      public List<Vessel> getAllScientificVessel() {
77  
78          Iterator<Object[]> list = queryListWithStatus(
79                  "allVessels",
80                  "refDate", DateType.INSTANCE, new Date(),
81                  "vesselTypeId", IntegerType.INSTANCE, VesselTypeId.SCIENTIFIC_RESEARCH_VESSEL.getValue());
82  
83          List<Vessel> result = Lists.newArrayList();
84          Cache vesselByCodeCache = cacheService.getCache("vesselByCode");
85          loadVessels(list, result, true, vesselByCodeCache);
86  
87          return Collections.unmodifiableList(result);
88  
89      }
90  
91      @Override
92      public List<Vessel> getAllFishingVessel() {
93  
94          Iterator<Object[]> list = queryListWithStatus(
95                  "allVessels",
96                  "refDate", DateType.INSTANCE, new Date(),
97                  "vesselTypeId", IntegerType.INSTANCE, VesselTypeId.FISHING_VESSEL.getValue());
98  
99          List<Vessel> result = Lists.newArrayList();
100         Cache vesselByCodeCache = cacheService.getCache("vesselByCode");
101         loadVessels(list, result, false, vesselByCodeCache);
102 
103         return Collections.unmodifiableList(result);
104 
105     }
106 
107     @Override
108     public List<Vessel> getAllVesselWithObsoletes() {
109 
110         List<Vessel> result = Lists.newArrayList();
111 
112         Iterator<Object[]> fishingVesselList = queryListWithStatus2(
113                 "allVesselsWithObsoletes",
114                 "refDate", DateType.INSTANCE, new Date(),
115                 "vesselTypeId", IntegerType.INSTANCE, VesselTypeId.FISHING_VESSEL.getValue());
116         loadVesselsWithObsoletes(fishingVesselList, result, false);
117         int fishingVesselCount = result.size();
118         if (log.isDebugEnabled()) {
119             log.debug("fishing vessels: " + fishingVesselCount);
120         }
121 
122         Iterator<Object[]> scientificVesselList = queryListWithStatus2(
123                 "allVesselsWithObsoletes",
124                 "refDate", DateType.INSTANCE, new Date(),
125                 "vesselTypeId", IntegerType.INSTANCE, VesselTypeId.SCIENTIFIC_RESEARCH_VESSEL.getValue());
126         loadVesselsWithObsoletes(scientificVesselList, result, true);
127         if (log.isDebugEnabled()) {
128             log.debug("scientific vessels: " + (result.size() - fishingVesselCount));
129         }
130 
131         return Collections.unmodifiableList(result);
132 
133     }
134 
135     @Override
136     public Vessel getVessel(String vesselCode) {
137 
138         if (log.isDebugEnabled()) {
139             log.debug("get vessel: " + vesselCode);
140         }
141         // On ne peut pas récupérer directement un unique objet à cause des période de validité d'immtriculation
142         // L'ordre induit par la requete nous donne cependant un match en dernière position
143         Iterator<Object[]> source = queryListWithStatus2(
144                 "vesselByCode",
145                 "vesselCode", StringType.INSTANCE, vesselCode,
146                 "refDate", DateType.INSTANCE, new Date()
147         );
148         Object[] vesselSource = null;
149         while (source.hasNext()) {
150             vesselSource = source.next();
151         }
152         if (vesselSource == null) {
153             throw new ApplicationTechnicalException("Could not find vessel with code: " + vesselCode);
154         }
155         return loadVessel(vesselSource);
156 
157     }
158 
159     @Override
160     public boolean isTemporaryVesselUsed(String code) {
161 
162         Long count = queryUniqueTyped("countVesselInCruise", "id", StringType.INSTANCE, code);
163         boolean result = count > 0;
164 
165         if (!result) {
166             count = queryUniqueTyped("countVesselInFishingOperation", "id", StringType.INSTANCE, code);
167             result = count > 0;
168         }
169 
170         if (!result) {
171             count = queryUniqueTyped("countVesselInOperationVesselAssociation", "id", StringType.INSTANCE, code);
172             result = count > 0;
173         }
174 
175         if (!result) {
176             count = queryUniqueTyped("countVesselInDailyActivityCalendar", "id", StringType.INSTANCE, code);
177             result = count > 0;
178         }
179 
180         if (!result) {
181             count = queryUniqueTyped("countVesselInLanding", "id", StringType.INSTANCE, code);
182             result = count > 0;
183         }
184 
185         if (!result) {
186             count = queryUniqueTyped("countVesselInFishingtrip", "id", StringType.INSTANCE, code);
187             result = count > 0;
188         }
189 
190         if (!result) {
191             count = queryUniqueTyped("countVesselInVesselUseFeatures", "id", StringType.INSTANCE, code);
192             result = count > 0;
193         }
194 
195         if (!result) {
196             count = queryUniqueTyped("countVesselInGearUseFeatures", "id", StringType.INSTANCE, code);
197             result = count > 0;
198         }
199 
200         if (!result) {
201             count = queryUniqueTyped("countVesselInGearPhysicalFeatures", "id", StringType.INSTANCE, code);
202             result = count > 0;
203         }
204 
205         return result;
206 
207     }
208 
209     @Override
210     public List<Vessel> addTemporaryVessels(List<Vessel> vessels) {
211 
212         Integer countryLocationId =
213                 locationDao.getLocationIdByLabelAndLocationLevel(
214                         LocationLabel.FRANCE.getValue(),
215                         new Integer[]{LocationLevelId.PAYS_ISO3.getValue()});
216         if (countryLocationId == null) {
217             throw new DataIntegrityViolationException("Default country location not found, with label=" + LocationLabel.FRANCE.getValue());
218         }
219 
220         List<Vessel> result = Lists.newArrayList();
221         for (Vessel source : vessels) {
222             Vessel added = addTemporaryVessel(source, countryLocationId);
223             result.add(added);
224         }
225         return Collections.unmodifiableList(result);
226 
227     }
228 
229     @Override
230     public List<Vessel> updateTemporaryVessels(List<Vessel> vessels) {
231 
232         Integer countryLocationId =
233                 locationDao.getLocationIdByLabelAndLocationLevel(
234                         LocationLabel.FRANCE.getValue(),
235                         new Integer[]{LocationLevelId.PAYS_ISO3.getValue()});
236         if (countryLocationId == null) {
237             throw new DataIntegrityViolationException("Default country location not found, with label=" + LocationLabel.FRANCE.getValue());
238         }
239 
240         List<Vessel> result = Lists.newArrayList();
241         for (Vessel source : vessels) {
242             Vessel updated = updateTemporaryVessel(source, countryLocationId);
243             result.add(updated);
244             source = updateTemporaryVessel(source, countryLocationId);
245             result.add(source);
246         }
247         return Collections.unmodifiableList(result);
248 
249     }
250 
251     @Override
252     public List<Vessel> linkTemporaryVessels(List<Vessel> vessels) {
253 
254         List<Vessel> result = Lists.newArrayList();
255         for (Vessel source : vessels) {
256             Vessel linked = linkTemporaryVessel(source);
257             result.add(linked);
258         }
259         return Collections.unmodifiableList(result);
260 
261     }
262 
263     @Override
264     public void replaceVessel(Vessel source, Vessel target, boolean delete) {
265 
266         Preconditions.checkNotNull(source);
267         Preconditions.checkNotNull(target);
268         Preconditions.checkState(Vessels.isTemporary(source));
269         Preconditions.checkState(!Vessels.isTemporary(target));
270 
271         String sourceId = source.getId();
272         String targetId = target.getId();
273 
274         queryUpdate("replaceVesselInCruise",
275                 "sourceId", StringType.INSTANCE, sourceId,
276                 "targetId", StringType.INSTANCE, targetId);
277 
278         queryUpdate("replaceVesselInFishingOperation",
279                 "sourceId", StringType.INSTANCE, sourceId,
280                 "targetId", StringType.INSTANCE, targetId);
281 
282         queryUpdate("replaceVesselInOperationVesselAssociation",
283                 "sourceId", StringType.INSTANCE, sourceId,
284                 "targetId", StringType.INSTANCE, targetId);
285 
286         queryUpdate("replaceVesselInDailyActivityCalendar",
287                 "sourceId", StringType.INSTANCE, sourceId,
288                 "targetId", StringType.INSTANCE, targetId);
289 
290         queryUpdate("replaceVesselInLanding",
291                 "sourceId", StringType.INSTANCE, sourceId,
292                 "targetId", StringType.INSTANCE, targetId);
293 
294         queryUpdate("replaceVesselInFishingtrip",
295                 "sourceId", StringType.INSTANCE, sourceId,
296                 "targetId", StringType.INSTANCE, targetId);
297 
298         queryUpdate("replaceVesselInVesselUseFeatures",
299                 "sourceId", StringType.INSTANCE, sourceId,
300                 "targetId", StringType.INSTANCE, targetId);
301 
302         queryUpdate("replaceVesselInGearUseFeatures",
303                 "sourceId", StringType.INSTANCE, sourceId,
304                 "targetId", StringType.INSTANCE, targetId);
305 
306         queryUpdate("replaceVesselInGearPhysicalFeatures",
307                 "sourceId", StringType.INSTANCE, sourceId,
308                 "targetId", StringType.INSTANCE, targetId);
309 
310         //TODO Check doublon...
311 
312         if (delete) {
313 
314             deleteTemporaryVessel(sourceId);
315 
316         }
317 
318     }
319 
320     @Override
321     public void deleteTemporaryVessels(Collection<String> codes) {
322 
323         for (String code : codes) {
324             deleteTemporaryVessel(code);
325         }
326 
327     }
328 
329     @Override
330     public void deleteTemporaryVessel(String code) {
331 
332         Preconditions.checkNotNull(code);
333         if (!code.startsWith(TemporaryDataHelper.TEMPORARY_NAME_PREFIX)) {
334             throw new ApplicationBusinessException(String.format("Can't delete a Vessel with a code %s not beginning with %s.", code, TemporaryDataHelper.TEMPORARY_NAME_PREFIX));
335         }
336         Vessel vessel = getVessel(code);
337         if (vessel == null) {
338             throw new ApplicationBusinessException(String.format("Vessel with code %s does not exists", code));
339         }
340 
341         vesselExtendDao.removeTemporaryVessel(code);
342 
343     }
344 
345     protected Vessel addTemporaryVessel(Vessel source, Integer registrationLocationId) {
346 
347         Preconditions.checkNotNull(source);
348         Preconditions.checkNotNull(source.getName());
349         Preconditions.checkNotNull(source.getInternationalRegistrationCode());
350         Preconditions.checkArgument(StringUtils.isBlank(source.getId()) || Vessels.isTemporaryId(source.getId()));
351 
352         Integer vesselTypeId = getVesselTypeId(source);
353 
354         fr.ifremer.adagio.core.dao.data.vessel.Vessel target =
355                 vesselExtendDao.createAsTemporary(
356                         null,
357                         source.getInternationalRegistrationCode(),
358                         registrationLocationId, source.getName(),
359                         vesselTypeId,
360                         false);
361 
362         // Fill the result bean
363         Vessel result = Vessels.newVessel();
364         result.setId(target.getCode());
365         result.setName(source.getName());
366         result.setRegistrationCode(source.getRegistrationCode());
367         result.setInternationalRegistrationCode(source.getInternationalRegistrationCode());
368         result.setScientificVessel(source.isScientificVessel());
369         setStatus(StatusCode.TEMPORARY.getValue(), result);
370         return result;
371 
372     }
373 
374     protected Vessel updateTemporaryVessel(Vessel source, Integer countryLocationId) {
375 
376         Preconditions.checkNotNull(source);
377         Preconditions.checkNotNull(source.getId());
378         Preconditions.checkNotNull(source.getName());
379         Preconditions.checkNotNull(source.getInternationalRegistrationCode());
380         Preconditions.checkArgument(Vessels.isTemporaryId(source.getId()));
381 
382         // Fill the result bean
383         Vessel result = getVessel(source.getId());
384         result.setName(source.getName());
385         result.setRegistrationCode(source.getRegistrationCode());
386         result.setInternationalRegistrationCode(source.getInternationalRegistrationCode());
387         result.setScientificVessel(source.isScientificVessel());
388         setStatus(StatusCode.TEMPORARY.getValue(), result);
389 
390         Integer vesselTypeId = getVesselTypeId(source);
391 
392         vesselExtendDao.updateTemporaryVessel(
393                 source.getId(),
394                 source.getRegistrationCode(),
395                 source.getInternationalRegistrationCode(),
396                 countryLocationId,
397                 source.getName(),
398                 vesselTypeId,
399                 false);
400 
401         return result;
402 
403     }
404 
405     private Integer getVesselTypeId(Vessel source) {
406         Integer vesselTypeId;
407         if (source.isScientificVessel()) {
408             vesselTypeId = VesselTypeId.SCIENTIFIC_RESEARCH_VESSEL.getValue();
409         } else {
410             vesselTypeId = VesselTypeId.FISHING_VESSEL.getValue();
411         }
412         return vesselTypeId;
413     }
414 
415     protected Vessel linkTemporaryVessel(Vessel source) {
416 
417         Preconditions.checkNotNull(source);
418         Preconditions.checkNotNull(source.getId());
419         Preconditions.checkNotNull(source.getName());
420         Preconditions.checkNotNull(source.getInternationalRegistrationCode());
421         Preconditions.checkArgument(Vessels.isTemporaryId(source.getId()));
422 
423         // Warning : return a list because more than one line could be found,
424         // but 'order by' assume that the first one in the good row
425         Iterator<Object[]> row = queryListWithStatus(
426                 "vesselByInternationalRegistrationCode",
427                 "vesselInternationalRegistrationCode", StringType.INSTANCE, source.getInternationalRegistrationCode(),
428                 "refDate", DateType.INSTANCE, new Date()
429         );
430         return row.hasNext() ? loadVessel(row.next()) : null;
431 
432     }
433 
434     protected void loadVessels(Iterator<Object[]> list, List<Vessel> result, boolean scientificVessel, Cache vesselByCodeCache) {
435         while (list.hasNext()) {
436             Object[] source = list.next();
437             Vessel target = loadVessel(source);
438             target.setScientificVessel(scientificVessel);
439             result.add(target);
440             // Add to cache
441             vesselByCodeCache.put(target.getId(), target);
442         }
443     }
444 
445     protected void loadVesselsWithObsoletes(Iterator<Object[]> list, List<Vessel> result, boolean scientificVessel) {
446 
447         Vessel lastTarget = null;
448         while (list.hasNext()) {
449             Object[] source = list.next();
450             Vessel target = loadVessel(source);
451             target.setScientificVessel(scientificVessel);
452             if (lastTarget != null && !target.getId().equals(lastTarget.getId())) {
453 
454                 // nouveau code à traiter, on doit enregister l'ancien navire
455                 result.add(lastTarget);
456             }
457             lastTarget = target;
458         }
459         result.add(lastTarget);
460 
461     }
462 
463     protected Vessel loadVessel(Object... source) {
464 
465         Vessel target = Vessels.newVessel();
466         target.setId((String) source[0]);
467         target.setRegistrationCode((String) source[1]);
468         target.setInternationalRegistrationCode((String) source[2]);
469         target.setName((String) source[3]);
470         Integer vesselTypeId = (Integer) source[4];
471         boolean scientificVessel = VesselTypeId.SCIENTIFIC_RESEARCH_VESSEL.getValue().equals(vesselTypeId);
472         target.setScientificVessel(scientificVessel);
473         setStatus((String) source[5], target);
474         return target;
475 
476     }
477 
478 }