Project

General

Profile

« Previous | Next » 

Revision 4d8fec30

Added by Andreas Müller almost 3 years ago

fix #9858 add updatedObjects to aggregation result for aggregated descriptions

View differences:

cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/description/DescriptionAggregationBase.java
94 94
    protected DeleteResult doInvoke() {
95 95

  
96 96
        try {
97
            //TODO FIXME use UpdateResult
98

  
99 97
            double start = System.currentTimeMillis();
100 98
            IProgressMonitor monitor = getConfig().getMonitor();
101 99

  
......
153 151
            logger.info("Time elapsed for invoking task(): " + (end - start) / (1000) + "s");
154 152

  
155 153
            done();
156
            return getResult();
157 154
        } catch (Exception e) {
158 155
            getResult().addException(new RuntimeException("Unhandled error during doInvoke", e));
159
            return getResult();
160 156
        }
157
        return getResult();
161 158
    }
162 159

  
163 160
    private DeleteResult handleException(Exception e, String unhandledMessage) {
......
286 283
        }
287 284

  
288 285
        //persist
289
        mergeAggregationResultIntoTargetDescription(targetDescription, resultHolder);
290
        removeDescriptionIfEmpty(targetDescription, resultHolder);  //AM: necessary? Seems to be done in addAggregationResultToDescription() already...
286
        boolean updated = mergeAggregationResultIntoTargetDescription(targetDescription, resultHolder);
287
        if (updated){
288
            getResult().addUpdatedObject(targetDescription);
289
        }
290
        removeDescriptionIfEmpty(targetDescription, resultHolder);
291 291
        deleteDescriptionsToDelete(resultHolder);
292 292
    }
293 293

  
......
300 300
                getSession().flush(); // move to service method #9801
301 301
                DeleteResult descriptionDeleteResult = repository.getDescriptionService().deleteDescription(descriptionToDelete);
302 302
                //TODO handle result somehow if not OK, but careful, descriptions may be linked >1x and therefore maybe deleted only after last link was removed
303
                this.getResult().includeResult(descriptionDeleteResult, true);
303
                if (descriptionDeleteResult.getDeletedObjects().contains(descriptionToDelete) && descriptionToDelete.isPersited()){
304
                    this.getResult().addDeletedObject(descriptionToDelete);
305
                }
306
//                this.getResult().includeResult(descriptionDeleteResult, true);
304 307
            }
305 308
        }
306 309
    }
......
320 323
     * Removes description elements not needed anymore from their description and
321 324
     * updates the {@link DeleteResult}.
322 325
     */
323
    protected void handleDescriptionElementsToRemove(TaxonDescription targetDescription,
326
    protected boolean handleDescriptionElementsToRemove(TaxonDescription targetDescription,
324 327
            Set<? extends DescriptionElementBase> elementsToRemove) {
328
        boolean updated = false;
325 329
        //remove all elements not needed anymore
326 330
        for(DescriptionElementBase elementToRemove : elementsToRemove){
327 331
            targetDescription.removeElement(elementToRemove);
328 332
            //AM: do we really want to add each element to the deleteResult?
329
            this.getResult().addDeletedObject(elementToRemove);
333
            //this.getResult().addDeletedObject(elementToRemove);
334
            updated |= elementToRemove.isPersited();
330 335
        }
336
        return updated;
331 337
    }
332 338

  
333 339
    /**
334 340
     * Adds the temporary aggregated data (resultHolder) to the description.
335 341
     * Tries to reuse existing data if possible.
336 342
     */
337
    protected abstract void mergeAggregationResultIntoTargetDescription(TaxonDescription targetDescription,
343
    protected abstract boolean mergeAggregationResultIntoTargetDescription(TaxonDescription targetDescription,
338 344
            ResultHolder resultHolder);
339 345

  
340 346
    protected abstract void aggregateToParentTaxon(TaxonNode taxonNode, ResultHolder resultHolder,
......
369 375

  
370 376
        // create a new one
371 377
        TaxonDescription newDescription = createNewDescription(taxon);
372

  
373
        //TODO maybe not necessary here as the new description only will be kept if not empty
374
        //(otherwise they could end up in updated and deleted objects which is unwanted)
375
        getResult().addUpdatedObject(newDescription);
376 378
        return newDescription;
377 379
    }
378 380

  
......
392 394
            for(DescriptionElementBase descriptionElement : deleteCandidates) {
393 395
                aggregationDescription.removeElement(descriptionElement);
394 396
                getDescriptionService().deleteDescriptionElement(descriptionElement);
395
                getResult().addDeletedObject(descriptionElement);
397
                if (descriptionElement.isPersited()){
398
                    getResult().addDeletedObject(descriptionElement);
399
                }
396 400
            }
397 401
            getDescriptionService().saveOrUpdate(aggregationDescription);
398 402
        }
399 403
    }
400 404

  
401
    protected <S extends DescriptionElementBase, TE extends DefinedTermBase<?>> void mergeDescriptionElements(
405
    protected <S extends DescriptionElementBase, TE extends DefinedTermBase<?>> boolean mergeDescriptionElements(
402 406
            TaxonDescription targetDescription, Map<TE, S> newElementsMap, Class<S> debClass) {
403 407

  
408
        boolean updated = false;
409

  
404 410
        //init elements to remove
405 411
        Set<DescriptionElementBase> elementsToRemove = new HashSet<>(
406 412
                targetDescription.getElements().stream()
......
424 430
            //if there is no element for this character in old data, add the new element for this character to the target description (otherwise reuse old element)
425 431
            if (elementToStay == null){
426 432
                targetDescription.addElement(newElement);
433
                updated = true;
427 434
            }else{
428 435
                elementsToRemove.remove(elementToStay);
429
                mergeDescriptionElement(elementToStay, newElement);
436
                updated |= mergeDescriptionElement(elementToStay, newElement);
430 437
            }
431 438
        }
432 439

  
433
        handleDescriptionElementsToRemove(targetDescription, elementsToRemove);
440
        updated |= handleDescriptionElementsToRemove(targetDescription, elementsToRemove);
441
        return updated;
434 442
    }
435 443

  
436 444
    /**
437 445
     * Merges a new (temporary description element into an existing one)
438 446
     */
439 447
    protected abstract <S extends DescriptionElementBase>
440
            void mergeDescriptionElement(S targetElement, S newElement);
448
            boolean mergeDescriptionElement(S targetElement, S newElement);
449

  
450
    protected boolean mergeSourcesForDescriptionElements(DescriptionElementBase deb,
451
            Set<DescriptionElementSource> newSources) {
441 452

  
442
    protected void mergeSourcesForDescriptionElements(DescriptionElementBase deb, Set<DescriptionElementSource> newSources) {
453
        boolean updated = false;
443 454
        Set<DescriptionElementSource> toDeleteSources = new HashSet<>(deb.getSources());
444 455
        for(DescriptionElementSource newSource : newSources) {
445 456
            boolean contained = false;
......
453 464
            if(!contained) {
454 465
                try {
455 466
                    deb.addSource(newSource.clone());
467
                    updated = true;
456 468
                } catch (CloneNotSupportedException e) {
457 469
                    // should never happen
458 470
                    throw new RuntimeException(e);
......
461 473
        }
462 474
        for (DescriptionElementSource toDeleteSource : toDeleteSources){
463 475
            deb.removeSource(toDeleteSource);
476
            updated |= toDeleteSource.isPersited();
464 477
        }
478
        return updated;
465 479
    }
466 480

  
467 481
    protected abstract TaxonDescription createNewDescription(Taxon taxon);
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/description/DistributionAggregation.java
24 24
import org.hibernate.search.Search;
25 25
import org.springframework.transaction.TransactionStatus;
26 26

  
27
import eu.etaxonomy.cdm.common.CdmUtils;
27 28
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
28 29
import eu.etaxonomy.cdm.model.common.CdmBase;
29 30
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
......
233 234
    }
234 235

  
235 236
    @Override
236
    protected void mergeAggregationResultIntoTargetDescription(TaxonDescription targetDescription,
237
    protected boolean mergeAggregationResultIntoTargetDescription(TaxonDescription targetDescription,
237 238
            ResultHolder resultHolder) {
238 239

  
240
        boolean updated = false;
241

  
239 242
        Class<? extends DescriptionElementBase> debClass = Distribution.class;
240 243
        Map<NamedArea, Distribution> accumulatedStatusMap = ((DistributionResultHolder)resultHolder).accumulatedStatusMap;
241 244

  
......
256 259
                // create a new distribution element
257 260
                targetDistribution = newElement;
258 261
                targetDescription.addElement(targetDistribution);
262
                updated = true;
259 263
            }else{
260
                mergeDescriptionElement(targetDistribution, newElement);
264
                updated |= mergeDescriptionElement(targetDistribution, newElement);
261 265
                elementsToRemove.remove(targetDistribution);  //we keep the distribution for reuse
262 266
            }
263
            mergeSourcesForDescriptionElements(targetDistribution, accumulatedStatusMap.get(area).getSources());
267
            updated |= mergeSourcesForDescriptionElements(targetDistribution, accumulatedStatusMap.get(area).getSources());
264 268
        }
265 269

  
266
        this.handleDescriptionElementsToRemove(targetDescription, elementsToRemove);
270
        updated |= this.handleDescriptionElementsToRemove(targetDescription, elementsToRemove);
271
        return updated;
267 272
    }
268 273

  
269 274
    @Override
270
    protected <S extends DescriptionElementBase> void mergeDescriptionElement(S targetElement,
275
    protected <S extends DescriptionElementBase> boolean mergeDescriptionElement(S targetElement,
271 276
            S newElement) {
277
        boolean updated = false;
272 278
        if (!(targetElement instanceof Distribution)){
273 279
            throw new AggregationException("Unexpected class: " + targetElement.getClass().getName());
274 280
        }else{
275 281
            Distribution targetDistribution = (Distribution)targetElement;
276 282
            Distribution newDistribution = (Distribution)newElement;
277
            targetDistribution.setStatus(newDistribution.getStatus());
283
            if (!CdmUtils.nullSafeEqual(targetDistribution.getStatus(), newDistribution.getStatus())){
284
                targetDistribution.setStatus(newDistribution.getStatus());
285
                updated = true;
286
            }
278 287
        }
288
        return updated;
279 289
    }
280 290

  
281 291
    @Override
cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/description/StructuredDescriptionAggregation.java
21 21
import java.util.stream.Collectors;
22 22

  
23 23
import eu.etaxonomy.cdm.common.BigDecimalUtil;
24
import eu.etaxonomy.cdm.common.CdmUtils;
24 25
import eu.etaxonomy.cdm.common.monitor.IProgressMonitor;
25 26
import eu.etaxonomy.cdm.model.common.CdmBase;
26 27
import eu.etaxonomy.cdm.model.common.ICdmBase;
......
139 140
    }
140 141

  
141 142
    @Override
142
    protected void mergeAggregationResultIntoTargetDescription(TaxonDescription targetDescription,
143
    protected boolean mergeAggregationResultIntoTargetDescription(TaxonDescription targetDescription,
143 144
            ResultHolder resultHolder) {
144 145

  
145 146
        StructuredDescriptionResultHolder structuredResultHolder = (StructuredDescriptionResultHolder)resultHolder;
146
        mergeDescriptionElements(targetDescription, structuredResultHolder.categoricalMap, CategoricalData.class);
147
        mergeDescriptionElements(targetDescription, structuredResultHolder.quantitativeMap, QuantitativeData.class);
148
        addAggregationSources(targetDescription, structuredResultHolder);
147
        boolean updated = mergeDescriptionElements(targetDescription, structuredResultHolder.categoricalMap, CategoricalData.class);
148
        updated |= mergeDescriptionElements(targetDescription, structuredResultHolder.quantitativeMap, QuantitativeData.class);
149
        updated |= mergeDescriptionSources(targetDescription, structuredResultHolder);
149 150

  
150 151
        if(!targetDescription.getElements().isEmpty()){
151 152
            dataSet.addDescription(targetDescription);
152 153
        }else{
153 154
            dataSet.removeDescription(targetDescription);
154 155
        }
156
        return updated;
155 157
    }
156 158

  
157 159
    @Override
......
159 161
        return deb.isInstanceOf(CategoricalData.class) || deb.isInstanceOf(QuantitativeData.class);
160 162
    }
161 163

  
162
    private <T extends DescriptionBase<?>> void addAggregationSources(TaxonDescription targetDescription,
164
    private <T extends DescriptionBase<?>> boolean mergeDescriptionSources(TaxonDescription targetDescription,
163 165
                StructuredDescriptionResultHolder structuredResultHolder) {
164 166

  
167
        boolean updated = false;
165 168
        //Remove sources from description
166 169
        Set<IdentifiableSource> sourcesToRemove = targetDescription.getSources().stream()
167 170
                .filter(source->source.getType().equals(OriginalSourceType.Aggregation))
......
172 175
            IdentifiableSource mergeSourceCandidate = findSourceCandidate(targetDescription, newSource);
173 176
            if (mergeSourceCandidate == null){
174 177
                addNewSource(targetDescription, newSource);
178
                updated = true;
175 179
            }else{
176
                mergeSource(mergeSourceCandidate, newSource);
180
                updated |= mergeSource(mergeSourceCandidate, newSource);
177 181
                sourcesToRemove.remove(mergeSourceCandidate);
178 182
            }
179 183
        }
......
181 185
        //remove remaining sources-to-be-removed
182 186
        for (IdentifiableSource sourceToRemove : sourcesToRemove) {
183 187
            targetDescription.removeSource(sourceToRemove);
188
            updated |= sourceToRemove.isPersited();
184 189
            ICdmBase target = CdmBase.deproxy(sourceToRemove.getCdmSource());
185 190
            if (target != null){
186 191
                sourceToRemove.setCdmSource(null); //workaround for missing orphan removal #9801
......
200 205
                }
201 206
            }
202 207
        }
208
        return updated;
203 209
    }
204 210

  
205 211
    private <T extends DescriptionBase<?>> void addNewSource(TaxonDescription targetDescription,
......
219 225
    }
220 226

  
221 227
    //mergeablity has been checked before
222
    private <T extends DescriptionBase<?>> void mergeSource(IdentifiableSource mergeCandidate, IdentifiableSource newSource) {
228
    private <T extends DescriptionBase<?>> boolean mergeSource(IdentifiableSource mergeCandidate, IdentifiableSource newSource) {
223 229

  
230
        boolean updated = false;
224 231
        ICdmBase newTarget = newSource.getCdmSource();
225 232
        if (newTarget != null){
226 233
            newTarget = CdmBase.deproxy(newTarget);
......
229 236
                T newTargetDesc = (T)newTarget;
230 237
                @SuppressWarnings("unchecked")
231 238
                T existingTargetDesc = CdmBase.deproxy((T)mergeCandidate.getCdmSource());
232
                mergeSourceDescription(existingTargetDesc, newTargetDesc);
239
                updated |= mergeSourceDescription(existingTargetDesc, newTargetDesc);
233 240
                ((IDescribable<T>)existingTargetDesc.describedEntity()).addDescription(existingTargetDesc);
234 241
                if (!existingTargetDesc.equals(newTargetDesc)){
235 242
                    ((IDescribable<T>)newTargetDesc.describedEntity()).removeDescription(newTargetDesc);
......
242 249
        }else{
243 250
            throw new AggregationException("Sources not linking to another CdmBase instance currently not yet supported.");
244 251
        }
252
        return updated;
245 253
    }
246 254

  
247
    private <T extends DescriptionBase<?>> void mergeSourceDescription(T existingSourceDescription, T newSourceDescription) {
255
    private <T extends DescriptionBase<?>> boolean mergeSourceDescription(T existingSourceDescription, T newSourceDescription) {
248 256

  
257
        boolean updated = false;
249 258
        Set<DescriptionElementBase> elementsToRemove = new HashSet<>(existingSourceDescription.getElements());
250 259
        Set<DescriptionElementBase> newElements = new HashSet<>(newSourceDescription.getElements());
251 260

  
......
256 265
                        && e.getFeature().equals(newElementClone.getFeature()))
257 266
                    .findFirst();
258 267
            if (matchingElement.isPresent()){
259
                mergeDescriptionElement(matchingElement.get(), newElementClone);
268
                updated |= mergeDescriptionElement(matchingElement.get(), newElementClone);
260 269
                elementsToRemove.remove(matchingElement.get());
261 270
            }else{
262 271
                existingSourceDescription.addElement(newElementClone);
272
                updated = true;
263 273
            }
264 274
        }
265
        addSourceDescriptionToDescribedEntity(newSourceDescription);
275
        updated |= addSourceDescriptionToDescribedEntity(newSourceDescription);
266 276
        existingSourceDescription.setTitleCache(newSourceDescription.getTitleCache(), true);
267 277

  
268 278
        for (DescriptionElementBase debToRemove : elementsToRemove){
269 279
            existingSourceDescription.removeElement(debToRemove);
280
            updated |= debToRemove.isPersited();
270 281
        }
271

  
282
        return updated;
272 283
    }
273 284

  
274 285
    @SuppressWarnings("unchecked")
275
    private <T extends DescriptionBase<?>> void addSourceDescriptionToDescribedEntity(T sourceDescription) {
276
        ((IDescribable<T>)sourceDescription.describedEntity()).addDescription(sourceDescription);
277
    }
278
    @SuppressWarnings("unchecked")
279
    private <T extends DescriptionBase<?>> void removeSourceDescriptionFromDescribedEntity(T sourceDescription) {
280
        ((IDescribable<T>)sourceDescription.describedEntity()).removeDescription(sourceDescription);
286
    private <T extends DescriptionBase<?>> boolean addSourceDescriptionToDescribedEntity(T sourceDescription) {
287
        boolean updated = false;
288
        IDescribable<T> describedEntity = ((IDescribable<T>)sourceDescription.describedEntity());
289
        if (describedEntity.getDescriptions().contains(sourceDescription)){
290
            describedEntity.addDescription(sourceDescription);
291
            updated = true;
292
        }
293
        return updated;
281 294
    }
282 295

  
283 296
    private IdentifiableSource findSourceCandidate(TaxonDescription targetDescription, IdentifiableSource newSource) {
......
336 349
    }
337 350

  
338 351
    @Override
339
    protected <S extends DescriptionElementBase> void mergeDescriptionElement(S targetElement,
352
    protected <S extends DescriptionElementBase> boolean mergeDescriptionElement(S targetElement,
340 353
            S newElement) {
341 354

  
355
        boolean updated = false;
342 356
        targetElement = CdmBase.deproxy(targetElement);
343 357
        newElement = CdmBase.deproxy(newElement);
344 358
        if (targetElement instanceof CategoricalData){
345
            mergeDescriptionElement((CategoricalData)targetElement, (CategoricalData)newElement);
359
            updated |= mergeDescriptionElement((CategoricalData)targetElement, (CategoricalData)newElement);
346 360
        }else if (targetElement.isInstanceOf(QuantitativeData.class)){
347
            mergeDescriptionElement((QuantitativeData)targetElement, (QuantitativeData)newElement);
361
            updated |= mergeDescriptionElement((QuantitativeData)targetElement, (QuantitativeData)newElement);
348 362
        }else{
349 363
            throw new AggregationException("Class not supported: " + targetElement.getClass().getName());
350 364
        }
365
        return updated;
351 366
    }
352 367

  
353
    private void mergeDescriptionElement(CategoricalData elementToStay,
368
    private boolean mergeDescriptionElement(CategoricalData elementToStay,
354 369
            CategoricalData newElement) {
355 370

  
356
        List<StateData> oldData = new ArrayList<>(elementToStay.getStateData());
371
        boolean updated = false;
372
        List<StateData> dataToRemove = new ArrayList<>(elementToStay.getStateData());
357 373
        List<StateData> newData = new ArrayList<>(newElement.getStateData());
358 374
        for (StateData newStateData : newData){
359 375
            State state = newStateData.getState();
360
            StateData oldStateData = firstByState(state, oldData);
376
            StateData oldStateData = firstByState(state, dataToRemove);
361 377
            if (oldStateData != null){
362 378
                //for now only state and count is used for aggregation, below code needs to be adapted if this changes
363
                oldStateData.setCount(newStateData.getCount());
364
                oldData.remove(oldStateData);
379
                if (!CdmUtils.nullSafeEqual(oldStateData.getCount(), newStateData.getCount())){
380
                    oldStateData.setCount(newStateData.getCount());
381
//                    getResult().addUpdatedObject(oldStateData);
382
                    updated = true;
383
                }
384
                dataToRemove.remove(oldStateData);
365 385
            }else{
366 386
                elementToStay.addStateData(newStateData);
387
                updated = true;
367 388
            }
368 389
        }
369
        for (StateData stateDataToRemove : oldData){
390
        for (StateData stateDataToRemove : dataToRemove){
370 391
            elementToStay.removeStateData(stateDataToRemove);
392
            updated |= stateDataToRemove.isPersited();
371 393
        }
394
        return updated;
372 395
    }
373 396

  
374 397
    private StateData firstByState(State state, List<StateData> oldData) {
......
383 406
        return null;
384 407
    }
385 408

  
386
    private void mergeDescriptionElement(QuantitativeData elementToStay,
409
    private boolean mergeDescriptionElement(QuantitativeData elementToStay,
387 410
            QuantitativeData newElement) {
388 411

  
412
        boolean updated = false;
413

  
389 414
        Set<StatisticalMeasurementValue> oldValues = new HashSet<>(elementToStay.getStatisticalValues());
390 415
        Set<StatisticalMeasurementValue> newValues = new HashSet<>(newElement.getStatisticalValues());
391 416
        for (StatisticalMeasurementValue newValue : newValues){
......
393 418
            StatisticalMeasurementValue oldValue = firstValueByType(type, oldValues);
394 419
            if (oldValue != null){
395 420
                //for now only state and count is used for aggregation, below code needs to be adapted if this changes
396
                oldValue.setValue(newValue.getValue());
421
                if (!CdmUtils.nullSafeEqual(oldValue.getValue(), newValue.getValue())){
422
                    oldValue.setValue(newValue.getValue());
423
                    updated = true;
424
                }
397 425
                oldValues.remove(oldValue);
398 426
            }else{
399 427
                elementToStay.addStatisticalValue(newValue);
428
                updated = true;
400 429
            }
401 430
        }
402 431
        for (StatisticalMeasurementValue valueToRemove : oldValues){
403 432
            elementToStay.removeStatisticalValue(valueToRemove);
433
            updated |= valueToRemove.isPersited();
404 434
        }
435
        return updated;
405 436
    }
406 437

  
407 438
    private StatisticalMeasurementValue firstValueByType(StatisticalMeasure type, Set<StatisticalMeasurementValue> oldValues) {
cdmlib-services/src/test/java/eu/etaxonomy/cdm/api/service/description/StructuredDescriptionAggregationTest.java
173 173
        // 1st aggregation
174 174
        DeleteResult result = engine.invoke(config, repository);
175 175
        verifyStatusOk(result);
176
        verifyUpdatedObjects(result, 4);
176 177
        commitAndStartNewTransaction();
177 178
        verifyAggregatedDescription(new TestConfig(config));
178 179

  
180
        //update data
179 181
        addSomeDataToFirstAggregation();
180 182
        commitAndStartNewTransaction();
181 183
        verifyAggregatedDescription(new TestConfig(config).setWithAddedData());
......
183 185
        // 2nd aggregation => should be same as originally as data was only added to aggregation to see if it is correctly deleted
184 186
        result = engine.invoke(config, repository);
185 187
        verifyStatusOk(result);
188
        verifyUpdatedObjects(result, 3);
186 189
        commitAndStartNewTransaction();
187 190
        verifyAggregatedDescription(new TestConfig(config));
188 191

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

  
197 200
    }
198 201

  
199 202
    private void addSomeDataToFirstAggregation() {
......
223 226
        @DataSet(value="StructuredDescriptionAggregationTest.xml"),
224 227
    })
225 228
    public void testDeleteTest() {
229

  
230
        //create test data
226 231
        createDefaultFeatureTree();
227 232
        DescriptiveDataSet dataSet = createTestData();
228 233
        commitAndStartNewTransaction();
229 234

  
230
        StructuredDescriptionAggregationConfiguration config = createConfig(dataSet);
231

  
232 235
        // 1st aggregation
236
        StructuredDescriptionAggregationConfiguration config = createConfig(dataSet);
233 237
        DeleteResult result = engine.invoke(config, repository);
238

  
239
        //verify
234 240
        verifyStatusOk(result);
235 241
        commitAndStartNewTransaction();
236 242
        verifyAggregatedDescription(new TestConfig(config));
237 243

  
244
        //remove data
238 245
        removeSomeDataFromFirstAggregation();
239 246
        commitAndStartNewTransaction();
240 247
        Assert.assertEquals("Should have 3 specimen desc, 1 literature desc, 2 individual association holder, "
......
244 251
        // 2nd aggregation
245 252
        result = engine.invoke(config, repository);
246 253
        verifyStatusOk(result);
254
        verifyUpdatedObjects(result, 3);
247 255
        commitAndStartNewTransaction();
248 256
        verifyAggregatedDescription(new TestConfig(config).setWithRemoved());
249 257
    }
......
265 273
        @DataSet(value="StructuredDescriptionAggregationTest.xml"),
266 274
    })
267 275
    public void testIncompleteQuantitativeData() {
276

  
277
        //create test data
268 278
        createDefaultFeatureTree();
269 279
        DescriptiveDataSet dataSet = DescriptiveDataSet.NewInstance();
270 280
        datasetService.save(dataSet);
......
284 294
        dataSet.setDescriptiveSystem(descriptiveSystem);
285 295
        commitAndStartNewTransaction();
286 296

  
297
        //aggregate
287 298
        StructuredDescriptionAggregationConfiguration config = createConfig(dataSet);
288

  
289 299
        DeleteResult result = engine.invoke(config, repository);
290
        verifyStatusOk(result);
291 300

  
301
        //verify
302
        verifyStatusOk(result);
303
        verifyUpdatedObjects(result, 3);
292 304
        Taxon taxLapsanaCommunisAlpina = (Taxon)taxonService.find(T_LAPSANA_COMMUNIS_ALPINA_UUID);
293 305
        TaxonDescription aggrDescLapsanaCommunisAlpina = verifyTaxonDescriptions(taxLapsanaCommunisAlpina, 1);
294 306
        verifyQuantitativeData(uuidFeatureLeafLength, null, new BigDecimal("0.0"), new BigDecimal("7.0"), null, aggrDescLapsanaCommunisAlpina);
......
328 340
        verifyStatusOk(result);
329 341
        Taxon taxLapsanaCommunisAlpina = (Taxon)taxonService.find(T_LAPSANA_COMMUNIS_ALPINA_UUID);
330 342
        //if no state at all exists in description even the description is not created (this was different before but changed with 9b8a8049439 / #9804)
343
        verifyUpdatedObjects(result, 0);
331 344
        verifyNumberTaxonDescriptions(taxLapsanaCommunisAlpina, 0);
332 345

  
333 346
        //add data for another feature
......
336 349
        commitAndStartNewTransaction();
337 350
        result = engine.invoke(config, repository);
338 351
        verifyStatusOk(result);
352
        verifyUpdatedObjects(result, 3);
339 353
        taxLapsanaCommunisAlpina = (Taxon)taxonService.find(T_LAPSANA_COMMUNIS_ALPINA_UUID);
340 354
        TaxonDescription aggrDescLapsanaCommunisAlpina = verifyTaxonDescriptions(taxLapsanaCommunisAlpina, 1);
341 355
        verifyNumberDescriptionElements(aggrDescLapsanaCommunisAlpina, uuidFeatureLeafColor, 0);  //we don't expect empty categorical data anymore #9804
......
348 362
        result = engine.invoke(config, repository);
349 363

  
350 364
        verifyStatusOk(result);
365
        verifyUpdatedObjects(result, 3);
351 366
        taxLapsanaCommunisAlpina = (Taxon)taxonService.find(T_LAPSANA_COMMUNIS_ALPINA_UUID);
352 367
        aggrDescLapsanaCommunisAlpina = verifyTaxonDescriptions(taxLapsanaCommunisAlpina, 2);  //for leafPA and for color
353 368
        List<StateData> sdAlpinaLeafColor = verifyCategoricalData(uuidFeatureLeafColor, 1, aggrDescLapsanaCommunisAlpina, false);
......
373 388
        // 1st aggregation
374 389
        DeleteResult result = engine.invoke(config, repository);
375 390
        verifyStatusOk(result);
391
        verifyUpdatedObjects(result, 4);
376 392
        commitAndStartNewTransaction();
377 393
        verifyAggregatedDescription(new TestConfig(config));
378 394

  
......
380 396
        config.setToParentSourceMode(AggregationSourceMode.NONE);
381 397
        result = engine.invoke(config, repository);
382 398
        verifyStatusOk(result);
399
        verifyUpdatedObjects(result, 2); //"Only the 2 subspecies aggregations should be updated"
383 400
        commitAndStartNewTransaction();
384 401
        verifyAggregatedDescription(new TestConfig(config));
385 402

  
......
387 404
        config.setToParentSourceMode(AggregationSourceMode.DESCRIPTION);
388 405
        result = engine.invoke(config, repository);
389 406
        verifyStatusOk(result);
407
        verifyUpdatedObjects(result, 4);
390 408
        commitAndStartNewTransaction();
391 409
        verifyAggregatedDescription(new TestConfig(config));
392 410

  
......
394 412
        config.setToParentSourceMode(AggregationSourceMode.TAXON);
395 413
        result = engine.invoke(config, repository);
396 414
        verifyStatusOk(result);
415
        verifyUpdatedObjects(result, 4);
397 416
        commitAndStartNewTransaction();
398 417
        verifyAggregatedDescription(new TestConfig(config));
399 418

  
......
401 420
        config.setToParentSourceMode(AggregationSourceMode.TAXON);
402 421
        result = engine.invoke(config, repository);
403 422
        verifyStatusOk(result);
423
        verifyUpdatedObjects(result, 2);
404 424
        commitAndStartNewTransaction();
405 425
        verifyAggregatedDescription(new TestConfig(config));
406 426

  
......
442 462
        @DataSet(value="StructuredDescriptionAggregationTest.xml"),
443 463
    })
444 464
    public void testAggregation() {
465

  
466
        //create test data
445 467
        createDefaultFeatureTree();
446 468
        DescriptiveDataSet dataSet = createTestData();
447 469
        commitAndStartNewTransaction();
448 470

  
471
        //aggregate
449 472
        StructuredDescriptionAggregationConfiguration config = createConfig(dataSet);
450

  
451 473
        DeleteResult result = engine.invoke(config, repository);
452 474
        commitAndStartNewTransaction();
453 475
        verifyStatusOk(result);
454 476
        verifyAggregatedDescription(new TestConfig(config));
455 477

  
478
        //aggregate again with literature (also tests re-aggregation issues)
456 479
        config.setIncludeLiterature(true);
457

  
458 480
        result = engine.invoke(config, repository);
459 481
        commitAndStartNewTransaction();
460 482
        verifyStatusOk(result);
......
470 492
        }
471 493
    }
472 494

  
495
    private void verifyUpdatedObjects(DeleteResult result, int n) {
496
        Assert.assertEquals(n, result.getUpdatedObjects().size());
497
    }
498

  
473 499
    private void verifyStatusError(DeleteResult result, String expectedMessage) {
474 500
        if (result.getStatus() != DeleteResult.Status.ERROR){
475 501
            Assert.fail("Aggregation should fail with status error " + result.toString());

Also available in: Unified diff