View Javadoc
1   package net.sumaris.core.service.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  
26  import com.google.common.base.Preconditions;
27  import com.google.common.collect.Lists;
28  import net.sumaris.core.config.SumarisConfiguration;
29  import net.sumaris.core.dao.data.MeasurementDao;
30  import net.sumaris.core.dao.data.OperationDao;
31  import net.sumaris.core.dao.data.VesselPositionDao;
32  import net.sumaris.core.dao.technical.SortDirection;
33  import net.sumaris.core.model.data.GearUseMeasurement;
34  import net.sumaris.core.model.data.IMeasurementEntity;
35  import net.sumaris.core.model.data.VesselUseMeasurement;
36  import net.sumaris.core.util.Beans;
37  import net.sumaris.core.vo.data.*;
38  import net.sumaris.core.vo.referential.ReferentialVO;
39  import org.apache.commons.collections4.CollectionUtils;
40  import org.slf4j.Logger;
41  import org.slf4j.LoggerFactory;
42  import org.springframework.beans.factory.annotation.Autowired;
43  import org.springframework.stereotype.Service;
44  
45  import java.util.Date;
46  import java.util.List;
47  import java.util.Objects;
48  import java.util.stream.Collectors;
49  
50  @Service("operationService")
51  public class OperationServiceImpl implements OperationService {
52  
53  	private static final Logger log = LoggerFactory.getLogger(OperationServiceImpl.class);
54  
55  	@Autowired
56  	protected SumarisConfiguration config;
57  
58  	@Autowired
59  	protected OperationDao operationDao;
60  
61  	@Autowired
62  	protected VesselPositionDao vesselPositionDao;
63  
64  	@Autowired
65  	protected MeasurementDao measurementDao;
66  
67  	@Autowired
68  	protected SampleService sampleService;
69  
70  	@Autowired
71  	protected BatchService batchService;
72  
73  	@Override
74  	public List<OperationVO> getAllByTripId(int tripId, int offset, int size, String sortAttribute,
75                                       SortDirection sortDirection) {
76  		return operationDao.getAllByTripId(tripId, offset, size, sortAttribute, sortDirection);
77  	}
78  
79  	@Override
80  	public List<OperationVO> saveAllByTripId(int tripId, List<OperationVO> operations) {
81  		return operationDao.saveAllByTripId(tripId, operations);
82  	}
83  
84  	@Override
85  	public OperationVO get(int operationId) {
86  		return operationDao.get(operationId);
87  	}
88  
89  	@Override
90  	public OperationVOrationVO.html#OperationVO">OperationVO save(final OperationVO source) {
91  		Preconditions.checkNotNull(source);
92  		Preconditions.checkNotNull(source.getStartDateTime(), "Missing startDateTime");
93  		Preconditions.checkNotNull(source.getEndDateTime(), "Missing endDateTime");
94  		Preconditions.checkNotNull(source.getRecorderDepartment(), "Missing recorderDepartment");
95  		Preconditions.checkNotNull(source.getRecorderDepartment().getId(), "Missing recorderDepartment.id");
96  
97  		// Default properties
98  		if (source.getQualityFlagId() == null) {
99  			source.setQualityFlagId(config.getDefaultQualityFlagId());
100 		}
101 
102 		OperationVO savedOperation = operationDao.save(source);
103 
104 		// Save positions
105 		{
106 			List<VesselPositionVO> positions = Beans.getList(source.getPositions());
107 			positions.forEach(m -> fillDefaultProperties(savedOperation, m));
108 			positions = vesselPositionDao.saveByOperationId(savedOperation.getId(), positions);
109 			savedOperation.setPositions(positions);
110 		}
111 
112 		// Save measurements (vessel use measurement)
113 		{
114 			if (source.getMeasurementValues() != null) {
115 				measurementDao.saveOperationVesselUseMeasurementsMap(savedOperation.getId(), source.getMeasurementValues());
116 			}
117 			else {
118 				List<MeasurementVO> measurements = Beans.getList(source.getMeasurements());
119 				measurements.forEach(m -> fillDefaultProperties(savedOperation, m, VesselUseMeasurement.class));
120 				measurements = measurementDao.saveOperationVesselUseMeasurements(savedOperation.getId(), measurements);
121 				savedOperation.setMeasurements(measurements);
122 			}
123 		}
124 
125 		// Save gear measurements (gear use measurement)
126 		{
127 			if (source.getGearMeasurementValues() != null) {
128 				measurementDao.saveOperationGearUseMeasurementsMap(savedOperation.getId(), source.getGearMeasurementValues());
129 			}
130 			else {
131 				List<MeasurementVO> measurements = Beans.getList(source.getGearMeasurements());
132 				measurements.forEach(m -> fillDefaultProperties(savedOperation, m, GearUseMeasurement.class));
133 				measurements = measurementDao.saveOperationGearUseMeasurements(savedOperation.getId(), measurements);
134 				savedOperation.setGearMeasurements(measurements);
135 			}
136 		}
137 
138 		// Save samples
139 		{
140 			List<SampleVO> samples = getSamplesAsList(savedOperation);
141 			samples.forEach(s -> fillDefaultProperties(savedOperation, s));
142 			samples = sampleService.saveByOperationId(savedOperation.getId(), samples);
143 
144 			// Prepare saved samples (e.g. to be used as graphQL query response)
145 			samples.forEach(sample -> {
146 				// Set parentId (instead of parent object)
147 				if (sample.getParentId() == null && sample.getParent() != null) {
148 					sample.setParentId(sample.getParent().getId());
149 				}
150 				// Remove link parent/children
151 				sample.setParent(null);
152 				sample.setChildren(null);
153 			});
154 			
155 			savedOperation.setSamples(samples);
156 		}
157 
158 		// Save batches
159 		{
160 
161 			List<BatchVO> batches = getAllBatches(savedOperation);
162 			batches.forEach(b -> fillDefaultProperties(savedOperation, b));
163 			batches = batchService.saveByOperationId(savedOperation.getId(), batches);
164 
165 			// Transform saved batches into flat list (e.g. to be used as graphQL query response)
166 			batches.forEach(batch -> {
167 				// Set parentId (instead of parent object)
168 				if (batch.getParentId() == null && batch.getParent() != null) {
169 					batch.setParentId(batch.getParent().getId());
170 				}
171 				// Remove link parent/children
172 				batch.setParent(null);
173 				batch.setChildren(null);
174 			});
175 
176 			savedOperation.setCatchBatch(null);
177 			savedOperation.setBatches(batches);
178 		}
179 
180 		return savedOperation;
181 	}
182 
183 	@Override
184 	public List<OperationVO> save(List<OperationVO> operations) {
185 		Preconditions.checkNotNull(operations);
186 
187 		return operations.stream()
188 				.map(this::save)
189 				.collect(Collectors.toList());
190 	}
191 
192 	@Override
193 	public void delete(int id) {
194 		operationDao.delete(id);
195 	}
196 	@Override
197 	public void delete(List<Integer> ids) {
198 		Preconditions.checkNotNull(ids);
199 		ids.stream()
200 				.filter(Objects::nonNull)
201 				.forEach(this::delete);
202 	}
203 
204 	/* -- protected methods -- */
205 
206 	protected void fillDefaultProperties(OperationVO parent, VesselPositionVO position) {
207 		if (position == null) return;
208 
209 		// Copy recorder department from the parent
210 		if (position.getRecorderDepartment() == null || position.getRecorderDepartment().getId() == null) {
211 			position.setRecorderDepartment(parent.getRecorderDepartment());
212 		}
213 
214 		position.setOperationId(parent.getId());
215 	}
216 
217 	protected void fillDefaultProperties(OperationVO parent, MeasurementVO measurement, Class<? extends IMeasurementEntity> entityClass) {
218 		if (measurement == null) return;
219 
220 		// Copy recorder department from the parent
221 		if (measurement.getRecorderDepartment() == null || measurement.getRecorderDepartment().getId() == null) {
222 			measurement.setRecorderDepartment(parent.getRecorderDepartment());
223 		}
224 
225 		measurement.setEntityName(entityClass.getSimpleName());
226 	}
227 
228 	protected void fillDefaultProperties(OperationVO parent, BatchVO batch) {
229 		if (batch == null) return;
230 
231 		// Copy recorder department from the parent
232 		if (batch.getRecorderDepartment() == null || batch.getRecorderDepartment().getId() == null) {
233 			batch.setRecorderDepartment(parent.getRecorderDepartment());
234 		}
235 
236 		batch.setOperationId(parent.getId());
237 	}
238 
239 	protected void fillDefaultProperties(BatchVO"../../../../../net/sumaris/core/vo/data/BatchVO.html#BatchVO">BatchVO parent, BatchVO batch) {
240 		if (batch == null) return;
241 
242 		// Copy recorder department from the parent
243 		if (batch.getRecorderDepartment() == null || batch.getRecorderDepartment().getId() == null) {
244 			batch.setRecorderDepartment(parent.getRecorderDepartment());
245 		}
246 
247 		if (parent.getId() == null) {
248 			// Need to be the parent object, when parent has not id yet (see issue #2)
249 			batch.setParent(parent);
250 		}
251 		else {
252 			batch.setParentId(parent.getId());
253 		}
254 		batch.setOperationId(parent.getOperationId());
255 	}
256 
257 	protected void fillDefaultProperties(OperationVO parent, SampleVO sample) {
258 		if (sample == null) return;
259 
260 		// Copy recorder department from the parent
261 		if (sample.getRecorderDepartment() == null || sample.getRecorderDepartment().getId() == null) {
262 			sample.setRecorderDepartment(parent.getRecorderDepartment());
263 		}
264 
265 		// Fill matrix
266 		if (sample.getMatrix() == null || sample.getMatrix().getId() == null) {
267 			ReferentialVO matrix = new ReferentialVO();
268 			matrix.setId(config.getMatrixIdIndividual());
269 			sample.setMatrix(matrix);
270 		}
271 
272 		// Fill sample (use operation end date time)
273 		if (sample.getSampleDate() == null) {
274 			Date sampleDate = parent.getEndDateTime() != null ? parent.getEndDateTime() : parent.getFishingEndDateTime();
275 			sample.setSampleDate(sampleDate);
276 		}
277 
278 		sample.setOperationId(parent.getId());
279 	}
280 
281 
282 
283 	protected List<BatchVO> getAllBatches(OperationVO operation) {
284 		BatchVO catchBatch = operation.getCatchBatch();
285 		fillDefaultProperties(operation, catchBatch);
286 		List<BatchVO> result = Lists.newArrayList();
287 		addAllBatchesToList(catchBatch, result);
288 		return result;
289 	}
290 
291 	protected void addAllBatchesToList(final BatchVO batch, final List<BatchVO> result) {
292 		if (batch == null) return;
293 
294 		// Add the batch itself
295 		if (!result.contains(batch)) result.add(batch);
296 
297 		// Process children
298 		if (CollectionUtils.isNotEmpty(batch.getChildren())) {
299 			// Recursive call
300 			batch.getChildren().forEach(child -> {
301 				fillDefaultProperties(batch, child);
302 				addAllBatchesToList(child, result);
303 			});
304 		}
305 	}
306 
307 	/**
308 	 * Get all samples, in the sample tree parent/children
309 	 * @param parent
310 	 * @return
311 	 */
312 	protected List<SampleVO> getSamplesAsList(final OperationVO parent) {
313 		final List<SampleVO> result = Lists.newArrayList();
314 		if (CollectionUtils.isNotEmpty(parent.getSamples())) {
315 			parent.getSamples().forEach(sample -> {
316 				fillDefaultProperties(parent, sample);
317 				sampleService.treeToList(sample, result);
318 			});
319 		}
320 		return result;
321 	}
322 
323 
324 }