Project

General

Profile

Download (17.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.api.service;
11

    
12
import java.util.ArrayList;
13
import java.util.HashSet;
14
import java.util.Iterator;
15
import java.util.List;
16
import java.util.Map;
17
import java.util.Map.Entry;
18
import java.util.Set;
19
import java.util.UUID;
20

    
21
import org.apache.log4j.Logger;
22
import org.springframework.beans.factory.annotation.Autowired;
23
import org.springframework.stereotype.Service;
24
import org.springframework.transaction.annotation.Transactional;
25

    
26
import eu.etaxonomy.cdm.api.service.config.NodeDeletionConfigurator.ChildHandling;
27
import eu.etaxonomy.cdm.api.service.config.TermNodeDeletionConfigurator;
28
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
29
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
30
import eu.etaxonomy.cdm.model.common.CdmBase;
31
import eu.etaxonomy.cdm.model.description.Character;
32
import eu.etaxonomy.cdm.model.description.Feature;
33
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
34
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
35
import eu.etaxonomy.cdm.model.term.DefinedTerm;
36
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
37
import eu.etaxonomy.cdm.model.term.Representation;
38
import eu.etaxonomy.cdm.model.term.TermNode;
39
import eu.etaxonomy.cdm.model.term.TermTree;
40
import eu.etaxonomy.cdm.model.term.TermType;
41
import eu.etaxonomy.cdm.model.term.TermVocabulary;
42
import eu.etaxonomy.cdm.persistence.dao.term.ITermNodeDao;
43
import eu.etaxonomy.cdm.persistence.dto.CharacterDto;
44
import eu.etaxonomy.cdm.persistence.dto.CharacterNodeDto;
45
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
46
import eu.etaxonomy.cdm.persistence.dto.TermDto;
47
import eu.etaxonomy.cdm.persistence.dto.TermNodeDto;
48
import eu.etaxonomy.cdm.persistence.dto.TermVocabularyDto;
49
import eu.etaxonomy.cdm.persistence.query.OrderHint;
50

    
51
/**
52
 * @author a.mueller
53
 * @since Jul 22, 2019
54
 */
55
@Service
56
@Transactional(readOnly = false)
57
public class TermNodeServiceImpl
58
        extends VersionableServiceBase<TermNode, ITermNodeDao>
59
        implements ITermNodeService {
60

    
61
    @SuppressWarnings("unused")
62
    private static final Logger logger = Logger.getLogger(TermNodeServiceImpl.class);
63

    
64
	@Override
65
    @Autowired
66
	protected void setDao(ITermNodeDao dao) {
67
		this.dao = dao;
68
	}
69

    
70
	@Autowired
71
    private ITermService termService;
72

    
73
	@Autowired
74
	private IVocabularyService vocabularyService;
75

    
76
	@Override
77
    public List<TermNode> list(TermType termType, Integer limit, Integer start,
78
	        List<OrderHint> orderHints, List<String> propertyPaths){
79
	    return dao.list(termType, limit, start, orderHints, propertyPaths);
80
	}
81

    
82
	@Override
83
	@Transactional(readOnly = false)
84
	public DeleteResult deleteNode(UUID nodeUuid, TermNodeDeletionConfigurator config) {
85
	    DeleteResult result = new DeleteResult();
86
        TermNode<Feature> node = CdmBase.deproxy(dao.load(nodeUuid));
87
	    result = isDeletable(nodeUuid, config);
88
	    if (result.isOk()){
89
	        TermNode<Feature> parent = node.getParent();
90
            parent = CdmBase.deproxy(parent, TermNode.class);
91
	        List<TermNode> children = new ArrayList<>(node.getChildNodes());
92

    
93
	        if (config.getChildHandling().equals(ChildHandling.DELETE)){
94

    
95
	            for (TermNode child: children){
96
	                deleteNode(child.getUuid(), config);
97
	               // node.removeChild(child);
98
	            }
99
	            if (parent != null){
100
	                parent.removeChild(node);
101
	            }
102

    
103
	        } else{
104

    
105
	            if (parent != null){
106
	                parent.removeChild(node);
107
	                for (TermNode child: children){
108
	                    node.removeChild(child);
109
	                    parent.addChild(child);
110
	                }
111
	            }else{
112
	                 result.setAbort();
113
	                 result.addException(new ReferencedObjectUndeletableException("The root node can not be deleted without its child nodes"));
114
	                 return result;
115
	             }
116
	         }
117

    
118
	         dao.delete(node);
119
	         result.addDeletedObject(node);
120
	         if(parent!=null){
121
	             result.addUpdatedObject(parent);
122
	         }
123
	         if (config.isDeleteElement()){
124
	             DefinedTermBase term = node.getTerm();
125
                 termService.delete(term.getUuid());
126
                 result.addDeletedObject(term);
127
             }
128
	     }
129
	     return result;
130
	 }
131
	 private UpdateResult createChildNode(UUID parentNodeUUID, UUID nodeUuid, DefinedTermBase term, UUID vocabularyUuid){
132
	     UpdateResult result =  createChildNode(parentNodeUUID, term, vocabularyUuid);
133
	     result.getCdmEntity().setUuid(nodeUuid);
134
	     return result;
135
	 }
136

    
137

    
138
	 @Override
139
     public UpdateResult createChildNode(UUID parentNodeUuid, DefinedTermBase term, UUID vocabularyUuid){
140
	     TermVocabulary vocabulary = vocabularyService.load(vocabularyUuid);
141

    
142
	     vocabulary.addTerm(term);
143
	     vocabularyService.save(vocabulary);
144
	     return addChildNode(parentNodeUuid, term.getUuid());
145
	 }
146

    
147
     @Override
148
     public UpdateResult addChildNode(UUID nodeUUID, UUID termChildUuid){
149
         return addChildNode(nodeUUID, termChildUuid, 0);
150
     }
151

    
152
	 @Override
153
	 public UpdateResult addChildNode(UUID nodeUUID, UUID termChildUuid, int position){
154
	     UpdateResult result = new UpdateResult();
155

    
156
	     TermNode node = load(nodeUUID);
157
	     DefinedTermBase child = HibernateProxyHelper.deproxy(termService.load(termChildUuid), DefinedTermBase.class);
158

    
159
	     if(!node.getGraph().isAllowDuplicates() && node.getGraph().getDistinctTerms().contains(child)){
160
	         result.setError();
161
	         result.addException(new Exception("This term tree does not allow duplicate terms."));
162
	         return result;
163
	     }
164

    
165
	     TermNode childNode;
166
         if(position<0) {
167
             childNode = node.addChild(child);
168
         }
169
         else{
170
             childNode = node.addChild(child, position);
171
         }
172
         save(childNode);
173
         result.addUpdatedObject(node);
174
         result.setCdmEntity(childNode);
175
         return result;
176
     }
177

    
178
	 @Override
179
	 public DeleteResult isDeletable(UUID nodeUuid, TermNodeDeletionConfigurator config){
180
	     TermNode<Feature> node = load(nodeUuid);
181
	     DeleteResult result = new DeleteResult();
182
	     Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(node);
183
	     for (CdmBase ref:references){
184
	         if (ref instanceof TermNode){
185
	             break;
186
	         }
187
	         if (ref instanceof TermTree){
188
	             TermTree<Feature> refTree = HibernateProxyHelper.deproxy(ref, TermTree.class);
189
	             if (node.getGraph().equals((refTree))){
190
	                 break;
191
	             }
192
	         }
193
	         result.setAbort();
194
	         result.addException(new ReferencedObjectUndeletableException("The featureNode is referenced by " + ref.getUserFriendlyDescription() +" with id " +ref.getId()));
195

    
196
	     }
197
	     return result;
198
	 }
199

    
200
    @Override
201
    public UpdateResult moveNode(UUID movedNodeUuid, UUID targetNodeUuid, int position) {
202
        UpdateResult result = new UpdateResult();
203
        List<String> propertyPaths = new ArrayList<>();
204
        propertyPaths.add("parent");
205
        propertyPaths.add("parent.children");
206
        propertyPaths.add("children");
207
        TermNode test = load(movedNodeUuid, propertyPaths);
208
        TermNode movedNode = CdmBase.deproxy(load(movedNodeUuid, propertyPaths), TermNode.class);
209
        TermNode targetNode = CdmBase.deproxy(load(targetNodeUuid, propertyPaths));
210
        TermNode parent = CdmBase.deproxy(movedNode.getParent());
211
        parent.removeChild(movedNode);
212
        if(position < 0){
213
            targetNode.addChild(movedNode);
214
        }
215
        else{
216
            targetNode.addChild(movedNode, position);
217
        }
218
        result.addUpdatedObject(targetNode);
219
        if(parent!=null){
220
            result.addUpdatedObject(parent);
221
        }
222
        result.setCdmEntity(movedNode);
223
        return result;
224
    }
225

    
226
    @Override
227
    public UpdateResult moveNode(UUID movedNodeUuid, UUID targetNodeUuid) {
228
        return moveNode(movedNodeUuid, targetNodeUuid, -1);
229
    }
230

    
231
    @Override
232
    public UpdateResult saveTermNodeDtoList(List<TermNodeDto> dtos){
233
        UpdateResult result = new UpdateResult();
234
        MergeResult<TermNode> mergeResult;
235
        List<UUID> uuids = new ArrayList<>();
236
        dtos.stream().forEach(dto -> uuids.add(dto.getUuid()));
237
        List<TermNode> nodes = dao.list(uuids, null, 0, null, null);
238
        //check all attributes for changes and adapt
239
        for (TermNode node: nodes){
240
            for (TermNodeDto dto: dtos){
241

    
242
                if (dto.getUuid().equals(node.getUuid())){
243
    //                only node changes, everything else will be handled by the operations/service methods
244
                    if (!dto.getInapplicableIf().equals(node.getInapplicableIf())){
245
                        node.getInapplicableIf().clear();
246
                        node.getInapplicableIf().addAll(dto.getInapplicableIf());
247
                    }
248
                    if (!dto.getOnlyApplicableIf().equals(node.getOnlyApplicableIf())){
249
                        node.getOnlyApplicableIf().clear();
250
                        node.getOnlyApplicableIf().addAll(dto.getOnlyApplicableIf());
251
                    }
252
                }
253
                mergeResult = dao.merge(node, true);
254
                result.addUpdatedObject(mergeResult.getMergedEntity());
255
            }
256
        }
257
        return result;
258
    }
259

    
260

    
261

    
262
    @Override
263
    public UpdateResult saveCharacterNodeDtoList(List<CharacterNodeDto> dtos){
264
        MergeResult<TermNode> mergeResult;
265
        UpdateResult result = new UpdateResult();
266
        List<UUID> nodeUuids = new ArrayList<>();
267

    
268
        dtos.stream().forEach(dto -> nodeUuids.add(dto.getUuid()));
269
        List<TermNode> nodes = dao.list(nodeUuids, null, 0, null, null);
270
        //check all attributes for changes and adapt
271
        Iterator<CharacterNodeDto> dtoIterator = dtos.iterator();
272
        for (TermNode<Character> node: nodes){
273
            for (CharacterNodeDto dto: dtos){
274
    //            TermNodeDto dto = dtoIterator.next();
275
                if (dto.getUuid().equals(node.getUuid())){
276

    
277
                    if (!dto.getInapplicableIf().equals(node.getInapplicableIf())){
278
                        node.getInapplicableIf().clear();
279
                        node.getInapplicableIf().addAll(dto.getInapplicableIf());
280
                    }
281
                    if (!dto.getOnlyApplicableIf().equals(node.getOnlyApplicableIf())){
282
                        node.getOnlyApplicableIf().clear();
283
                        node.getOnlyApplicableIf().addAll(dto.getOnlyApplicableIf());
284
                    }
285

    
286
                    Character character = null;
287
                    CharacterDto characterDto = (CharacterDto) dto.getTerm();
288
                    character = HibernateProxyHelper.deproxy(node.getTerm(), Character.class);
289

    
290
                    //supportsXXX
291
                    //TODO add all other supportsXXX (6 are missing)
292
                    character.setSupportsCategoricalData(characterDto.isSupportsCategoricalData());
293
                    character.setSupportsQuantitativeData(characterDto.isSupportsQuantitativeData());
294

    
295
                    //availableForXXX
296
                    character.setAvailableForTaxon(characterDto.isAvailableForTaxon());
297
                    character.setAvailableForOccurrence(characterDto.isAvailableForOccurrence());
298
                    character.setAvailableForTaxonName(characterDto.isAvailableForTaxonName());
299

    
300
//                  representations
301
                    for (Representation rep: dto.getTerm().getRepresentations()){
302
                        Representation oldRep = character.getRepresentation(rep.getLanguage());
303
                        if (oldRep == null){
304
                            oldRep = new Representation();
305
                            oldRep.setLanguage(rep.getLanguage());
306
                            character.addRepresentation(oldRep);
307
                        }
308
                        oldRep.setLabel(rep.getLabel());
309
                        oldRep.setAbbreviatedLabel(rep.getAbbreviatedLabel());
310
                        oldRep.setText(rep.getText());
311
                        oldRep.setPlural(rep.getPlural());
312
                    }
313
                    Set<Representation> deleteRepresentations = new HashSet<>();
314
                    if (character.getRepresentations().size() > dto.getTerm().getRepresentations().size()){
315
                        for (Representation rep: character.getRepresentations()){
316
                            if(dto.getTerm().getRepresentation(rep.getLanguage()) == null){
317
                                deleteRepresentations.add(rep);
318
                            }
319
                        }
320
                    }
321

    
322
                    if (!deleteRepresentations.isEmpty()){
323
                        for (Representation rep: deleteRepresentations){
324
                            character.removeRepresentation(rep);
325
                        }
326

    
327
                    }
328

    
329
//                  structural modifier
330
                    if (characterDto.getStructureModifier() != null){
331
                        DefinedTerm structureModifier = (DefinedTerm) termService.load(characterDto.getStructureModifier().getUuid());
332
                        character.setStructureModifier(structureModifier);
333
                    }else{
334
                        character.setStructureModifier(null);
335
                    }
336
//                  recommended measurement units
337
                    character.getRecommendedMeasurementUnits().clear();
338
                    List<UUID> uuids = new ArrayList<>();
339
                    for (TermDto termDto: characterDto.getRecommendedMeasurementUnits()){
340
                        uuids.add(termDto.getUuid());
341
                    }
342
                    List<DefinedTermBase> terms;
343
                    if (!uuids.isEmpty()){
344
                        terms = termService.load(uuids, null);
345
                        Set<MeasurementUnit> measurementUnits = new HashSet<>();
346
                        for (DefinedTermBase term: terms){
347
                            if (term instanceof MeasurementUnit){
348
                                measurementUnits.add((MeasurementUnit)term);
349
                            }
350
                        }
351
                        character.getRecommendedMeasurementUnits().addAll(measurementUnits);
352
                    }
353
//                  statistical measures
354
                    character.getRecommendedStatisticalMeasures().clear();
355
                    uuids = new ArrayList<>();
356
                    for (TermDto termDto: characterDto.getRecommendedStatisticalMeasures()){
357
                        uuids.add(termDto.getUuid());
358
                    }
359
                    if (!uuids.isEmpty()){
360
                        terms = termService.load(uuids, null);
361
                        Set<StatisticalMeasure> statisticalMeasures = new HashSet<>();
362
                        for (DefinedTermBase term: terms){
363
                            if (term instanceof StatisticalMeasure){
364
                                statisticalMeasures.add((StatisticalMeasure)term);
365
                            }
366
                        }
367
                        character.getRecommendedStatisticalMeasures().addAll(statisticalMeasures);
368
                    }
369

    
370
//                  recommended mod. vocabularies
371
                    character.getRecommendedModifierEnumeration().clear();
372
                    uuids = new ArrayList<>();
373
                    for (TermVocabularyDto termDto: characterDto.getRecommendedModifierEnumeration()){
374
                        uuids.add(termDto.getUuid());
375
                    }
376
                    List<TermVocabulary> termVocs;
377
                    if (!uuids.isEmpty()){
378
                        termVocs = vocabularyService.load(uuids, null);
379
                        for (TermVocabulary voc: termVocs){
380
                            character.addRecommendedModifierEnumeration(voc);
381
                        }
382
                    }
383

    
384
//                  supported state vocabularies
385
                    character.getSupportedCategoricalEnumerations().clear();
386
                    uuids = new ArrayList<>();
387
                    for (TermVocabularyDto termDto: characterDto.getSupportedCategoricalEnumerations()){
388
                        uuids.add(termDto.getUuid());
389
                    }
390
                    if (!uuids.isEmpty()){
391
                        termVocs = vocabularyService.load(uuids, null);
392

    
393
                        for (TermVocabulary voc: termVocs){
394
                            character.addSupportedCategoricalEnumeration(voc);
395
                        }
396
                    }
397
                    node.setTerm(character);
398
                    mergeResult = dao.merge(node, true);
399
                    result.addUpdatedObject(mergeResult.getMergedEntity());
400

    
401
                }
402

    
403
            }
404

    
405
        }
406
        return result;
407
    }
408

    
409
    @Override
410
    public UpdateResult saveNewCharacterNodeDtoMap(Map<Character, CharacterNodeDto> dtos, UUID vocabularyUuid){
411
        UpdateResult result = new UpdateResult();
412
        UpdateResult resultLocal = new UpdateResult();
413
        for (Entry<Character, CharacterNodeDto> dtoEntry: dtos.entrySet()){
414
            resultLocal = createChildNode(dtoEntry.getValue().getParentUuid(), dtoEntry.getKey(), vocabularyUuid);
415
            dtoEntry.getValue().setUuid(resultLocal.getCdmEntity().getUuid());
416
            result.includeResult(resultLocal);
417
        }
418
        List<CharacterNodeDto> dtoList = new ArrayList<>(dtos.values());
419
        result.includeResult(saveCharacterNodeDtoList(dtoList));
420
        return result;
421

    
422
    }
423

    
424

    
425

    
426
}
(93-93/100)