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
.IOriginalSource
;
38 import eu
.etaxonomy
.cdm
.model
.common
.ISourceable
;
39 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
40 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
41 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
42 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
43 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
44 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
45 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
46 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
47 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
48 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
49 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
50 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
51 import eu
.etaxonomy
.cdm
.model
.description
.TextData
;
52 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
53 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
54 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
55 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
56 import eu
.etaxonomy
.cdm
.model
.media
.ImageFile
;
57 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
58 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
59 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
60 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
61 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
62 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
63 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
64 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
65 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
72 public abstract class CdmImportBase
<CONFIG
extends IImportConfigurator
, STATE
extends ImportStateBase
> extends CdmIoBase
<STATE
> implements ICdmImport
<CONFIG
, STATE
>{
73 private static Logger logger
= Logger
.getLogger(CdmImportBase
.class);
75 protected static final boolean CREATE
= true;
76 protected static final boolean IMAGE_GALLERY
= true;
78 public static final UUID uuidUserDefinedNamedAreaLevelVocabulary
= UUID
.fromString("255144da-8d95-457e-a327-9752a8f85e5a");
79 public static final UUID uuidUserDefinedNamedAreaVocabulary
= UUID
.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");
80 public static final UUID uuidUserDefinedExtensionTypeVocabulary
= UUID
.fromString("e28c1394-1be8-4847-8b81-ab44eb6d5bc8");
81 public static final UUID uuidUserDefinedReferenceSystemVocabulary
= UUID
.fromString("467591a3-10b4-4bf1-9239-f06ece33e90a");
82 public static final UUID uuidUserDefinedFeatureVocabulary
= UUID
.fromString("fe5fccb3-a2f2-4b97-b199-6e2743cf1627");
83 public static final UUID uuidUserDefinedAnnotationTypeVocabulary
= UUID
.fromString("cd9ecdd2-9cae-4890-9032-ad83293ae883");
84 public static final UUID uuidUserDefinedMarkerTypeVocabulary
= UUID
.fromString("5f02a261-fd7d-4fce-bbe4-21472de8cd51");
87 private static final String UuidOnly
= "UUIDOnly";
88 private static final String UuidLabel
= "UUID or label";
89 private static final String UuidLabelAbbrev
= "UUID, label or abbreviation";
90 private static final String UuidAbbrev
= "UUID or abbreviation";
92 public enum TermMatchMode
{
93 UUID_ONLY(0, UuidOnly
)
94 ,UUID_LABEL(1, UuidLabel
)
95 ,UUID_LABEL_ABBREVLABEL(2, UuidLabelAbbrev
)
96 ,UUID_ABBREVLABEL(3, UuidAbbrev
)
101 private String representation
;
102 private TermMatchMode(int id
, String representation
){
104 this.representation
= representation
;
109 public String
getRepresentation() {
110 return representation
;
112 public TermMatchMode
valueOf(int id
){
114 case 0: return UUID_ONLY
;
115 case 1: return UUID_LABEL
;
116 case 2: return UUID_LABEL_ABBREVLABEL
;
117 case 3: return UUID_ABBREVLABEL
;
118 default: return UUID_ONLY
;
125 protected Classification
makeTree(STATE state
, Reference reference
){
126 Reference ref
= CdmBase
.deproxy(reference
, Reference
.class);
127 String treeName
= "Classification (Import)";
128 if (ref
!= null && CdmUtils
.isNotEmpty(ref
.getTitleCache())){
129 treeName
= ref
.getTitleCache();
131 Classification tree
= Classification
.NewInstance(treeName
);
132 tree
.setReference(ref
);
135 // use defined uuid for first tree
136 CONFIG config
= (CONFIG
)state
.getConfig();
137 if (state
.countTrees() < 1 ){
138 tree
.setUuid(config
.getClassificationUuid());
140 getClassificationService().save(tree
);
141 state
.putTree(ref
, tree
);
147 * Alternative memory saving method variant of
148 * {@link #makeTree(STATE state, Reference ref)} which stores only the
149 * UUID instead of the full tree in the <code>ImportStateBase</code> by
150 * using <code>state.putTreeUuid(ref, tree);</code>
156 protected Classification
makeTreeMemSave(STATE state
, Reference ref
){
157 String treeName
= "Classification (Import)";
158 if (ref
!= null && CdmUtils
.isNotEmpty(ref
.getTitleCache())){
159 treeName
= ref
.getTitleCache();
161 Classification tree
= Classification
.NewInstance(treeName
);
162 tree
.setReference(ref
);
165 // use defined uuid for first tree
166 CONFIG config
= (CONFIG
)state
.getConfig();
167 if (state
.countTrees() < 1 ){
168 tree
.setUuid(config
.getClassificationUuid());
170 getClassificationService().save(tree
);
171 state
.putTreeUuid(ref
, tree
);
176 protected ExtensionType
getExtensionType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
177 return getExtensionType(state
, uuid
, label
, text
, labelAbbrev
, null);
179 protected ExtensionType
getExtensionType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<ExtensionType
> voc
){
181 uuid
= UUID
.randomUUID();
183 ExtensionType extensionType
= state
.getExtensionType(uuid
);
184 if (extensionType
== null){
185 extensionType
= (ExtensionType
)getTermService().find(uuid
);
186 if (extensionType
== null){
187 extensionType
= ExtensionType
.NewInstance(text
, label
, labelAbbrev
);
188 extensionType
.setUuid(uuid
);
190 boolean isOrdered
= false;
191 voc
= getVocabulary(uuidUserDefinedExtensionTypeVocabulary
, "User defined vocabulary for extension types", "User Defined Extension Types", null, null, isOrdered
, extensionType
);
193 voc
.addTerm(extensionType
);
194 getTermService().saveOrUpdate(extensionType
);
196 state
.putExtensionType(extensionType
);
198 return extensionType
;
202 protected MarkerType
getMarkerType(STATE state
, String keyString
) {
203 IInputTransformer transformer
= state
.getTransformer();
204 MarkerType markerType
= null;
206 markerType
= transformer
.getMarkerTypeByKey(keyString
);
207 } catch (UndefinedTransformerMethodException e
) {
208 logger
.info("getMarkerTypeByKey not yet implemented for this import");
210 if (markerType
== null ){
213 uuid
= transformer
.getMarkerTypeUuid(keyString
);
214 return getMarkerType(state
, uuid
, keyString
, keyString
, keyString
);
215 } catch (UndefinedTransformerMethodException e
) {
216 logger
.warn("getMarkerTypeUuid not yet implemented for this import");
222 protected MarkerType
getMarkerType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
223 return getMarkerType(state
, uuid
, label
, text
, labelAbbrev
, null);
227 protected MarkerType
getMarkerType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<MarkerType
> voc
){
229 uuid
= UUID
.randomUUID();
231 MarkerType markerType
= state
.getMarkerType(uuid
);
232 if (markerType
== null){
233 markerType
= (MarkerType
)getTermService().find(uuid
);
234 if (markerType
== null){
235 markerType
= MarkerType
.NewInstance(label
, text
, labelAbbrev
);
236 markerType
.setUuid(uuid
);
238 boolean isOrdered
= false;
239 voc
= getVocabulary(uuidUserDefinedMarkerTypeVocabulary
, "User defined vocabulary for marker types", "User Defined Marker Types", null, null, isOrdered
, markerType
);
241 voc
.addTerm(markerType
);
242 getTermService().save(markerType
);
244 state
.putMarkerType(markerType
);
249 protected AnnotationType
getAnnotationType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<AnnotationType
> voc
){
251 uuid
= UUID
.randomUUID();
253 AnnotationType annotationType
= state
.getAnnotationType(uuid
);
254 if (annotationType
== null){
255 annotationType
= (AnnotationType
)getTermService().find(uuid
);
256 if (annotationType
== null){
257 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
258 annotationType
.setUuid(uuid
);
260 boolean isOrdered
= false;
261 voc
= getVocabulary(uuidUserDefinedAnnotationTypeVocabulary
, "User defined vocabulary for annotation types", "User Defined Annotation Types", null, null, isOrdered
, annotationType
);
264 voc
.addTerm(annotationType
);
265 getTermService().save(annotationType
);
267 state
.putAnnotationType(annotationType
);
269 return annotationType
;
273 protected ReferenceSystem
getReferenceSystem(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary voc
){
275 uuid
= UUID
.randomUUID();
277 ReferenceSystem refSystem
= state
.getReferenceSystem(uuid
);
278 if (refSystem
== null){
279 refSystem
= (ReferenceSystem
)getTermService().find(uuid
);
280 if (refSystem
== null){
281 refSystem
= ReferenceSystem
.NewInstance(text
, label
, labelAbbrev
);
283 boolean isOrdered
= false;
284 voc
= getVocabulary(uuidUserDefinedReferenceSystemVocabulary
, "User defined vocabulary for named areas", "User Defined Reference System", null, null, isOrdered
, refSystem
);
286 voc
.addTerm(refSystem
);
287 refSystem
.setUuid(uuid
);
288 getTermService().save(refSystem
);
290 state
.putReferenceSystem(refSystem
);
297 * Returns a named area for a given uuid by first . If the named area does not
307 protected NamedArea
getNamedArea(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
){
308 return getNamedArea(state
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, null, null);
311 protected NamedArea
getNamedArea(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
, TermVocabulary voc
, TermMatchMode matchMode
){
313 uuid
= UUID
.randomUUID();
315 if (matchMode
== null){
316 matchMode
= TermMatchMode
.UUID_ONLY
;
318 NamedArea namedArea
= state
.getNamedArea(uuid
);
319 if (namedArea
== null){
320 //TODO matching still experimental
321 namedArea
= (NamedArea
)getTermService().find(uuid
);
322 if (namedArea
== null && matchMode
.equals(TermMatchMode
.UUID_LABEL
)){
323 logger
.warn("UUID_LABEL not yet implemented");
325 if (namedArea
== null && matchMode
.equals(TermMatchMode
.UUID_ABBREVLABEL
)){
326 Pager
<NamedArea
> areaPager
= getTermService().findByRepresentationAbbreviation(labelAbbrev
, NamedArea
.class, null, null);
327 namedArea
= findBestMatchingArea(areaPager
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, voc
);
329 if (namedArea
== null && matchMode
.equals(TermMatchMode
.UUID_LABEL_ABBREVLABEL
)){
330 logger
.warn("UUID_LABEL not yet implemented");
333 if (namedArea
== null){
334 namedArea
= NamedArea
.NewInstance(text
, label
, labelAbbrev
);
336 boolean isOrdered
= true;
337 voc
= getVocabulary(uuidUserDefinedNamedAreaVocabulary
, "User defined vocabulary for named areas", "User Defined Named Areas", null, null, isOrdered
, namedArea
);
339 voc
.addTerm(namedArea
);
340 namedArea
.setType(areaType
);
341 namedArea
.setLevel(level
);
342 namedArea
.setUuid(uuid
);
343 getTermService().save(namedArea
);
345 state
.putNamedArea(namedArea
);
351 private NamedArea
findBestMatchingArea(Pager
<NamedArea
> areaPager
, UUID uuid
, String label
, String text
, String abbrev
,
352 NamedAreaType areaType
, NamedAreaLevel level
, TermVocabulary voc
) {
353 // TODO preliminary implementation
354 List
<NamedArea
> list
= areaPager
.getRecords();
355 if (list
.size() == 0){
357 }else if (list
.size() == 1){
359 }else if (list
.size() > 1){
360 String message
= "There is more than 1 matching area for %s, %s, %s. As a preliminary implementation I take the first";
361 message
= String
.format(message
, label
, abbrev
, text
);
362 logger
.warn(message
);
369 protected NamedAreaLevel
getNamedAreaLevel(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<NamedAreaLevel
> voc
){
371 uuid
= UUID
.randomUUID();
373 NamedAreaLevel namedAreaLevel
= state
.getNamedAreaLevel(uuid
);
374 if (namedAreaLevel
== null){
375 namedAreaLevel
= CdmBase
.deproxy(getTermService().find(uuid
), NamedAreaLevel
.class);
376 if (namedAreaLevel
== null){
377 namedAreaLevel
= NamedAreaLevel
.NewInstance(text
, label
, labelAbbrev
);
379 boolean isOrdered
= true;
380 voc
= getVocabulary(uuidUserDefinedNamedAreaLevelVocabulary
, "User defined vocabulary for named area levels", "User Defined Named Area Levels", null, null, isOrdered
, namedAreaLevel
);
382 voc
.addTerm(namedAreaLevel
);
383 namedAreaLevel
.setUuid(uuid
);
384 getTermService().save(namedAreaLevel
);
386 state
.putNamedAreaLevel(namedAreaLevel
);
388 return namedAreaLevel
;
393 * Returns a feature if it exists, null otherwise.
394 * @see #getFeature(ImportStateBase, UUID, String, String, String, TermVocabulary)
399 protected Feature
getFeature(STATE state
, UUID uuid
){
400 return getFeature(state
, uuid
, null, null, null, null);
404 * Returns a feature for a given uuid by first checking if the uuid has already been used in this import, if not
405 * checking if the feature exists in the database, if not creating it anew (with vocabulary etc.).
406 * If label, text and labelAbbrev are all <code>null</code> no feature is created.
414 protected Feature
getFeature(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, TermVocabulary
<Feature
> voc
){
418 Feature feature
= state
.getFeature(uuid
);
419 if (feature
== null){
420 feature
= (Feature
)getTermService().find(uuid
);
421 if (feature
== null && ! hasNoLabel(label
, text
, labelAbbrev
)){
422 feature
= Feature
.NewInstance(text
, label
, labelAbbrev
);
423 feature
.setUuid(uuid
);
424 feature
.setSupportsTextData(true);
425 // UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8");
427 boolean isOrdered
= false;
428 voc
= getVocabulary(uuidUserDefinedFeatureVocabulary
, "User defined vocabulary for features", "User Defined Features", null, null, isOrdered
, feature
);
430 voc
.addTerm(feature
);
431 getTermService().save(feature
);
433 state
.putFeature(feature
);
438 private boolean hasNoLabel(String label
, String text
, String labelAbbrev
) {
439 return label
== null && text
== null && labelAbbrev
== null;
444 * Returns a presence term for a given uuid by first ...
452 protected PresenceTerm
getPresenceTerm(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
456 PresenceTerm presenceTerm
= state
.getPresenceTerm(uuid
);
457 if (presenceTerm
== null){
458 presenceTerm
= (PresenceTerm
)getTermService().find(uuid
);
459 if (presenceTerm
== null){
460 presenceTerm
= PresenceTerm
.NewInstance(text
, label
, labelAbbrev
);
461 presenceTerm
.setUuid(uuid
);
462 //set vocabulary ; FIXME use another user-defined vocabulary
463 UUID uuidPresenceVoc
= UUID
.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05");
464 TermVocabulary
<PresenceTerm
> voc
= getVocabularyService().find(uuidPresenceVoc
);
465 voc
.addTerm(presenceTerm
);
466 getTermService().save(presenceTerm
);
468 state
.putPresenceTerm(presenceTerm
);
474 * Returns a language for a given uuid by first ...
482 protected Language
getLanguage(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
486 Language language
= state
.getLanguage(uuid
);
487 if (language
== null){
488 language
= (Language
)getTermService().find(uuid
);
489 if (language
== null){
490 language
= Language
.NewInstance(text
, label
, labelAbbrev
);
492 language
.setUuid(uuid
);
493 //set vocabulary ; FIXME use another user-defined vocabulary
494 UUID uuidLanguageVoc
= UUID
.fromString("45ac7043-7f5e-4f37-92f2-3874aaaef2de");
495 TermVocabulary
<Language
> voc
= getVocabularyService().find(uuidLanguageVoc
);
496 voc
.addTerm(language
);
497 getTermService().save(language
);
499 state
.putLanguage(language
);
510 protected <T
extends DefinedTermBase
> TermVocabulary
<T
> getVocabulary(UUID uuid
, String text
, String label
, String abbrev
, URI termSourceUri
, boolean isOrdered
, T type
) {
511 List
<String
> propPath
= Arrays
.asList(new String
[]{"terms"});
512 TermVocabulary
<T
> voc
= getVocabularyService().load(uuid
, propPath
);
515 voc
= OrderedTermVocabulary
.NewInstance(text
, label
, abbrev
, termSourceUri
);
517 voc
= TermVocabulary
.NewInstance(text
, label
, abbrev
, termSourceUri
);
520 getVocabularyService().save(voc
);
526 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
527 * If cdmBase is not sourceable nothing happens.
528 * TODO Move to DbImportBase once this exists.
529 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
532 * @param dbIdAttribute
535 * @throws SQLException
537 public void addOriginalSource(CdmBase cdmBase
, Object idAttributeValue
, String namespace
, Reference citation
) {
538 if (cdmBase
instanceof ISourceable
){
539 IOriginalSource source
;
540 ISourceable sourceable
= (ISourceable
)cdmBase
;
541 Object id
= idAttributeValue
;
542 String strId
= String
.valueOf(id
);
543 String microCitation
= null;
544 if (cdmBase
instanceof IdentifiableEntity
){
545 source
= IdentifiableSource
.NewInstance(strId
, namespace
, citation
, microCitation
);
546 }else if (cdmBase
instanceof DescriptionElementBase
){
547 source
= DescriptionElementSource
.NewInstance(strId
, namespace
, citation
, microCitation
);
549 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.");
552 sourceable
.addSource(source
);
553 }else if (cdmBase
!= null){
554 logger
.warn("Sourced object does not implement ISourceable: " + cdmBase
.getClass() + "," + cdmBase
.getUuid());
556 logger
.warn("Sourced object is null");
561 * @see #addOriginalSource(CdmBase, Object, String, Reference)
564 * @param dbIdAttribute
567 * @throws SQLException
569 public void addOriginalSource(ResultSet rs
, CdmBase cdmBase
, String dbIdAttribute
, String namespace
, Reference citation
) throws SQLException
{
570 Object id
= rs
.getObject(dbIdAttribute
);
571 addOriginalSource(cdmBase
, id
, namespace
, citation
);
576 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
577 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
578 * If the name is an autonym and has no combination author/basionym author the authors are taken from
583 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon
, Taxon childTaxon
) {
584 NonViralName parentName
= HibernateProxyHelper
.deproxy(parentTaxon
.getName(), NonViralName
.class);
585 NonViralName childName
= HibernateProxyHelper
.deproxy(childTaxon
.getName(), NonViralName
.class);
586 fillMissingEpithets(parentName
, childName
);
590 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
591 * or <i>species</i> respectively the according epithets are taken from the parent name.
592 * If the name is an autonym and has no combination author/basionym author the authors are taken from
597 protected void fillMissingEpithets(NonViralName parentName
, NonViralName childName
) {
598 if (CdmUtils
.isEmpty(childName
.getGenusOrUninomial()) && childName
.getRank().isLower(Rank
.GENUS()) ){
599 childName
.setGenusOrUninomial(parentName
.getGenusOrUninomial());
602 if (CdmUtils
.isEmpty(childName
.getSpecificEpithet()) && childName
.getRank().isLower(Rank
.SPECIES()) ){
603 childName
.setSpecificEpithet(parentName
.getSpecificEpithet());
605 if (childName
.isAutonym() && childName
.getCombinationAuthorTeam() == null && childName
.getBasionymAuthorTeam() == null ){
606 childName
.setCombinationAuthorTeam(parentName
.getCombinationAuthorTeam());
607 childName
.setBasionymAuthorTeam(parentName
.getBasionymAuthorTeam());
612 * Returns the taxon description for a taxon. If there are multiple taxon descriptions
613 * an arbitrary one is chosen.
614 * If no taxon description exists, a new one is created if <code>createNewIfNotExists</code>
615 * is <code>true</code>.
616 * @param createNewIfNotExists
617 * @param isImageGallery if true only taxon description being image galleries are considered.
618 * If false only taxon description being no image galleries are considered.
621 public TaxonDescription
getTaxonDescription(Taxon taxon
, boolean isImageGallery
, boolean createNewIfNotExists
) {
622 Reference ref
= null;
623 return getTaxonDescription(taxon
, ref
, isImageGallery
, createNewIfNotExists
);
627 * Like {@link #getTaxonDescription(Taxon, boolean, boolean)}
628 * Only matches a description if the given reference is a source of the description.<BR>
629 * If a new description is created the given reference will be added as a source.
631 * @see #getTaxonDescription(Taxon, boolean, boolean)
633 public TaxonDescription
getTaxonDescription(Taxon taxon
, Reference ref
, boolean isImageGallery
, boolean createNewIfNotExists
) {
634 TaxonDescription result
= null;
635 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
636 for (TaxonDescription description
: descriptions
){
637 if (description
.isImageGallery() == isImageGallery
){
638 if (hasCorrespondingSource(ref
, description
)){
639 result
= description
;
644 if (result
== null && createNewIfNotExists
){
645 result
= TaxonDescription
.NewInstance(taxon
);
646 result
.setImageGallery(isImageGallery
);
648 result
.addSource(null, null, ref
, null);
656 * Returns the textdata that holds general information about a feature for a taxon description.
657 * This is mainly necessary for descriptions that have more than one description element for
658 * a given feature such as 'distribution', 'description' or 'common name'. It may also hold
659 * for hierarchical features where no description element exists for a higher hierarchie level.
660 * Example: the description feature has subfeatures. But some information like authorship, figures,
661 * sources need to be added to the description itself.
662 * Currently a feature placeholder is marked by a marker of type 'feature placeholder'. Maybe in future
663 * there will be a boolean marker in the TextData class itself.
668 * @param createIfNotExists
671 protected TextData
getFeaturePlaceholder(STATE state
, DescriptionBase
<?
> description
, Feature feature
, boolean createIfNotExists
) {
672 UUID featurePlaceholderUuid
= MarkupTransformer
.uuidFeaturePlaceholder
;
673 for (DescriptionElementBase element
: description
.getElements()){
674 if (element
.isInstanceOf(TextData
.class)){
675 TextData textData
= CdmBase
.deproxy(element
, TextData
.class);
676 if (textData
.getFeature() == null || ! textData
.getFeature().equals(feature
)){
679 for (Marker marker
: textData
.getMarkers()){
680 MarkerType markerType
= marker
.getMarkerType();
681 if (markerType
!= null &&
682 markerType
.getUuid().equals(featurePlaceholderUuid
) &&
683 marker
.getValue() == true){
689 if (createIfNotExists
){
690 TextData newPlaceholder
= TextData
.NewInstance(feature
);
691 MarkerType placeholderMarkerType
= getMarkerType(state
, featurePlaceholderUuid
, "Feature Placeholder", "Feature Placeholder", null);
692 Marker marker
= Marker
.NewInstance(placeholderMarkerType
, true);
693 newPlaceholder
.addMarker(marker
);
694 description
.addElement(newPlaceholder
);
695 return newPlaceholder
;
704 * Returns true, if this description has a source with a citation equal to the given reference.
705 * Returns true if the given reference is null.
709 private boolean hasCorrespondingSource(Reference ref
, TaxonDescription description
) {
711 for (IdentifiableSource source
: description
.getSources()){
712 if (ref
.equals(source
.getCitation())){
724 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
725 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
726 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
727 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the
728 * same secundum reference is returned. If no such single taxon exists an
729 * {@link IllegalStateException illegal state exception} is thrown.
733 protected Taxon
getAcceptedTaxon(TaxonBase
<?
> taxonBase
) {
734 if (taxonBase
== null){
736 }else if(taxonBase
.isInstanceOf(Taxon
.class)){
737 return CdmBase
.deproxy(taxonBase
, Taxon
.class);
738 }else if(taxonBase
.isInstanceOf(Synonym
.class)){
739 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
740 Set
<Taxon
> acceptedTaxa
= synonym
.getAcceptedTaxa();
741 if (acceptedTaxa
.size() == 0){
743 }else if (acceptedTaxa
.size() == 1){
744 return acceptedTaxa
.iterator().next();
746 Reference sec
= synonym
.getSec();
748 Set
<Taxon
> taxaWithSameSec
= new HashSet
<Taxon
>();
749 for (Taxon taxon
: acceptedTaxa
){
750 if (sec
.equals(taxon
.getSec())){
751 taxaWithSameSec
.add(taxon
);
754 if (taxaWithSameSec
.size() == 1){
755 return taxaWithSameSec
.iterator().next();
758 throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
761 throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase
.getClass().getName());
768 * @param derivedUnitFacade
769 * @param multimediaObject
770 * @throws MalformedURLException
772 protected Media
getImageMedia(String multimediaObject
, boolean readDataFromUrl
) throws MalformedURLException
{
773 if( multimediaObject
== null){
776 ImageInfo imageInfo
= null;
779 uri
= new URI(multimediaObject
);
781 if (readDataFromUrl
){
782 imageInfo
= ImageInfo
.NewInstance(uri
, 0);
784 } catch (Exception e
) {
785 String message
= "An error occurred when trying to read image meta data: " + e
.getMessage();
786 logger
.warn(message
);
788 ImageFile imageFile
= ImageFile
.NewInstance(uri
, null, imageInfo
);
789 MediaRepresentation representation
= MediaRepresentation
.NewInstance();
790 if(imageInfo
!= null){
791 representation
.setMimeType(imageInfo
.getMimeType());
793 representation
.addRepresentationPart(imageFile
);
794 Media media
= Media
.NewInstance();
795 media
.addRepresentation(representation
);
797 } catch (URISyntaxException e1
) {
798 String message
= "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " + multimediaObject
;
799 logger
.warn(message
);