Project

General

Profile

Download (22.3 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.HashMap;
14
import java.util.HashSet;
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.DataChangeNoRollbackException;
29
import eu.etaxonomy.cdm.api.service.exception.ReferencedObjectUndeletableException;
30
import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
31
import eu.etaxonomy.cdm.model.common.CdmBase;
32
import eu.etaxonomy.cdm.model.description.Character;
33
import eu.etaxonomy.cdm.model.description.Feature;
34
import eu.etaxonomy.cdm.model.description.FeatureState;
35
import eu.etaxonomy.cdm.model.description.MeasurementUnit;
36
import eu.etaxonomy.cdm.model.description.State;
37
import eu.etaxonomy.cdm.model.description.StatisticalMeasure;
38
import eu.etaxonomy.cdm.model.term.DefinedTerm;
39
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
40
import eu.etaxonomy.cdm.model.term.Representation;
41
import eu.etaxonomy.cdm.model.term.TermNode;
42
import eu.etaxonomy.cdm.model.term.TermTree;
43
import eu.etaxonomy.cdm.model.term.TermType;
44
import eu.etaxonomy.cdm.model.term.TermVocabulary;
45
import eu.etaxonomy.cdm.persistence.dao.term.ITermNodeDao;
46
import eu.etaxonomy.cdm.persistence.dto.CharacterDto;
47
import eu.etaxonomy.cdm.persistence.dto.CharacterNodeDto;
48
import eu.etaxonomy.cdm.persistence.dto.FeatureStateDto;
49
import eu.etaxonomy.cdm.persistence.dto.MergeResult;
50
import eu.etaxonomy.cdm.persistence.dto.TermDto;
51
import eu.etaxonomy.cdm.persistence.dto.TermNodeDto;
52
import eu.etaxonomy.cdm.persistence.dto.TermVocabularyDto;
53
import eu.etaxonomy.cdm.persistence.query.OrderHint;
54

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

    
65
    @SuppressWarnings("unused")
66
    private static final Logger logger = Logger.getLogger(TermNodeServiceImpl.class);
67

    
68
	@Override
69
    @Autowired
70
	protected void setDao(ITermNodeDao dao) {
71
		this.dao = dao;
72
	}
73

    
74
	@Autowired
75
    private ITermService termService;
76

    
77
	@Autowired
78
	private IVocabularyService vocabularyService;
79

    
80
	@Override
81
    public List<TermNode> list(TermType termType, Integer limit, Integer start,
82
	        List<OrderHint> orderHints, List<String> propertyPaths){
83
	    return dao.list(termType, limit, start, orderHints, propertyPaths);
84
	}
85

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

    
97
	        if (config.getChildHandling().equals(ChildHandling.DELETE)){
98

    
99
	            for (TermNode<?> child: children){
100
	                deleteNode(child.getUuid(), config);
101
	               // node.removeChild(child);
102
	            }
103
	            if (parent != null){
104
	                parent.removeChild(node);
105
	            }
106

    
107
	        } else{
108

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

    
122
	         dao.delete(node);
123
	         result.addDeletedObject(node);
124
	         if(parent!=null){
125
	             result.addUpdatedObject(parent);
126
	         }
127
	         if (config.isDeleteElement()){
128
	             DefinedTermBase<?> term = node.getTerm();
129
                 termService.delete(term.getUuid());
130
                 result.addDeletedObject(term);
131
             }
132
	     }
133
	     return result;
134
	 }
135

    
136
	 private UpdateResult createChildNode(UUID parentNodeUUID, UUID nodeUuid, DefinedTermBase term, UUID vocabularyUuid){
137
	     UpdateResult result =  createChildNode(parentNodeUUID, term, vocabularyUuid);
138
	     result.getCdmEntity().setUuid(nodeUuid);
139
	     return result;
140
	 }
141

    
142

    
143
	 @Override
144
     public UpdateResult createChildNode(UUID parentNodeUuid, DefinedTermBase term, UUID vocabularyUuid){
145
	     TermVocabulary vocabulary = vocabularyService.load(vocabularyUuid);
146

    
147
	     vocabulary.addTerm(term);
148
	     vocabularyService.save(vocabulary);
149
	     return addChildNode(parentNodeUuid, term.getUuid());
150
	 }
151

    
152
     @Override
153
     public UpdateResult addChildNode(UUID nodeUUID, UUID termChildUuid){
154
         return addChildNode(nodeUUID, termChildUuid, 0);
155
     }
156

    
157
	 @Override
158
	 public UpdateResult addChildNode(UUID nodeUUID, UUID termChildUuid, int position){
159
	     UpdateResult result = new UpdateResult();
160

    
161
	     TermNode node = load(nodeUUID);
162
	     if (node == null){
163
	         result.setError();
164
             result.addException(new Exception("The parent node does not exist."));
165
             return result;
166
	     }
167
	     DefinedTermBase child = HibernateProxyHelper.deproxy(termService.load(termChildUuid), DefinedTermBase.class);
168

    
169
	     if(node != null && node.getGraph() != null && !node.getGraph().isAllowDuplicates() && node.getGraph().getDistinctTerms().contains(child)){
170
	         result.setError();
171
	         result.addException(new Exception("This term tree does not allow duplicate terms."));
172
	         return result;
173
	     }
174

    
175
	     TermNode childNode;
176
         if(position<0) {
177
             childNode = node.addChild(child);
178
         }
179
         else{
180
             childNode = node.addChild(child, position);
181
         }
182
         save(childNode);
183
         result.addUpdatedObject(node);
184
         result.setCdmEntity(childNode);
185
         return result;
186
     }
187

    
188
	@Override
189
	public DeleteResult isDeletable(UUID nodeUuid, TermNodeDeletionConfigurator config){
190
	    TermNode<Feature> node = load(nodeUuid);
191
	    DeleteResult result = new DeleteResult();
192
        if (node == null){
193
            result.addException(new DataChangeNoRollbackException("The object is not available anymore."));
194
            result.setAbort();
195
            return result;
196
        }
197
	    Set<CdmBase> references = commonService.getReferencingObjectsForDeletion(node);
198
	    for (CdmBase ref:references){
199
	        if (ref instanceof TermNode){
200
	            break;
201
	        }
202
	        if (ref instanceof TermTree){
203
	            TermTree<Feature> refTree = HibernateProxyHelper.deproxy(ref, TermTree.class);
204
	            if (node.getGraph().equals((refTree))){
205
	                break;
206
	            }
207
	        }
208
	        result.setAbort();
209
	        result.addException(new ReferencedObjectUndeletableException("The featureNode is referenced by " + ref.getUserFriendlyDescription() +" with id " +ref.getId()));
210
	    }
211
	    return result;
212
	}
213

    
214
    @Override
215
    public UpdateResult moveNode(UUID movedNodeUuid, UUID targetNodeUuid, int position) {
216
        UpdateResult result = new UpdateResult();
217
        List<String> propertyPaths = new ArrayList<>();
218
        propertyPaths.add("parent");
219
        propertyPaths.add("parent.children");
220
        propertyPaths.add("children");
221
        TermNode test = load(movedNodeUuid, propertyPaths);
222
        TermNode movedNode = CdmBase.deproxy(load(movedNodeUuid, propertyPaths), TermNode.class);
223
        TermNode<?> targetNode = CdmBase.deproxy(load(targetNodeUuid, propertyPaths));
224
        TermNode<?> parent = CdmBase.deproxy(movedNode.getParent());
225
        parent.removeChild(movedNode);
226
        if(position < 0){
227
            targetNode.addChild(movedNode);
228
        }
229
        else{
230
            targetNode.addChild(movedNode, position);
231
        }
232
        result.addUpdatedObject(targetNode);
233
        result.addUpdatedObject(parent);
234
        result.setCdmEntity(movedNode);
235
        return result;
236
    }
237

    
238
    @Override
239
    public UpdateResult moveNode(UUID movedNodeUuid, UUID targetNodeUuid) {
240
        return moveNode(movedNodeUuid, targetNodeUuid, -1);
241
    }
242

    
243
    @Override
244
    public UpdateResult saveTermNodeDtoList(List<TermNodeDto> dtos){
245
        UpdateResult result = new UpdateResult();
246
        List<UUID> uuids = new ArrayList<>();
247
        dtos.stream().forEach(dto -> uuids.add(dto.getUuid()));
248
        List<TermNode> nodes = dao.list(uuids, null, 0, null, null);
249
        //check all attributes for changes and adapt
250
        for (TermNode<?> node: nodes){
251
            for (TermNodeDto dto: dtos){
252

    
253
                if (dto.getUuid().equals(node.getUuid())){
254
    //                only node changes, everything else will be handled by the operations/service methods
255
                    updateFeatureStates(node, dto, true);
256
                    updateFeatureStates(node, dto, false);
257

    
258
                }
259
                MergeResult<TermNode> mergeResult = dao.merge(node, true);
260
                result.addUpdatedObject(mergeResult.getMergedEntity());
261
            }
262
        }
263
        return result;
264
    }
265

    
266
    /**
267
     * @param node
268
     * @param dto
269
     */
270
    private void updateFeatureStates(TermNode<?> node, TermNodeDto dto, boolean inApplicable) {
271
        Map<FeatureState, FeatureStateDto> changeState = new HashMap<>();
272
        Set<FeatureStateDto> newStates = new HashSet<>();
273
        Set<FeatureState> deleteState = new HashSet<>();
274
        boolean stillExist = false;
275
        Set<FeatureState> setToUpdate = null;
276
        Set<FeatureStateDto> setForUpdate = null;
277
        if (inApplicable){
278
            setToUpdate = node.getInapplicableIf();
279
            setForUpdate = dto.getInapplicableIf();
280
        }else{
281
            setToUpdate = node.getOnlyApplicableIf();
282
            setForUpdate = dto.getOnlyApplicableIf();
283
        }
284
        for (FeatureState featureState: setToUpdate){
285
            stillExist = false;
286
            for (FeatureStateDto featureStateDto: setForUpdate){
287
                if (featureStateDto.getUuid() != null && featureStateDto.getUuid().equals(featureState.getUuid())){
288
                    stillExist = true;
289
                    if (featureStateDto.getFeature().getUuid().equals(featureState.getFeature().getUuid()) && featureStateDto.getState().getUuid().equals(featureState.getState().getUuid())){
290
                        //do nothing
291
                    }else{
292
                        changeState.put(featureState, featureStateDto);
293
                    }
294
                    break;
295
                }
296
            }
297
            if (!stillExist){
298
                deleteState.add(featureState);
299
            }
300

    
301
        }
302

    
303
        for (FeatureStateDto featureStateDto: setForUpdate){
304
            stillExist = false;
305
            if (featureStateDto.getUuid() == null){
306
                newStates.add(featureStateDto);
307
            }else{
308
                for (FeatureState featureState: setToUpdate){
309
                    if (featureStateDto.getUuid() != null && featureStateDto.getUuid().equals(featureState.getUuid())){
310
                        stillExist = true;
311
                        break;
312
                    }
313
                }
314
                if (!stillExist){
315
                    newStates.add(featureStateDto);
316
                }
317
            }
318

    
319
        }
320
        if (inApplicable){
321
            node.getInapplicableIf().removeAll(deleteState);
322
        }else{
323
            node.getOnlyApplicableIf().removeAll(deleteState);
324
        }
325
        for (Entry<FeatureState, FeatureStateDto> change: changeState.entrySet()){
326
            if (!change.getKey().getFeature().getUuid().equals(change.getValue().getFeature().getUuid())){
327
                DefinedTermBase term = termService.load(change.getValue().getFeature().getUuid());
328
                if (term instanceof Feature){
329
                    Feature feature = HibernateProxyHelper.deproxy(term, Feature.class);
330
                    change.getKey().setFeature(feature);
331
                }
332

    
333
            }
334
            if (!change.getKey().getState().getUuid().equals(change.getValue().getState().getUuid())){
335
                DefinedTermBase term = termService.load(change.getValue().getState().getUuid());
336
                if (term instanceof State){
337
                    State state = HibernateProxyHelper.deproxy(term, State.class);
338
                    change.getKey().setState(state);
339
                }
340

    
341
            }
342
            if (inApplicable){
343
                node.getInapplicableIf().add(change.getKey());
344
            }else{
345
                node.getOnlyApplicableIf().add(change.getKey());
346
            }
347
        }
348
        for (FeatureStateDto stateDto: newStates){
349
            Feature feature = null;
350
            State state = null;
351
            DefinedTermBase term = termService.find(stateDto.getFeature().getUuid());
352
            term = HibernateProxyHelper.deproxy(term);
353
            if (term instanceof Character){
354
                feature = HibernateProxyHelper.deproxy(term, Character.class);
355
            }
356
            DefinedTermBase termState = termService.load(stateDto.getState().getUuid());
357
            if (termState instanceof State){
358
                state = HibernateProxyHelper.deproxy(termState, State.class);
359
            }
360
            FeatureState newState = FeatureState.NewInstance(feature, state);
361
            if (inApplicable){
362
                node.getInapplicableIf().add(newState);
363
            }else{
364
                node.getOnlyApplicableIf().add(newState);
365
            }
366
        }
367
    }
368

    
369
    @Override
370
    public UpdateResult saveCharacterNodeDtoList(List<CharacterNodeDto> dtos){
371
        MergeResult<TermNode> mergeResult;
372
        UpdateResult result = new UpdateResult();
373
        List<UUID> nodeUuids = new ArrayList<>();
374

    
375
        dtos.stream().forEach(dto -> nodeUuids.add(dto.getUuid()));
376
        List<TermNode> nodes = dao.list(nodeUuids, null, 0, null, null);
377
        //check all attributes for changes and adapt
378
        for (TermNode<Character> node: nodes){
379
            for (CharacterNodeDto dto: dtos){
380
    //            TermNodeDto dto = dtoIterator.next();
381
                if (dto.getUuid().equals(node.getUuid())){
382
                    updateFeatureStates(node, dto, true);
383
                    updateFeatureStates(node, dto, false);
384
//                    if (!dto.getInapplicableIf().equals(node.getInapplicableIf())){
385
//                        node.getInapplicableIf().clear();
386
//                        node.getInapplicableIf().addAll(dto.getInapplicableIf());
387
//                    }
388
//                    if (!dto.getOnlyApplicableIf().equals(node.getOnlyApplicableIf())){
389
//                        node.getOnlyApplicableIf().clear();
390
//                        node.getOnlyApplicableIf().addAll(dto.getOnlyApplicableIf());
391
//                    }
392

    
393
                    Character character = null;
394
                    CharacterDto characterDto = (CharacterDto) dto.getTerm();
395
                    character = HibernateProxyHelper.deproxy(node.getTerm(), Character.class);
396
                    if (characterDto.getRatioTo() != null){
397
                        TermNode ratioToStructure = this.load(characterDto.getRatioTo().getUuid());
398
                        character.setRatioToStructure(ratioToStructure);
399
                    }else{
400
                        character.setRatioToStructure(null);
401
                    }
402

    
403
                    //supportsXXX
404
                    //TODO add all other supportsXXX (6 are missing)
405
                    character.setSupportsCategoricalData(characterDto.isSupportsCategoricalData());
406
                    character.setSupportsQuantitativeData(characterDto.isSupportsQuantitativeData());
407

    
408
                    //availableForXXX
409
                    character.setAvailableForTaxon(characterDto.isAvailableForTaxon());
410
                    character.setAvailableForOccurrence(characterDto.isAvailableForOccurrence());
411
                    character.setAvailableForTaxonName(characterDto.isAvailableForTaxonName());
412

    
413
//                  representations
414
                    for (Representation rep: dto.getTerm().getRepresentations()){
415
                        Representation oldRep = character.getRepresentation(rep.getLanguage());
416
                        if (oldRep == null){
417
                            oldRep = new Representation();
418
                            oldRep.setLanguage(rep.getLanguage());
419
                            character.addRepresentation(oldRep);
420
                        }
421
                        oldRep.setLabel(rep.getLabel());
422
                        oldRep.setAbbreviatedLabel(rep.getAbbreviatedLabel());
423
                        oldRep.setText(rep.getText());
424
                        oldRep.setPlural(rep.getPlural());
425
                    }
426
                    Set<Representation> deleteRepresentations = new HashSet<>();
427
                    if (character.getRepresentations().size() > dto.getTerm().getRepresentations().size()){
428
                        for (Representation rep: character.getRepresentations()){
429
                            if(dto.getTerm().getRepresentation(rep.getLanguage()) == null){
430
                                deleteRepresentations.add(rep);
431
                            }
432
                        }
433
                    }
434

    
435
                    if (!deleteRepresentations.isEmpty()){
436
                        for (Representation rep: deleteRepresentations){
437
                            character.removeRepresentation(rep);
438
                        }
439
                    }
440

    
441
//                  structural modifier
442
                    if (characterDto.getStructureModifier() != null){
443
                        DefinedTerm structureModifier = (DefinedTerm) termService.load(characterDto.getStructureModifier().getUuid());
444
                        character.setStructureModifier(structureModifier);
445
                    }else{
446
                        character.setStructureModifier(null);
447
                    }
448
//                  recommended measurement units
449
                    character.getRecommendedMeasurementUnits().clear();
450
                    List<UUID> uuids = new ArrayList<>();
451
                    for (TermDto termDto: characterDto.getRecommendedMeasurementUnits()){
452
                        uuids.add(termDto.getUuid());
453
                    }
454
                    List<DefinedTermBase> terms;
455
                    if (!uuids.isEmpty()){
456
                        terms = termService.load(uuids, null);
457
                        Set<MeasurementUnit> measurementUnits = new HashSet<>();
458
                        for (DefinedTermBase term: terms){
459
                            if (term instanceof MeasurementUnit){
460
                                measurementUnits.add((MeasurementUnit)term);
461
                            }
462
                        }
463
                        character.getRecommendedMeasurementUnits().addAll(measurementUnits);
464
                    }
465
//                  statistical measures
466
                    character.getRecommendedStatisticalMeasures().clear();
467
                    uuids = new ArrayList<>();
468
                    for (TermDto termDto: characterDto.getRecommendedStatisticalMeasures()){
469
                        uuids.add(termDto.getUuid());
470
                    }
471
                    if (!uuids.isEmpty()){
472
                        terms = termService.load(uuids, null);
473
                        Set<StatisticalMeasure> statisticalMeasures = new HashSet<>();
474
                        for (DefinedTermBase<?> term: terms){
475
                            if (term instanceof StatisticalMeasure){
476
                                statisticalMeasures.add((StatisticalMeasure)term);
477
                            }
478
                        }
479
                        character.getRecommendedStatisticalMeasures().addAll(statisticalMeasures);
480
                    }
481

    
482
//                  recommended mod. vocabularies
483
                    character.getRecommendedModifierEnumeration().clear();
484
                    uuids = new ArrayList<>();
485
                    for (TermVocabularyDto termDto: characterDto.getRecommendedModifierEnumeration()){
486
                        uuids.add(termDto.getUuid());
487
                    }
488
                    List<TermVocabulary> termVocs;
489
                    if (!uuids.isEmpty()){
490
                        termVocs = vocabularyService.load(uuids, null);
491
                        for (TermVocabulary voc: termVocs){
492
                            character.addRecommendedModifierEnumeration(voc);
493
                        }
494
                    }
495

    
496
//                  supported state vocabularies
497
                    character.getSupportedCategoricalEnumerations().clear();
498
                    uuids = new ArrayList<>();
499
                    for (TermVocabularyDto termDto: characterDto.getSupportedCategoricalEnumerations()){
500
                        uuids.add(termDto.getUuid());
501
                    }
502
                    if (!uuids.isEmpty()){
503
                        termVocs = vocabularyService.load(uuids, null);
504

    
505
                        for (TermVocabulary voc: termVocs){
506
                            character.addSupportedCategoricalEnumeration(voc);
507
                        }
508
                    }
509
                    node.setTerm(character);
510
                    mergeResult = dao.merge(node, true);
511
                    result.addUpdatedObject(mergeResult.getMergedEntity());
512
                }
513
            }
514
        }
515
        return result;
516
    }
517

    
518
    @Override
519
    public UpdateResult saveNewCharacterNodeDtoMap(Map<Character, CharacterNodeDto> dtos, UUID vocabularyUuid){
520
        UpdateResult result = new UpdateResult();
521
        UpdateResult resultLocal = new UpdateResult();
522
        for (Entry<Character, CharacterNodeDto> dtoEntry: dtos.entrySet()){
523
            resultLocal = createChildNode(dtoEntry.getValue().getParentUuid(), dtoEntry.getKey(), vocabularyUuid);
524
            dtoEntry.getValue().setUuid(resultLocal.getCdmEntity().getUuid());
525
            result.includeResult(resultLocal);
526
        }
527
        List<CharacterNodeDto> dtoList = new ArrayList<>(dtos.values());
528
        result.includeResult(saveCharacterNodeDtoList(dtoList));
529
        return result;
530
    }
531
}
(88-88/95)