1
|
/**
|
2
|
* Copyright (C) 2011 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
|
package eu.etaxonomy.cdm.api.service;
|
10
|
|
11
|
import static org.junit.Assert.assertTrue;
|
12
|
|
13
|
import java.io.FileNotFoundException;
|
14
|
import java.util.ArrayList;
|
15
|
import java.util.Arrays;
|
16
|
import java.util.List;
|
17
|
|
18
|
import org.apache.commons.lang.RandomStringUtils;
|
19
|
import org.junit.Before;
|
20
|
import org.junit.Test;
|
21
|
import org.unitils.dbunit.annotation.DataSet;
|
22
|
import org.unitils.spring.annotation.SpringBeanByType;
|
23
|
|
24
|
import eu.etaxonomy.cdm.api.service.statistics.Statistics;
|
25
|
import eu.etaxonomy.cdm.api.service.statistics.StatisticsConfigurator;
|
26
|
import eu.etaxonomy.cdm.api.service.statistics.StatisticsPartEnum;
|
27
|
import eu.etaxonomy.cdm.api.service.statistics.StatisticsTypeEnum;
|
28
|
import eu.etaxonomy.cdm.model.common.Language;
|
29
|
import eu.etaxonomy.cdm.model.description.CommonTaxonName;
|
30
|
import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
|
31
|
import eu.etaxonomy.cdm.model.description.DescriptionElementSource;
|
32
|
import eu.etaxonomy.cdm.model.description.TaxonDescription;
|
33
|
import eu.etaxonomy.cdm.model.description.TaxonNameDescription;
|
34
|
import eu.etaxonomy.cdm.model.description.TextData;
|
35
|
import eu.etaxonomy.cdm.model.name.IBotanicalName;
|
36
|
import eu.etaxonomy.cdm.model.name.Rank;
|
37
|
import eu.etaxonomy.cdm.model.name.TaxonNameFactory;
|
38
|
import eu.etaxonomy.cdm.model.reference.OriginalSourceType;
|
39
|
import eu.etaxonomy.cdm.model.reference.Reference;
|
40
|
import eu.etaxonomy.cdm.model.reference.ReferenceFactory;
|
41
|
import eu.etaxonomy.cdm.model.taxon.Classification;
|
42
|
import eu.etaxonomy.cdm.model.taxon.Synonym;
|
43
|
import eu.etaxonomy.cdm.model.taxon.SynonymType;
|
44
|
import eu.etaxonomy.cdm.model.taxon.Taxon;
|
45
|
import eu.etaxonomy.cdm.test.integration.CdmTransactionalIntegrationTest;
|
46
|
|
47
|
public class StatisticsServiceImplTest2 extends CdmTransactionalIntegrationTest {
|
48
|
|
49
|
// ************constants to set up the expected results for all:
|
50
|
// ********************
|
51
|
|
52
|
// ............................................
|
53
|
|
54
|
// here is the list of the types that will be test counted in the
|
55
|
// parts (ALL, CLASSIFICATION)
|
56
|
private static final List<StatisticsTypeEnum> TYPES = Arrays
|
57
|
.asList(new StatisticsTypeEnum[] {
|
58
|
StatisticsTypeEnum.CLASSIFICATION,
|
59
|
StatisticsTypeEnum.ACCEPTED_TAXA,
|
60
|
StatisticsTypeEnum.ALL_TAXA,
|
61
|
StatisticsTypeEnum.ALL_REFERENCES, // this functionality
|
62
|
// for
|
63
|
// classifications is still missing for in the Statistics
|
64
|
// Service
|
65
|
StatisticsTypeEnum.SYNONYMS,
|
66
|
StatisticsTypeEnum.TAXON_NAMES,
|
67
|
StatisticsTypeEnum.NOMENCLATURAL_REFERENCES,
|
68
|
StatisticsTypeEnum.DESCRIPTIVE_SOURCE_REFERENCES });
|
69
|
|
70
|
// private static final String[] TYPES = { "CLASSIFICATION",
|
71
|
// "ACCEPTED_TAXA",
|
72
|
// "ALL_TAXA", "ALL_REFERENCES" };
|
73
|
|
74
|
// ................parts ..............................
|
75
|
|
76
|
private static final List<String> PARTS = Arrays.asList(new String[] {
|
77
|
"ALL", "CLASSIFICATION" });
|
78
|
// .........................................................
|
79
|
|
80
|
private ArrayList<Classification> classifications;
|
81
|
|
82
|
// ****************** services: ************************
|
83
|
@SpringBeanByType
|
84
|
private IStatisticsService service;
|
85
|
@SpringBeanByType
|
86
|
private IClassificationService classificationService;
|
87
|
@SpringBeanByType
|
88
|
private ITaxonService taxonService;
|
89
|
@SpringBeanByType
|
90
|
private IReferenceService referenceService;
|
91
|
@SpringBeanByType
|
92
|
private IDescriptionService descriptionService;
|
93
|
@SpringBeanByType
|
94
|
private IDescriptionElementService descriptionElementService;
|
95
|
|
96
|
// ............................................
|
97
|
|
98
|
@Before
|
99
|
// @DataSet
|
100
|
public void setUp() throws Exception {
|
101
|
// createTestData(3, 10, 7, 16, 4);
|
102
|
// OutputStream out= new ByteArrayOutputStream();
|
103
|
// printDataSet(out);
|
104
|
// System.out.println(out.toString());
|
105
|
}
|
106
|
|
107
|
@Test
|
108
|
@DataSet
|
109
|
public void testGetCountStatistics() {
|
110
|
|
111
|
// create configurator needed to call
|
112
|
// StatisticsService.getCountStatistics()
|
113
|
List<StatisticsConfigurator> configuratorList = createConfiguratorList(
|
114
|
(String[]) PARTS.toArray(), TYPES);
|
115
|
|
116
|
// run method of StatisticsService
|
117
|
List<Statistics> statisticsList = service
|
118
|
.getCountStatistics(configuratorList);
|
119
|
|
120
|
// print out result
|
121
|
logger.info("statistics service result: ");
|
122
|
for (Statistics statistics : statisticsList) {
|
123
|
logger.info(statistics.getCountMap().toString());
|
124
|
}
|
125
|
|
126
|
assertTrue(true);
|
127
|
}
|
128
|
|
129
|
private List<StatisticsConfigurator> createConfiguratorList(String[] part,
|
130
|
List<StatisticsTypeEnum> types) {
|
131
|
|
132
|
ArrayList<StatisticsConfigurator> configuratorList = new ArrayList<>();
|
133
|
|
134
|
// 1. get types for configurators:
|
135
|
// in our case all the configurators will have the same types
|
136
|
// so we calculate the types once and save them in a helperConfigurator
|
137
|
StatisticsConfigurator helperConfigurator = new StatisticsConfigurator();
|
138
|
|
139
|
if (types != null) {
|
140
|
for (StatisticsTypeEnum type : types) {
|
141
|
helperConfigurator.addType(type);
|
142
|
}
|
143
|
} else {
|
144
|
for (StatisticsTypeEnum enumValue : StatisticsTypeEnum.values()) {
|
145
|
helperConfigurator.addType(enumValue);
|
146
|
}
|
147
|
}
|
148
|
|
149
|
// 2. determine the entities and put each of them in a configurator:
|
150
|
|
151
|
// if no part was given:
|
152
|
if (part == null) {
|
153
|
helperConfigurator.addFilter(null); // part= null means search all
|
154
|
// DB
|
155
|
configuratorList.add(helperConfigurator);
|
156
|
}
|
157
|
// else parse list of parts and create configurator for each:
|
158
|
else {
|
159
|
for (String string : part) {
|
160
|
if (string.equals(StatisticsPartEnum.ALL.toString())) {
|
161
|
helperConfigurator.addFilter(null);
|
162
|
configuratorList.add(helperConfigurator);
|
163
|
} else if (string.equals(StatisticsPartEnum.CLASSIFICATION
|
164
|
.toString())) {
|
165
|
List<Classification> classificationsList = classificationService
|
166
|
.listClassifications(null, 0, null, null);
|
167
|
for (Classification classification : classificationsList) {
|
168
|
StatisticsConfigurator newConfigurator = new StatisticsConfigurator();
|
169
|
newConfigurator.setType(helperConfigurator.getType());
|
170
|
newConfigurator.getFilter().addAll(
|
171
|
helperConfigurator.getFilter());
|
172
|
newConfigurator.addFilter(classification);
|
173
|
configuratorList.add(newConfigurator);
|
174
|
}
|
175
|
}
|
176
|
}
|
177
|
}
|
178
|
|
179
|
return configuratorList;
|
180
|
}
|
181
|
|
182
|
public void createTestDataSet(int noOfClassifications, int noOfAcceptedTaxa,
|
183
|
int noOfSynonyms, int noOfDescrSrcReferences, int sharedTaxa)
|
184
|
throws Exception {
|
185
|
|
186
|
// create more parameters:
|
187
|
int noOfNomRefs = noOfAcceptedTaxa + noOfSynonyms - 4;
|
188
|
|
189
|
// missing in this example data:
|
190
|
// synonyms, that are attached to several taxa (same or different
|
191
|
// classification)
|
192
|
|
193
|
// --------------------variables for counting produced elements
|
194
|
// ------------------
|
195
|
|
196
|
int descrSrcReferencesCounter = 0;
|
197
|
|
198
|
// create noOfClassifications classifications
|
199
|
classifications = new ArrayList<Classification>();
|
200
|
|
201
|
for (int i = 1; i <= noOfClassifications; i++) {
|
202
|
Classification classification = Classification
|
203
|
.NewInstance("European Abies" + i);
|
204
|
classifications.add(classification);
|
205
|
classificationService.save(classification);
|
206
|
|
207
|
}
|
208
|
// create all taxa, references and synonyms and attach them to one or
|
209
|
// more classifications
|
210
|
|
211
|
// variables: flags
|
212
|
int remainder = noOfAcceptedTaxa;
|
213
|
Reference sec = ReferenceFactory.newBook();
|
214
|
boolean secondClassificationForTaxonFlag = false;
|
215
|
boolean synonymFlag = false;
|
216
|
boolean tNomRefFlag = false;
|
217
|
boolean sNomRefFlag = false;
|
218
|
boolean tDescrSourceRefFlag = false;
|
219
|
boolean sDescrSourceRefFlag = false;
|
220
|
|
221
|
// variables: counter (pre-loop)
|
222
|
int descriptiveElementsPerTaxon = (noOfDescrSrcReferences / noOfAcceptedTaxa) + 1;
|
223
|
|
224
|
int taxaInClass;
|
225
|
int classiCounter = 0, sharedClassification = 0, synonymCounter = 0, nomRefCounter = 0;
|
226
|
|
227
|
// iterate over classifications and add taxa
|
228
|
for (/* see above */; remainder > 0
|
229
|
&& classiCounter < noOfClassifications; /* see below */) {
|
230
|
|
231
|
// compute no of taxa to be created in this classification
|
232
|
if (classiCounter >= noOfClassifications - 1) { // last classification
|
233
|
// gets all left taxa
|
234
|
taxaInClass = remainder;
|
235
|
} else { // take half of left taxa for this class:
|
236
|
taxaInClass = remainder / 2;
|
237
|
}
|
238
|
|
239
|
// iterate over amount of taxa meant to be in this classification
|
240
|
for (int taxonCounter = 1; taxonCounter <= taxaInClass; taxonCounter++) {
|
241
|
|
242
|
// create a String for the Name
|
243
|
RandomStringUtils.randomAlphabetic(10);
|
244
|
String randomName = RandomStringUtils.randomAlphabetic(5) + " "
|
245
|
+ RandomStringUtils.randomAlphabetic(10);
|
246
|
|
247
|
// create a name for the taxon
|
248
|
IBotanicalName name = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
|
249
|
name.setNameCache(randomName, true);
|
250
|
|
251
|
// create nomenclatural reference for taxon name (if left)
|
252
|
if (nomRefCounter < noOfNomRefs) {
|
253
|
// we remember this taxon has a nomenclatural reference:
|
254
|
tNomRefFlag = true;
|
255
|
Reference nomRef = ReferenceFactory.newBook();
|
256
|
name.setNomenclaturalReference(nomRef);
|
257
|
referenceService.save(nomRef);
|
258
|
nomRefCounter++;
|
259
|
}
|
260
|
|
261
|
// create a new sec for every other taxon
|
262
|
if (taxonCounter % 2 != 0) {
|
263
|
sec = createSecReference(classiCounter, taxonCounter);
|
264
|
}
|
265
|
|
266
|
// create the taxon
|
267
|
Taxon taxon = Taxon.NewInstance(name, sec);
|
268
|
|
269
|
// create descriptions, description sources and their references
|
270
|
|
271
|
if (descrSrcReferencesCounter < noOfDescrSrcReferences) {
|
272
|
|
273
|
tDescrSourceRefFlag = true;
|
274
|
|
275
|
// create a description and 2 description elements with
|
276
|
// references for taxon name
|
277
|
TaxonNameDescription nameDescr = TaxonNameDescription
|
278
|
.NewInstance();
|
279
|
CommonTaxonName nameElement = CommonTaxonName.NewInstance(
|
280
|
"Veilchen" + taxonCounter, Language.GERMAN());
|
281
|
TextData textElement = new TextData();
|
282
|
Reference nameElementRef = ReferenceFactory.newArticle();
|
283
|
Reference textElementRef = ReferenceFactory
|
284
|
.newBookSection();
|
285
|
nameElement.addSource(
|
286
|
OriginalSourceType.PrimaryTaxonomicSource, null,
|
287
|
null, nameElementRef, "name: ");
|
288
|
textElement.addSource(
|
289
|
OriginalSourceType.PrimaryTaxonomicSource, null,
|
290
|
null, textElementRef, "text: ");
|
291
|
nameDescr.addElement(nameElement);
|
292
|
nameDescr.addElement(textElement);
|
293
|
name.addDescription(nameDescr);
|
294
|
// taxon.getName().addDescription(nameDescr);
|
295
|
referenceService.save(nameElementRef);
|
296
|
referenceService.save(textElementRef);
|
297
|
descriptionService.save(nameDescr);
|
298
|
// System.out.println("Descriptive Src Ref for TaxonName: "+nameElementRef.getId()+" Taxon: "+taxon.getId()+" name: "+taxon.getTitleCache());
|
299
|
// System.out.println("Descriptive Src Ref for TaxonName: "+textElementRef.getId()+" Taxon: "+taxon.getId()+" name: "+taxon.getTitleCache());
|
300
|
|
301
|
// ###
|
302
|
// create descriptions, description sources and their
|
303
|
// references
|
304
|
// for taxon
|
305
|
TaxonDescription taxonDescription = new TaxonDescription();
|
306
|
for (int i = 0; i < descriptiveElementsPerTaxon; i++) {
|
307
|
DescriptionElementBase descriptionElement = new TextData();
|
308
|
DescriptionElementSource descriptionElementSource = DescriptionElementSource
|
309
|
.NewInstance(OriginalSourceType.PrimaryTaxonomicSource);
|
310
|
Reference article = ReferenceFactory.newArticle();
|
311
|
|
312
|
descriptionElementSource.setCitation(article);
|
313
|
descriptionElement.addSource(descriptionElementSource);
|
314
|
taxonDescription.addElement(descriptionElement);
|
315
|
referenceService.save(article);
|
316
|
descriptionElementService.save(descriptionElement);
|
317
|
System.out.println("Descriptive Src Ref for Taxon: "+article.getId()+" Taxon: "+taxon.getId()+" name: "+taxon.getTitleCache());
|
318
|
|
319
|
}
|
320
|
descriptionService.save(taxonDescription);
|
321
|
taxon.addDescription(taxonDescription);
|
322
|
|
323
|
//TODO create Sspecimen connected to taxon via TaxonDescription->DescriptionElement=IndividualAssoziation->setAssociatedSpecimenOrObservation(SpecimenOrObservationBase)
|
324
|
// TODO and NameBase->SpecimenTypeDesignation->
|
325
|
// DerrivedUnit???
|
326
|
|
327
|
// create a Specimen for taxon with description, descr.
|
328
|
// element and referece
|
329
|
//
|
330
|
// SpecimenOrObservationBase specimen = DerivedUnit.NewInstance(SpecimenOrObservationType.Fossil);
|
331
|
// SpecimenDescription specimenDescription =
|
332
|
// SpecimenDescription.NewInstance(specimen);
|
333
|
// DescriptionElementBase descrElement = new TextData();
|
334
|
// Reference specimenRef = ReferenceFactory.newArticle();
|
335
|
//// descrElement.add;
|
336
|
//
|
337
|
//
|
338
|
// descriptionService.save(specimenDescription);
|
339
|
// taxon.addSource(
|
340
|
// OriginalSourceType.PrimaryTaxonomicSource,
|
341
|
// null, null, nameElementRef, " ");
|
342
|
// taxon.add(specimen);
|
343
|
|
344
|
descrSrcReferencesCounter += descriptiveElementsPerTaxon + 2 + 1;
|
345
|
|
346
|
}
|
347
|
|
348
|
// add taxon to classification
|
349
|
classifications.get(classiCounter).addChildTaxon(taxon, null,
|
350
|
null);
|
351
|
|
352
|
// now if there are any left, we create a synonym for the taxon
|
353
|
if (synonymCounter < noOfSynonyms) {
|
354
|
synonymFlag = true;
|
355
|
randomName = RandomStringUtils.randomAlphabetic(5) + " "
|
356
|
+ RandomStringUtils.randomAlphabetic(10);
|
357
|
// name for synonym
|
358
|
name = TaxonNameFactory.NewBotanicalInstance(Rank.SPECIES());
|
359
|
name.setNameCache(randomName, true);
|
360
|
|
361
|
// create nomenclatural reference for synonym name (if left)
|
362
|
if (nomRefCounter < noOfNomRefs) {
|
363
|
sNomRefFlag = true;
|
364
|
Reference nomRef = ReferenceFactory.newBook();
|
365
|
name.setNomenclaturalReference(nomRef);
|
366
|
referenceService.save(nomRef);
|
367
|
nomRefCounter++;
|
368
|
}
|
369
|
|
370
|
if (descrSrcReferencesCounter < noOfDescrSrcReferences) {
|
371
|
sDescrSourceRefFlag = true;
|
372
|
|
373
|
// create a description and 2 description elements with
|
374
|
// references for synonym name
|
375
|
TaxonNameDescription nameDescr = TaxonNameDescription
|
376
|
.NewInstance();
|
377
|
CommonTaxonName nameElement = CommonTaxonName
|
378
|
.NewInstance("anderes Veilchen" + taxonCounter,
|
379
|
Language.GERMAN());
|
380
|
TextData textElement = new TextData();
|
381
|
Reference nameElementRef = ReferenceFactory
|
382
|
.newArticle();
|
383
|
Reference textElementRef = ReferenceFactory
|
384
|
.newBookSection();
|
385
|
nameElement.addSource(
|
386
|
OriginalSourceType.PrimaryTaxonomicSource,
|
387
|
null, null, nameElementRef, "name: ");
|
388
|
textElement.addSource(
|
389
|
OriginalSourceType.PrimaryTaxonomicSource,
|
390
|
null, null, textElementRef, "text: ");
|
391
|
nameDescr.addElement(nameElement);
|
392
|
nameDescr.addElement(textElement);
|
393
|
name.addDescription(nameDescr);
|
394
|
// taxon.getName().addDescription(nameDescr);
|
395
|
referenceService.save(nameElementRef);
|
396
|
referenceService.save(textElementRef);
|
397
|
descriptionService.save(nameDescr);
|
398
|
descrSrcReferencesCounter += 2;
|
399
|
System.out.println("Descriptive Src Ref for Synonym: "+nameElementRef.getId()+" Taxon: "+taxon.getId()+" name: "+taxon.getTitleCache());
|
400
|
System.out.println("Descriptive Src Ref for Synonym: "+textElementRef.getId()+" Taxon: "+taxon.getId()+" name: "+taxon.getTitleCache());
|
401
|
}
|
402
|
|
403
|
// create a new reference for every other synonym:
|
404
|
if (taxonCounter % 2 != 0) {
|
405
|
sec = createSecReference(classiCounter, taxonCounter);
|
406
|
}
|
407
|
Synonym synonym = Synonym.NewInstance(name, sec);
|
408
|
taxonService.save(synonym);
|
409
|
taxon.addSynonym(synonym,
|
410
|
SynonymType.SYNONYM_OF());
|
411
|
|
412
|
synonymCounter++;
|
413
|
}
|
414
|
|
415
|
// if this is not the last classification and there are
|
416
|
// taxa left that should be in more than one classification
|
417
|
// we add the taxon to the next class in the list too.
|
418
|
|
419
|
if (classiCounter < noOfClassifications
|
420
|
&& sharedClassification < sharedTaxa) {
|
421
|
classifications.get(classiCounter + 1).addChildTaxon(taxon,
|
422
|
null, null);
|
423
|
|
424
|
// we remember that this taxon is attached to 2
|
425
|
// classifications:
|
426
|
secondClassificationForTaxonFlag = true;
|
427
|
sharedClassification++;
|
428
|
classificationService.saveOrUpdate(classifications
|
429
|
.get(classiCounter + 1));
|
430
|
|
431
|
}
|
432
|
|
433
|
taxonService.save(taxon);
|
434
|
classificationService.saveOrUpdate(classifications
|
435
|
.get(classiCounter));
|
436
|
|
437
|
// count the data created with this taxon:
|
438
|
int c = classiCounter;
|
439
|
|
440
|
if (secondClassificationForTaxonFlag) {
|
441
|
c++;
|
442
|
}
|
443
|
|
444
|
// put flags back:
|
445
|
secondClassificationForTaxonFlag = false;
|
446
|
tNomRefFlag = false;
|
447
|
sNomRefFlag = false;
|
448
|
synonymFlag = false;
|
449
|
tDescrSourceRefFlag = false;
|
450
|
sDescrSourceRefFlag = false;
|
451
|
}
|
452
|
|
453
|
// modify variables (post-loop)
|
454
|
classiCounter++;
|
455
|
remainder -= taxaInClass;
|
456
|
|
457
|
}
|
458
|
|
459
|
commit();
|
460
|
|
461
|
writeDbUnitDataSetFile(new String[] { "TAXONBASE", "TAXONNAME",
|
462
|
"TAXONRELATIONSHIP", "REFERENCE",
|
463
|
"DESCRIPTIONELEMENTBASE",
|
464
|
"DESCRIPTIONELEMENTBASE_ORIGINALSOURCEBASE",
|
465
|
"ORIGINALSOURCEBASE", "DESCRIPTIONBASE", "REFERENCE_ORIGINALSOURCEBASE","LANGUAGESTRING",
|
466
|
"CLASSIFICATION", "TAXONNODE",
|
467
|
"HIBERNATE_SEQUENCES" });
|
468
|
|
469
|
// "AGENTBASE","HOMOTYPICALGROUP","LANGUAGESTRING",
|
470
|
// "DESCRIPTIONELEMENTBASE_LANGUAGESTRING", "HIBERNATE_SEQUENCES"
|
471
|
}
|
472
|
|
473
|
/**
|
474
|
* create and count a new sec Reference
|
475
|
*/
|
476
|
private Reference createSecReference(int classiCounter, int taxonCounter) {
|
477
|
Reference sec;
|
478
|
sec = ReferenceFactory.newBook();
|
479
|
sec.setTitle("book " + classiCounter + "." + taxonCounter);
|
480
|
referenceService.save(sec);
|
481
|
return sec;
|
482
|
}
|
483
|
|
484
|
@Override
|
485
|
public void createTestDataSet() throws FileNotFoundException {}
|
486
|
|
487
|
}
|