1 package net.sumaris.core.service.referential;
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 com.google.common.collect.ImmutableMap;
27 import com.google.common.collect.ImmutableSet;
28 import com.google.common.collect.Lists;
29 import com.google.common.collect.Maps;
30 import com.vividsolutions.jts.geom.MultiPolygon;
31 import net.sumaris.core.dao.referential.ReferentialDao;
32 import net.sumaris.core.dao.referential.ValidityStatusDao;
33 import net.sumaris.core.dao.referential.location.*;
34 import net.sumaris.core.model.referential.ValidityStatus;
35 import net.sumaris.core.model.referential.ValidityStatusEnum;
36 import net.sumaris.core.model.referential.location.*;
37 import net.sumaris.core.util.Beans;
38 import net.sumaris.core.vo.referential.LocationVO;
39 import net.sumaris.core.vo.referential.ReferentialVO;
40 import org.apache.commons.lang3.StringUtils;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.springframework.beans.factory.annotation.Autowired;
44 import org.springframework.core.io.ResourceLoader;
45 import org.springframework.stereotype.Service;
46
47 import java.io.PrintStream;
48 import java.util.*;
49 import java.util.regex.Pattern;
50 import java.util.stream.Collectors;
51
52 @Service("locationService")
53 public class LocationServiceImpl implements LocationService{
54
55 private static final Logger log = LoggerFactory.getLogger(LocationServiceImpl.class);
56
57 @Autowired
58 protected LocationDao locationDao;
59
60 @Autowired
61 protected LocationAreaDao locationAreaDao;
62
63 @Autowired
64 protected ValidityStatusDao validityStatusDao;
65
66 @Autowired
67 protected LocationLevelDao locationLevelDao;
68
69 @Autowired
70 protected LocationClassificationDao locationClassificationDao;
71
72 @Autowired
73 protected ReferentialDao referentialDao;
74
75 @Autowired
76 private ResourceLoader resourceLoader;
77
78 @Override
79 public void insertOrUpdateRectangleLocations() {
80
81 if (log.isInfoEnabled()) {
82 log.info("Checking all statistical rectangles exists...");
83 }
84
85
86 Map<String, LocationLevel> locationLevels = createAndGetLocationLevels(ImmutableMap.<String, String>builder()
87 .put(LocationLevelEnum.RECTANGLE_ICES.getLabel(), "ICES rectangle")
88 .put(LocationLevelEnum.RECTANGLE_CGPM_GFCM.getLabel(), "CGPM/GFCM rectangle")
89 .build());
90
91 LocationLevel icesRectangleLocationLevel = locationLevels.get(LocationLevelEnum.RECTANGLE_ICES.getLabel());
92 Objects.requireNonNull(icesRectangleLocationLevel);
93 LocationLevel cgpmRquareLocationLevel = locationLevels.get(LocationLevelEnum.RECTANGLE_CGPM_GFCM.getLabel());
94 Objects.requireNonNull(cgpmRquareLocationLevel);
95
96 ValidityStatus validStatus = validityStatusDao.getOne(ValidityStatusEnum.VALID.getId());
97
98
99 List<LocationVO> existingLocations = locationLevels.values().stream()
100 .map(level -> locationDao.getByLocationLevel(level.getId()))
101 .flatMap(list -> list.stream())
102 .collect(Collectors.toList());
103
104 Map<String, LocationVO> rectangleByLabelMap = Beans.splitByProperty(existingLocations, Location.Fields.LABEL);
105
106 int locationInsertCount = 0;
107 Date creationDate = new Date();
108
109 Set<String> labels = ImmutableSet.<String>builder()
110
111 .addAll(Locations.getAllIcesRectangleLabels(resourceLoader, false))
112
113 .addAll(Locations.getAllCgpmGfcmRectangleLabels(resourceLoader, false))
114 .build();
115
116 if (labels.size() == existingLocations.size()) {
117 log.info(String.format("No missing rectangle detected (%s found)", existingLocations.size()));
118 return;
119 }
120
121 log.info(String.format("Inserting missing rectangle (%s existing - %s expected)", existingLocations.size(), labels.size()));
122
123 for (String label: labels) {
124
125 if (!rectangleByLabelMap.containsKey(label)) {
126 Locationntial/location/Location.html#Location">Location location = new Location();
127 location.setLabel(label);
128 location.setName(label);
129 location.setCreationDate(creationDate);
130 if (label.startsWith("M")) {
131 location.setLocationLevel(cgpmRquareLocationLevel);
132 }
133 else {
134 location.setLocationLevel(icesRectangleLocationLevel);
135 }
136 location.setValidityStatus(validStatus);
137 locationDao.create(location);
138 locationInsertCount++;
139 }
140 }
141 if (log.isInfoEnabled()) {
142 log.info(String.format("LOCATION: INSERT count: %s", locationInsertCount));
143 }
144 }
145
146 @Override
147 public void insertOrUpdateSquares10() {
148 if (log.isInfoEnabled()) {
149 log.info("Checking all squares 10'x10' exists...");
150 }
151
152
153 Map<String, LocationLevel> locationLevels = createAndGetLocationLevels(ImmutableMap.<String, String>builder()
154 .put(LocationLevelEnum.SQUARE_10.getLabel(), "Square 10'x10'")
155 .build());
156
157 LocationLevel square10LocationLevel = locationLevels.get(LocationLevelEnum.SQUARE_10.getLabel());
158 Objects.requireNonNull(square10LocationLevel);
159
160 ValidityStatus validStatus = validityStatusDao.getOne(ValidityStatusEnum.VALID.getId());
161
162
163 Map<String, LocationVO> rectangleByLabelMap = Beans.splitByProperty(getExistingRectangles(), Location.Fields.LABEL);
164
165
166 List<LocationVO> existingLocations = locationDao.getByLocationLevel(square10LocationLevel.getId());
167 Map<String, LocationVO> locationByLabelMap = Beans.splitByProperty(existingLocations, Location.Fields.LABEL);
168
169 int locationInsertCount = 0;
170 int locationAssociationInsertCount = 0;
171 Date creationDate = new Date();
172
173 Set<String> labels = Locations.getAllSquare10Labels(resourceLoader, false);
174
175 if (labels.size() == existingLocations.size()) {
176 log.info(String.format("No missing square 10'x10' (%s found)", existingLocations.size()));
177 return;
178 }
179
180 log.info(String.format("Inserting missing square 10'x10' (%s existing - %s expected)", existingLocations.size(), labels.size()));
181
182 for (String label: labels) {
183
184 if (!locationByLabelMap.containsKey(label)) {
185 Locationntial/location/Location.html#Location">Location location = new Location();
186 location.setLabel(label);
187 location.setName(label);
188 location.setCreationDate(creationDate);
189 location.setUpdateDate(creationDate);
190 location.setLocationLevel(square10LocationLevel);
191 location.setValidityStatus(validStatus);
192 location = locationDao.create(location);
193 locationByLabelMap.put(label, locationDao.toLocationVO(location));
194 locationInsertCount++;
195 }
196 }
197
198
199 for (String label: labels) {
200 String parentRectangleLabel = Locations.convertSquare10ToRectangle(label);
201
202
203 if (parentRectangleLabel != null) {
204 LocationVO parentLocation = rectangleByLabelMap.get(parentRectangleLabel);
205 LocationVO childLocation = locationByLabelMap.get(label);
206
207
208 if (parentLocation != null && !locationDao.hasAssociation(childLocation.getId(), parentLocation.getId())) {
209 locationDao.addAssociation(childLocation.getId(), parentLocation.getId(), 1d);
210 locationAssociationInsertCount++;
211 }
212 }
213 }
214
215 if (log.isInfoEnabled()) {
216 log.info(String.format("LOCATION: INSERT count: %s", locationInsertCount));
217 log.info(String.format("LOCATION_ASSOCIATION: INSERT count: %s", locationAssociationInsertCount));
218 }
219 }
220
221 public void insertOrUpdateRectangleAndSquareAreas() {
222
223
224 Map<String, LocationLevel> locationLevels = createAndGetLocationLevels(ImmutableMap.<String, String>builder()
225 .put(LocationLevelEnum.RECTANGLE_ICES.getLabel(), "ICES rectangle")
226 .put(LocationLevelEnum.RECTANGLE_CGPM_GFCM.getLabel(), "CGPM/GFCM rectangle")
227 .put(LocationLevelEnum.SQUARE_10.getLabel(), "Square 10' x 10'")
228 .build());
229 LocationLevel icesRectangleLocationLevel = locationLevels.get(LocationLevelEnum.RECTANGLE_ICES.getLabel());
230 Objects.requireNonNull(icesRectangleLocationLevel);
231 LocationLevel cgpmRectangleLocationLevel = locationLevels.get(LocationLevelEnum.RECTANGLE_CGPM_GFCM.getLabel());
232 Objects.requireNonNull(cgpmRectangleLocationLevel);
233 LocationLevel square10LocationLevel = locationLevels.get(LocationLevelEnum.SQUARE_10.getLabel());
234 Preconditions.checkNotNull(square10LocationLevel);
235
236 ValidityStatus notValidStatus = validityStatusDao.getOne(ValidityStatusEnum.INVALID.getId());
237 Pattern rectangleLabelPattern = Pattern.compile("[M]?[0-9]{2,3}[A-Z][0-9]");
238
239 Map<String, LocationVO> rectangleByLabelMap = Maps.newHashMap();
240
241 int locationInsertCount = 0;
242 int locationUpdateCount = 0;
243 int locationAreaInsertCount = 0;
244 int locationAreaUpdateCount = 0;
245
246
247 List<LocationVO> rectangleLocations = getExistingRectangles();
248 List<LocationVO> square10Locations = locationDao.getByLocationLevel(square10LocationLevel.getId());
249
250 while (rectangleLocations.size() > 0) {
251 for (LocationVO location : rectangleLocations) {
252
253 Integer objectId = location.getId();
254 String rectangleLabel = location.getLabel();
255 if (!rectangleLabelPattern.matcher(rectangleLabel).matches()) {
256 log.warn(String.format("Invalid rectangle label {%s.} No geometry will be created for this rectangle.", rectangleLabel));
257 continue;
258 }
259 if (log.isDebugEnabled()) {
260 log.debug(String.format("Updating geometry of rectangle {%s}", rectangleLabel));
261 }
262
263
264 LocationArea locationArea = locationAreaDao.findById(objectId).orElse(null);
265 MultiPolygon geometry = (MultiPolygon) Locations.getGeometryFromRectangleLabel(rectangleLabel, true);
266 Preconditions.checkNotNull(geometry, "No geometry found for rectangle with label:" + rectangleLabel);
267
268 if (locationArea == null) {
269 locationArea = new LocationArea();
270 locationArea.setId(objectId);
271 locationArea.setPosition(geometry);
272 locationAreaDao.save(locationArea);
273 locationAreaInsertCount++;
274 } else if (locationArea.getPosition() == null
275 || !geometry.equals(locationArea.getPosition())) {
276 locationArea.setPosition(geometry);
277 locationAreaDao.save(locationArea);
278 locationAreaUpdateCount++;
279 }
280
281
282 rectangleByLabelMap.put(rectangleLabel, location);
283 }
284
285
286 rectangleLocations = Lists.newArrayList();
287
288
289 for (LocationVO location : square10Locations) {
290
291 Integer objectId = location.getId();
292 String squareLabel = location.getLabel();
293 if (squareLabel == null || squareLabel.length() != 8) {
294 log.warn(String.format("Invalid square label: %s. No geometry will be created for this square.", squareLabel));
295 continue;
296 }
297
298
299 LocationArea locationArea = locationAreaDao.getOne(objectId);
300 MultiPolygon geometry = (MultiPolygon) Locations.getGeometryFromSquare10Label(squareLabel);
301 Preconditions.checkNotNull(geometry, "No geometry found for square with label:" + squareLabel);
302
303 if (locationArea == null) {
304 locationArea = new LocationArea();
305 locationArea.setId(objectId);
306 locationArea.setPosition(geometry);
307 locationAreaDao.save(locationArea);
308 locationAreaInsertCount++;
309 } else if (locationArea.getPosition() == null
310 || !geometry.equals(locationArea.getPosition())) {
311 locationArea.setPosition(geometry);
312 locationAreaDao.save(locationArea);
313 locationAreaUpdateCount++;
314 }
315
316
317 String parentRectangleLabel = Locations.convertSquare10ToRectangle(squareLabel);
318 LocationVO parentLocation = rectangleByLabelMap.get(parentRectangleLabel);
319
320
321 if (parentLocation == null) {
322
323 parentLocation = new LocationVO();
324 parentLocation.setLabel(parentRectangleLabel);
325 parentLocation.setName(parentRectangleLabel);
326 if (parentRectangleLabel.startsWith("M")) {
327 parentLocation.setLevelId(cgpmRectangleLocationLevel.getId());
328 }
329 else {
330 parentLocation.setLevelId(icesRectangleLocationLevel.getId());
331 }
332 parentLocation.setValidityStatusId(notValidStatus.getId());
333 parentLocation = (LocationVO)referentialDao.save(parentLocation);
334
335
336 if (rectangleLocations.contains(parentLocation) == false) {
337 rectangleLocations.add(parentLocation);
338 rectangleByLabelMap.put(parentRectangleLabel, parentLocation);
339 }
340 }
341
342
343 if (parentLocation != null && !locationDao.hasAssociation(location.getId(), parentLocation.getId())) {
344 locationDao.addAssociation(location.getId(), parentLocation.getId(), 1d);
345 locationUpdateCount++;
346 }
347 }
348
349
350 square10Locations = Lists.newArrayList();
351 }
352
353 if (log.isInfoEnabled()) {
354 log.info(String.format("LOCATION: INSERT count: %s", locationInsertCount));
355 log.info(String.format(" UPDATE count: %s", locationUpdateCount));
356 log.info(String.format("LOCATION_AREA: INSERT count: %s", locationAreaInsertCount));
357 log.info(String.format(" UPDATE count: %s", locationAreaUpdateCount));
358 }
359 }
360
361 @Override
362 public void updateLocationHierarchy() {
363 if (log.isInfoEnabled()) {
364 log.info("Updating location hierarchy...");
365 }
366 locationDao.updateLocationHierarchy();
367 }
368
369 @Override
370 public void printLocationPorts(PrintStream out, String indentation) {
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445 }
446
447
448 @Override
449 public String getLocationLabelByLatLong(Number latitude, Number longitude) {
450 if (longitude == null || latitude == null) {
451 throw new IllegalArgumentException("Arguments 'latitude' and 'longitude' should not be null.");
452 }
453
454
455 String rectangleLabel = Locations.getRectangleLabelByLatLong(latitude, longitude);
456 if (StringUtils.isNotBlank(rectangleLabel)) return rectangleLabel;
457
458
459
460
461 return null;
462 }
463
464 @Override
465 public Integer getLocationIdByLatLong(Number latitude, Number longitude) {
466 String locationLabel = getLocationLabelByLatLong(latitude, longitude);
467 if (locationLabel == null) return null;
468 ReferentialVO location = referentialDao.findByUniqueLabel(Location.class.getSimpleName(), locationLabel);
469 return location == null ? null : location.getId();
470 }
471
472 @Override
473 @Deprecated
474 public void updateRectanglesAndSquares() {
475
476 insertOrUpdateRectangleAndSquareAreas();
477 }
478
479
480
481 protected Map<String, LocationLevel> createAndGetLocationLevels(Map<String, String> levels) {
482 Map<String, LocationLevel> result = Maps.newHashMap();
483
484 Date creationDate = new Date();
485 LocationClassification defaultClassification = locationClassificationDao.getByLabel(LocationClassificationEnum.SEA.getLabel());
486
487 for (String label: levels.keySet()) {
488 String name = StringUtils.trimToNull(levels.get(label));
489
490 LocationLevel locationLevel = locationLevelDao.findByLabel(label);
491 if (locationLevel == null) {
492 if (log.isInfoEnabled()) {
493 log.info(String.format("Adding new LocationLevel with label {%s}", label));
494 }
495 locationLevel = new LocationLevel();
496 locationLevel.setLabel(label);
497 locationLevel.setName(name);
498 locationLevel.setCreationDate(creationDate);
499 locationLevel.setLocationClassification(defaultClassification);
500 locationLevel = locationLevelDao.create(locationLevel);
501 }
502 result.put(label, locationLevel);
503 }
504 return result;
505 }
506
507 protected List<LocationVO> getExistingRectangles() {
508
509 Map<String, LocationLevel> locationLevels = createAndGetLocationLevels(ImmutableMap.<String, String>builder()
510 .put(LocationLevelEnum.RECTANGLE_ICES.getLabel(), "ICES rectangle")
511 .put(LocationLevelEnum.RECTANGLE_CGPM_GFCM.getLabel(), "CGPM/GFCM rectangle")
512 .build());
513
514
515 return locationLevels.values()
516 .stream()
517 .map(level -> locationDao.getByLocationLevel(level.getId()))
518 .flatMap(list -> list.stream())
519 .collect(Collectors.toList());
520
521 }
522 }