2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.cdm
.io
.common
;
12 import java
.net
.MalformedURLException
;
14 import java
.net
.URISyntaxException
;
15 import java
.sql
.ResultSet
;
16 import java
.sql
.SQLException
;
17 import java
.util
.Arrays
;
18 import java
.util
.HashSet
;
19 import java
.util
.List
;
21 import java
.util
.UUID
;
23 import org
.apache
.log4j
.Logger
;
25 import eu
.etaxonomy
.cdm
.api
.service
.pager
.Pager
;
26 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
27 import eu
.etaxonomy
.cdm
.common
.media
.ImageInfo
;
28 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
29 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.IInputTransformer
;
30 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
31 import eu
.etaxonomy
.cdm
.io
.markup
.MarkupTransformer
;
32 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
33 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
34 import eu
.etaxonomy
.cdm
.model
.common
.DefinedTermBase
;
35 import eu
.etaxonomy
.cdm
.model
.common
.DescriptionElementSource
;
36 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
37 import eu
.etaxonomy
.cdm
.model
.common
.Figure
;
38 import eu
.etaxonomy
.cdm
.model
.common
.IOriginalSource
;
39 import eu
.etaxonomy
.cdm
.model
.common
.ISourceable
;
40 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
41 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
42 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
43 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
44 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
45 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
46 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
47 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
48 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
49 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
50 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
51 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
52 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
53 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
54 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
55 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
56 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
57 import eu
.etaxonomy
.cdm
.model
.media
.ImageFile
;
58 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
59 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
60 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
61 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
62 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
63 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
64 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
65 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
66 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
73 public abstract class CdmImportBase
<CONFIG
extends IImportConfigurator
, STATE
extends ImportStateBase
> extends CdmIoBase
<STATE
> implements ICdmImport
<CONFIG
, STATE
>{
74 private static Logger logger
= Logger
.getLogger(CdmImportBase
.class);
76 protected static final boolean CREATE
= true;
77 protected static final boolean IMAGE_GALLERY
= true;
78 protected static final boolean READ_MEDIA_DATA
= true;
80 public static final UUID uuidUserDefinedNamedAreaLevelVocabulary
= UUID
.fromString("255144da-8d95-457e-a327-9752a8f85e5a");
81 public static final UUID uuidUserDefinedNamedAreaVocabulary
= UUID
.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");
82 public static final UUID uuidUserDefinedExtensionTypeVocabulary
= UUID
.fromString("e28c1394-1be8-4847-8b81-ab44eb6d5bc8");
83 public static final UUID uuidUserDefinedReferenceSystemVocabulary
= UUID
.fromString("467591a3-10b4-4bf1-9239-f06ece33e90a");
84 public static final UUID uuidUserDefinedFeatureVocabulary
= UUID
.fromString("fe5fccb3-a2f2-4b97-b199-6e2743cf1627");
85 public static final UUID uuidUserDefinedAnnotationTypeVocabulary
= UUID
.fromString("cd9ecdd2-9cae-4890-9032-ad83293ae883");
86 public static final UUID uuidUserDefinedMarkerTypeVocabulary
= UUID
.fromString("5f02a261-fd7d-4fce-bbe4-21472de8cd51");
89 private static final String UuidOnly
= "UUIDOnly";
90 private static final String UuidLabel
= "UUID or label";
91 private static final String UuidLabelAbbrev
= "UUID, label or abbreviation";
92 private static final String UuidAbbrev
= "UUID or abbreviation";
94 public enum TermMatchMode
{
95 UUID_ONLY(0, UuidOnly
)
96 ,UUID_LABEL(1, UuidLabel
)
97 ,UUID_LABEL_ABBREVLABEL(2, UuidLabelAbbrev
)
98 ,UUID_ABBREVLABEL(3, UuidAbbrev
)
103 private String representation
;
104 private TermMatchMode(int id
, String representation
){
106 this.representation
= representation
;
111 public String
getRepresentation() {
112 return representation
;
114 public TermMatchMode
valueOf(int id
){
116 case 0: return UUID_ONLY
;
117 case 1: return UUID_LABEL
;
118 case 2: return UUID_LABEL_ABBREVLABEL
;
119 case 3: return UUID_ABBREVLABEL
;
120 default: return UUID_ONLY
;
127 protected Classification
makeTree(STATE state
, Reference reference
){
128 Reference ref
= CdmBase
.deproxy(reference
, Reference
.class);
129 String treeName
= "Classification (Import)";
130 if (ref
!= null && CdmUtils
.isNotEmpty(ref
.getTitleCache())){
131 treeName
= ref
.getTitleCache();
133 Classification tree
= Classification
.NewInstance(treeName
);
134 tree
.setReference(ref
);
137 // use defined uuid for first tree
138 CONFIG config
= (CONFIG
)state
.getConfig();
139 if (state
.countTrees() < 1 ){
140 tree
.setUuid(config
.getClassificationUuid());
142 getClassificationService().save(tree
);
143 state
.putTree(ref
, tree
);
149 * Alternative memory saving method variant of
150 * {@link #makeTree(STATE state, Reference ref)} which stores only the
151 * UUID instead of the full tree in the <code>ImportStateBase</code> by
152 * using <code>state.putTreeUuid(ref, tree);</code>
158 protected Classification
makeTreeMemSave(STATE state
, Reference ref
){
159 String treeName
= "Classification (Import)";
160 if (ref
!= null && CdmUtils
.isNotEmpty(ref
.getTitleCache())){
161 treeName
= ref
.getTitleCache();
163 Classification tree
= Classification
.NewInstance(treeName
);
164 tree
.setReference(ref
);
167 // use defined uuid for first tree
168 CONFIG config
= (CONFIG
)state
.getConfig();
169 if (state
.countTrees() < 1 ){
170 tree
.setUuid(config
.getClassificationUuid());
172 getClassificationService().save(tree
);
173 state
.putTreeUuid(ref
, tree
);
178 protected ExtensionType
getExtensionType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
179 return getExtensionType(state
, uuid
, label
, text
, labelAbbrev
, null);
181 protected ExtensionType
getExtensionType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<ExtensionType
> voc
){
183 uuid
= UUID
.randomUUID();
185 ExtensionType extensionType
= state
.getExtensionType(uuid
);
186 if (extensionType
== null){
187 extensionType
= (ExtensionType
)getTermService().find(uuid
);
188 if (extensionType
== null){
189 extensionType
= ExtensionType
.NewInstance(text
, label
, labelAbbrev
);
190 extensionType
.setUuid(uuid
);
192 boolean isOrdered
= false;
193 voc
= getVocabulary(uuidUserDefinedExtensionTypeVocabulary
, "User defined vocabulary for extension types", "User Defined Extension Types", null, null, isOrdered
, extensionType
);
195 voc
.addTerm(extensionType
);
196 getTermService().saveOrUpdate(extensionType
);
198 state
.putExtensionType(extensionType
);
200 return extensionType
;
204 protected MarkerType
getMarkerType(STATE state
, String keyString
) {
205 IInputTransformer transformer
= state
.getTransformer();
206 MarkerType markerType
= null;
208 markerType
= transformer
.getMarkerTypeByKey(keyString
);
209 } catch (UndefinedTransformerMethodException e
) {
210 logger
.info("getMarkerTypeByKey not yet implemented for this import");
212 if (markerType
== null ){
215 uuid
= transformer
.getMarkerTypeUuid(keyString
);
216 return getMarkerType(state
, uuid
, keyString
, keyString
, keyString
);
217 } catch (UndefinedTransformerMethodException e
) {
218 logger
.warn("getMarkerTypeUuid not yet implemented for this import");
224 protected MarkerType
getMarkerType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
225 return getMarkerType(state
, uuid
, label
, text
, labelAbbrev
, null);
229 protected MarkerType
getMarkerType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<MarkerType
> voc
){
231 uuid
= UUID
.randomUUID();
233 MarkerType markerType
= state
.getMarkerType(uuid
);
234 if (markerType
== null){
235 markerType
= (MarkerType
)getTermService().find(uuid
);
236 if (markerType
== null){
237 markerType
= MarkerType
.NewInstance(label
, text
, labelAbbrev
);
238 markerType
.setUuid(uuid
);
240 boolean isOrdered
= false;
241 voc
= getVocabulary(uuidUserDefinedMarkerTypeVocabulary
, "User defined vocabulary for marker types", "User Defined Marker Types", null, null, isOrdered
, markerType
);
243 voc
.addTerm(markerType
);
244 getTermService().save(markerType
);
246 state
.putMarkerType(markerType
);
251 protected AnnotationType
getAnnotationType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<AnnotationType
> voc
){
253 uuid
= UUID
.randomUUID();
255 AnnotationType annotationType
= state
.getAnnotationType(uuid
);
256 if (annotationType
== null){
257 annotationType
= (AnnotationType
)getTermService().find(uuid
);
258 if (annotationType
== null){
259 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
260 annotationType
.setUuid(uuid
);
262 boolean isOrdered
= false;
263 voc
= getVocabulary(uuidUserDefinedAnnotationTypeVocabulary
, "User defined vocabulary for annotation types", "User Defined Annotation Types", null, null, isOrdered
, annotationType
);
266 voc
.addTerm(annotationType
);
267 getTermService().save(annotationType
);
269 state
.putAnnotationType(annotationType
);
271 return annotationType
;
275 protected ReferenceSystem
getReferenceSystem(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary voc
){
277 uuid
= UUID
.randomUUID();
279 ReferenceSystem refSystem
= state
.getReferenceSystem(uuid
);
280 if (refSystem
== null){
281 refSystem
= (ReferenceSystem
)getTermService().find(uuid
);
282 if (refSystem
== null){
283 refSystem
= ReferenceSystem
.NewInstance(text
, label
, labelAbbrev
);
285 boolean isOrdered
= false;
286 voc
= getVocabulary(uuidUserDefinedReferenceSystemVocabulary
, "User defined vocabulary for named areas", "User Defined Reference System", null, null, isOrdered
, refSystem
);
288 voc
.addTerm(refSystem
);
289 refSystem
.setUuid(uuid
);
290 getTermService().save(refSystem
);
292 state
.putReferenceSystem(refSystem
);
299 * Returns a named area for a given uuid by first . If the named area does not
309 protected NamedArea
getNamedArea(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
){
310 return getNamedArea(state
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, null, null);
313 protected NamedArea
getNamedArea(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
, TermVocabulary voc
, TermMatchMode matchMode
){
314 Class
<NamedArea
> clazz
= NamedArea
.class;
316 uuid
= UUID
.randomUUID();
318 if (matchMode
== null){
319 matchMode
= TermMatchMode
.UUID_ONLY
;
321 NamedArea namedArea
= state
.getNamedArea(uuid
);
322 if (namedArea
== null){
323 DefinedTermBase term
= getTermService().find(uuid
);
324 namedArea
= CdmBase
.deproxy(term
,NamedArea
.class);
325 //TODO matching still experimental
326 if (namedArea
== null && (matchMode
.equals(TermMatchMode
.UUID_LABEL
) || matchMode
.equals(TermMatchMode
.UUID_LABEL_ABBREVLABEL
))){
328 Pager
<NamedArea
> areaPager
= (Pager
)getTermService().findByTitle(clazz
, label
, null, null, null, null, null, null);
329 namedArea
= findBestMatchingArea(areaPager
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, voc
);
331 if (namedArea
== null && (matchMode
.equals(TermMatchMode
.UUID_ABBREVLABEL
) || matchMode
.equals(TermMatchMode
.UUID_LABEL_ABBREVLABEL
))){
332 Pager
<NamedArea
> areaPager
= getTermService().findByRepresentationAbbreviation(labelAbbrev
, clazz
, null, null);
333 namedArea
= findBestMatchingArea(areaPager
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, voc
);
336 if (namedArea
== null){
337 namedArea
= NamedArea
.NewInstance(text
, label
, labelAbbrev
);
339 boolean isOrdered
= true;
340 voc
= getVocabulary(uuidUserDefinedNamedAreaVocabulary
, "User defined vocabulary for named areas", "User Defined Named Areas", null, null, isOrdered
, namedArea
);
342 voc
.addTerm(namedArea
);
343 namedArea
.setType(areaType
);
344 namedArea
.setLevel(level
);
345 namedArea
.setUuid(uuid
);
346 getTermService().save(namedArea
);
348 state
.putNamedArea(namedArea
);
354 private NamedArea
findBestMatchingArea(Pager
<NamedArea
> areaPager
, UUID uuid
, String label
, String text
, String abbrev
,
355 NamedAreaType areaType
, NamedAreaLevel level
, TermVocabulary voc
) {
356 // TODO preliminary implementation
357 List
<NamedArea
> list
= areaPager
.getRecords();
358 if (list
.size() == 0){
360 }else if (list
.size() == 1){
362 }else if (list
.size() > 1){
363 String message
= "There is more than 1 matching area for %s, %s, %s. As a preliminary implementation I take the first";
364 message
= String
.format(message
, label
, abbrev
, text
);
365 logger
.warn(message
);
372 protected NamedAreaLevel
getNamedAreaLevel(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<NamedAreaLevel
> voc
){
374 uuid
= UUID
.randomUUID();
376 NamedAreaLevel namedAreaLevel
= state
.getNamedAreaLevel(uuid
);
377 if (namedAreaLevel
== null){
378 //TODO propPath just for testing
379 List
<String
> propPath
= Arrays
.asList("vocabulary");
380 DefinedTermBase
<NamedAreaLevel
> term
= getTermService().load(uuid
, propPath
);
381 namedAreaLevel
= CdmBase
.deproxy(term
, NamedAreaLevel
.class);
382 if (namedAreaLevel
== null){
383 namedAreaLevel
= NamedAreaLevel
.NewInstance(text
, label
, labelAbbrev
);
385 boolean isOrdered
= true;
386 voc
= getVocabulary(uuidUserDefinedNamedAreaLevelVocabulary
, "User defined vocabulary for named area levels", "User Defined Named Area Levels", null, null, isOrdered
, namedAreaLevel
);
388 //FIXME only for debugging
389 Set
<NamedAreaLevel
> terms
= voc
.getTerms();
390 for (NamedAreaLevel level
: terms
){
391 TermVocabulary
<NamedAreaLevel
> levelVoc
= level
.getVocabulary();
392 if (levelVoc
== null){
393 logger
.error("Level voc is null");
395 logger
.warn("Level voc is not null");
398 voc
.addTerm(namedAreaLevel
);
399 namedAreaLevel
.setUuid(uuid
);
400 getTermService().save(namedAreaLevel
);
402 state
.putNamedAreaLevel(namedAreaLevel
);
404 return namedAreaLevel
;
409 * Returns a feature if it exists, null otherwise.
410 * @see #getFeature(ImportStateBase, UUID, String, String, String, TermVocabulary)
415 protected Feature
getFeature(STATE state
, UUID uuid
){
416 return getFeature(state
, uuid
, null, null, null, null);
420 * Returns a feature for a given uuid by first checking if the uuid has already been used in this import, if not
421 * checking if the feature exists in the database, if not creating it anew (with vocabulary etc.).
422 * If label, text and labelAbbrev are all <code>null</code> no feature is created.
430 protected Feature
getFeature(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<Feature
> voc
){
434 Feature feature
= state
.getFeature(uuid
);
435 if (feature
== null){
436 feature
= (Feature
)getTermService().find(uuid
);
437 if (feature
== null && ! hasNoLabel(label
, text
, labelAbbrev
)){
438 feature
= Feature
.NewInstance(text
, label
, labelAbbrev
);
439 feature
.setUuid(uuid
);
440 feature
.setSupportsTextData(true);
441 // UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8");
443 boolean isOrdered
= false;
444 voc
= getVocabulary(uuidUserDefinedFeatureVocabulary
, "User defined vocabulary for features", "User Defined Features", null, null, isOrdered
, feature
);
446 voc
.addTerm(feature
);
447 getTermService().save(feature
);
449 state
.putFeature(feature
);
454 private boolean hasNoLabel(String label
, String text
, String labelAbbrev
) {
455 return label
== null && text
== null && labelAbbrev
== null;
460 * Returns a presence term for a given uuid by first ...
468 protected PresenceTerm
getPresenceTerm(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
472 PresenceTerm presenceTerm
= state
.getPresenceTerm(uuid
);
473 if (presenceTerm
== null){
474 presenceTerm
= (PresenceTerm
)getTermService().find(uuid
);
475 if (presenceTerm
== null){
476 presenceTerm
= PresenceTerm
.NewInstance(text
, label
, labelAbbrev
);
477 presenceTerm
.setUuid(uuid
);
478 //set vocabulary ; FIXME use another user-defined vocabulary
479 UUID uuidPresenceVoc
= UUID
.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05");
480 TermVocabulary
<PresenceTerm
> voc
= getVocabularyService().find(uuidPresenceVoc
);
481 voc
.addTerm(presenceTerm
);
482 getTermService().save(presenceTerm
);
484 state
.putPresenceTerm(presenceTerm
);
490 * Returns a language for a given uuid by first ...
498 protected Language
getLanguage(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
502 Language language
= state
.getLanguage(uuid
);
503 if (language
== null){
504 language
= (Language
)getTermService().find(uuid
);
505 if (language
== null){
506 language
= Language
.NewInstance(text
, label
, labelAbbrev
);
508 language
.setUuid(uuid
);
509 //set vocabulary ; FIXME use another user-defined vocabulary
510 UUID uuidLanguageVoc
= UUID
.fromString("45ac7043-7f5e-4f37-92f2-3874aaaef2de");
511 TermVocabulary
<Language
> voc
= getVocabularyService().find(uuidLanguageVoc
);
512 voc
.addTerm(language
);
513 getTermService().save(language
);
515 state
.putLanguage(language
);
526 protected <T
extends DefinedTermBase
> TermVocabulary
<T
> getVocabulary(UUID uuid
, String text
, String label
, String abbrev
, URI termSourceUri
, boolean isOrdered
, T type
) {
527 List
<String
> propPath
= Arrays
.asList(new String
[]{"terms"});
528 TermVocabulary
<T
> voc
= getVocabularyService().load(uuid
, propPath
);
531 voc
= OrderedTermVocabulary
.NewInstance(text
, label
, abbrev
, termSourceUri
);
533 voc
= TermVocabulary
.NewInstance(text
, label
, abbrev
, termSourceUri
);
536 getVocabularyService().save(voc
);
542 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
543 * If cdmBase is not sourceable nothing happens.
544 * TODO Move to DbImportBase once this exists.
545 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
548 * @param dbIdAttribute
551 * @throws SQLException
553 public void addOriginalSource(CdmBase cdmBase
, Object idAttributeValue
, String namespace
, Reference citation
) {
554 if (cdmBase
instanceof ISourceable
){
555 IOriginalSource source
;
556 ISourceable sourceable
= (ISourceable
)cdmBase
;
557 Object id
= idAttributeValue
;
558 String strId
= String
.valueOf(id
);
559 String microCitation
= null;
560 if (cdmBase
instanceof IdentifiableEntity
){
561 source
= IdentifiableSource
.NewInstance(strId
, namespace
, citation
, microCitation
);
562 }else if (cdmBase
instanceof DescriptionElementBase
){
563 source
= DescriptionElementSource
.NewInstance(strId
, namespace
, citation
, microCitation
);
565 logger
.warn("ISourceable not beeing identifiable entities or description element base are not yet supported. CdmBase is of type " + cdmBase
.getClass().getName() + ". Original source not added.");
568 sourceable
.addSource(source
);
569 }else if (cdmBase
!= null){
570 logger
.warn("Sourced object does not implement ISourceable: " + cdmBase
.getClass() + "," + cdmBase
.getUuid());
572 logger
.warn("Sourced object is null");
577 * @see #addOriginalSource(CdmBase, Object, String, Reference)
580 * @param dbIdAttribute
583 * @throws SQLException
585 public void addOriginalSource(ResultSet rs
, CdmBase cdmBase
, String dbIdAttribute
, String namespace
, Reference citation
) throws SQLException
{
586 Object id
= rs
.getObject(dbIdAttribute
);
587 addOriginalSource(cdmBase
, id
, namespace
, citation
);
592 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
593 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
594 * If the name is an autonym and has no combination author/basionym author the authors are taken from
599 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon
, Taxon childTaxon
) {
600 NonViralName parentName
= HibernateProxyHelper
.deproxy(parentTaxon
.getName(), NonViralName
.class);
601 NonViralName childName
= HibernateProxyHelper
.deproxy(childTaxon
.getName(), NonViralName
.class);
602 fillMissingEpithets(parentName
, childName
);
606 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
607 * or <i>species</i> respectively the according epithets are taken from the parent name.
608 * If the name is an autonym and has no combination author/basionym author the authors are taken from
613 protected void fillMissingEpithets(NonViralName parentName
, NonViralName childName
) {
614 if (CdmUtils
.isEmpty(childName
.getGenusOrUninomial()) && childName
.getRank().isLower(Rank
.GENUS()) ){
615 childName
.setGenusOrUninomial(parentName
.getGenusOrUninomial());
618 if (CdmUtils
.isEmpty(childName
.getSpecificEpithet()) && childName
.getRank().isLower(Rank
.SPECIES()) ){
619 childName
.setSpecificEpithet(parentName
.getSpecificEpithet());
621 if (childName
.isAutonym() && childName
.getCombinationAuthorTeam() == null && childName
.getBasionymAuthorTeam() == null ){
622 childName
.setCombinationAuthorTeam(parentName
.getCombinationAuthorTeam());
623 childName
.setBasionymAuthorTeam(parentName
.getBasionymAuthorTeam());
628 * Returns the taxon description for a taxon. If there are multiple taxon descriptions
629 * an arbitrary one is chosen.
630 * If no taxon description exists, a new one is created if <code>createNewIfNotExists</code>
631 * is <code>true</code>.
632 * @param createNewIfNotExists
633 * @param isImageGallery if true only taxon description being image galleries are considered.
634 * If false only taxon description being no image galleries are considered.
637 public TaxonDescription
getTaxonDescription(Taxon taxon
, boolean isImageGallery
, boolean createNewIfNotExists
) {
638 Reference ref
= null;
639 return getTaxonDescription(taxon
, ref
, isImageGallery
, createNewIfNotExists
);
643 * Like {@link #getTaxonDescription(Taxon, boolean, boolean)}
644 * Only matches a description if the given reference is a source of the description.<BR>
645 * If a new description is created the given reference will be added as a source.
647 * @see #getTaxonDescription(Taxon, boolean, boolean)
649 public TaxonDescription
getTaxonDescription(Taxon taxon
, Reference ref
, boolean isImageGallery
, boolean createNewIfNotExists
) {
650 TaxonDescription result
= null;
651 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
652 for (TaxonDescription description
: descriptions
){
653 if (description
.isImageGallery() == isImageGallery
){
654 if (hasCorrespondingSource(ref
, description
)){
655 result
= description
;
660 if (result
== null && createNewIfNotExists
){
661 result
= TaxonDescription
.NewInstance(taxon
);
662 result
.setImageGallery(isImageGallery
);
664 result
.addSource(null, null, ref
, null);
672 * Returns the textdata that holds general information about a feature for a taxon description.
673 * This is mainly necessary for descriptions that have more than one description element for
674 * a given feature such as 'distribution', 'description' or 'common name'. It may also hold
675 * for hierarchical features where no description element exists for a higher hierarchie level.
676 * Example: the description feature has subfeatures. But some information like authorship, figures,
677 * sources need to be added to the description itself.
678 * Currently a feature placeholder is marked by a marker of type 'feature placeholder'. Maybe in future
679 * there will be a boolean marker in the TextData class itself.
684 * @param createIfNotExists
687 protected TextData
getFeaturePlaceholder(STATE state
, DescriptionBase
<?
> description
, Feature feature
, boolean createIfNotExists
) {
688 UUID featurePlaceholderUuid
= MarkupTransformer
.uuidFeaturePlaceholder
;
689 for (DescriptionElementBase element
: description
.getElements()){
690 if (element
.isInstanceOf(TextData
.class)){
691 TextData textData
= CdmBase
.deproxy(element
, TextData
.class);
692 if (textData
.getFeature() == null || ! textData
.getFeature().equals(feature
)){
695 for (Marker marker
: textData
.getMarkers()){
696 MarkerType markerType
= marker
.getMarkerType();
697 if (markerType
!= null &&
698 markerType
.getUuid().equals(featurePlaceholderUuid
) &&
699 marker
.getValue() == true){
705 if (createIfNotExists
){
706 TextData newPlaceholder
= TextData
.NewInstance(feature
);
707 MarkerType placeholderMarkerType
= getMarkerType(state
, featurePlaceholderUuid
, "Feature Placeholder", "Feature Placeholder", null);
708 Marker marker
= Marker
.NewInstance(placeholderMarkerType
, true);
709 newPlaceholder
.addMarker(marker
);
710 description
.addElement(newPlaceholder
);
711 return newPlaceholder
;
720 * Returns true, if this description has a source with a citation equal to the given reference.
721 * Returns true if the given reference is null.
725 private boolean hasCorrespondingSource(Reference ref
, TaxonDescription description
) {
727 for (IdentifiableSource source
: description
.getSources()){
728 if (ref
.equals(source
.getCitation())){
740 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
741 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
742 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
743 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the
744 * same secundum reference is returned. If no such single taxon exists an
745 * {@link IllegalStateException illegal state exception} is thrown.
749 protected Taxon
getAcceptedTaxon(TaxonBase
<?
> taxonBase
) {
750 if (taxonBase
== null){
752 }else if(taxonBase
.isInstanceOf(Taxon
.class)){
753 return CdmBase
.deproxy(taxonBase
, Taxon
.class);
754 }else if(taxonBase
.isInstanceOf(Synonym
.class)){
755 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
756 Set
<Taxon
> acceptedTaxa
= synonym
.getAcceptedTaxa();
757 if (acceptedTaxa
.size() == 0){
759 }else if (acceptedTaxa
.size() == 1){
760 return acceptedTaxa
.iterator().next();
762 Reference sec
= synonym
.getSec();
764 Set
<Taxon
> taxaWithSameSec
= new HashSet
<Taxon
>();
765 for (Taxon taxon
: acceptedTaxa
){
766 if (sec
.equals(taxon
.getSec())){
767 taxaWithSameSec
.add(taxon
);
770 if (taxaWithSameSec
.size() == 1){
771 return taxaWithSameSec
.iterator().next();
774 throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
777 throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase
.getClass().getName());
786 * @param readDataFromUrl
787 * @see #READ_MEDIA_DATA
789 * @throws MalformedURLException
791 protected Media
getImageMedia(String uriString
, boolean readMediaData
, boolean isFigure
) throws MalformedURLException
{
792 if( uriString
== null){
795 ImageInfo imageInfo
= null;
798 uri
= new URI(uriString
);
801 imageInfo
= ImageInfo
.NewInstance(uri
, 0);
803 } catch (Exception e
) {
804 String message
= "An error occurred when trying to read image meta data: " + e
.getMessage();
805 logger
.warn(message
);
806 fireWarningEvent(message
, "unknown location", 2, 0);
808 ImageFile imageFile
= ImageFile
.NewInstance(uri
, null, imageInfo
);
809 MediaRepresentation representation
= MediaRepresentation
.NewInstance();
810 if(imageInfo
!= null){
811 representation
.setMimeType(imageInfo
.getMimeType());
812 representation
.setSuffix(imageInfo
.getSuffix());
814 representation
.addRepresentationPart(imageFile
);
815 Media media
= isFigure ? Figure
.NewInstance() : Media
.NewInstance();
816 media
.addRepresentation(representation
);
818 } catch (URISyntaxException e1
) {
819 String message
= "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " + uriString
;
820 logger
.warn(message
);
821 fireWarningEvent(message
, "unknown location", 4, 0);