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
|
}
|