1
|
// $Id$
|
2
|
/**
|
3
|
* Copyright (C) 2007 EDIT
|
4
|
* European Distributed Institute of Taxonomy
|
5
|
* http://www.e-taxonomy.eu
|
6
|
*
|
7
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
8
|
* See LICENSE.TXT at the top of this package for the full license terms.
|
9
|
*/
|
10
|
|
11
|
package eu.etaxonomy.cdm.api.service;
|
12
|
|
13
|
import java.io.IOException;
|
14
|
import java.net.URI;
|
15
|
import java.net.URISyntaxException;
|
16
|
import java.util.ArrayList;
|
17
|
import java.util.Arrays;
|
18
|
import java.util.Collection;
|
19
|
import java.util.HashMap;
|
20
|
import java.util.HashSet;
|
21
|
import java.util.List;
|
22
|
import java.util.Map;
|
23
|
import java.util.Map.Entry;
|
24
|
import java.util.Set;
|
25
|
import java.util.UUID;
|
26
|
|
27
|
import org.apache.log4j.Logger;
|
28
|
import org.apache.lucene.index.CorruptIndexException;
|
29
|
import org.apache.lucene.queryParser.ParseException;
|
30
|
import org.apache.lucene.search.BooleanClause.Occur;
|
31
|
import org.apache.lucene.search.BooleanQuery;
|
32
|
import org.apache.lucene.search.SortField;
|
33
|
import org.hibernate.TransientObjectException;
|
34
|
import org.hibernate.search.spatial.impl.Rectangle;
|
35
|
import org.joda.time.Partial;
|
36
|
import org.springframework.beans.factory.annotation.Autowired;
|
37
|
import org.springframework.stereotype.Service;
|
38
|
import org.springframework.transaction.annotation.Transactional;
|
39
|
|
40
|
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
|
41
|
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeConfigurator;
|
42
|
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacadeNotSupportedException;
|
43
|
import eu.etaxonomy.cdm.api.service.DeleteResult.DeleteStatus;
|
44
|
import eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase;
|
45
|
import eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator;
|
46
|
import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO;
|
47
|
import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO.ContigFile;
|
48
|
import eu.etaxonomy.cdm.api.service.dto.DerivateHierarchyDTO.MolecularData;
|
49
|
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
|
50
|
import eu.etaxonomy.cdm.api.service.molecular.ISequenceService;
|
51
|
import eu.etaxonomy.cdm.api.service.pager.Pager;
|
52
|
import eu.etaxonomy.cdm.api.service.pager.impl.DefaultPagerImpl;
|
53
|
import eu.etaxonomy.cdm.api.service.search.ILuceneIndexToolProvider;
|
54
|
import eu.etaxonomy.cdm.api.service.search.ISearchResultBuilder;
|
55
|
import eu.etaxonomy.cdm.api.service.search.LuceneSearch;
|
56
|
import eu.etaxonomy.cdm.api.service.search.LuceneSearch.TopGroupsWithMaxScore;
|
57
|
import eu.etaxonomy.cdm.api.service.search.QueryFactory;
|
58
|
import eu.etaxonomy.cdm.api.service.search.SearchResult;
|
59
|
import eu.etaxonomy.cdm.api.service.search.SearchResultBuilder;
|
60
|
import eu.etaxonomy.cdm.api.service.util.TaxonRelationshipEdge;
|
61
|
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
|
62
|
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
|
63
|
import eu.etaxonomy.cdm.model.CdmBaseType;
|
64
|
import eu.etaxonomy.cdm.model.agent.AgentBase;
|
65
|
import eu.etaxonomy.cdm.model.common.CdmBase;
|
66
|
import eu.etaxonomy.cdm.model.common.DefinedTerm;
|
67
|
import eu.etaxonomy.cdm.model.common.DefinedTermBase;
|
68
|
import eu.etaxonomy.cdm.model.common.ICdmBase;
|
69
|
import eu.etaxonomy.cdm.model.common.Language;
|
70
|
import eu.etaxonomy.cdm.model.common.UuidAndTitleCache;
|
71
|
import eu.etaxonomy.cdm.model.description.DescriptionBase;
|
72
|
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
|
73
|
import eu.etaxonomy.cdm.model.description.IndividualsAssociation;
|
74
|
import eu.etaxonomy.cdm.model.description.SpecimenDescription;
|
75
|
import eu.etaxonomy.cdm.model.description.TaxonDescription;
|
76
|
import eu.etaxonomy.cdm.model.location.Country;
|
77
|
import eu.etaxonomy.cdm.model.location.NamedArea;
|
78
|
import eu.etaxonomy.cdm.model.media.Media;
|
79
|
import eu.etaxonomy.cdm.model.media.MediaRepresentation;
|
80
|
import eu.etaxonomy.cdm.model.media.MediaRepresentationPart;
|
81
|
import eu.etaxonomy.cdm.model.media.MediaUtils;
|
82
|
import eu.etaxonomy.cdm.model.molecular.AmplificationResult;
|
83
|
import eu.etaxonomy.cdm.model.molecular.DnaSample;
|
84
|
import eu.etaxonomy.cdm.model.molecular.Sequence;
|
85
|
import eu.etaxonomy.cdm.model.molecular.SingleRead;
|
86
|
import eu.etaxonomy.cdm.model.name.SpecimenTypeDesignation;
|
87
|
import eu.etaxonomy.cdm.model.name.TaxonNameBase;
|
88
|
import eu.etaxonomy.cdm.model.name.TypeDesignationStatusBase;
|
89
|
import eu.etaxonomy.cdm.model.occurrence.DerivationEvent;
|
90
|
import eu.etaxonomy.cdm.model.occurrence.DerivedUnit;
|
91
|
import eu.etaxonomy.cdm.model.occurrence.DeterminationEvent;
|
92
|
import eu.etaxonomy.cdm.model.occurrence.FieldUnit;
|
93
|
import eu.etaxonomy.cdm.model.occurrence.GatheringEvent;
|
94
|
import eu.etaxonomy.cdm.model.occurrence.MediaSpecimen;
|
95
|
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
|
96
|
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
|
97
|
import eu.etaxonomy.cdm.model.taxon.Taxon;
|
98
|
import eu.etaxonomy.cdm.model.taxon.TaxonBase;
|
99
|
import eu.etaxonomy.cdm.persistence.dao.common.ICdmGenericDao;
|
100
|
import eu.etaxonomy.cdm.persistence.dao.common.IDefinedTermDao;
|
101
|
import eu.etaxonomy.cdm.persistence.dao.initializer.AbstractBeanInitializer;
|
102
|
import eu.etaxonomy.cdm.persistence.dao.occurrence.IOccurrenceDao;
|
103
|
import eu.etaxonomy.cdm.persistence.query.OrderHint;
|
104
|
import eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy;
|
105
|
|
106
|
/**
|
107
|
* @author a.babadshanjan
|
108
|
* @created 01.09.2008
|
109
|
*/
|
110
|
@Service
|
111
|
@Transactional(readOnly = true)
|
112
|
public class OccurrenceServiceImpl extends IdentifiableServiceBase<SpecimenOrObservationBase,IOccurrenceDao> implements IOccurrenceService {
|
113
|
|
114
|
static private final Logger logger = Logger.getLogger(OccurrenceServiceImpl.class);
|
115
|
|
116
|
@Autowired
|
117
|
private IDefinedTermDao definedTermDao;
|
118
|
|
119
|
@Autowired
|
120
|
private IDescriptionService descriptionService;
|
121
|
|
122
|
@Autowired
|
123
|
private ITaxonService taxonService;
|
124
|
|
125
|
@Autowired
|
126
|
private ITermService termService;
|
127
|
|
128
|
@Autowired
|
129
|
private INameService nameService;
|
130
|
|
131
|
@Autowired
|
132
|
private ISequenceService sequenceService;
|
133
|
|
134
|
@Autowired
|
135
|
private AbstractBeanInitializer beanInitializer;
|
136
|
|
137
|
@Autowired
|
138
|
private ILuceneIndexToolProvider luceneIndexToolProvider;
|
139
|
|
140
|
@Autowired
|
141
|
private ICdmGenericDao genericDao;
|
142
|
|
143
|
|
144
|
public OccurrenceServiceImpl() {
|
145
|
logger.debug("Load OccurrenceService Bean");
|
146
|
}
|
147
|
|
148
|
|
149
|
/* (non-Javadoc)
|
150
|
* @see eu.etaxonomy.cdm.api.service.IIdentifiableEntityService#updateTitleCache(java.lang.Integer, eu.etaxonomy.cdm.strategy.cache.common.IIdentifiableEntityCacheStrategy)
|
151
|
*/
|
152
|
@Override
|
153
|
@Transactional(readOnly = false)
|
154
|
public void updateTitleCache(Class<? extends SpecimenOrObservationBase> clazz, Integer stepSize, IIdentifiableEntityCacheStrategy<SpecimenOrObservationBase> cacheStrategy, IProgressMonitor monitor) {
|
155
|
if (clazz == null){
|
156
|
clazz = SpecimenOrObservationBase.class;
|
157
|
}
|
158
|
super.updateTitleCacheImpl(clazz, stepSize, cacheStrategy, monitor);
|
159
|
}
|
160
|
|
161
|
|
162
|
/**
|
163
|
* FIXME Candidate for harmonization
|
164
|
* move to termService
|
165
|
*/
|
166
|
@Override
|
167
|
public Country getCountryByIso(String iso639) {
|
168
|
return this.definedTermDao.getCountryByIso(iso639);
|
169
|
|
170
|
}
|
171
|
|
172
|
/**
|
173
|
* FIXME Candidate for harmonization
|
174
|
* move to termService
|
175
|
*/
|
176
|
@Override
|
177
|
public List<Country> getCountryByName(String name) {
|
178
|
List<? extends DefinedTermBase> terms = this.definedTermDao.findByTitle(Country.class, name, null, null, null, null, null, null) ;
|
179
|
List<Country> countries = new ArrayList<Country>();
|
180
|
for (int i=0;i<terms.size();i++){
|
181
|
countries.add((Country)terms.get(i));
|
182
|
}
|
183
|
return countries;
|
184
|
}
|
185
|
|
186
|
@Override
|
187
|
@Autowired
|
188
|
protected void setDao(IOccurrenceDao dao) {
|
189
|
this.dao = dao;
|
190
|
}
|
191
|
|
192
|
@Override
|
193
|
public Pager<DerivationEvent> getDerivationEvents(SpecimenOrObservationBase occurence, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
|
194
|
Integer numberOfResults = dao.countDerivationEvents(occurence);
|
195
|
|
196
|
List<DerivationEvent> results = new ArrayList<DerivationEvent>();
|
197
|
if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
|
198
|
results = dao.getDerivationEvents(occurence, pageSize, pageNumber,propertyPaths);
|
199
|
}
|
200
|
|
201
|
return new DefaultPagerImpl<DerivationEvent>(pageNumber, numberOfResults, pageSize, results);
|
202
|
}
|
203
|
|
204
|
/* (non-Javadoc)
|
205
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#countDeterminations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.taxon.TaxonBase)
|
206
|
*/
|
207
|
@Override
|
208
|
public int countDeterminations(SpecimenOrObservationBase occurence, TaxonBase taxonbase) {
|
209
|
return dao.countDeterminations(occurence, taxonbase);
|
210
|
}
|
211
|
|
212
|
@Override
|
213
|
public Pager<DeterminationEvent> getDeterminations(SpecimenOrObservationBase occurrence, TaxonBase taxonBase, Integer pageSize,Integer pageNumber, List<String> propertyPaths) {
|
214
|
Integer numberOfResults = dao.countDeterminations(occurrence, taxonBase);
|
215
|
|
216
|
List<DeterminationEvent> results = new ArrayList<DeterminationEvent>();
|
217
|
if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
|
218
|
results = dao.getDeterminations(occurrence,taxonBase, pageSize, pageNumber, propertyPaths);
|
219
|
}
|
220
|
|
221
|
return new DefaultPagerImpl<DeterminationEvent>(pageNumber, numberOfResults, pageSize, results);
|
222
|
}
|
223
|
|
224
|
@Override
|
225
|
public Pager<Media> getMedia(SpecimenOrObservationBase occurence,Integer pageSize, Integer pageNumber, List<String> propertyPaths) {
|
226
|
Integer numberOfResults = dao.countMedia(occurence);
|
227
|
|
228
|
List<Media> results = new ArrayList<Media>();
|
229
|
if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
|
230
|
results = dao.getMedia(occurence, pageSize, pageNumber, propertyPaths);
|
231
|
}
|
232
|
|
233
|
return new DefaultPagerImpl<Media>(pageNumber, numberOfResults, pageSize, results);
|
234
|
}
|
235
|
|
236
|
/* (non-Javadoc)
|
237
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#list(java.lang.Class, eu.etaxonomy.cdm.model.taxon.TaxonBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
|
238
|
*/
|
239
|
@Override
|
240
|
public Pager<SpecimenOrObservationBase> list(Class<? extends SpecimenOrObservationBase> type, TaxonBase determinedAs, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
|
241
|
Integer numberOfResults = dao.count(type,determinedAs);
|
242
|
List<SpecimenOrObservationBase> results = new ArrayList<SpecimenOrObservationBase>();
|
243
|
pageNumber = pageNumber == null ? 0 : pageNumber;
|
244
|
if(numberOfResults > 0) { // no point checking again //TODO use AbstractPagerImpl.hasResultsInRange(numberOfResults, pageNumber, pageSize)
|
245
|
Integer start = pageSize == null ? 0 : pageSize * pageNumber;
|
246
|
results = dao.list(type,determinedAs, pageSize, start, orderHints,propertyPaths);
|
247
|
}
|
248
|
return new DefaultPagerImpl<SpecimenOrObservationBase>(pageNumber, numberOfResults, pageSize, results);
|
249
|
}
|
250
|
|
251
|
@Override
|
252
|
public List<UuidAndTitleCache<DerivedUnit>> getDerivedUnitUuidAndTitleCache() {
|
253
|
return dao.getDerivedUnitUuidAndTitleCache();
|
254
|
}
|
255
|
|
256
|
@Override
|
257
|
public List<UuidAndTitleCache<FieldUnit>> getFieldUnitUuidAndTitleCache() {
|
258
|
return dao.getFieldUnitUuidAndTitleCache();
|
259
|
}
|
260
|
|
261
|
/* (non-Javadoc)
|
262
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getDerivedUnitFacade(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
|
263
|
*/
|
264
|
@Override
|
265
|
public DerivedUnitFacade getDerivedUnitFacade(DerivedUnit derivedUnit, List<String> propertyPaths) throws DerivedUnitFacadeNotSupportedException {
|
266
|
derivedUnit = (DerivedUnit)dao.load(derivedUnit.getUuid(), null);
|
267
|
DerivedUnitFacadeConfigurator config = DerivedUnitFacadeConfigurator.NewInstance();
|
268
|
config.setThrowExceptionForNonSpecimenPreservationMethodRequest(false);
|
269
|
DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(derivedUnit, config);
|
270
|
beanInitializer.initialize(derivedUnitFacade, propertyPaths);
|
271
|
return derivedUnitFacade;
|
272
|
}
|
273
|
|
274
|
/* (non-Javadoc)
|
275
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDerivedUnitFacades(eu.etaxonomy.cdm.model.description.DescriptionBase, java.util.List)
|
276
|
*/
|
277
|
@Override
|
278
|
public List<DerivedUnitFacade> listDerivedUnitFacades(
|
279
|
DescriptionBase description, List<String> propertyPaths) {
|
280
|
|
281
|
List<DerivedUnitFacade> derivedUnitFacadeList = new ArrayList<DerivedUnitFacade>();
|
282
|
IndividualsAssociation tempIndividualsAssociation;
|
283
|
SpecimenOrObservationBase tempSpecimenOrObservationBase;
|
284
|
List<DescriptionElementBase> elements = descriptionService.listDescriptionElements(description, null, IndividualsAssociation.class, null, 0, Arrays.asList(new String []{"associatedSpecimenOrObservation"}));
|
285
|
for(DescriptionElementBase element : elements){
|
286
|
if(element instanceof IndividualsAssociation){
|
287
|
tempIndividualsAssociation = (IndividualsAssociation)element;
|
288
|
if(tempIndividualsAssociation.getAssociatedSpecimenOrObservation() != null){
|
289
|
tempSpecimenOrObservationBase = HibernateProxyHelper.deproxy(tempIndividualsAssociation.getAssociatedSpecimenOrObservation(), SpecimenOrObservationBase.class);
|
290
|
if(tempSpecimenOrObservationBase instanceof DerivedUnit){
|
291
|
try {
|
292
|
derivedUnitFacadeList.add(DerivedUnitFacade.NewInstance((DerivedUnit)tempSpecimenOrObservationBase));
|
293
|
} catch (DerivedUnitFacadeNotSupportedException e) {
|
294
|
logger.warn(tempIndividualsAssociation.getAssociatedSpecimenOrObservation().getTitleCache() + " : " +e.getMessage());
|
295
|
}
|
296
|
}
|
297
|
}
|
298
|
|
299
|
}
|
300
|
}
|
301
|
|
302
|
beanInitializer.initializeAll(derivedUnitFacadeList, propertyPaths);
|
303
|
|
304
|
return derivedUnitFacadeList;
|
305
|
}
|
306
|
|
307
|
|
308
|
/* (non-Javadoc)
|
309
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listByAnyAssociation(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
|
310
|
*/
|
311
|
@Override
|
312
|
public <T extends SpecimenOrObservationBase> List<T> listByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
|
313
|
Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
|
314
|
|
315
|
return pageByAssociatedTaxon(type, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
|
316
|
}
|
317
|
|
318
|
/* (non-Javadoc)
|
319
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listByAnyAssociation(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
|
320
|
*/
|
321
|
@Override
|
322
|
public Collection<FieldUnit> listFieldUnitsByAssociatedTaxon(Set<TaxonRelationshipEdge> includeRelationships,
|
323
|
Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
|
324
|
|
325
|
if(!getSession().contains(associatedTaxon)){
|
326
|
associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
|
327
|
}
|
328
|
|
329
|
Set<FieldUnit> fieldUnits = new HashSet<FieldUnit>();
|
330
|
|
331
|
List<SpecimenOrObservationBase> records = pageByAssociatedTaxon(null, includeRelationships, associatedTaxon, maxDepth, pageSize, pageNumber, orderHints, propertyPaths).getRecords();
|
332
|
for(SpecimenOrObservationBase<?> specimen:records){
|
333
|
fieldUnits.addAll(getFieldUnits(specimen.getUuid()));
|
334
|
}
|
335
|
return fieldUnits;
|
336
|
}
|
337
|
|
338
|
@Override
|
339
|
public DerivateHierarchyDTO assembleDerivateHierarchyDTO(FieldUnit fieldUnit, UUID associatedTaxonUuid){
|
340
|
|
341
|
if(!getSession().contains(fieldUnit)){
|
342
|
fieldUnit = (FieldUnit) load(fieldUnit.getUuid());
|
343
|
}
|
344
|
TaxonBase associatedTaxon = taxonService.load(associatedTaxonUuid);
|
345
|
|
346
|
DerivateHierarchyDTO dto = new DerivateHierarchyDTO();
|
347
|
Map<UUID, TypeDesignationStatusBase> typeSpecimenUUIDtoTypeDesignationStatus = new HashMap<UUID, TypeDesignationStatusBase>();
|
348
|
|
349
|
//gather types for this taxon name
|
350
|
TaxonNameBase<?,?> name = associatedTaxon.getName();
|
351
|
Set<?> typeDesignations = name.getSpecimenTypeDesignations();
|
352
|
for (Object object : typeDesignations) {
|
353
|
if(object instanceof SpecimenTypeDesignation){
|
354
|
SpecimenTypeDesignation specimenTypeDesignation = (SpecimenTypeDesignation)object;
|
355
|
DerivedUnit typeSpecimen = specimenTypeDesignation.getTypeSpecimen();
|
356
|
final TypeDesignationStatusBase typeStatus = specimenTypeDesignation.getTypeStatus();
|
357
|
typeSpecimenUUIDtoTypeDesignationStatus.put(typeSpecimen.getUuid(), typeStatus);
|
358
|
}
|
359
|
}
|
360
|
|
361
|
if(fieldUnit.getGatheringEvent()!=null){
|
362
|
GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
|
363
|
//Country
|
364
|
final NamedArea country = gatheringEvent.getCountry();
|
365
|
dto.setCountry(country!=null?country.getDescription():"");
|
366
|
//Collection
|
367
|
final AgentBase collector = gatheringEvent.getCollector();
|
368
|
final String fieldNumber = fieldUnit.getFieldNumber();
|
369
|
dto.setCollection(((collector!=null?collector:"") + " " + (fieldNumber!=null?fieldNumber:"")).trim());
|
370
|
//Date
|
371
|
final Partial gatheringDate = gatheringEvent.getGatheringDate();
|
372
|
dto.setDate(gatheringDate!=null?gatheringDate.toString():"");
|
373
|
}
|
374
|
|
375
|
//Taxon Name
|
376
|
dto.setTaxonName(associatedTaxon.getName().getFullTitleCache());
|
377
|
|
378
|
|
379
|
Collection<DerivedUnit> derivedUnits = new ArrayList<DerivedUnit>();
|
380
|
getDerivedUnitsFor(fieldUnit, derivedUnits);
|
381
|
|
382
|
//Herbaria map
|
383
|
Map<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> collectionToCountMap = new HashMap<eu.etaxonomy.cdm.model.occurrence.Collection, Integer>();
|
384
|
//List of accession numbers for citation
|
385
|
List<String> preservedSpecimenAccessionNumbers = new ArrayList<String>();
|
386
|
|
387
|
//iterate over sub derivates
|
388
|
for (DerivedUnit derivedUnit : derivedUnits) {
|
389
|
//current accession number
|
390
|
String currentAccessionNumber = derivedUnit.getAccessionNumber()!=null?derivedUnit.getAccessionNumber():"";
|
391
|
//current herbarium
|
392
|
String currentHerbarium = "";
|
393
|
eu.etaxonomy.cdm.model.occurrence.Collection collection = derivedUnit.getCollection();
|
394
|
if(collection!=null){
|
395
|
currentHerbarium = collection.getCode()!=null?collection.getCode():"";
|
396
|
//count herbaria
|
397
|
Integer count = collectionToCountMap.get(collection);
|
398
|
if(count==null){
|
399
|
count = 1;
|
400
|
}
|
401
|
else{
|
402
|
count++;
|
403
|
}
|
404
|
collectionToCountMap.put(collection, count);
|
405
|
}
|
406
|
//check if derived unit is a type
|
407
|
if(typeSpecimenUUIDtoTypeDesignationStatus.keySet().contains(derivedUnit.getUuid())){
|
408
|
dto.setHasType(true);
|
409
|
TypeDesignationStatusBase typeDesignationStatus = typeSpecimenUUIDtoTypeDesignationStatus.get(derivedUnit.getUuid());
|
410
|
String typeStatus = typeDesignationStatus.getLabel();
|
411
|
dto.addTypes(typeStatus, currentAccessionNumber);
|
412
|
}
|
413
|
//assemble molecular data
|
414
|
//pattern: DNAMarker [contig1, primer1_1, primer1_2, ...][contig2, primer2_1, ...]...
|
415
|
if(derivedUnit instanceof DnaSample){
|
416
|
if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.TissueSample){
|
417
|
//TODO implement TissueSample assembly for web service
|
418
|
}
|
419
|
if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.DnaSample){
|
420
|
|
421
|
DnaSample dna = (DnaSample)derivedUnit;
|
422
|
if(!dna.getSequences().isEmpty()){
|
423
|
dto.setHasDna(true);
|
424
|
}
|
425
|
for(Sequence sequence:dna.getSequences()){
|
426
|
URI boldUri = null;
|
427
|
try {
|
428
|
boldUri = sequence.getBoldUri();
|
429
|
} catch (URISyntaxException e1) {
|
430
|
logger.error("Could not create BOLD URI", e1);
|
431
|
}
|
432
|
final DefinedTerm dnaMarker = sequence.getDnaMarker();
|
433
|
MolecularData molecularData = dto.addProviderLink(boldUri!=null?boldUri:null,dnaMarker!=null?dnaMarker.getLabel():"[no marker]");
|
434
|
|
435
|
//contig file FIXME show primer although contig not present?
|
436
|
if(sequence.getContigFile()!=null){
|
437
|
MediaRepresentationPart contigMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(sequence.getContigFile());
|
438
|
if(contigMediaRepresentationPart!=null){
|
439
|
ContigFile contigFile = molecularData.addContigFile(contigMediaRepresentationPart.getUri(), "contig");
|
440
|
//primer files
|
441
|
if(sequence.getSingleReads()!=null){
|
442
|
for (SingleRead singleRead : sequence.getSingleReads()) {
|
443
|
MediaRepresentationPart pherogramMediaRepresentationPart = MediaUtils.getFirstMediaRepresentationPart(singleRead.getPherogram());
|
444
|
if(pherogramMediaRepresentationPart!=null){
|
445
|
contigFile.addPrimerLink(pherogramMediaRepresentationPart.getUri(), "primer");
|
446
|
}
|
447
|
}
|
448
|
}
|
449
|
}
|
450
|
}
|
451
|
}
|
452
|
}
|
453
|
}
|
454
|
//assemble media data
|
455
|
else if(derivedUnit instanceof MediaSpecimen){
|
456
|
|
457
|
MediaSpecimen media = (MediaSpecimen)derivedUnit;
|
458
|
String mediaUriString = getMediaUriString(media);
|
459
|
if(media.getKindOfUnit()!=null){
|
460
|
//specimen scan
|
461
|
if(media.getKindOfUnit().getUuid().equals(UUID.fromString("acda15be-c0e2-4ea8-8783-b9b0c4ad7f03"))){
|
462
|
dto.setHasSpecimenScan(true);
|
463
|
final String imageLinkText = currentHerbarium+" "+currentAccessionNumber;
|
464
|
dto.addSpecimenScan(mediaUriString==null?"":mediaUriString, !imageLinkText.equals(" ")?imageLinkText:"[no accession]");
|
465
|
}
|
466
|
//detail image
|
467
|
else if(media.getKindOfUnit().getUuid().equals(UUID.fromString("31eb8d02-bf5d-437c-bcc6-87a626445f34"))){
|
468
|
dto.setHasDetailImage(true);
|
469
|
String motif = "";
|
470
|
if(media.getMediaSpecimen()!=null && media.getMediaSpecimen().getTitle()!=null){
|
471
|
motif = media.getMediaSpecimen().getTitle().getText();
|
472
|
}
|
473
|
dto.addDetailImage(mediaUriString==null?"":mediaUriString, motif!=null?motif:"[no motif]");
|
474
|
}
|
475
|
}
|
476
|
}
|
477
|
//assemble preserved specimen data
|
478
|
else if(derivedUnit.getRecordBasis()==SpecimenOrObservationType.PreservedSpecimen){
|
479
|
if(!currentAccessionNumber.isEmpty()){
|
480
|
preservedSpecimenAccessionNumbers.add(currentAccessionNumber);
|
481
|
}
|
482
|
}
|
483
|
}
|
484
|
|
485
|
final String separator = ", ";
|
486
|
//assemble citation
|
487
|
String citation = "";
|
488
|
citation += !dto.getCountry().isEmpty()?dto.getCountry()+separator:"";
|
489
|
if(fieldUnit.getGatheringEvent()!=null){
|
490
|
if(fieldUnit.getGatheringEvent().getLocality()!=null){
|
491
|
citation += fieldUnit.getGatheringEvent().getLocality().getText();
|
492
|
citation += separator;
|
493
|
}
|
494
|
if(fieldUnit.getGatheringEvent().getExactLocation()!=null
|
495
|
&& fieldUnit.getGatheringEvent().getExactLocation().getLatitude()!=null
|
496
|
&& fieldUnit.getGatheringEvent().getExactLocation().getLongitude()!=null){
|
497
|
citation += fieldUnit.getGatheringEvent().getExactLocation().getLatitude().toString();
|
498
|
citation += separator;
|
499
|
citation += fieldUnit.getGatheringEvent().getExactLocation().getLongitude().toString();
|
500
|
citation += separator;
|
501
|
}
|
502
|
}
|
503
|
citation += !dto.getCollection().isEmpty()?dto.getCollection():"";
|
504
|
if(!preservedSpecimenAccessionNumbers.isEmpty()){
|
505
|
citation += " (";
|
506
|
for(String accessionNumber:preservedSpecimenAccessionNumbers){
|
507
|
if(!accessionNumber.isEmpty()){
|
508
|
citation += accessionNumber+separator;
|
509
|
}
|
510
|
}
|
511
|
citation = removeTail(citation, separator);
|
512
|
citation += ")";
|
513
|
}
|
514
|
citation = removeTail(citation, separator);
|
515
|
dto.setCitation(citation);
|
516
|
|
517
|
//assemble herbaria string
|
518
|
String herbariaString = "";
|
519
|
for(Entry<eu.etaxonomy.cdm.model.occurrence.Collection, Integer> e:collectionToCountMap.entrySet()){
|
520
|
eu.etaxonomy.cdm.model.occurrence.Collection collection = e.getKey();
|
521
|
if(collection.getCode()!=null){
|
522
|
herbariaString += collection.getCode();
|
523
|
}
|
524
|
if(e.getValue()>1){
|
525
|
herbariaString += "("+e.getValue()+")";
|
526
|
}
|
527
|
herbariaString += separator;
|
528
|
}
|
529
|
herbariaString = removeTail(herbariaString, separator);
|
530
|
dto.setHerbarium(herbariaString);
|
531
|
|
532
|
return dto;
|
533
|
}
|
534
|
|
535
|
|
536
|
/**
|
537
|
* @param string
|
538
|
* @param tail
|
539
|
* @return
|
540
|
*/
|
541
|
private String removeTail(String string, final String tail) {
|
542
|
if(string.endsWith(tail)){
|
543
|
string = string.substring(0, string.length()-tail.length());
|
544
|
}
|
545
|
return string;
|
546
|
}
|
547
|
|
548
|
private String getMediaUriString(MediaSpecimen mediaSpecimen){
|
549
|
String mediaUri = null;
|
550
|
Collection<MediaRepresentation> mediaRepresentations = mediaSpecimen.getMediaSpecimen().getRepresentations();
|
551
|
if(mediaRepresentations!=null && !mediaRepresentations.isEmpty()){
|
552
|
Collection<MediaRepresentationPart> mediaRepresentationParts = mediaRepresentations.iterator().next().getParts();
|
553
|
if(mediaRepresentationParts!=null && !mediaRepresentationParts.isEmpty()){
|
554
|
MediaRepresentationPart part = mediaRepresentationParts.iterator().next();
|
555
|
if(part.getUri()!=null){
|
556
|
mediaUri = part.getUri().toASCIIString();
|
557
|
}
|
558
|
}
|
559
|
}
|
560
|
return mediaUri;
|
561
|
}
|
562
|
|
563
|
private void getDerivedUnitsFor(SpecimenOrObservationBase<?> specimen, Collection<DerivedUnit> derivedUnits){
|
564
|
for(DerivationEvent derivationEvent:specimen.getDerivationEvents()){
|
565
|
for(DerivedUnit derivative:derivationEvent.getDerivatives()){
|
566
|
derivedUnits.add(derivative);
|
567
|
getDerivedUnitsFor(derivative, derivedUnits);
|
568
|
}
|
569
|
}
|
570
|
}
|
571
|
|
572
|
|
573
|
/* (non-Javadoc)
|
574
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#pageByAssociatedTaxon(java.lang.Class, java.util.Set, eu.etaxonomy.cdm.model.taxon.Taxon, java.lang.Integer, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
|
575
|
*/
|
576
|
@SuppressWarnings("unchecked")
|
577
|
@Override
|
578
|
public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
|
579
|
Taxon associatedTaxon, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
|
580
|
|
581
|
Set<Taxon> taxa = new HashSet<Taxon>();
|
582
|
Set<Integer> occurrenceIds = new HashSet<Integer>();
|
583
|
List<T> occurrences = new ArrayList<T>();
|
584
|
|
585
|
// Integer limit = PagerUtils.limitFor(pageSize);
|
586
|
// Integer start = PagerUtils.startFor(pageSize, pageNumber);
|
587
|
|
588
|
if(!getSession().contains(associatedTaxon)){
|
589
|
associatedTaxon = (Taxon) taxonService.load(associatedTaxon.getUuid());
|
590
|
}
|
591
|
|
592
|
if(includeRelationships != null) {
|
593
|
taxa = taxonService.listRelatedTaxa(associatedTaxon, includeRelationships, maxDepth, null, null, propertyPaths);
|
594
|
}
|
595
|
|
596
|
taxa.add(associatedTaxon);
|
597
|
|
598
|
for (Taxon taxon : taxa) {
|
599
|
List<T> perTaxonOccurrences = dao.listByAssociatedTaxon(type, taxon, null, null, orderHints, propertyPaths);
|
600
|
for (SpecimenOrObservationBase o : perTaxonOccurrences) {
|
601
|
occurrenceIds.add(o.getId());
|
602
|
}
|
603
|
}
|
604
|
occurrences = (List<T>) dao.listByIds(occurrenceIds, pageSize, pageNumber, orderHints, propertyPaths);
|
605
|
|
606
|
return new DefaultPagerImpl<T>(pageNumber, occurrenceIds.size(), pageSize, occurrences);
|
607
|
|
608
|
}
|
609
|
|
610
|
|
611
|
@Override
|
612
|
public <T extends SpecimenOrObservationBase> Pager<T> pageByAssociatedTaxon(Class<T> type, Set<TaxonRelationshipEdge> includeRelationships,
|
613
|
String taxonUUID, Integer maxDepth, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints, List<String> propertyPaths) {
|
614
|
|
615
|
UUID uuid = UUID.fromString(taxonUUID);
|
616
|
Taxon tax = (Taxon) taxonService.load(uuid);
|
617
|
//TODO REMOVE NULL STATEMENT
|
618
|
type=null;
|
619
|
return pageByAssociatedTaxon( type,includeRelationships,tax, maxDepth, pageSize, pageNumber, orderHints, propertyPaths );
|
620
|
|
621
|
}
|
622
|
|
623
|
|
624
|
@Override
|
625
|
public Pager<SearchResult<SpecimenOrObservationBase>> findByFullText(
|
626
|
Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle boundingBox, List<Language> languages,
|
627
|
boolean highlightFragments, Integer pageSize, Integer pageNumber, List<OrderHint> orderHints,
|
628
|
List<String> propertyPaths) throws CorruptIndexException, IOException, ParseException {
|
629
|
|
630
|
LuceneSearch luceneSearch = prepareByFullTextSearch(clazz, queryString, boundingBox, languages, highlightFragments);
|
631
|
|
632
|
// --- execute search
|
633
|
TopGroupsWithMaxScore topDocsResultSet = luceneSearch.executeSearch(pageSize, pageNumber);
|
634
|
|
635
|
Map<CdmBaseType, String> idFieldMap = new HashMap<CdmBaseType, String>();
|
636
|
idFieldMap.put(CdmBaseType.SPECIMEN_OR_OBSERVATIONBASE, "id");
|
637
|
|
638
|
// --- initialize taxa, highlight matches ....
|
639
|
ISearchResultBuilder searchResultBuilder = new SearchResultBuilder(luceneSearch, luceneSearch.getQuery());
|
640
|
@SuppressWarnings("rawtypes")
|
641
|
List<SearchResult<SpecimenOrObservationBase>> searchResults = searchResultBuilder.createResultSet(
|
642
|
topDocsResultSet, luceneSearch.getHighlightFields(), dao, idFieldMap, propertyPaths);
|
643
|
|
644
|
int totalHits = topDocsResultSet != null ? topDocsResultSet.topGroups.totalGroupCount : 0;
|
645
|
|
646
|
return new DefaultPagerImpl<SearchResult<SpecimenOrObservationBase>>(pageNumber, totalHits, pageSize,
|
647
|
searchResults);
|
648
|
|
649
|
}
|
650
|
|
651
|
|
652
|
/**
|
653
|
* @param clazz
|
654
|
* @param queryString
|
655
|
* @param languages
|
656
|
* @param highlightFragments
|
657
|
* @return
|
658
|
*/
|
659
|
private LuceneSearch prepareByFullTextSearch(Class<? extends SpecimenOrObservationBase> clazz, String queryString, Rectangle bbox,
|
660
|
List<Language> languages, boolean highlightFragments) {
|
661
|
|
662
|
BooleanQuery finalQuery = new BooleanQuery();
|
663
|
BooleanQuery textQuery = new BooleanQuery();
|
664
|
|
665
|
LuceneSearch luceneSearch = new LuceneSearch(luceneIndexToolProvider, FieldUnit.class);
|
666
|
QueryFactory queryFactory = luceneIndexToolProvider.newQueryFactoryFor(FieldUnit.class);
|
667
|
|
668
|
// --- criteria
|
669
|
luceneSearch.setCdmTypRestriction(clazz);
|
670
|
if(queryString != null){
|
671
|
textQuery.add(queryFactory.newTermQuery("titleCache", queryString), Occur.SHOULD);
|
672
|
finalQuery.add(textQuery, Occur.MUST);
|
673
|
}
|
674
|
|
675
|
// --- spacial query
|
676
|
if(bbox != null){
|
677
|
finalQuery.add(QueryFactory.buildSpatialQueryByRange(bbox, "gatheringEvent.exactLocation.point"), Occur.MUST);
|
678
|
}
|
679
|
|
680
|
luceneSearch.setQuery(finalQuery);
|
681
|
|
682
|
// --- sorting
|
683
|
SortField[] sortFields = new SortField[]{SortField.FIELD_SCORE, new SortField("titleCache__sort", SortField.STRING, false)};
|
684
|
luceneSearch.setSortFields(sortFields);
|
685
|
|
686
|
if(highlightFragments){
|
687
|
luceneSearch.setHighlightFields(queryFactory.getTextFieldNamesAsArray());
|
688
|
}
|
689
|
return luceneSearch;
|
690
|
}
|
691
|
|
692
|
|
693
|
/* (non-Javadoc)
|
694
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#getFieldUnits(eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
|
695
|
*/
|
696
|
@Override
|
697
|
public Collection<FieldUnit> getFieldUnits(UUID derivedUnitUuid) {
|
698
|
//It will search recursively over all {@link DerivationEvent}s and get the "originals" ({@link SpecimenOrObservationBase})
|
699
|
//from which this DerivedUnit was derived until all FieldUnits are found.
|
700
|
|
701
|
//FIXME: use HQL queries to increase performance
|
702
|
SpecimenOrObservationBase<?> specimen = load(derivedUnitUuid);
|
703
|
// specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
|
704
|
Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
|
705
|
|
706
|
if(specimen instanceof FieldUnit){
|
707
|
fieldUnits.add((FieldUnit) specimen);
|
708
|
}
|
709
|
else if(specimen instanceof DerivedUnit){
|
710
|
getFieldUnits((DerivedUnit) specimen, fieldUnits);
|
711
|
}
|
712
|
return fieldUnits;
|
713
|
}
|
714
|
|
715
|
|
716
|
/**
|
717
|
* @param original
|
718
|
* @param fieldUnits
|
719
|
*/
|
720
|
private void getFieldUnits(DerivedUnit derivedUnit, Collection<FieldUnit> fieldUnits) {
|
721
|
Set<SpecimenOrObservationBase> originals = derivedUnit.getOriginals();
|
722
|
if(originals!=null && !originals.isEmpty()){
|
723
|
for(SpecimenOrObservationBase<?> original:originals){
|
724
|
if(original instanceof FieldUnit){
|
725
|
fieldUnits.add((FieldUnit) original);
|
726
|
}
|
727
|
else if(original instanceof DerivedUnit){
|
728
|
getFieldUnits((DerivedUnit) original, fieldUnits);
|
729
|
}
|
730
|
}
|
731
|
}
|
732
|
}
|
733
|
|
734
|
/* (non-Javadoc)
|
735
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveSequence(eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.DnaSample, eu.etaxonomy.cdm.model.molecular.Sequence)
|
736
|
*/
|
737
|
@Override
|
738
|
public boolean moveSequence(DnaSample from, DnaSample to, Sequence sequence) {
|
739
|
//reload specimens to avoid session conflicts
|
740
|
from = (DnaSample) load(from.getUuid());
|
741
|
to = (DnaSample) load(to.getUuid());
|
742
|
sequence = sequenceService.load(sequence.getUuid());
|
743
|
|
744
|
if(from==null || to==null || sequence==null){
|
745
|
throw new TransientObjectException("One of the CDM entities has not been saved to the data base yet. Moving only works for persisted/saved CDM entities.\n" +
|
746
|
"Operation was move "+sequence+ " from "+from+" to "+to);
|
747
|
}
|
748
|
from.removeSequence(sequence);
|
749
|
saveOrUpdate(from);
|
750
|
to.addSequence(sequence);
|
751
|
saveOrUpdate(to);
|
752
|
return true;
|
753
|
}
|
754
|
|
755
|
/* (non-Javadoc)
|
756
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#moveDerivate(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.model.occurrence.DerivedUnit)
|
757
|
*/
|
758
|
@Override
|
759
|
public boolean moveDerivate(SpecimenOrObservationBase<?> from, SpecimenOrObservationBase<?> to, DerivedUnit derivate) {
|
760
|
//reload specimens to avoid session conflicts
|
761
|
from = load(from.getUuid());
|
762
|
to = load(to.getUuid());
|
763
|
derivate = (DerivedUnit) load(derivate.getUuid());
|
764
|
|
765
|
if(from==null || to==null || derivate==null){
|
766
|
throw new TransientObjectException("One of the CDM entities has not been saved to the data base yet. Moving only works for persisted/saved CDM entities.\n" +
|
767
|
"Operation was move "+derivate+ " from "+from+" to "+to);
|
768
|
}
|
769
|
|
770
|
SpecimenOrObservationType derivateType = derivate.getRecordBasis();
|
771
|
SpecimenOrObservationType toType = to.getRecordBasis();
|
772
|
//check if type is a sub derivate type
|
773
|
if(toType==SpecimenOrObservationType.FieldUnit //moving to FieldUnit always works
|
774
|
|| derivateType==SpecimenOrObservationType.Media //moving media always works
|
775
|
|| (derivateType.isKindOf(toType) && toType!=derivateType)){ //moving only to parent derivate type
|
776
|
//remove derivation event from parent specimen of dragged object
|
777
|
DerivationEvent eventToRemove = null;
|
778
|
for(DerivationEvent event:from.getDerivationEvents()){
|
779
|
if(event.getDerivatives().contains(derivate)){
|
780
|
eventToRemove = event;
|
781
|
break;
|
782
|
}
|
783
|
}
|
784
|
from.removeDerivationEvent(eventToRemove);
|
785
|
saveOrUpdate(from);
|
786
|
//add new derivation event to target
|
787
|
DerivationEvent derivedFromNewOriginalEvent = DerivationEvent.NewSimpleInstance(to, derivate, eventToRemove==null?null:eventToRemove.getType());
|
788
|
to.addDerivationEvent(derivedFromNewOriginalEvent);
|
789
|
derivate.setDerivedFrom(derivedFromNewOriginalEvent);
|
790
|
saveOrUpdate(to);
|
791
|
return true;
|
792
|
}
|
793
|
return false;
|
794
|
}
|
795
|
|
796
|
@Override
|
797
|
public Collection<ICdmBase> getNonCascadedAssociatedElements(SpecimenOrObservationBase<?> specimen){
|
798
|
//potential fields that are not persisted cascadingly
|
799
|
/*
|
800
|
* SOOB
|
801
|
-DescriptionBase
|
802
|
-determinations
|
803
|
--modifier TERM
|
804
|
-kindOfUnit TERM
|
805
|
-lifeStage TERM
|
806
|
-sex TERM
|
807
|
|
808
|
FieldUnit
|
809
|
-GatheringEvent
|
810
|
--Country TERM
|
811
|
--CollectingAreas TERM
|
812
|
|
813
|
DerivedUnit
|
814
|
-collection
|
815
|
--institute
|
816
|
---types TERM
|
817
|
-preservationMethod
|
818
|
--medium TERM
|
819
|
-storedUnder CDM TaxonNameBase
|
820
|
*/
|
821
|
|
822
|
Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
|
823
|
|
824
|
//Choose the correct entry point to traverse the graph (FieldUnit or DerivedUnit)
|
825
|
|
826
|
//FieldUnit
|
827
|
if(specimen instanceof FieldUnit){
|
828
|
nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements((FieldUnit)specimen));
|
829
|
}
|
830
|
//DerivedUnit
|
831
|
else if(specimen instanceof DerivedUnit){
|
832
|
DerivedUnit derivedUnit = (DerivedUnit)specimen;
|
833
|
if(derivedUnit.getDerivedFrom()!=null){
|
834
|
Collection<FieldUnit> fieldUnits = new ArrayList<FieldUnit>();
|
835
|
getFieldUnits(derivedUnit, fieldUnits);
|
836
|
for(FieldUnit fieldUnit:fieldUnits){
|
837
|
nonCascadedCdmEntities.addAll(getFieldUnitNonCascadedAssociatedElements(fieldUnit));
|
838
|
}
|
839
|
}
|
840
|
}
|
841
|
return nonCascadedCdmEntities;
|
842
|
}
|
843
|
|
844
|
private Collection<ICdmBase> getFieldUnitNonCascadedAssociatedElements(FieldUnit fieldUnit){
|
845
|
//get non cascaded element on SpecimenOrObservationBase level
|
846
|
Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(fieldUnit);
|
847
|
|
848
|
//get FieldUnit specific elements
|
849
|
GatheringEvent gatheringEvent = fieldUnit.getGatheringEvent();
|
850
|
if(gatheringEvent!=null){
|
851
|
//country
|
852
|
if(gatheringEvent.getCountry()!=null){
|
853
|
nonCascadedCdmEntities.add(gatheringEvent.getCountry());
|
854
|
}
|
855
|
//collecting areas
|
856
|
for (NamedArea namedArea : gatheringEvent.getCollectingAreas()) {
|
857
|
nonCascadedCdmEntities.add(namedArea);
|
858
|
}
|
859
|
}
|
860
|
for (DerivationEvent derivationEvent : fieldUnit.getDerivationEvents()) {
|
861
|
for (DerivedUnit derivedUnit : derivationEvent.getDerivatives()) {
|
862
|
nonCascadedCdmEntities.addAll(getDerivedUnitNonCascadedAssociatedElements(derivedUnit));
|
863
|
}
|
864
|
}
|
865
|
return nonCascadedCdmEntities;
|
866
|
}
|
867
|
|
868
|
private Collection<ICdmBase> getDerivedUnitNonCascadedAssociatedElements(DerivedUnit derivedUnit){
|
869
|
//get non cascaded element on SpecimenOrObservationBase level
|
870
|
Collection<ICdmBase> nonCascadedCdmEntities = getSpecimenOrObservationNonCascadedAssociatedElements(derivedUnit);
|
871
|
|
872
|
//get DerivedUnit specific elements
|
873
|
if(derivedUnit.getCollection()!=null && derivedUnit.getCollection().getInstitute()!=null){
|
874
|
for (DefinedTerm type : derivedUnit.getCollection().getInstitute().getTypes()) {
|
875
|
nonCascadedCdmEntities.add(type);
|
876
|
}
|
877
|
}
|
878
|
if(derivedUnit.getPreservation()!=null && derivedUnit.getPreservation().getMedium()!=null){
|
879
|
nonCascadedCdmEntities.add(derivedUnit.getPreservation().getMedium());
|
880
|
}
|
881
|
if(derivedUnit.getStoredUnder()!=null){
|
882
|
nonCascadedCdmEntities.add(derivedUnit.getStoredUnder());
|
883
|
}
|
884
|
return nonCascadedCdmEntities;
|
885
|
}
|
886
|
|
887
|
/**
|
888
|
* @param specimen
|
889
|
* @return
|
890
|
*/
|
891
|
private Collection<ICdmBase> getSpecimenOrObservationNonCascadedAssociatedElements(
|
892
|
SpecimenOrObservationBase<?> specimen) {
|
893
|
Collection<ICdmBase> nonCascadedCdmEntities = new HashSet<ICdmBase>();
|
894
|
//scan SpecimenOrObservationBase
|
895
|
for(DeterminationEvent determinationEvent:specimen.getDeterminations()){
|
896
|
//modifier
|
897
|
if(determinationEvent.getModifier()!=null){
|
898
|
nonCascadedCdmEntities.add(determinationEvent.getModifier());
|
899
|
}
|
900
|
}
|
901
|
//kindOfUnit
|
902
|
if(specimen.getKindOfUnit()!=null){
|
903
|
nonCascadedCdmEntities.add(specimen.getKindOfUnit());
|
904
|
}
|
905
|
//lifeStage
|
906
|
if(specimen.getLifeStage()!=null){
|
907
|
nonCascadedCdmEntities.add(specimen.getLifeStage());
|
908
|
}
|
909
|
//sex
|
910
|
if(specimen.getSex()!=null){
|
911
|
nonCascadedCdmEntities.add(specimen.getSex());
|
912
|
}
|
913
|
return nonCascadedCdmEntities;
|
914
|
}
|
915
|
|
916
|
/* (non-Javadoc)
|
917
|
* @see eu.etaxonomy.cdm.api.service.VersionableServiceBase#isDeletable(eu.etaxonomy.cdm.model.common.VersionableEntity, eu.etaxonomy.cdm.api.service.config.DeleteConfiguratorBase)
|
918
|
*/
|
919
|
@Override
|
920
|
public DeleteResult isDeletable(SpecimenOrObservationBase specimen, DeleteConfiguratorBase config) {
|
921
|
DeleteResult deleteResult = super.isDeletable(specimen, config);
|
922
|
SpecimenDeleteConfigurator specimenDeleteConfigurator = (SpecimenDeleteConfigurator)config;
|
923
|
|
924
|
//check elements found by super method
|
925
|
Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
|
926
|
boolean isDeletable = true;
|
927
|
for (CdmBase cdmBase : relatedObjects) {
|
928
|
//check for type designation
|
929
|
if(cdmBase.isInstanceOf(SpecimenTypeDesignation.class) && !specimenDeleteConfigurator.isDeleteFromTypeDesignation()){
|
930
|
isDeletable = false;
|
931
|
deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is a type specimen."));
|
932
|
break;
|
933
|
}
|
934
|
//check for IndividualsAssociations
|
935
|
else if(cdmBase.isInstanceOf(IndividualsAssociation.class) && !specimenDeleteConfigurator.isDeleteFromIndividualsAssociation()){
|
936
|
isDeletable = false;
|
937
|
deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still associated via IndividualsAssociations"));
|
938
|
break;
|
939
|
}
|
940
|
//check for specimen/taxon description
|
941
|
else if((cdmBase.isInstanceOf(SpecimenDescription.class) || cdmBase.isInstanceOf(TaxonDescription.class))
|
942
|
&& !specimenDeleteConfigurator.isDeleteFromDescription()){
|
943
|
isDeletable = false;
|
944
|
deleteResult.addException(new ReferencedObjectUndeletableException("Specimen is still used in a Description."));
|
945
|
break;
|
946
|
}
|
947
|
//check for children and parents (derivation events)
|
948
|
else if(cdmBase.isInstanceOf(DerivationEvent.class)){
|
949
|
DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(cdmBase, DerivationEvent.class);
|
950
|
//check if derivation event is derivedFrom event (parent -> child)
|
951
|
if(derivationEvent.getDerivatives().contains(specimen)){
|
952
|
//if it is then the specimen is still deletable
|
953
|
continue;
|
954
|
}
|
955
|
else if(!specimenDeleteConfigurator.isDeleteChildren()){
|
956
|
//if not and children should not be deleted then it is undeletable
|
957
|
isDeletable = false;
|
958
|
deleteResult.addException(new ReferencedObjectUndeletableException("Derivate still has child derivates."));
|
959
|
break;
|
960
|
}
|
961
|
else{
|
962
|
//check all children if they can be deleted
|
963
|
Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
|
964
|
DeleteResult childResult = new DeleteResult();
|
965
|
for (DerivedUnit derivedUnit : derivatives) {
|
966
|
childResult.includeResult(isDeletable(derivedUnit, specimenDeleteConfigurator));
|
967
|
}
|
968
|
if(!childResult.isOk()){
|
969
|
isDeletable = false;
|
970
|
deleteResult.includeResult(childResult);
|
971
|
break;
|
972
|
}
|
973
|
}
|
974
|
}
|
975
|
//check for amplification
|
976
|
else if(cdmBase.isInstanceOf(AmplificationResult.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){
|
977
|
isDeletable = false;
|
978
|
deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in amplification results."));
|
979
|
break;
|
980
|
}
|
981
|
//check for sequence
|
982
|
else if(cdmBase.isInstanceOf(Sequence.class) && !specimenDeleteConfigurator.isDeleteMolecularData()){
|
983
|
isDeletable = false;
|
984
|
deleteResult.addException(new ReferencedObjectUndeletableException("DnaSample is used in sequences."));
|
985
|
break;
|
986
|
}
|
987
|
}
|
988
|
if(isDeletable){
|
989
|
//set to OK when config allows to delete related objects
|
990
|
deleteResult.setStatus(DeleteStatus.OK);
|
991
|
}
|
992
|
|
993
|
return deleteResult;
|
994
|
}
|
995
|
|
996
|
/* (non-Javadoc)
|
997
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#delete(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, eu.etaxonomy.cdm.api.service.config.SpecimenDeleteConfigurator)
|
998
|
*/
|
999
|
@Override
|
1000
|
public DeleteResult delete(SpecimenOrObservationBase<?> specimen, SpecimenDeleteConfigurator config) {
|
1001
|
specimen = HibernateProxyHelper.deproxy(specimen, SpecimenOrObservationBase.class);
|
1002
|
|
1003
|
DeleteResult deleteResult = isDeletable(specimen, config);
|
1004
|
if(!deleteResult.isOk()){
|
1005
|
return deleteResult;
|
1006
|
}
|
1007
|
|
1008
|
//check related objects
|
1009
|
Set<CdmBase> relatedObjects = deleteResult.getRelatedObjects();
|
1010
|
for (CdmBase relatedObject : relatedObjects) {
|
1011
|
//check for TypeDesignations
|
1012
|
if(relatedObject.isInstanceOf(SpecimenTypeDesignation.class)){
|
1013
|
SpecimenTypeDesignation designation = HibernateProxyHelper.deproxy(relatedObject, SpecimenTypeDesignation.class);
|
1014
|
designation.setTypeSpecimen(null);
|
1015
|
Set<TaxonNameBase> typifiedNames = designation.getTypifiedNames();
|
1016
|
for (TaxonNameBase taxonNameBase : typifiedNames) {
|
1017
|
taxonNameBase.removeTypeDesignation(designation);
|
1018
|
}
|
1019
|
}
|
1020
|
//delete IndividualsAssociation
|
1021
|
if(relatedObject.isInstanceOf(IndividualsAssociation.class)){
|
1022
|
IndividualsAssociation assciation = HibernateProxyHelper.deproxy(relatedObject, IndividualsAssociation.class);
|
1023
|
assciation.setAssociatedSpecimenOrObservation(null);
|
1024
|
assciation.getInDescription().removeElement(assciation);
|
1025
|
}
|
1026
|
//check for taxon description
|
1027
|
if(relatedObject.isInstanceOf(TaxonDescription.class)){
|
1028
|
TaxonDescription taxonDescription = HibernateProxyHelper.deproxy(relatedObject, TaxonDescription.class);
|
1029
|
taxonDescription.setDescribedSpecimenOrObservation(null);
|
1030
|
}
|
1031
|
//check for specimen description
|
1032
|
if(relatedObject.isInstanceOf(SpecimenDescription.class)){
|
1033
|
SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(relatedObject, SpecimenDescription.class);
|
1034
|
//check if specimen is "described" specimen
|
1035
|
if(specimenDescription.getDescribedSpecimenOrObservation().equals(specimen)){
|
1036
|
specimenDescription.setDescribedSpecimenOrObservation(null);
|
1037
|
}
|
1038
|
//check if description is a description of the given specimen
|
1039
|
if(specimen.getDescriptions().contains(specimenDescription)){
|
1040
|
specimen.removeDescription(specimenDescription);
|
1041
|
}
|
1042
|
}
|
1043
|
//check for amplification
|
1044
|
if(relatedObject.isInstanceOf(AmplificationResult.class)){
|
1045
|
AmplificationResult amplificationResult = HibernateProxyHelper.deproxy(relatedObject, AmplificationResult.class);
|
1046
|
amplificationResult.getDnaSample().removeAmplificationResult(amplificationResult);
|
1047
|
}
|
1048
|
//check for sequence
|
1049
|
if(relatedObject.isInstanceOf(Sequence.class)){
|
1050
|
Sequence sequence = HibernateProxyHelper.deproxy(relatedObject, Sequence.class);
|
1051
|
sequence.getDnaSample().removeSequence(sequence);
|
1052
|
}
|
1053
|
//check for children and parents (derivation events)
|
1054
|
if(relatedObject.isInstanceOf(DerivationEvent.class)){
|
1055
|
DerivationEvent derivationEvent = HibernateProxyHelper.deproxy(relatedObject, DerivationEvent.class);
|
1056
|
//parent derivation event (derivedFrom)
|
1057
|
if(derivationEvent.getDerivatives().contains(specimen) && specimen.isInstanceOf(DerivedUnit.class)){
|
1058
|
derivationEvent.removeDerivative(HibernateProxyHelper.deproxy(specimen, DerivedUnit.class));
|
1059
|
if(derivationEvent.getDerivatives().isEmpty()){
|
1060
|
Set<SpecimenOrObservationBase> originals = derivationEvent.getOriginals();
|
1061
|
for (SpecimenOrObservationBase specimenOrObservationBase : originals) {
|
1062
|
specimenOrObservationBase.removeDerivationEvent(derivationEvent);
|
1063
|
}
|
1064
|
}
|
1065
|
}
|
1066
|
//child derivation events
|
1067
|
else{
|
1068
|
deleteResult.includeResult(deepDelete(specimen, config));
|
1069
|
}
|
1070
|
}
|
1071
|
}
|
1072
|
|
1073
|
deleteResult.includeResult(delete(specimen));
|
1074
|
return deleteResult;
|
1075
|
}
|
1076
|
|
1077
|
/* (non-Javadoc)
|
1078
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#deleteDerivateHierarchy(eu.etaxonomy.cdm.model.common.ICdmBase)
|
1079
|
*/
|
1080
|
@Override
|
1081
|
public DeleteResult deleteDerivateHierarchy(CdmBase from, SpecimenDeleteConfigurator config) {
|
1082
|
DeleteResult deleteResult = new DeleteResult();
|
1083
|
if(from.isInstanceOf(Sequence.class)){
|
1084
|
if(!config.isDeleteMolecularData()){
|
1085
|
deleteResult.setAbort();
|
1086
|
deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));
|
1087
|
return deleteResult;
|
1088
|
}
|
1089
|
Sequence sequence = HibernateProxyHelper.deproxy(from, Sequence.class);
|
1090
|
sequence.getDnaSample().removeSequence(sequence);
|
1091
|
deleteResult = sequenceService.delete(sequence);
|
1092
|
}
|
1093
|
else if(from.isInstanceOf(SingleRead.class)) {
|
1094
|
if(!config.isDeleteMolecularData()){
|
1095
|
deleteResult.setAbort();
|
1096
|
deleteResult.addException(new ReferencedObjectUndeletableException("deleting molecur data is not allowed in config"));
|
1097
|
return deleteResult;
|
1098
|
}
|
1099
|
SingleRead singleRead = HibernateProxyHelper.deproxy(from, SingleRead.class);
|
1100
|
singleRead.getAmplificationResult().removeSingleRead(singleRead);
|
1101
|
deleteResult.setStatus(DeleteStatus.OK);
|
1102
|
}
|
1103
|
else if(from.isInstanceOf(SpecimenOrObservationBase.class)) {
|
1104
|
deleteResult = deepDelete(HibernateProxyHelper.deproxy(from, SpecimenOrObservationBase.class), config);
|
1105
|
}
|
1106
|
return deleteResult;
|
1107
|
}
|
1108
|
|
1109
|
private DeleteResult deepDelete(SpecimenOrObservationBase<?> entity, SpecimenDeleteConfigurator config){
|
1110
|
DeleteResult deleteResult = isDeletable(entity, config);
|
1111
|
if(!deleteResult.isOk()){
|
1112
|
return deleteResult;
|
1113
|
}
|
1114
|
Set<DerivationEvent> derivationEvents = entity.getDerivationEvents();
|
1115
|
for (DerivationEvent derivationEvent : derivationEvents) {
|
1116
|
Set<DerivedUnit> derivatives = derivationEvent.getDerivatives();
|
1117
|
for (DerivedUnit derivedUnit : derivatives) {
|
1118
|
deleteResult.includeResult(deepDelete(derivedUnit, config));
|
1119
|
}
|
1120
|
}
|
1121
|
deleteResult.includeResult(delete(entity, config));
|
1122
|
return deleteResult;
|
1123
|
}
|
1124
|
|
1125
|
/* (non-Javadoc)
|
1126
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listAssociatedTaxa(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase)
|
1127
|
*/
|
1128
|
@Override
|
1129
|
public Collection<IndividualsAssociation> listIndividualsAssociations(SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
|
1130
|
return dao.listIndividualsAssociations(specimen, null, null, null, null);
|
1131
|
}
|
1132
|
|
1133
|
/* (non-Javadoc)
|
1134
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listTypeDesignations(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
|
1135
|
*/
|
1136
|
@Override
|
1137
|
public Collection<SpecimenTypeDesignation> listTypeDesignations(SpecimenOrObservationBase<?> specimen,
|
1138
|
Integer limit, Integer start, List<OrderHint> orderHints, List<String> propertyPaths) {
|
1139
|
return dao.listTypeDesignations(specimen, limit, start, orderHints, propertyPaths);
|
1140
|
}
|
1141
|
|
1142
|
/* (non-Javadoc)
|
1143
|
* @see eu.etaxonomy.cdm.api.service.IOccurrenceService#listDescriptionsWithDescriptionSpecimen(eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase, java.lang.Integer, java.lang.Integer, java.util.List, java.util.List)
|
1144
|
*/
|
1145
|
@Override
|
1146
|
public Collection<DescriptionBase<?>> listDescriptionsWithDescriptionSpecimen(
|
1147
|
SpecimenOrObservationBase<?> specimen, Integer limit, Integer start, List<OrderHint> orderHints,
|
1148
|
List<String> propertyPaths) {
|
1149
|
return dao.listDescriptionsWithDescriptionSpecimen(specimen, limit, start, orderHints, propertyPaths);
|
1150
|
}
|
1151
|
|
1152
|
}
|