1 package eu
.etaxonomy
.cdm
.persistence
.dao
.hibernate
.statistics
;
3 import static org
.junit
.Assert
.assertTrue
;
5 import java
.io
.FileNotFoundException
;
6 import java
.util
.ArrayList
;
7 import java
.util
.Arrays
;
8 import java
.util
.Collections
;
9 import java
.util
.HashMap
;
10 import java
.util
.List
;
12 import java
.util
.Random
;
14 import java
.util
.UUID
;
16 import org
.apache
.commons
.lang
.RandomStringUtils
;
17 import org
.apache
.log4j
.Logger
;
18 import org
.junit
.After
;
19 import org
.junit
.Before
;
20 import org
.junit
.Test
;
21 import org
.unitils
.spring
.annotation
.SpringBeanByType
;
23 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
24 import eu
.etaxonomy
.cdm
.model
.description
.CommonTaxonName
;
25 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
26 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementSource
;
27 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
28 import eu
.etaxonomy
.cdm
.model
.description
.TaxonNameDescription
;
29 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
30 import eu
.etaxonomy
.cdm
.model
.name
.IBotanicalName
;
31 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
32 import eu
.etaxonomy
.cdm
.model
.name
.TaxonNameFactory
;
33 import eu
.etaxonomy
.cdm
.model
.reference
.OriginalSourceType
;
34 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
35 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceFactory
;
36 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
37 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
38 import eu
.etaxonomy
.cdm
.model
.taxon
.SynonymType
;
39 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
40 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonNode
;
41 import eu
.etaxonomy
.cdm
.model
.view
.context
.AuditEventContextHolder
;
42 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionDao
;
43 import eu
.etaxonomy
.cdm
.persistence
.dao
.description
.IDescriptionElementDao
;
44 import eu
.etaxonomy
.cdm
.persistence
.dao
.reference
.IReferenceDao
;
45 import eu
.etaxonomy
.cdm
.persistence
.dao
.statistics
.IStatisticsDao
;
46 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.IClassificationDao
;
47 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonDao
;
48 import eu
.etaxonomy
.cdm
.persistence
.dao
.taxon
.ITaxonNodeDao
;
49 import eu
.etaxonomy
.cdm
.test
.integration
.CdmTransactionalIntegrationTest
;
51 public class StatisticsDaoHibernateImplTest
52 extends CdmTransactionalIntegrationTest
{
54 private static final Logger logger
= Logger
.getLogger(StatisticsDaoHibernateImplTest
.class);
57 private IStatisticsDao statisticsDao
;
59 private UUID nodeUuid
;
61 private List
<Classification
> classifications
;
66 private static final int NO_OF_ACCEPTED_TAXA
= 10;
68 // choose a number (less than NO_OF_ACCEPTED_TAXA)
69 private static final int NO_OF_CLASSIFICATIONS
= 3;
71 // must be less or equal to NO_OF_ACCEPTED_TAXA
72 private static final int NO_OF_SYNONYMS
= 7;
74 // taxa that occure in several classifications:
75 // must NOT be more than NO_OF_ACCEPTED_TAXA
76 private static final int NO_OF_SHARED_TAXA
= 4;
78 // must be NO_OF_ACCEPTED_TAXA + NO_OF_SYNONYMS
79 private static final int NO_OF_ALLTAXA
= NO_OF_ACCEPTED_TAXA
82 // must be NO_OF_ACCEPTED_TAXA+NO_OF_SYNONYMS
83 private static final int NO_OF_TAXON_NAMES
= NO_OF_ACCEPTED_TAXA
86 // this represents an approx. no of the amount that will actually generated!
87 private static final int NO_OF_DESCRIPTIVE_SOURCE_REFERENCES
= 16;
89 // private static final int NO_OF_ALL_REFERENCES = NO_OF_ACCEPTED_TAXA + 0;
91 // must not be more than NO_OF_ACCEPTED_TAXA+NO_OF_SYNONYMS
92 private static final int NO_OF_NOMENCLATURAL_REFERENCES
= NO_OF_ACCEPTED_TAXA
95 // --------------------variables for all ------------------
97 private Long no_of_all_references
= new Long(0);
98 private Long no_of_descriptive_source_references
= new Long(0);
100 // ............................................
102 // log the type enum to an int constant:
103 private Map
<String
, Long
> typeMap_ALL
;
105 // ------------------ variables for CLASSIFICATIONS -----------------------
107 // int[] anArray = new int[NO_OF_CLASSIFICATIONS];
108 private static List
<Long
> no_of_all_taxa_c
= new ArrayList
<Long
>(
109 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
110 private static List
<Long
> no_of_accepted_taxa_c
= new ArrayList
<Long
>(
111 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
112 private static List
<Long
> no_of_synonyms_c
= new ArrayList
<Long
>(
113 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
114 private static List
<Long
> no_of_taxon_names_c
= new ArrayList
<Long
>(
115 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
116 private static List
<Long
> no_of_descriptive_source_references_c
= new ArrayList
<Long
>(
117 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
118 private static List
<Long
> no_of_all_references_c
= new ArrayList
<Long
>(
119 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
120 private static List
<Long
> no_of_nomenclatural_references_c
= new ArrayList
<Long
>(
121 Collections
.nCopies(NO_OF_CLASSIFICATIONS
, new Long(0)));
122 // we do not count classifications in classifications
124 // ........................... constant map ..........................
126 private static final Map
<String
, List
<Long
>> typeCountMap_CLASSIFICATION
= new HashMap
<String
, List
<Long
>>() {
128 put("CLASSIFICATION",
129 new ArrayList
<Long
>(Arrays
.asList((Long
) null, null, null)));
130 put("ALL_TAXA", no_of_all_taxa_c
);
131 put("ACCEPTED_TAXA", no_of_accepted_taxa_c
);
132 put("SYNONYMS", no_of_synonyms_c
);
133 put("TAXON_NAMES", no_of_taxon_names_c
);
134 put("DESCRIPTIVE_SOURCE_REFERENCES",
135 no_of_descriptive_source_references_c
);
136 put("ALL_REFERENCES", no_of_all_references_c
);
137 put("NOMENCLATURAL_REFERENCES", no_of_nomenclatural_references_c
);
141 // ****************** services: ************************
143 private IStatisticsDao service
;
145 private IClassificationDao classificationDao
;
147 private ITaxonDao taxonDao
;
149 private IReferenceDao referenceDao
;
151 private IDescriptionDao descriptionDao
;
153 private IDescriptionElementDao descriptionElementDao
;
155 private ITaxonNodeDao taxonNodeDao
;
159 public void setUp() {
160 // nodeUuid =UUID.fromString("46cd7e78-f7d5-4c31-937b-2bc5074618c4");
161 nodeUuid
= UUID
.fromString("0b5846e5-b8d2-4ca9-ac51-099286ea4adc");
163 AuditEventContextHolder
.clearContext();
168 public void tearDown() {
169 AuditEventContextHolder
.clearContext();
174 public void testGetAllChildNodes() {
177 for (Classification classification
: classifications
) {
179 root
= createTaxTree(classification
);
181 result
=statisticsDao
.getAllChildNodeIds(root
.getUuid());
182 logger
.debug("classification "+ classification
.getName()+": ");
183 logger
.debug("result: "+result
.toString());
186 if (logger
.isTraceEnabled()) {
189 // result=statisticsDao.getAllTaxonIds(nodeUuid);
190 // statisticsDao.getAllTaxonIds();
192 // fail("Not yet implemented");
195 private void createDataSet() {
196 // create NO_OF_CLASSIFICATIONS classifications
197 classifications
= new ArrayList
<Classification
>();
199 for (int i
= 1; i
<= NO_OF_CLASSIFICATIONS
; i
++) {
200 Classification classification
= Classification
201 .NewInstance("European Abies" + i
);
202 classifications
.add(classification
);
203 classificationDao
.save(classification
);
205 // create all taxa, references and synonyms and attach them to one or
206 // more classifications
209 int remainder
= NO_OF_ACCEPTED_TAXA
;
210 Reference sec
= ReferenceFactory
.newBook();
211 boolean secondClassificationForTaxonFlag
= false;
212 boolean synonymFlag
= false;
213 boolean tNomRefFlag
= false;
214 boolean sNomRefFlag
= false;
215 boolean tDescrSourceRefFlag
= false;
216 boolean sDescrSourceRefFlag
= false;
218 // variables: counter (pre-loop)
219 int descriptiveElementsPerTaxon
= (NO_OF_DESCRIPTIVE_SOURCE_REFERENCES
/ NO_OF_ACCEPTED_TAXA
) + 1;
222 int classiCounter
= 0, sharedClassification
= 0, synonymCounter
= 0, nomRefCounter
= 0;
224 // iterate over classifications and add taxa
225 for (/* see above */; remainder
> 0
226 && classiCounter
< NO_OF_CLASSIFICATIONS
; /* see below */) {
228 // compute no of taxa to be created in this classification
229 if (classiCounter
>= NO_OF_CLASSIFICATIONS
- 1) { // last
233 taxaInClass
= remainder
;
234 } else { // take half of left taxa for this class:
235 taxaInClass
= remainder
/ 2;
238 // iterate over amount of taxa meant to be in this classification
239 for (int taxonCounter
= 1; taxonCounter
<= taxaInClass
; taxonCounter
++) {
241 // create a String for the Name
242 RandomStringUtils
.randomAlphabetic(10);
243 String randomName
= RandomStringUtils
.randomAlphabetic(5) + " "
244 + RandomStringUtils
.randomAlphabetic(10);
246 // create a name for the taxon
247 IBotanicalName name
= TaxonNameFactory
.NewBotanicalInstance(Rank
.SPECIES());
248 name
.setNameCache(randomName
, true);
250 // create nomenclatural reference for taxon name (if left)
251 if (nomRefCounter
< NO_OF_NOMENCLATURAL_REFERENCES
) {
252 // we remember this taxon has a nomenclatural reference:
254 Reference nomRef
= ReferenceFactory
.newBook();
255 name
.setNomenclaturalReference(nomRef
);
256 referenceDao
.save(nomRef
);
260 // create a new sec for every other taxon
261 if (taxonCounter
% 2 != 0) {
262 sec
= createSecReference(classiCounter
, taxonCounter
);
266 Taxon taxon
= Taxon
.NewInstance(name
, sec
);
268 // create descriptions, description sources and their references
270 if (no_of_descriptive_source_references
< NO_OF_DESCRIPTIVE_SOURCE_REFERENCES
) {
272 tDescrSourceRefFlag
= true;
274 // create a description and 2 description elements with
275 // references for taxon name
276 TaxonNameDescription nameDescr
= TaxonNameDescription
.NewInstance();
277 CommonTaxonName nameElement
= CommonTaxonName
.NewInstance(
278 "Veilchen" + taxonCounter
, Language
.GERMAN());
279 TextData textElement
= new TextData();
280 Reference nameElementRef
= ReferenceFactory
.newArticle();
281 Reference textElementRef
= ReferenceFactory
283 nameElement
.addSource(OriginalSourceType
.PrimaryTaxonomicSource
, null, null, nameElementRef
, "name: ");
284 textElement
.addSource(OriginalSourceType
.PrimaryTaxonomicSource
, null, null, textElementRef
, "text: ");
285 nameDescr
.addElement(nameElement
);
286 nameDescr
.addElement(textElement
);
287 name
.addDescription(nameDescr
);
288 // taxon.getName().addDescription(nameDescr);
289 referenceDao
.save(nameElementRef
);
290 referenceDao
.save(textElementRef
);
291 descriptionDao
.save(nameDescr
);
293 // create descriptions, description sources and their
296 TaxonDescription taxonDescription
= new TaxonDescription();
297 for (int i
= 0; i
< descriptiveElementsPerTaxon
; i
++) {
298 DescriptionElementBase descriptionElement
= new TextData();
299 DescriptionElementSource descriptionElementSource
= DescriptionElementSource
300 .NewInstance(OriginalSourceType
.PrimaryTaxonomicSource
);
301 Reference article
= ReferenceFactory
.newArticle();
303 descriptionElementSource
.setCitation(article
);
304 descriptionElement
.addSource(descriptionElementSource
);
305 taxonDescription
.addElement(descriptionElement
);
306 referenceDao
.save(article
);
307 descriptionElementDao
.save(descriptionElement
);
310 descriptionDao
.save(taxonDescription
);
311 taxon
.addDescription(taxonDescription
);
313 // create a Specimen for taxon with description, descr.
314 // element and referece
316 // Specimen specimen = Specimen.NewInstance();
317 // SpecimenDescription specimenDescription =
318 // SpecimenDescription.NewInstance(specimen);
319 // DescriptionElementBase descrElement = new TextData();
320 // Reference specimenRef = ReferenceFactory.newArticle();
321 // descrElement.addSource(null, null, specimenRef, null);
324 // descriptionService.save(specimenDescription);
325 // taxon.add(specimen);
327 no_of_descriptive_source_references
+= descriptiveElementsPerTaxon
+ 2 + 1;
331 // add taxon to classification
332 classifications
.get(classiCounter
).addChildTaxon(taxon
, null, null);
334 // now if there are any left, we create a synonym for the taxon
335 if (synonymCounter
< NO_OF_SYNONYMS
) {
337 randomName
= RandomStringUtils
.randomAlphabetic(5) + " "
338 + RandomStringUtils
.randomAlphabetic(10);
340 name
= TaxonNameFactory
.NewBotanicalInstance(Rank
.SPECIES());
341 name
.setNameCache(randomName
, true);
343 // create nomenclatural reference for synonym name (if left)
344 if (nomRefCounter
< NO_OF_NOMENCLATURAL_REFERENCES
) {
346 Reference nomRef
= ReferenceFactory
.newBook();
347 name
.setNomenclaturalReference(nomRef
);
348 referenceDao
.save(nomRef
);
352 if (no_of_descriptive_source_references
< NO_OF_DESCRIPTIVE_SOURCE_REFERENCES
) {
353 sDescrSourceRefFlag
= true;
355 // create a description and 2 description elements with
356 // references for synonym name
357 TaxonNameDescription nameDescr
= TaxonNameDescription
.NewInstance();
358 CommonTaxonName nameElement
= CommonTaxonName
359 .NewInstance("anderes Veilchen" + taxonCounter
,
361 TextData textElement
= new TextData();
362 Reference nameElementRef
= ReferenceFactory
.newArticle();
363 Reference textElementRef
= ReferenceFactory
.newBookSection();
364 nameElement
.addSource(OriginalSourceType
.PrimaryTaxonomicSource
, null, null, nameElementRef
,"name: ");
365 textElement
.addSource(OriginalSourceType
.PrimaryTaxonomicSource
, null, null, textElementRef
,"text: ");
366 nameDescr
.addElement(nameElement
);
367 nameDescr
.addElement(textElement
);
368 name
.addDescription(nameDescr
);
369 // taxon.getName().addDescription(nameDescr);
370 referenceDao
.save(nameElementRef
);
371 referenceDao
.save(textElementRef
);
372 descriptionDao
.save(nameDescr
);
373 no_of_descriptive_source_references
+= 2;
376 // create a new reference for every other synonym:
377 if (taxonCounter
% 2 != 0) {
378 sec
= createSecReference(classiCounter
, taxonCounter
);
380 Synonym synonym
= Synonym
.NewInstance(name
, sec
);
381 taxonDao
.save(synonym
);
382 taxon
.addSynonym(synonym
,
383 SynonymType
.SYNONYM_OF());
388 // if this is not the last classification and there are
389 // taxa left that should be in more than one classification
390 // we add the taxon to the next class in the list too.
391 if (classiCounter
< NO_OF_CLASSIFICATIONS
392 && sharedClassification
< NO_OF_SHARED_TAXA
) {
393 classifications
.get(classiCounter
+ 1).addChildTaxon(taxon
, null, null);
395 // we remember that this taxon is attached to 2
397 secondClassificationForTaxonFlag
= true;
398 sharedClassification
++;
399 classificationDao
.saveOrUpdate(classifications
400 .get(classiCounter
+ 1));
403 taxonDao
.save(taxon
);
404 classificationDao
.saveOrUpdate(classifications
405 .get(classiCounter
));
407 // count the data created with this taxon:
408 int c
= classiCounter
;
410 if (secondClassificationForTaxonFlag
) {
414 // run the following loop once, if this taxon only belongs to
417 // twice, if it is attached to 2 classifications
418 for (int i
= classiCounter
; i
<= c
; i
++) {
420 // count everything just created for this taxon:
421 increment(no_of_accepted_taxa_c
, i
);
422 increment(no_of_taxon_names_c
, i
);
424 increment(no_of_nomenclatural_references_c
, i
);
427 increment(no_of_nomenclatural_references_c
, i
);
430 increment(no_of_synonyms_c
, i
);
431 increment(no_of_taxon_names_c
, i
);
433 if (taxonCounter
% 2 != 0) {
434 increment(no_of_all_references_c
, i
);
436 increment(no_of_all_references_c
, i
);
439 if (tDescrSourceRefFlag
) {
440 increment(no_of_descriptive_source_references_c
, i
,
441 descriptiveElementsPerTaxon
+ 2);
444 if (sDescrSourceRefFlag
) {
445 increment(no_of_descriptive_source_references_c
, i
, 2);
449 secondClassificationForTaxonFlag
= false;
453 tDescrSourceRefFlag
= false;
454 sDescrSourceRefFlag
= false;
457 // modify variables (post-loop)
459 remainder
-= taxaInClass
;
462 merge(no_of_accepted_taxa_c
, no_of_synonyms_c
, no_of_all_taxa_c
);
463 merge(no_of_all_references_c
, no_of_nomenclatural_references_c
,
464 no_of_all_references_c
);
466 // TODO Auto-generated method stub
471 * create and count a new sec Reference
473 * @param classiCounter
474 * @param taxonCounter
477 private Reference
createSecReference(int classiCounter
, int taxonCounter
) {
479 sec
= ReferenceFactory
.newBook();
480 sec
.setTitle("book " + classiCounter
+ "." + taxonCounter
);
481 referenceDao
.save(sec
);
482 no_of_all_references
++;
488 * @param inClassification
491 private void increment(List
<Long
> no_of_sth
, int inClassification
,
493 no_of_sth
.set(inClassification
, (no_of_sth
.get(inClassification
))
497 private void increment(List
<Long
> no_of_sth
, int inClassification
) {
498 increment(no_of_sth
, inClassification
, 1);
501 private void merge(List
<Long
> no_of_sth1
, List
<Long
> no_of_sth2
,
502 List
<Long
> no_of_sum
) {
504 for (int i
= 0; i
< NO_OF_CLASSIFICATIONS
; i
++) {
505 Long sum
= no_of_sth1
.get(i
) + no_of_sth2
.get(i
);
506 no_of_sum
.set(i
, sum
);
511 private TaxonNode
createTaxTree(Classification classification
) {
512 Random rand
= new Random();
514 Set
<TaxonNode
> nodes
= classification
.getAllNodes();
515 ArrayList
<TaxonNode
> children
= new ArrayList
<>();
516 TaxonNode parent
= nodes
.iterator().next();
518 TaxonNode root
= parent
;
519 nodes
.remove(parent
);
520 while (!nodes
.isEmpty()) {
521 int n
= rand
.nextInt(2) + 1;
522 for (int i
= 1; i
<= n
&& !(nodes
.isEmpty()); i
++) {
523 TaxonNode nextNode
= nodes
.iterator().next();
524 nextNode
= parent
.addChildNode(nextNode
, null, null);
525 children
.add(nextNode
);
526 nodes
.remove(nextNode
);
529 parent
= children
.get(0);
539 private void print() {
540 for (Classification classification
: classifications
) {
541 System
.out
.println("Classification:" + classification
.toString());
542 for (TaxonNode node
: classification
.getAllNodes()) {
543 System
.out
.println("\tTaxon: " + node
.getTaxon().toString()+" node UUID: "+ node
.getUuid());
544 System
.out
.println(" \t(Name: "
545 + node
.getTaxon().getName().toString() + ")");
546 System
.out
.print("\tChildren: ");
547 for (TaxonNode childNode
: node
.getChildNodes()) {
548 System
.out
.print(/*childNode.getTaxon().getName() + */" node UUID: "+ node
.getUuid()+" ");
550 System
.out
.println();
552 if (node
.getTaxon().getName().getNomenclaturalReference() != null) {
553 System
.out
.println(" \t(Nomencl. Ref.: "
554 + node
.getTaxon().getName()
555 .getNomenclaturalReference().getId() + ")");
557 for (Synonym synonym
: node
.getTaxon().getSynonyms()) {
558 System
.out
.println("\t\tSynonym: " + synonym
.toString());
559 System
.out
.println(" \t\t(Name: "
560 + synonym
.getName().toString() + ")");
561 if (synonym
.getName().getNomenclaturalReference() != null) {
562 System
.out
.println(" \t\t(Nomencl. Ref.: "
563 + synonym
.getName().getNomenclaturalReference()
566 System
.out
.println();
571 System
.out
.println();
572 System
.out
.println("end!");
577 * @see eu.etaxonomy.cdm.test.integration.CdmIntegrationTest#createTestData()
580 public void createTestDataSet() throws FileNotFoundException
{
581 // TODO Auto-generated method stub