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
.HashSet
;
19 import java
.util
.UUID
;
21 import org
.apache
.log4j
.Logger
;
23 import eu
.etaxonomy
.cdm
.common
.CdmUtils
;
24 import eu
.etaxonomy
.cdm
.common
.mediaMetaData
.ImageMetaData
;
25 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
26 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.IInputTransformer
;
27 import eu
.etaxonomy
.cdm
.io
.common
.mapping
.UndefinedTransformerMethodException
;
28 import eu
.etaxonomy
.cdm
.model
.common
.AnnotationType
;
29 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
30 import eu
.etaxonomy
.cdm
.model
.common
.DescriptionElementSource
;
31 import eu
.etaxonomy
.cdm
.model
.common
.ExtensionType
;
32 import eu
.etaxonomy
.cdm
.model
.common
.IOriginalSource
;
33 import eu
.etaxonomy
.cdm
.model
.common
.ISourceable
;
34 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableEntity
;
35 import eu
.etaxonomy
.cdm
.model
.common
.IdentifiableSource
;
36 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
37 import eu
.etaxonomy
.cdm
.model
.common
.MarkerType
;
38 import eu
.etaxonomy
.cdm
.model
.common
.Representation
;
39 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
40 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
41 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
42 import eu
.etaxonomy
.cdm
.model
.description
.PresenceTerm
;
43 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
44 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
45 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaLevel
;
46 import eu
.etaxonomy
.cdm
.model
.location
.NamedAreaType
;
47 import eu
.etaxonomy
.cdm
.model
.media
.ImageFile
;
48 import eu
.etaxonomy
.cdm
.model
.media
.Media
;
49 import eu
.etaxonomy
.cdm
.model
.media
.MediaRepresentation
;
50 import eu
.etaxonomy
.cdm
.model
.name
.NonViralName
;
51 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
52 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
53 import eu
.etaxonomy
.cdm
.model
.taxon
.Classification
;
54 import eu
.etaxonomy
.cdm
.model
.taxon
.Synonym
;
55 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
56 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonBase
;
63 public abstract class CdmImportBase
<CONFIG
extends IImportConfigurator
, STATE
extends ImportStateBase
> extends CdmIoBase
<STATE
> implements ICdmImport
<CONFIG
, STATE
>{
64 private static Logger logger
= Logger
.getLogger(CdmImportBase
.class);
66 protected Classification
makeTree(STATE state
, Reference reference
){
67 Reference ref
= CdmBase
.deproxy(reference
, Reference
.class);
68 String treeName
= "Classification (Import)";
69 if (ref
!= null && CdmUtils
.isNotEmpty(ref
.getTitleCache())){
70 treeName
= ref
.getTitleCache();
72 Classification tree
= Classification
.NewInstance(treeName
);
73 tree
.setReference(ref
);
76 // use defined uuid for first tree
77 CONFIG config
= (CONFIG
)state
.getConfig();
78 if (state
.countTrees() < 1 ){
79 tree
.setUuid(config
.getClassificationUuid());
81 getClassificationService().save(tree
);
82 state
.putTree(ref
, tree
);
88 * Alternative memory saving method variant of
89 * {@link #makeTree(STATE state, Reference ref)} which stores only the
90 * UUID instead of the full tree in the <code>ImportStateBase</code> by
91 * using <code>state.putTreeUuid(ref, tree);</code>
97 protected Classification
makeTreeMemSave(STATE state
, Reference ref
){
98 String treeName
= "Classification (Import)";
99 if (ref
!= null && CdmUtils
.isNotEmpty(ref
.getTitleCache())){
100 treeName
= ref
.getTitleCache();
102 Classification tree
= Classification
.NewInstance(treeName
);
103 tree
.setReference(ref
);
106 // use defined uuid for first tree
107 CONFIG config
= (CONFIG
)state
.getConfig();
108 if (state
.countTrees() < 1 ){
109 tree
.setUuid(config
.getClassificationUuid());
111 getClassificationService().save(tree
);
112 state
.putTreeUuid(ref
, tree
);
117 protected ExtensionType
getExtensionType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
119 uuid
= UUID
.randomUUID();
121 ExtensionType extensionType
= state
.getExtensionType(uuid
);
122 if (extensionType
== null){
123 extensionType
= (ExtensionType
)getTermService().find(uuid
);
124 if (extensionType
== null){
125 extensionType
= ExtensionType
.NewInstance(text
, label
, labelAbbrev
);
126 extensionType
.setUuid(uuid
);
127 UUID uuidExtensionTypeVoc
= UUID
.fromString("117cc307-5bd4-4b10-9b2f-2e14051b3b20");
128 TermVocabulary voc
= getVocabularyService().find(uuidExtensionTypeVoc
);
129 voc
.addTerm(extensionType
);
130 getTermService().save(extensionType
);
132 state
.putExtensionType(extensionType
);
134 return extensionType
;
138 protected MarkerType
getMarkerType(STATE state
, String keyString
) {
139 IInputTransformer transformer
= state
.getTransformer();
140 MarkerType markerType
= null;
142 markerType
= transformer
.getMarkerTypeByKey(keyString
);
143 } catch (UndefinedTransformerMethodException e
) {
144 logger
.info("getMarkerTypeByKey not yet implemented for this import");
146 if (markerType
== null ){
149 uuid
= transformer
.getMarkerTypeUuid(keyString
);
150 return getMarkerType(state
, uuid
, keyString
, keyString
, keyString
);
151 } catch (UndefinedTransformerMethodException e
) {
152 logger
.warn("getMarkerTypeUuid not yet implemented for this import");
158 protected MarkerType
getMarkerType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
160 uuid
= UUID
.randomUUID();
162 MarkerType markerType
= state
.getMarkerType(uuid
);
163 if (markerType
== null){
164 markerType
= (MarkerType
)getTermService().find(uuid
);
165 if (markerType
== null){
166 markerType
= MarkerType
.NewInstance(label
, text
, labelAbbrev
);
167 markerType
.setUuid(uuid
);
168 UUID uuidMarkerTypeVoc
= UUID
.fromString("19dffff7-e142-429c-a420-5d28e4ebe305");
169 TermVocabulary voc
= getVocabularyService().find(uuidMarkerTypeVoc
);
170 voc
.addTerm(markerType
);
171 getTermService().save(markerType
);
173 state
.putMarkerType(markerType
);
178 protected AnnotationType
getAnnotationType(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
180 uuid
= UUID
.randomUUID();
182 AnnotationType annotationType
= state
.getAnnotationType(uuid
);
183 if (annotationType
== null){
184 annotationType
= (AnnotationType
)getTermService().find(uuid
);
185 if (annotationType
== null){
186 annotationType
= AnnotationType
.NewInstance(label
, text
, labelAbbrev
);
187 annotationType
.setUuid(uuid
);
188 UUID uuidAnnotationTypeVoc
= UUID
.fromString("ca04609b-1ba0-4d31-9c2e-aa8eb2f4e62d");
189 TermVocabulary voc
= getVocabularyService().find(uuidAnnotationTypeVoc
);
190 voc
.addTerm(annotationType
);
191 getTermService().save(annotationType
);
193 state
.putAnnotationType(annotationType
);
195 return annotationType
;
198 public static final UUID uuidUserDefinedNamedAreaVocabulary
= UUID
.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");
200 * Returns a named area for a given uuid by first . If the named area does not
210 protected NamedArea
getNamedArea(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
){
211 return getNamedArea(state
, uuid
, label
, text
, labelAbbrev
, areaType
, level
, null);
214 protected NamedArea
getNamedArea(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
, NamedAreaType areaType
, NamedAreaLevel level
, TermVocabulary voc
){
216 uuid
= UUID
.randomUUID();
218 NamedArea namedArea
= state
.getNamedArea(uuid
);
219 if (namedArea
== null){
220 namedArea
= (NamedArea
)getTermService().find(uuid
);
221 if (namedArea
== null){
222 namedArea
= NamedArea
.NewInstance(text
, label
, labelAbbrev
);
224 voc
= getVocabulary(uuidUserDefinedNamedAreaVocabulary
, "User defined vocabulary for named areas", "User Defined Named Areas", null);
226 voc
.addTerm(namedArea
);
227 namedArea
.setType(areaType
);
228 namedArea
.setLevel(level
);
229 namedArea
.setUuid(uuid
);
230 getTermService().save(namedArea
);
232 state
.putNamedArea(namedArea
);
238 * Returns a feature for a given uuid by first ...
246 protected Feature
getFeature(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
250 Feature feature
= state
.getFeature(uuid
);
251 if (feature
== null){
252 feature
= (Feature
)getTermService().find(uuid
);
253 if (feature
== null){
254 feature
= Feature
.NewInstance(text
, label
, labelAbbrev
);
255 feature
.setUuid(uuid
);
256 feature
.setSupportsTextData(true);
257 //set vocabulary ; FIXME use another user-defined vocabulary
258 UUID uuidFeatureVoc
= UUID
.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8");
259 TermVocabulary
<Feature
> voc
= getVocabularyService().find(uuidFeatureVoc
);
260 voc
.addTerm(feature
);
261 getTermService().save(feature
);
263 state
.putFeature(feature
);
269 * Returns a presence term for a given uuid by first ...
277 protected PresenceTerm
getPresenceTerm(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
281 PresenceTerm presenceTerm
= state
.getPresenceTerm(uuid
);
282 if (presenceTerm
== null){
283 presenceTerm
= (PresenceTerm
)getTermService().find(uuid
);
284 if (presenceTerm
== null){
285 presenceTerm
= PresenceTerm
.NewInstance(text
, label
, labelAbbrev
);
286 presenceTerm
.setUuid(uuid
);
287 //set vocabulary ; FIXME use another user-defined vocabulary
288 UUID uuidPresenceVoc
= UUID
.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05");
289 TermVocabulary
<PresenceTerm
> voc
= getVocabularyService().find(uuidPresenceVoc
);
290 voc
.addTerm(presenceTerm
);
291 getTermService().save(presenceTerm
);
293 state
.putPresenceTerm(presenceTerm
);
299 * Returns a language for a given uuid by first ...
307 protected Language
getLanguage(STATE state
, UUID uuid
, String label
, String text
, String labelAbbrev
){
311 Language language
= state
.getLanguage(uuid
);
312 if (language
== null){
313 language
= (Language
)getTermService().find(uuid
);
314 if (language
== null){
315 language
= Language
.NewInstance(text
, label
, labelAbbrev
);
317 language
.setUuid(uuid
);
318 //set vocabulary ; FIXME use another user-defined vocabulary
319 UUID uuidLanguageVoc
= UUID
.fromString("45ac7043-7f5e-4f37-92f2-3874aaaef2de");
320 TermVocabulary
<Language
> voc
= getVocabularyService().find(uuidLanguageVoc
);
321 voc
.addTerm(language
);
322 getTermService().save(language
);
324 state
.putLanguage(language
);
335 protected TermVocabulary
getVocabulary(UUID uuid
, String text
, String label
, String abbrev
) {
336 TermVocabulary voc
= getVocabularyService().find(uuid
);
338 voc
= TermVocabulary
.NewInstance(text
, label
, abbrev
, null);
340 getVocabularyService().save(voc
);
346 * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.
347 * If cdmBase is not sourceable nothing happens.
348 * TODO Move to DbImportBase once this exists.
349 * TODO also implemented in DbImportObjectCreationMapper (reduce redundance)
352 * @param dbIdAttribute
355 * @throws SQLException
357 public void addOriginalSource(CdmBase cdmBase
, Object idAttributeValue
, String namespace
, Reference citation
) {
358 if (cdmBase
instanceof ISourceable
){
359 IOriginalSource source
;
360 ISourceable sourceable
= (ISourceable
)cdmBase
;
361 Object id
= idAttributeValue
;
362 String strId
= String
.valueOf(id
);
363 String microCitation
= null;
364 if (cdmBase
instanceof IdentifiableEntity
){
365 source
= IdentifiableSource
.NewInstance(strId
, namespace
, citation
, microCitation
);
366 }else if (cdmBase
instanceof DescriptionElementBase
){
367 source
= DescriptionElementSource
.NewInstance(strId
, namespace
, citation
, microCitation
);
369 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.");
372 sourceable
.addSource(source
);
373 }else if (cdmBase
!= null){
374 logger
.warn("Sourced object does not implement ISourceable: " + cdmBase
.getClass() + "," + cdmBase
.getUuid());
376 logger
.warn("Sourced object is null");
381 * @see #addOriginalSource(CdmBase, Object, String, Reference)
384 * @param dbIdAttribute
387 * @throws SQLException
389 public void addOriginalSource(ResultSet rs
, CdmBase cdmBase
, String dbIdAttribute
, String namespace
, Reference citation
) throws SQLException
{
390 Object id
= rs
.getObject(dbIdAttribute
);
391 addOriginalSource(cdmBase
, id
, namespace
, citation
);
396 * If the child taxon is missing genus or species epithet information and the rank is below <i>genus</i>
397 * or <i>species</i> respectively the according epithets are taken from the parent taxon.
398 * If the name is an autonym and has no combination author/basionym author the authors are taken from
403 protected void fillMissingEpithetsForTaxa(Taxon parentTaxon
, Taxon childTaxon
) {
404 NonViralName parentName
= HibernateProxyHelper
.deproxy(parentTaxon
.getName(), NonViralName
.class);
405 NonViralName childName
= HibernateProxyHelper
.deproxy(childTaxon
.getName(), NonViralName
.class);
406 fillMissingEpithets(parentName
, childName
);
410 * If the child name is missing genus or species epithet information and the rank is below <i>genus</i>
411 * or <i>species</i> respectively the according epithets are taken from the parent name.
412 * If the name is an autonym and has no combination author/basionym author the authors are taken from
417 protected void fillMissingEpithets(NonViralName parentName
, NonViralName childName
) {
418 if (CdmUtils
.isEmpty(childName
.getGenusOrUninomial()) && childName
.getRank().isLower(Rank
.GENUS()) ){
419 childName
.setGenusOrUninomial(parentName
.getGenusOrUninomial());
422 if (CdmUtils
.isEmpty(childName
.getSpecificEpithet()) && childName
.getRank().isLower(Rank
.SPECIES()) ){
423 childName
.setSpecificEpithet(parentName
.getSpecificEpithet());
425 if (childName
.isAutonym() && childName
.getCombinationAuthorTeam() == null && childName
.getBasionymAuthorTeam() == null ){
426 childName
.setCombinationAuthorTeam(parentName
.getCombinationAuthorTeam());
427 childName
.setBasionymAuthorTeam(parentName
.getBasionymAuthorTeam());
432 * Returns the image gallery for a taxon. If there are multiple taxon descriptions
433 * marked as image galleries an arbitrary one is chosen.
434 * If no image gallery exists, a new one is created if <code>createNewIfNotExists</code>
435 * is <code>true</code>.
436 * @param createNewIfNotExists
439 public TaxonDescription
getTaxonDescription(Taxon taxon
, boolean isImageGallery
, boolean createNewIfNotExists
) {
440 TaxonDescription result
= null;
441 Set
<TaxonDescription
> descriptions
= taxon
.getDescriptions();
442 for (TaxonDescription description
: descriptions
){
443 if (description
.isImageGallery() == isImageGallery
){
444 result
= description
;
448 if (result
== null && createNewIfNotExists
){
449 result
= TaxonDescription
.NewInstance(taxon
);
450 result
.setImageGallery(isImageGallery
);
457 * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>
458 * If taxonBase is of type taxon the same object is returned. If taxonBase is of type
459 * synonym the accepted taxon is returned if one exists. If no accepted taxon exists
460 * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the
461 * same secundum reference is returned. If no such single taxon exists an
462 * {@link IllegalStateException illegal state exception} is thrown.
466 protected Taxon
getAcceptedTaxon(TaxonBase
<?
> taxonBase
) {
467 if (taxonBase
== null){
469 }else if(taxonBase
.isInstanceOf(Taxon
.class)){
470 return CdmBase
.deproxy(taxonBase
, Taxon
.class);
471 }else if(taxonBase
.isInstanceOf(Synonym
.class)){
472 Synonym synonym
= CdmBase
.deproxy(taxonBase
, Synonym
.class);
473 Set
<Taxon
> acceptedTaxa
= synonym
.getAcceptedTaxa();
474 if (acceptedTaxa
.size() == 0){
476 }else if (acceptedTaxa
.size() == 1){
477 return acceptedTaxa
.iterator().next();
479 Reference sec
= synonym
.getSec();
481 Set
<Taxon
> taxaWithSameSec
= new HashSet
<Taxon
>();
482 for (Taxon taxon
: acceptedTaxa
){
483 if (sec
.equals(taxon
.getSec())){
484 taxaWithSameSec
.add(taxon
);
487 if (taxaWithSameSec
.size() == 1){
488 return taxaWithSameSec
.iterator().next();
491 throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");
494 throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase
.getClass().getName());
501 * @param derivedUnitFacade
502 * @param multimediaObject
503 * @throws MalformedURLException
505 protected Media
getImageMedia(String multimediaObject
, boolean readDataFromUrl
) throws MalformedURLException
{
506 if( multimediaObject
== null){
509 ImageMetaData imd
= ImageMetaData
.newInstance();
512 uri
= new URI(multimediaObject
);
514 if (readDataFromUrl
){
515 imd
.readMetaData(uri
, 0);
517 } catch (Exception e
) {
518 String message
= "An error occurred when trying to read image meta data: " + e
.getMessage();
519 logger
.warn(message
);
521 ImageFile imf
= ImageFile
.NewInstance(uri
, null, imd
);
522 MediaRepresentation representation
= MediaRepresentation
.NewInstance();
523 representation
.setMimeType(imd
.getMimeType());
524 representation
.addRepresentationPart(imf
);
525 Media media
= Media
.NewInstance();
526 media
.addRepresentation(representation
);
528 } catch (URISyntaxException e1
) {
529 String message
= "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " + multimediaObject
;
530 logger
.warn(message
);