Project

General

Profile

« Previous | Next » 

Revision 3c420001

Added by Andreas Müller over 2 years ago

ref #9801, ref #7980, ref #8871 remove aggregated source descriptions from aggregation and fix persistence issues

View differences:

cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/reference/CdmLinkSource.java
94 94
        }
95 95
    }
96 96

  
97
    //maybe only workaround #9801
98
    public boolean hasNoTarget(){
99
        return taxon == null && description == null;
100
    }
101

  
97 102
    public void setTarget(ICdmTarget target) {
98 103
        target = CdmBase.deproxy(target);
99
        if (target instanceof DescriptionBase<?>){
104
        if (target == null){
105
            setToNull(); //workaround? #9801
106
        }else if (target instanceof DescriptionBase<?>){
100 107
            this.description = (DescriptionBase<?>)target;
101 108
        }else if (target instanceof Taxon){
102 109
            this.taxon = (Taxon)target;
......
105 112
        }
106 113
    }
107 114

  
115
    //workaround? #9801
116
    private void setToNull() {
117
        this.description = null;
118
        this.taxon = null;
119
    }
120

  
108 121
// ********************************* CLONE **********************************/
109 122

  
110 123
    @Override
cdmlib-model/src/main/java/eu/etaxonomy/cdm/model/reference/OriginalSourceBase.java
226 226
        if (cdmTarget != null){
227 227
            this.cdmSource = CdmLinkSource.NewInstance(cdmTarget);
228 228
        }else{
229
            if (cdmSource != null){
230
                cdmSource.setTarget(null);  //as long as orphan-removal does not work #9801
231
            }
229 232
            this.cdmSource = null;
230 233
        }
231 234
    }
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/DescriptionServiceImpl.java
684 684
            }
685 685
        }
686 686
        if (deleteResult.isOk() ){
687
            CdmBase.deproxy(description);
687 688
        	if (description instanceof TaxonDescription){
688
        		TaxonDescription taxDescription = HibernateProxyHelper.deproxy(description, TaxonDescription.class);
689
        		TaxonDescription taxDescription = (TaxonDescription)description;
689 690
        		Taxon tax = taxDescription.getTaxon();
690
        		tax.removeDescription(taxDescription, true);
691
                deleteResult.addUpdatedObject(tax);
691
        		if (tax != null){
692
        		    tax.removeDescription(taxDescription, true);
693
        		    deleteResult.addUpdatedObject(tax);
694
        		}
692 695
        	}
693
        	else if (HibernateProxyHelper.isInstanceOf(description, SpecimenDescription.class)){
694
        	    SpecimenDescription specimenDescription = HibernateProxyHelper.deproxy(description, SpecimenDescription.class);
696
        	else if (description instanceof SpecimenDescription){
697
        	    SpecimenDescription specimenDescription = (SpecimenDescription)description;
695 698
        	    SpecimenOrObservationBase<?> specimen = specimenDescription.getDescribedSpecimenOrObservation();
696
        	    specimen.removeDescription(specimenDescription);
697
        	    deleteResult.addUpdatedObject(specimen);
699
        	    if (specimen != null){
700
        	        specimen.removeDescription(specimenDescription);
701
        	        deleteResult.addUpdatedObject(specimen);
702
        	    }
698 703
        	}
699 704

  
700 705
        	for (DescriptiveDataSet dataset : description.getDescriptiveDataSets()) {
......
735 740
                continue;
736 741
            } else if (ref instanceof DescriptionElementBase){
737 742
                continue;
743
            } else if (ref instanceof CdmLinkSource && ((CdmLinkSource)ref).hasNoTarget()) {
744
                continue; //maybe only workaround #9801
738 745
            }else {
739 746
                String message = "The description can't be completely deleted because it is referenced by " + ref.getUserFriendlyTypeName() ;
740 747
                result.setAbort();
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/description/DescriptionAggregationBase.java
23 23
import org.springframework.transaction.support.DefaultTransactionDefinition;
24 24

  
25 25
import eu.etaxonomy.cdm.api.application.ICdmRepository;
26
import eu.etaxonomy.cdm.api.service.DeleteResult;
26 27
import eu.etaxonomy.cdm.api.service.IClassificationService;
27 28
import eu.etaxonomy.cdm.api.service.IDescriptionService;
28 29
import eu.etaxonomy.cdm.api.service.IDescriptiveDataSetService;
......
283 284
    private void deleteDescriptionsToDelete(DescriptionAggregationBase<T, CONFIG>.ResultHolder resultHolder) {
284 285
        for (DescriptionBase<?> descriptionToDelete : resultHolder.descriptionsToDelete){
285 286
            if (descriptionToDelete.isPersited()){
286
                repository.getDescriptionService().delete(descriptionToDelete);
287
                getSession().flush(); // move to service method #9801
288
                DeleteResult result = repository.getDescriptionService().deleteDescription(descriptionToDelete);
289
                //TODO handle result somehow if not OK, but careful, descriptions may be linked >1x and therefore maybe deleted only after last link was removed
287 290
            }
288 291
        }
289 292
    }
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/description/StructuredDescriptionAggregation.java
41 41
import eu.etaxonomy.cdm.model.description.StatisticalMeasurementValue;
42 42
import eu.etaxonomy.cdm.model.description.TaxonDescription;
43 43
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
44
import eu.etaxonomy.cdm.model.reference.ICdmTarget;
45 44
import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
46 45
import eu.etaxonomy.cdm.model.taxon.Taxon;
47 46
import eu.etaxonomy.cdm.model.taxon.TaxonNode;
......
177 176
        //remove remaining sources-to-be-removed
178 177
        for (IdentifiableSource sourceToRemove : sourcesToRemove) {
179 178
            targetDescription.removeSource(sourceToRemove);
180
            ICdmTarget target = sourceToRemove.getCdmSource();
179
            ICdmBase target = CdmBase.deproxy(sourceToRemove.getCdmSource());
181 180
            if (target != null){
182
                if (target.isInstanceOf(DescriptionBase.class)){
181
                sourceToRemove.setCdmSource(null); //workaround for missing orphan removal #9801
182
                if (target instanceof DescriptionBase){
183 183
                    @SuppressWarnings("unchecked")
184 184
                    T descriptionToDelete = (T)target;
185
                    ((IDescribable<T>)descriptionToDelete.describedEntity()).removeDescription(descriptionToDelete);
186
                    structuredResultHolder.descriptionsToDelete.add(descriptionToDelete);
185
                    if (descriptionToDelete.isCloneForSource()){
186
                        //TODO maybe this is not really needed as it is later done anyway with .deltedDescription
187
                        //but currently this still leads to an re-saved by cascade exception
188
                        ((IDescribable<T>)descriptionToDelete.describedEntity()).removeDescription(descriptionToDelete);
189
                        structuredResultHolder.descriptionsToDelete.add(descriptionToDelete);
190
                    }
187 191
                }else if (target.isInstanceOf(Taxon.class)){
188 192
                    //nothing to do for now
189 193
                } else {
......
222 226
                T existingTargetDesc = CdmBase.deproxy((T)mergeCandidate.getCdmSource());
223 227
                mergeSourceDescription(existingTargetDesc, newTargetDesc);
224 228
                ((IDescribable<T>)existingTargetDesc.describedEntity()).addDescription(existingTargetDesc);
225
                ((IDescribable<T>)newTargetDesc.describedEntity()).removeDescription(newTargetDesc);
229
                if (!existingTargetDesc.equals(newTargetDesc)){
230
                    ((IDescribable<T>)newTargetDesc.describedEntity()).removeDescription(newTargetDesc);
231
                }
226 232
            }else if (newTarget instanceof Taxon){
227 233
                //nothing to do for now (we do not support reuse of sources linking to different taxa yet)
228 234
            }else{
......
312 318
    }
313 319

  
314 320
    private <T extends DescriptionBase<?>> T cloneNewSourceDescription(T newSourceDescription) {
321
        if (!getConfig().isCloneAggregatedSourceDescriptions() && newSourceDescription.isAggregatedStructuredDescription()){
322
            return newSourceDescription;
323
        }
315 324
        @SuppressWarnings("unchecked")
316 325
        T clonedDescription = (T)newSourceDescription.clone();
326
//        clonedDescription.removeSources();
317 327
        clonedDescription.removeDescriptiveDataSet(dataSet);
318 328
        clonedDescription.getTypes().add(DescriptionType.CLONE_FOR_SOURCE);
319 329
        clonedDescription.setTitleCache("Clone: " + clonedDescription.getTitleCache(), true);
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/description/StructuredDescriptionAggregationConfiguration.java
27 27

  
28 28
    boolean includeDefault = true;
29 29
    boolean includeLiterature = true;
30
    /**
31
     * If source mode is {@link AggregationSourceMode#DESCRIPTION} descriptions
32
     * are cloned as sources. This parameter defines if aggregated descriptions
33
     * being the sources for further aggregation should also be cloned or
34
     * can be handled as stable as usually they are not changing overtime
35
     * or stability is not a requirement.
36
     * TODO maybe we want to move it to base class
37
     * TODO maybe we need the same for non-aggregated descriptions
38
     * (generell or specific for specimen, literature and/or default descriptions).
39
     */
40
    boolean cloneAggregatedSourceDescriptions = false;
30 41

  
31 42
    private MissingMinimumMode missingMinimumMode = MissingMinimumMode.MinToZero;
32 43
    private MissingMaximumMode missingMaximumMode = MissingMaximumMode.MaxToMin;
......
102 113
    public void setMissingMaximumMode(MissingMaximumMode missingMaximumMode) {
103 114
        this.missingMaximumMode = missingMaximumMode;
104 115
    }
116

  
117
    public boolean isCloneAggregatedSourceDescriptions() {
118
        // TODO Auto-generated method stub
119
        return false;
120
    }
105 121
}
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/description/StructuredDescriptionAggregationTest.java
174 174
        UpdateResult result = engine.invoke(config, repository);
175 175
        verifyStatusOk(result);
176 176
        commitAndStartNewTransaction();
177
        verifyAggregatedDescription(new TestConfig());
177
        verifyAggregatedDescription(new TestConfig(config));
178 178

  
179 179
        addSomeDataToFirstAggregation();
180 180
        commitAndStartNewTransaction();
181
        verifyAggregatedDescription(new TestConfig().setWithAddedData());
181
        verifyAggregatedDescription(new TestConfig(config).setWithAddedData());
182 182

  
183 183
        // 2nd aggregation => should be same as originally as data was only added to aggregation to see if it is correctly deleted
184 184
        result = engine.invoke(config, repository);
185 185
        verifyStatusOk(result);
186 186
        commitAndStartNewTransaction();
187
        verifyAggregatedDescription(new TestConfig());
187
        verifyAggregatedDescription(new TestConfig(config));
188 188

  
189 189
        // reaggregate with an element having a feature not yet in the existing descriptions
190 190
        addNewFeature();
......
192 192
        result = engine.invoke(config, repository);
193 193
        verifyStatusOk(result);
194 194
        commitAndStartNewTransaction();
195
        verifyAggregatedDescription(new TestConfig().setWithFeature());
195
        verifyAggregatedDescription(new TestConfig(config).setWithFeature());
196 196

  
197 197
    }
198 198

  
......
233 233
        UpdateResult result = engine.invoke(config, repository);
234 234
        verifyStatusOk(result);
235 235
        commitAndStartNewTransaction();
236
        verifyAggregatedDescription(new TestConfig());
236
        verifyAggregatedDescription(new TestConfig(config));
237 237

  
238 238
        removeSomeDataFromFirstAggregation();
239 239
        commitAndStartNewTransaction();
240 240
        Assert.assertEquals("Should have 3 specimen desc, 1 literature desc, 2 individual association holder, "
241
                + "4 aggregated descriptions, 4 cloned specimen descriptions (still not deleted), (3 cloned aggregated descriptions?) = 17",
242
                17, descriptionService.count(null));
241
                + "4 aggregated descriptions, 4 cloned specimen descriptions (still not deleted), (0(3) cloned aggregated descriptions?) = 14",
242
                14, descriptionService.count(null));
243 243

  
244 244
        // 2nd aggregation
245 245
        result = engine.invoke(config, repository);
246 246
        verifyStatusOk(result);
247 247
        commitAndStartNewTransaction();
248
        verifyAggregatedDescription(new TestConfig().setWithRemoved());
248
        verifyAggregatedDescription(new TestConfig(config).setWithRemoved());
249 249
    }
250 250

  
251 251
    private void removeSomeDataFromFirstAggregation() {
......
348 348
        UpdateResult result = engine.invoke(config, repository);
349 349
        verifyStatusOk(result);
350 350
        commitAndStartNewTransaction();
351
        verifyAggregatedDescription(new TestConfig().setAggConfig(config));
351
        verifyAggregatedDescription(new TestConfig(config));
352 352

  
353 353
        config.setWithinTaxonSourceMode(AggregationSourceMode.DESCRIPTION);
354 354
        config.setToParentSourceMode(AggregationSourceMode.NONE);
355 355
        result = engine.invoke(config, repository);
356 356
        verifyStatusOk(result);
357 357
        commitAndStartNewTransaction();
358
        verifyAggregatedDescription(new TestConfig().setAggConfig(config));
358
        verifyAggregatedDescription(new TestConfig(config));
359 359

  
360 360
        config.setWithinTaxonSourceMode(AggregationSourceMode.NONE);
361 361
        config.setToParentSourceMode(AggregationSourceMode.DESCRIPTION);
362 362
        result = engine.invoke(config, repository);
363 363
        verifyStatusOk(result);
364 364
        commitAndStartNewTransaction();
365
        verifyAggregatedDescription(new TestConfig().setAggConfig(config));
365
        verifyAggregatedDescription(new TestConfig(config));
366 366

  
367 367
        config.setWithinTaxonSourceMode(AggregationSourceMode.DESCRIPTION);
368 368
        config.setToParentSourceMode(AggregationSourceMode.TAXON);
369 369
        result = engine.invoke(config, repository);
370 370
        verifyStatusOk(result);
371 371
        commitAndStartNewTransaction();
372
        verifyAggregatedDescription(new TestConfig().setAggConfig(config));
372
        verifyAggregatedDescription(new TestConfig(config));
373 373

  
374 374
        config.setWithinTaxonSourceMode(AggregationSourceMode.NONE);
375 375
        config.setToParentSourceMode(AggregationSourceMode.TAXON);
376 376
        result = engine.invoke(config, repository);
377 377
        verifyStatusOk(result);
378 378
        commitAndStartNewTransaction();
379
        verifyAggregatedDescription(new TestConfig().setAggConfig(config));
379
        verifyAggregatedDescription(new TestConfig(config));
380 380

  
381 381
        config.setWithinTaxonSourceMode(AggregationSourceMode.ALL);
382 382
        config.setToParentSourceMode(AggregationSourceMode.DESCRIPTION);
......
425 425
        UpdateResult result = engine.invoke(config, repository);
426 426
        commitAndStartNewTransaction();
427 427
        verifyStatusOk(result);
428
        verifyAggregatedDescription(new TestConfig());
428
        verifyAggregatedDescription(new TestConfig(config));
429 429

  
430 430
        config.setIncludeLiterature(true);
431 431

  
432 432
        result = engine.invoke(config, repository);
433 433
        commitAndStartNewTransaction();
434 434
        verifyStatusOk(result);
435
        verifyAggregatedDescription(new TestConfig().setWithLiterature());
435
        verifyAggregatedDescription(new TestConfig(config));
436 436
    }
437 437

  
438 438
    private void verifyStatusOk(UpdateResult result) {
......
472 472

  
473 473
    private class TestConfig{
474 474
        boolean withAddedData;
475
        boolean withLiterature;
476 475
        boolean withRemovedData;
477 476
        boolean withFeature;
478
        AggregationSourceMode withinTaxonSourceMode = AggregationSourceMode.DESCRIPTION;
479
        AggregationSourceMode toParentSourceMode = AggregationSourceMode.DESCRIPTION;
477
        final boolean withLiterature;
478
        final boolean cloneAggSourceDesc;
479
        final AggregationSourceMode withinTaxonSourceMode;
480
        final AggregationSourceMode toParentSourceMode;
480 481

  
481
        private TestConfig setWithAddedData() {withAddedData = true; return this;}
482
        private TestConfig setWithLiterature() {withLiterature = true; return this;}
483
        private TestConfig setWithRemoved() {withRemovedData = true; return this;}
484
        private TestConfig setWithFeature() {withFeature = true; return this;}
485 482

  
486
        public TestConfig setAggConfig(StructuredDescriptionAggregationConfiguration config) {
483
        private TestConfig(StructuredDescriptionAggregationConfiguration config) {
487 484
            withinTaxonSourceMode = config.getWithinTaxonSourceMode();
488 485
            toParentSourceMode = config.getToParentSourceMode();
489
            return this;
486
            cloneAggSourceDesc = config.isCloneAggregatedSourceDescriptions();
487
            withLiterature = config.isIncludeLiterature();
490 488
        }
489
        private TestConfig setWithAddedData() {withAddedData = true; return this;}
490
        private TestConfig setWithRemoved() {withRemovedData = true; return this;}
491
        private TestConfig setWithFeature() {withFeature = true; return this;}
491 492
    }
492 493

  
493 494
    private void verifyAggregatedDescription(TestConfig config) {
......
499 500
        boolean withFeature = config.withFeature;
500 501
        boolean isToParentNone = config.toParentSourceMode.isNone();
501 502
        boolean isToParentTaxon = config.toParentSourceMode.isTaxon();
503
        boolean cloneAggSourceDesc = config.cloneAggSourceDesc;
504

  
502 505
        int intDel = withRemovedData? -1 : 0;
503 506
        int intLit = withLiterature? 1 : 0;
504 507

  
......
562 565
        if (nToParentDescs > 0){
563 566
            Assert.assertEquals(1, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_ALPINA_UUID).size());
564 567
            Assert.assertEquals(1, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_ADENOPHORA_UUID).size());
565
            Assert.assertNotEquals(aggrDescLapsanaCommunisAlpina, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_ALPINA_UUID).get(0));
568
            if (cloneAggSourceDesc){
569
                Assert.assertNotEquals(aggrDescLapsanaCommunisAlpina, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_ALPINA_UUID).get(0));
570
            }else{
571
                Assert.assertEquals(aggrDescLapsanaCommunisAlpina, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_ALPINA_UUID).get(0));
572
            }
566 573
        }else if (isToParentTaxon){
567 574
            Map<UUID, List<Taxon>> taxonToTaxonSourceMap = getSourceTaxonMap(aggrDescLapsanaCommunis);
568 575
            Assert.assertEquals(1, taxonToTaxonSourceMap.get(T_LAPSANA_COMMUNIS_ALPINA_UUID).size());
......
587 594
        Assert.assertEquals(nToParentDescs, taxonDescriptionMap.size());
588 595
        if (nToParentDescs > 0){
589 596
            Assert.assertEquals(1, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_UUID).size());
590
            Assert.assertNotEquals(aggrDescLapsanaCommunis, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_UUID).get(0));
597
            if (cloneAggSourceDesc){
598
                Assert.assertNotEquals(aggrDescLapsanaCommunis, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_UUID).get(0));
599
            }else{
600
                Assert.assertEquals(aggrDescLapsanaCommunis, taxonDescriptionMap.get(T_LAPSANA_COMMUNIS_UUID).get(0));
601
            }
602

  
591 603
        }else if (isToParentTaxon){
592 604
            Map<UUID, List<Taxon>> taxonToTaxonSourceMap = getSourceTaxonMap(aggrDescLapsana);
593 605
            Assert.assertEquals(1, taxonToTaxonSourceMap.get(T_LAPSANA_COMMUNIS_UUID).size());
......
595 607
        }
596 608

  
597 609
        //total description count
598
        nCloned = (isToParentNone || isToParentTaxon ? 0 : 3) + (isWithinNone ? 0 : 4);
610
        nCloned = (isToParentNone || isToParentTaxon || !cloneAggSourceDesc ? 0 : 3) + (isWithinNone ? 0 : 4);
599 611
        Assert.assertEquals("Should have 4 specimen desc, 1 literature desc, 2 individual association holder, "
600 612
                + "4 aggregated descriptions, 4/0 cloned specimen descriptions, (3/4/0 cloned aggregated descriptions?) = 18/19",
601 613
                11+nCloned+intLit+(intDel*2), descriptionService.count(null));

Also available in: Unified diff