View Javadoc
1   package net.sumaris.core.dao.data;
2   
3   /*-
4    * #%L
5    * SUMARiS:: Core
6    * %%
7    * Copyright (C) 2018 SUMARiS Consortium
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 net.sumaris.core.dao.referential.ReferentialDao;
27  import net.sumaris.core.dao.technical.model.IEntity;
28  import net.sumaris.core.model.data.PhysicalGear;
29  import net.sumaris.core.model.data.PhysicalGearMeasurement;
30  import net.sumaris.core.model.data.Trip;
31  import net.sumaris.core.model.referential.gear.Gear;
32  import net.sumaris.core.util.Beans;
33  import net.sumaris.core.vo.administration.programStrategy.ProgramVO;
34  import net.sumaris.core.vo.administration.user.DepartmentVO;
35  import net.sumaris.core.vo.data.MeasurementVO;
36  import net.sumaris.core.vo.data.PhysicalGearVO;
37  import net.sumaris.core.vo.referential.ReferentialVO;
38  import org.apache.commons.collections4.CollectionUtils;
39  import org.apache.commons.collections4.MapUtils;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  import org.springframework.beans.factory.annotation.Autowired;
43  import org.springframework.stereotype.Repository;
44  
45  import javax.persistence.EntityManager;
46  import javax.persistence.TypedQuery;
47  import javax.persistence.criteria.CriteriaBuilder;
48  import javax.persistence.criteria.CriteriaQuery;
49  import javax.persistence.criteria.ParameterExpression;
50  import javax.persistence.criteria.Root;
51  import java.sql.Timestamp;
52  import java.util.List;
53  import java.util.Map;
54  import java.util.Objects;
55  import java.util.stream.Collectors;
56  
57  @Repository("physicalGearDao")
58  public class PhysicalGearDaoImpl extends BaseDataDaoImpl implements PhysicalGearDao {
59  
60      /** Logger. */
61      private static final Logger log =
62              LoggerFactory.getLogger(PhysicalGearDaoImpl.class);
63  
64      @Autowired
65      private ReferentialDao referentialDao;
66  
67      @Autowired
68      private MeasurementDao measurementDao;
69  
70  
71      @Override
72      public List<PhysicalGearVO> getPhysicalGearByTripId(int tripId) {
73          CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
74          CriteriaQuery<PhysicalGear> query = builder.createQuery(PhysicalGear.class);
75          Root<PhysicalGear> root = query.from(PhysicalGear.class);
76  
77          ParameterExpression<Integer> tripIdParam = builder.parameter(Integer.class);
78  
79          query.select(root)
80              .where(builder.equal(root.get(PhysicalGear.Fields.TRIP).get(IEntity.Fields.ID), tripIdParam));
81  
82          TypedQuery<PhysicalGear> q = getEntityManager().createQuery(query)
83                  .setParameter(tripIdParam, tripId);
84          return toPhysicalGearVOs(q.getResultList());
85      }
86  
87      @Override
88      public List<PhysicalGearVO> save(final int tripId, final List<PhysicalGearVO> sources) {
89  
90          // Load parent entity
91          Trip parent = get(Trip.class, tripId);
92          ProgramVOprogramStrategy/ProgramVO.html#ProgramVO">ProgramVO parentProgram = new ProgramVO();
93          parentProgram.setId(parent.getProgram().getId());
94  
95          // Remember existing entities
96          final Map<Integer, PhysicalGear> sourcesToRemove = Beans.splitById(parent.getPhysicalGears());
97  
98          // Save each sources
99          List<PhysicalGearVO> result = sources.stream().map(gear -> {
100             gear.setTripId(tripId);
101             gear.setProgram(parentProgram);
102 
103             if (gear.getId() != null) {
104                 sourcesToRemove.remove(gear.getId());
105             }
106             return save(gear);
107         }).collect(Collectors.toList());
108 
109         // Remove unused entities
110         if (MapUtils.isNotEmpty(sourcesToRemove)) {
111             sourcesToRemove.values().forEach(this::delete);
112         }
113 
114         // Save measurements on each gears
115         // NOTE: using the savedGear to be sure to get an id
116         result.forEach(source -> {
117 
118             if (source.getMeasurementValues() != null) {
119                 measurementDao.savePhysicalGearMeasurementsMap(source.getId(), source.getMeasurementValues());
120             }
121             else {
122                 List<MeasurementVO> measurements = Beans.getList(source.getMeasurements());
123                 int rankOrder = 1;
124                 for (MeasurementVO m : measurements) {
125                     fillDefaultProperties(source, m);
126                     m.setRankOrder(rankOrder++);
127                 }
128                 measurements = measurementDao.savePhysicalGearMeasurements(source.getId(), measurements);
129                 source.setMeasurements(measurements);
130             }
131         });
132 
133         return result;
134     }
135 
136     @Override
137     public PhysicalGearVO../../../../net/sumaris/core/vo/data/PhysicalGearVO.html#PhysicalGearVO">PhysicalGearVO save(PhysicalGearVO source) {
138         Preconditions.checkNotNull(source);
139         Preconditions.checkNotNull(source.getGear(), "Missing gear");
140         Preconditions.checkNotNull(source.getGear().getId(), "Missing gear.id");
141 
142         EntityManager session = getEntityManager();
143         PhysicalGear entity = null;
144         if (source.getId() != null) {
145             entity = get(PhysicalGear.class, source.getId());
146         }
147         boolean isNew = (entity == null);
148         if (isNew) {
149             entity = new PhysicalGear();
150         }
151         else {
152             // Lock entityName
153             // TODO: Use an optimistic lock, as we already lock the parent entity
154             //lockForUpdate(entity, LockModeType.OPTIMISTIC);
155         }
156 
157         // VO -> Entity
158         physicalGearVOToEntity(source, entity, true );
159 
160         // Update update_dt
161         Timestamp newUpdateDate = getDatabaseCurrentTimestamp();
162         entity.setUpdateDate(newUpdateDate);
163 
164         // Save entityName
165         if (isNew) {
166             // Force creation date
167             entity.setCreationDate(newUpdateDate);
168             source.setCreationDate(newUpdateDate);
169 
170             session.persist(entity);
171             source.setId(entity.getId());
172         } else {
173             session.merge(entity);
174         }
175 
176         source.setUpdateDate(newUpdateDate);
177 
178         //session.flush();
179         //session.clear();
180 
181         return source;
182     }
183 
184     @Override
185     public PhysicalGearVO toPhysicalGearVO(PhysicalGear source, boolean withDetails) {
186         if (source == null) return null;
187 
188         PhysicalGearVOGearVO.html#PhysicalGearVO">PhysicalGearVO target = new PhysicalGearVO();
189 
190         Beans.copyProperties(source, target);
191 
192         // Gear
193         ReferentialVO gear = referentialDao.toReferentialVO(source.getGear());
194         target.setGear(gear);
195 
196         if (withDetails) {
197 
198             // Quality flag
199             target.setQualityFlagId(source.getQualityFlag().getId());
200 
201             // Recorder department
202             DepartmentVO recorderDepartment = referentialDao.toTypedVO(source.getRecorderDepartment(), DepartmentVO.class).orElse(null);
203             target.setRecorderDepartment(recorderDepartment);
204 
205         }
206 
207         return target;
208     }
209 
210     @Override
211     public PhysicalGearVO toPhysicalGearVO(PhysicalGear source) {
212         return toPhysicalGearVO(source, true);
213     }
214 
215     /* -- protected methods -- */
216 
217     protected void delete(PhysicalGear entity) {
218         Preconditions.checkNotNull(entity);
219 
220         if (CollectionUtils.isNotEmpty(entity.getMeasurements())) {
221             // TODO: check if deleted
222             log.warn("Check if measurements of physical gear id=" +entity.getId()+ " has been deleted");
223         }
224         getEntityManager().remove(entity);
225     }
226 
227     protected void physicalGearVOToEntity(PhysicalGearVO source, PhysicalGear target, boolean copyIfNull) {
228 
229         // Copy properties
230         copyRootDataProperties(source, target, copyIfNull);
231 
232         // Gear
233         target.setGear(load(Gear.class, source.getGear().getId()));
234 
235         // Trip
236         Integer tripId = source.getTripId() != null ? source.getTripId() : (source.getTrip() != null ? source.getTrip().getId() : null);
237         if (copyIfNull || (tripId != null)) {
238             if (tripId == null) {
239                 target.setTrip(null);
240             }
241             else {
242                 target.setTrip(load(Trip.class, tripId));
243             }
244         }
245     }
246 
247     protected  List<PhysicalGearVO> toPhysicalGearVOs(List<PhysicalGear> source) {
248         return source.stream()
249                 .map(this::toPhysicalGearVO)
250                 .filter(Objects::nonNull)
251                 .collect(Collectors.toList());
252     }
253 
254     void fillDefaultProperties(PhysicalGearVO parent, MeasurementVO measurement) {
255         if (measurement == null) return;
256 
257         // Copy recorder department from the parent
258         if (measurement.getRecorderDepartment() == null || measurement.getRecorderDepartment().getId() == null) {
259             measurement.setRecorderDepartment(parent.getRecorderDepartment());
260         }
261         // Copy recorder person from the parent
262         if (measurement.getRecorderPerson() == null || measurement.getRecorderPerson().getId() == null) {
263             measurement.setRecorderPerson(parent.getRecorderPerson());
264         }
265 
266         measurement.setEntityName(PhysicalGearMeasurement.class.getSimpleName());
267     }
268 }