1 package net.sumaris.core.dao.data;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import com.google.common.base.Preconditions;
26 import lombok.AllArgsConstructor;
27 import lombok.Data;
28 import net.sumaris.core.dao.referential.ReferentialDao;
29 import net.sumaris.core.dao.referential.location.LocationDao;
30 import net.sumaris.core.dao.technical.SortDirection;
31 import net.sumaris.core.model.data.Vessel;
32 import net.sumaris.core.model.data.VesselFeatures;
33 import net.sumaris.core.model.data.VesselRegistrationPeriod;
34 import net.sumaris.core.model.referential.Status;
35 import net.sumaris.core.util.Beans;
36 import net.sumaris.core.vo.administration.user.DepartmentVO;
37 import net.sumaris.core.vo.data.VesselSnapshotVO;
38 import net.sumaris.core.vo.filter.VesselFilterVO;
39 import net.sumaris.core.vo.referential.LocationVO;
40 import net.sumaris.core.vo.referential.ReferentialVO;
41 import org.apache.commons.collections4.CollectionUtils;
42 import org.apache.commons.lang3.StringUtils;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45 import org.springframework.beans.factory.annotation.Autowired;
46 import org.springframework.stereotype.Repository;
47
48 import javax.persistence.TypedQuery;
49 import javax.persistence.criteria.*;
50 import java.util.Collection;
51 import java.util.Date;
52 import java.util.List;
53 import java.util.Objects;
54 import java.util.stream.Collectors;
55
56
57
58
59 @Repository("vesselSnapshotDao")
60 public class VesselSnapshotDaoImpl extends BaseDataDaoImpl implements VesselSnapshotDao {
61
62
63 private static final Logger log = LoggerFactory.getLogger(VesselSnapshotDaoImpl.class);
64
65 @Autowired
66 private LocationDao locationDao;
67
68 @Autowired
69 private ReferentialDao referentialDao;
70
71 @Override
72 public VesselSnapshotVO getByIdAndDate(int vesselId, Date date) {
73 VesselFilterVOFilterVO.html#VesselFilterVO">VesselFilterVO filter = new VesselFilterVO();
74 filter.setVesselId(vesselId);
75 filter.setDate(date);
76 List<VesselSnapshotVO> res = findByFilter(filter, 0, 1, VesselFeatures.Fields.START_DATE, SortDirection.DESC);
77
78
79 if (res.size() == 0) {
80
81 filter.setDate(null);
82 res = findByFilter(filter, 0, 1, VesselFeatures.Fields.START_DATE, SortDirection.DESC);
83 if (res.size() == 0) {
84 VesselSnapshotVOhtml#VesselSnapshotVO">VesselSnapshotVO unknownVessel = new VesselSnapshotVO();
85 unknownVessel.setId(vesselId);
86 unknownVessel.setName("Unknown vessel " + vesselId);
87 return unknownVessel;
88 }
89 }
90 return res.get(0);
91 }
92
93 @Override
94 public List<VesselSnapshotVO> findByFilter(VesselFilterVO filter, int offset, int size, String sortAttribute, SortDirection sortDirection) {
95 Preconditions.checkArgument(offset >= 0);
96 Preconditions.checkArgument(size > 0);
97
98 CriteriaBuilder cb = entityManager.getCriteriaBuilder();
99 CriteriaQuery<VesselSnapshotResult> query = cb.createQuery(VesselSnapshotResult.class);
100 Root<VesselFeatures> root = query.from(VesselFeatures.class);
101
102 Join<VesselFeatures, Vessel> vesselJoin = root.join(VesselFeatures.Fields.VESSEL, JoinType.INNER);
103 Join<Vessel, VesselRegistrationPeriod> vrpJoin = vesselJoin.join(Vessel.Fields.VESSEL_REGISTRATION_PERIODS, JoinType.LEFT);
104
105 query.multiselect(root, vrpJoin);
106
107
108 addSorting(query, cb, root, sortAttribute, sortDirection);
109
110
111 if (filter == null) {
112 TypedQuery<VesselSnapshotResult> q = getEntityManager().createQuery(query)
113 .setFirstResult(offset)
114 .setMaxResults(size);
115 return toVesselSnapshotVOs(q.getResultList());
116 }
117
118 List<Integer> statusIds = CollectionUtils.isEmpty(filter.getStatusIds())
119 ? null
120 : filter.getStatusIds();
121
122
123 ParameterExpression<Date> dateParam = cb.parameter(Date.class);
124 ParameterExpression<Integer> vesselIdParam = cb.parameter(Integer.class);
125 ParameterExpression<Integer> vesselFeaturesIdParam = cb.parameter(Integer.class);
126 ParameterExpression<String> searchNameParam = cb.parameter(String.class);
127 ParameterExpression<String> searchExteriorMarkingParam = cb.parameter(String.class);
128 ParameterExpression<String> searchRegistrationCodeParam = cb.parameter(String.class);
129 ParameterExpression<Boolean> hasStatusIdsParam = cb.parameter(Boolean.class);
130 ParameterExpression<Collection> statusIdsParam = cb.parameter(Collection.class);
131
132 query.where(cb.and(
133
134 cb.or(
135 cb.and(
136
137 cb.isNull(dateParam),
138 cb.isNull(root.get(VesselFeatures.Fields.END_DATE)),
139 cb.isNull(vrpJoin.get(VesselRegistrationPeriod.Fields.END_DATE))
140 ),
141 cb.and(
142 cb.isNotNull(dateParam),
143 cb.and(
144 cb.or(
145 cb.isNull(root.get(VesselFeatures.Fields.END_DATE)),
146 cb.greaterThan(root.get(VesselFeatures.Fields.END_DATE), dateParam)
147 ),
148 cb.lessThan(root.get(VesselFeatures.Fields.START_DATE), dateParam)
149 ),
150 cb.and(
151 cb.or(
152 cb.isNull(vrpJoin.get(VesselRegistrationPeriod.Fields.END_DATE)),
153 cb.greaterThan(vrpJoin.get(VesselRegistrationPeriod.Fields.END_DATE), dateParam)
154 ),
155 cb.lessThan(vrpJoin.get(VesselRegistrationPeriod.Fields.START_DATE), dateParam)
156 )
157 )
158 ),
159
160
161 cb.or(
162 cb.isNull(vesselFeaturesIdParam),
163 cb.equal(root.get(VesselFeatures.Fields.ID), vesselFeaturesIdParam)
164 ),
165
166
167 cb.or(
168 cb.isNull(vesselIdParam),
169 cb.equal(vesselJoin.get(Vessel.Fields.ID), vesselIdParam))
170 ),
171
172
173 cb.or(
174 cb.isNull(searchNameParam),
175 cb.like(cb.lower(root.get(VesselFeatures.Fields.NAME)), cb.lower(searchNameParam)),
176 cb.like(cb.lower(root.get(VesselFeatures.Fields.EXTERIOR_MARKING)), cb.lower(searchExteriorMarkingParam)),
177 cb.like(cb.lower(vrpJoin.get(VesselRegistrationPeriod.Fields.REGISTRATION_CODE)), cb.lower(searchRegistrationCodeParam))
178 ),
179
180
181 cb.or(
182 cb.isFalse(hasStatusIdsParam),
183 cb.in(vesselJoin.get(Vessel.Fields.STATUS).get(Status.Fields.ID)).value(statusIdsParam)
184 )
185 );
186
187
188 String searchText = StringUtils.trimToNull(filter.getSearchText());
189 String searchTextAsPrefix = null;
190 if (StringUtils.isNotBlank(searchText)) {
191 searchTextAsPrefix = (searchText + "*");
192 searchTextAsPrefix = searchTextAsPrefix.replaceAll("[*]+", "*");
193 searchTextAsPrefix = searchTextAsPrefix.replaceAll("[%]", "\\%");
194 searchTextAsPrefix = searchTextAsPrefix.replaceAll("[*]", "%");
195 }
196 String searchTextAnyMatch = StringUtils.isNotBlank(searchTextAsPrefix) ? ("%"+searchTextAsPrefix) : null;
197
198 TypedQuery<VesselSnapshotResult> q = entityManager.createQuery(query)
199 .setParameter(dateParam, filter.getDate())
200 .setParameter(vesselFeaturesIdParam, filter.getVesselFeaturesId())
201 .setParameter(vesselIdParam, filter.getVesselId())
202 .setParameter(searchExteriorMarkingParam, searchTextAsPrefix)
203 .setParameter(searchRegistrationCodeParam, searchTextAsPrefix)
204 .setParameter(searchNameParam, searchTextAnyMatch)
205 .setParameter(hasStatusIdsParam, CollectionUtils.isNotEmpty(statusIds))
206 .setParameter(statusIdsParam, statusIds)
207 .setFirstResult(offset)
208 .setMaxResults(size);
209 List<VesselSnapshotResult> result = q.getResultList();
210 return toVesselSnapshotVOs(result);
211 }
212
213 private List<VesselSnapshotVO> toVesselSnapshotVOs(List<VesselSnapshotResult> source) {
214 return source.stream()
215 .map(this::toVesselSnapshotVO)
216 .filter(Objects::nonNull)
217 .collect(Collectors.toList());
218 }
219
220 private VesselSnapshotVO toVesselSnapshotVO(VesselSnapshotResult source) {
221 if (source == null)
222 return null;
223
224 VesselSnapshotVOshotVO.html#VesselSnapshotVO">VesselSnapshotVO target = new VesselSnapshotVO();
225
226
227 VesselFeatures features = source.getVesselFeatures();
228
229 Beans.copyProperties(features, target);
230
231
232 if (features.getLengthOverAll() != null) {
233 target.setLengthOverAll(features.getLengthOverAll().doubleValue() /100);
234 }
235
236 if (features.getGrossTonnageGrt() != null) {
237 target.setGrossTonnageGrt(features.getGrossTonnageGrt().doubleValue() / 100);
238 }
239 if (features.getGrossTonnageGt() != null) {
240 target.setGrossTonnageGt(features.getGrossTonnageGt().doubleValue() / 100);
241 }
242
243 target.setId(features.getVessel().getId());
244 target.setVesselStatusId(features.getVessel().getStatus().getId());
245 target.setQualityFlagId(features.getQualityFlag().getId());
246
247
248 ReferentialVO vesselType = referentialDao.toReferentialVO(features.getVessel().getVesselType());
249 target.setVesselType(vesselType);
250
251
252 LocationVO basePortLocation = locationDao.toLocationVO(features.getBasePortLocation());
253 target.setBasePortLocation(basePortLocation);
254
255
256 DepartmentVO recorderDepartment = referentialDao.toTypedVO(features.getRecorderDepartment(), DepartmentVO.class).orElse(null);
257 target.setRecorderDepartment(recorderDepartment);
258
259
260 VesselRegistrationPeriod period = source.getVesselRegistrationPeriod();
261 if (period != null) {
262
263
264 target.setRegistrationCode(period.getRegistrationCode());
265
266 LocationVO registrationLocation = locationDao.toLocationVO(period.getRegistrationLocation());
267 target.setRegistrationLocation(registrationLocation);
268 }
269
270 return target;
271
272 }
273
274 @Data
275 @AllArgsConstructor
276 public static class VesselSnapshotResult {
277 VesselFeatures vesselFeatures;
278 VesselRegistrationPeriod vesselRegistrationPeriod;
279 }
280
281 }