bugfix use of application context in io (until now the defaultIoApplicationContext...
[cdmlib.git] / cdmlib-io / src / main / java / eu / etaxonomy / cdm / io / common / CdmImportBase.java
index b928a1912d60d10b39a3a48f5c707a921ec71dc1..8044f8f309bc750a222bdebed9f6ae0f0c930293 100644 (file)
@@ -9,37 +9,61 @@
 \r
 package eu.etaxonomy.cdm.io.common;\r
 \r
+import java.net.MalformedURLException;\r
+import java.net.URI;\r
+import java.net.URISyntaxException;\r
 import java.sql.ResultSet;\r
 import java.sql.SQLException;\r
+import java.util.Arrays;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Set;\r
 import java.util.UUID;\r
 \r
 import org.apache.log4j.Logger;\r
 \r
+import eu.etaxonomy.cdm.api.service.pager.Pager;\r
 import eu.etaxonomy.cdm.common.CdmUtils;\r
+import eu.etaxonomy.cdm.common.media.ImageInfo;\r
 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;\r
 import eu.etaxonomy.cdm.io.common.mapping.IInputTransformer;\r
 import eu.etaxonomy.cdm.io.common.mapping.UndefinedTransformerMethodException;\r
+import eu.etaxonomy.cdm.io.markup.MarkupTransformer;\r
 import eu.etaxonomy.cdm.model.common.AnnotationType;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.model.common.DefinedTermBase;\r
 import eu.etaxonomy.cdm.model.common.DescriptionElementSource;\r
 import eu.etaxonomy.cdm.model.common.ExtensionType;\r
+import eu.etaxonomy.cdm.model.common.Figure;\r
 import eu.etaxonomy.cdm.model.common.IOriginalSource;\r
 import eu.etaxonomy.cdm.model.common.ISourceable;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;\r
 import eu.etaxonomy.cdm.model.common.IdentifiableSource;\r
 import eu.etaxonomy.cdm.model.common.Language;\r
+import eu.etaxonomy.cdm.model.common.Marker;\r
 import eu.etaxonomy.cdm.model.common.MarkerType;\r
+import eu.etaxonomy.cdm.model.common.OrderedTermVocabulary;\r
 import eu.etaxonomy.cdm.model.common.TermVocabulary;\r
+import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;\r
 import eu.etaxonomy.cdm.model.description.Feature;\r
+import eu.etaxonomy.cdm.model.description.PresenceTerm;\r
+import eu.etaxonomy.cdm.model.description.TaxonDescription;\r
+import eu.etaxonomy.cdm.model.description.TextData;\r
 import eu.etaxonomy.cdm.model.location.NamedArea;\r
 import eu.etaxonomy.cdm.model.location.NamedAreaLevel;\r
 import eu.etaxonomy.cdm.model.location.NamedAreaType;\r
+import eu.etaxonomy.cdm.model.location.ReferenceSystem;\r
+import eu.etaxonomy.cdm.model.media.ImageFile;\r
+import eu.etaxonomy.cdm.model.media.Media;\r
+import eu.etaxonomy.cdm.model.media.MediaRepresentation;\r
 import eu.etaxonomy.cdm.model.name.NonViralName;\r
 import eu.etaxonomy.cdm.model.name.Rank;\r
-import eu.etaxonomy.cdm.model.reference.ReferenceBase;\r
+import eu.etaxonomy.cdm.model.reference.Reference;\r
+import eu.etaxonomy.cdm.model.taxon.Classification;\r
+import eu.etaxonomy.cdm.model.taxon.Synonym;\r
 import eu.etaxonomy.cdm.model.taxon.Taxon;\r
-import eu.etaxonomy.cdm.model.taxon.TaxonomicTree;\r
+import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
 \r
 /**\r
  * @author a.mueller\r
@@ -48,23 +72,74 @@ import eu.etaxonomy.cdm.model.taxon.TaxonomicTree;
  */\r
 public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE extends ImportStateBase> extends CdmIoBase<STATE> implements ICdmImport<CONFIG, STATE>{\r
        private static Logger logger = Logger.getLogger(CdmImportBase.class);\r
+       \r
+       protected static final boolean CREATE = true;\r
+       protected static final boolean IMAGE_GALLERY = true;\r
+       protected static final boolean READ_MEDIA_DATA = true;\r
 \r
-       protected TaxonomicTree makeTree(STATE state, ReferenceBase reference){\r
-               ReferenceBase ref = CdmBase.deproxy(reference, ReferenceBase.class);\r
-               String treeName = "TaxonTree (Import)";\r
+       public static final UUID uuidUserDefinedNamedAreaLevelVocabulary = UUID.fromString("255144da-8d95-457e-a327-9752a8f85e5a");\r
+       public static final UUID uuidUserDefinedNamedAreaVocabulary = UUID.fromString("b2238399-a3af-4f6d-b7eb-ff5d0899bf1b");\r
+       public static final UUID uuidUserDefinedExtensionTypeVocabulary = UUID.fromString("e28c1394-1be8-4847-8b81-ab44eb6d5bc8");\r
+       public static final UUID uuidUserDefinedReferenceSystemVocabulary = UUID.fromString("467591a3-10b4-4bf1-9239-f06ece33e90a");\r
+       public static final UUID uuidUserDefinedFeatureVocabulary = UUID.fromString("fe5fccb3-a2f2-4b97-b199-6e2743cf1627");\r
+       public static final UUID uuidUserDefinedAnnotationTypeVocabulary = UUID.fromString("cd9ecdd2-9cae-4890-9032-ad83293ae883");\r
+       public static final UUID uuidUserDefinedMarkerTypeVocabulary = UUID.fromString("5f02a261-fd7d-4fce-bbe4-21472de8cd51");\r
+       \r
+       \r
+       private static final String UuidOnly = "UUIDOnly";\r
+       private static final String UuidLabel = "UUID or label";\r
+       private static final String UuidLabelAbbrev = "UUID, label or abbreviation";\r
+       private static final String UuidAbbrev = "UUID or abbreviation";\r
+       \r
+       public enum TermMatchMode{\r
+               UUID_ONLY(0, UuidOnly)\r
+               ,UUID_LABEL(1, UuidLabel)\r
+               ,UUID_LABEL_ABBREVLABEL(2, UuidLabelAbbrev)\r
+               ,UUID_ABBREVLABEL(3, UuidAbbrev)\r
+               ;\r
+               \r
+               \r
+               private int id;\r
+               private String representation;\r
+               private TermMatchMode(int id, String representation){\r
+                       this.id = id;\r
+                       this.representation = representation;\r
+               }\r
+               public int getId() {\r
+                       return id;\r
+               }\r
+               public String getRepresentation() {\r
+                       return representation;\r
+               }\r
+               public TermMatchMode valueOf(int id){\r
+                       switch (id){\r
+                               case 0: return UUID_ONLY;\r
+                               case 1: return UUID_LABEL;\r
+                               case 2: return UUID_LABEL_ABBREVLABEL;\r
+                               case 3: return UUID_ABBREVLABEL;\r
+                               default: return UUID_ONLY;\r
+                       }\r
+               }\r
+               \r
+               \r
+       }\r
+       \r
+       protected Classification makeTree(STATE state, Reference reference){\r
+               Reference ref = CdmBase.deproxy(reference, Reference.class);\r
+               String treeName = "Classification (Import)";\r
                if (ref != null && CdmUtils.isNotEmpty(ref.getTitleCache())){\r
                        treeName = ref.getTitleCache();\r
                }\r
-               TaxonomicTree tree = TaxonomicTree.NewInstance(treeName);\r
+               Classification tree = Classification.NewInstance(treeName);\r
                tree.setReference(ref);\r
                \r
 \r
                // use defined uuid for first tree\r
                CONFIG config = (CONFIG)state.getConfig();\r
                if (state.countTrees() < 1 ){\r
-                       tree.setUuid(config.getTaxonomicTreeUuid());\r
+                       tree.setUuid(config.getClassificationUuid());\r
                }\r
-               getTaxonTreeService().save(tree);\r
+               getClassificationService().save(tree);\r
                state.putTree(ref, tree);\r
                return tree;\r
        }\r
@@ -72,7 +147,7 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
        \r
        /**\r
         * Alternative memory saving method variant of\r
-        * {@link #makeTree(STATE state, ReferenceBase ref)} which stores only the\r
+        * {@link #makeTree(STATE state, Reference ref)} which stores only the\r
         * UUID instead of the full tree in the <code>ImportStateBase</code> by \r
         * using <code>state.putTreeUuid(ref, tree);</code>\r
         * \r
@@ -80,35 +155,45 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
         * @param ref\r
         * @return\r
         */\r
-       protected TaxonomicTree makeTreeMemSave(STATE state, ReferenceBase ref){\r
-               String treeName = "TaxonTree (Import)";\r
+       protected Classification makeTreeMemSave(STATE state, Reference ref){\r
+               String treeName = "Classification (Import)";\r
                if (ref != null && CdmUtils.isNotEmpty(ref.getTitleCache())){\r
                        treeName = ref.getTitleCache();\r
                }\r
-               TaxonomicTree tree = TaxonomicTree.NewInstance(treeName);\r
+               Classification tree = Classification.NewInstance(treeName);\r
                tree.setReference(ref);\r
                \r
 \r
                // use defined uuid for first tree\r
                CONFIG config = (CONFIG)state.getConfig();\r
                if (state.countTrees() < 1 ){\r
-                       tree.setUuid(config.getTaxonomicTreeUuid());\r
+                       tree.setUuid(config.getClassificationUuid());\r
                }\r
-               getTaxonTreeService().save(tree);\r
+               getClassificationService().save(tree);\r
                state.putTreeUuid(ref, tree);\r
                return tree;\r
        }\r
        \r
        \r
        protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev){\r
+               return getExtensionType(state, uuid, label, text, labelAbbrev, null);\r
+       }\r
+       protected ExtensionType getExtensionType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<ExtensionType> voc){\r
+               if (uuid == null){\r
+                       uuid = UUID.randomUUID();\r
+               }\r
                ExtensionType extensionType = state.getExtensionType(uuid);\r
                if (extensionType == null){\r
                        extensionType = (ExtensionType)getTermService().find(uuid);\r
                        if (extensionType == null){\r
                                extensionType = ExtensionType.NewInstance(text, label, labelAbbrev);\r
                                extensionType.setUuid(uuid);\r
-                               ExtensionType.DOI().getVocabulary().addTerm(extensionType);\r
-                               getTermService().save(extensionType);\r
+                               if (voc == null){\r
+                                       boolean isOrdered = false;\r
+                                       voc = getVocabulary(uuidUserDefinedExtensionTypeVocabulary, "User defined vocabulary for extension types", "User Defined Extension Types", null, null, isOrdered, extensionType);\r
+                               }\r
+                               voc.addTerm(extensionType);\r
+                               getTermService().saveOrUpdate(extensionType);\r
                        }\r
                        state.putExtensionType(extensionType);\r
                }\r
@@ -137,13 +222,25 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
        }\r
        \r
        protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev){\r
+               return getMarkerType(state, uuid, label, text, labelAbbrev, null);\r
+       }\r
+\r
+       \r
+       protected MarkerType getMarkerType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<MarkerType> voc){\r
+               if (uuid == null){\r
+                       uuid = UUID.randomUUID();\r
+               }\r
                MarkerType markerType = state.getMarkerType(uuid);\r
                if (markerType == null){\r
                        markerType = (MarkerType)getTermService().find(uuid);\r
                        if (markerType == null){\r
                                markerType = MarkerType.NewInstance(label, text, labelAbbrev);\r
                                markerType.setUuid(uuid);\r
-                               MarkerType.COMPLETE().getVocabulary().addTerm(markerType);\r
+                               if (voc == null){\r
+                                       boolean isOrdered = false;\r
+                                       voc = getVocabulary(uuidUserDefinedMarkerTypeVocabulary, "User defined vocabulary for marker types", "User Defined Marker Types", null, null, isOrdered, markerType);\r
+                               }\r
+                               voc.addTerm(markerType);\r
                                getTermService().save(markerType);\r
                        }\r
                        state.putMarkerType(markerType);\r
@@ -151,14 +248,22 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                return markerType;\r
        }\r
        \r
-       protected AnnotationType getAnnotationType(STATE state, UUID uuid, String label, String text, String labelAbbrev){\r
+       protected AnnotationType getAnnotationType(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<AnnotationType> voc){\r
+               if (uuid == null){\r
+                       uuid = UUID.randomUUID();\r
+               }\r
                AnnotationType annotationType = state.getAnnotationType(uuid);\r
                if (annotationType == null){\r
                        annotationType = (AnnotationType)getTermService().find(uuid);\r
                        if (annotationType == null){\r
                                annotationType = AnnotationType.NewInstance(label, text, labelAbbrev);\r
                                annotationType.setUuid(uuid);\r
-                               AnnotationType.EDITORIAL().getVocabulary().addTerm(annotationType);\r
+                               if (voc == null){\r
+                                       boolean isOrdered = false;\r
+                                       voc = getVocabulary(uuidUserDefinedAnnotationTypeVocabulary, "User defined vocabulary for annotation types", "User Defined Annotation Types", null, null, isOrdered, annotationType);\r
+                               }\r
+                               \r
+                               voc.addTerm(annotationType);\r
                                getTermService().save(annotationType);\r
                        }\r
                        state.putAnnotationType(annotationType);\r
@@ -166,6 +271,30 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                return annotationType;\r
        }\r
        \r
+       \r
+       protected ReferenceSystem getReferenceSystem(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary voc){\r
+               if (uuid == null){\r
+                       uuid = UUID.randomUUID();\r
+               }\r
+               ReferenceSystem refSystem = state.getReferenceSystem(uuid);\r
+               if (refSystem == null){\r
+                       refSystem = (ReferenceSystem)getTermService().find(uuid);\r
+                       if (refSystem == null){\r
+                               refSystem = ReferenceSystem.NewInstance(text, label, labelAbbrev);\r
+                               if (voc == null){\r
+                                       boolean isOrdered = false;\r
+                                       voc = getVocabulary(uuidUserDefinedReferenceSystemVocabulary, "User defined vocabulary for named areas", "User Defined Reference System", null, null, isOrdered, refSystem);\r
+                               }\r
+                               voc.addTerm(refSystem);\r
+                               refSystem.setUuid(uuid);\r
+                               getTermService().save(refSystem);\r
+                       }\r
+                       state.putReferenceSystem(refSystem);\r
+               }\r
+               return refSystem;\r
+               \r
+       }\r
+       \r
        /**\r
         * Returns a named area for a given uuid by first . If the named area does not\r
         * @param state\r
@@ -178,11 +307,38 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
         * @return\r
         */\r
        protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level){\r
+               return getNamedArea(state, uuid, label, text, labelAbbrev, areaType, level, null, null);\r
+       }\r
+\r
+       protected NamedArea getNamedArea(STATE state, UUID uuid, String label, String text, String labelAbbrev, NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc, TermMatchMode matchMode){\r
+               Class<NamedArea> clazz = NamedArea.class;\r
+               if (uuid == null){\r
+                       uuid = UUID.randomUUID();\r
+               }\r
+               if (matchMode == null){\r
+                       matchMode = TermMatchMode.UUID_ONLY;\r
+               }\r
                NamedArea namedArea = state.getNamedArea(uuid);\r
                if (namedArea == null){\r
-                       namedArea = (NamedArea)getTermService().find(uuid);\r
+                       //TODO matching still experimental\r
+                       namedArea = CdmBase.deproxy(getTermService().find(uuid),NamedArea.class);\r
+                       if (namedArea == null && (matchMode.equals(TermMatchMode.UUID_LABEL) || matchMode.equals(TermMatchMode.UUID_LABEL_ABBREVLABEL ))){\r
+                               //TODO test\r
+                               Pager<NamedArea> areaPager = (Pager)getTermService().findByTitle(clazz, label, null, null, null, null, null, null);\r
+                               namedArea = findBestMatchingArea(areaPager, uuid, label, text, labelAbbrev, areaType, level, voc);\r
+                       }\r
+                       if (namedArea == null && (matchMode.equals(TermMatchMode.UUID_ABBREVLABEL) || matchMode.equals(TermMatchMode.UUID_LABEL_ABBREVLABEL))){\r
+                               Pager<NamedArea> areaPager = getTermService().findByRepresentationAbbreviation(labelAbbrev, clazz, null, null);\r
+                               namedArea = findBestMatchingArea(areaPager, uuid, label, text, labelAbbrev, areaType, level, voc);\r
+                       }\r
+                       \r
                        if (namedArea == null){\r
                                namedArea = NamedArea.NewInstance(text, label, labelAbbrev);\r
+                               if (voc == null){\r
+                                       boolean isOrdered = true;\r
+                                       voc = getVocabulary(uuidUserDefinedNamedAreaVocabulary, "User defined vocabulary for named areas", "User Defined Named Areas", null, null, isOrdered, namedArea);\r
+                               }\r
+                               voc.addTerm(namedArea);\r
                                namedArea.setType(areaType);\r
                                namedArea.setLevel(level);\r
                                namedArea.setUuid(uuid);\r
@@ -193,8 +349,63 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                return namedArea;\r
        }\r
        \r
+       \r
+       private NamedArea findBestMatchingArea(Pager<NamedArea> areaPager, UUID uuid, String label, String text, String abbrev,\r
+                       NamedAreaType areaType, NamedAreaLevel level, TermVocabulary voc) {\r
+               // TODO preliminary implementation\r
+               List<NamedArea> list = areaPager.getRecords();\r
+               if (list.size() == 0){\r
+                       return null;\r
+               }else if (list.size() == 1){\r
+                       return list.get(0);\r
+               }else if (list.size() > 1){\r
+                       String message = "There is more than 1 matching area for %s, %s, %s. As a preliminary implementation I take the first";\r
+                       message = String.format(message, label, abbrev, text);\r
+                       logger.warn(message);\r
+                       return list.get(0);\r
+               }\r
+               return null;\r
+       }\r
+\r
+\r
+       protected NamedAreaLevel getNamedAreaLevel(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<NamedAreaLevel> voc){\r
+               if (uuid == null){\r
+                       uuid = UUID.randomUUID();\r
+               }\r
+               NamedAreaLevel namedAreaLevel = state.getNamedAreaLevel(uuid);\r
+               if (namedAreaLevel == null){\r
+                       namedAreaLevel = CdmBase.deproxy(getTermService().find(uuid), NamedAreaLevel.class);\r
+                       if (namedAreaLevel == null){\r
+                               namedAreaLevel = NamedAreaLevel.NewInstance(text, label, labelAbbrev);\r
+                               if (voc == null){\r
+                                       boolean isOrdered = true;\r
+                                       voc = getVocabulary(uuidUserDefinedNamedAreaLevelVocabulary, "User defined vocabulary for named area levels", "User Defined Named Area Levels", null, null, isOrdered, namedAreaLevel);\r
+                               }\r
+                               voc.addTerm(namedAreaLevel);\r
+                               namedAreaLevel.setUuid(uuid);\r
+                               getTermService().save(namedAreaLevel);\r
+                       }\r
+                       state.putNamedAreaLevel(namedAreaLevel);\r
+               }\r
+               return namedAreaLevel;\r
+       }\r
+       \r
+       \r
        /**\r
-        * Returns a feature for a given uuid by first ...\r
+        * Returns a feature if it exists, null otherwise.\r
+        * @see #getFeature(ImportStateBase, UUID, String, String, String, TermVocabulary)\r
+        * @param state\r
+        * @param uuid\r
+        * @return\r
+        */\r
+       protected Feature getFeature(STATE state, UUID uuid){\r
+               return getFeature(state, uuid, null, null, null, null);\r
+       }\r
+       \r
+       /**\r
+        * Returns a feature for a given uuid by first checking if the uuid has already been used in this import, if not\r
+        * checking if the feature exists in the database, if not creating it anew (with vocabulary etc.).\r
+        * If label, text and labelAbbrev are all <code>null</code> no feature is created.\r
         * @param state\r
         * @param uuid\r
         * @param label\r
@@ -202,20 +413,22 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
         * @param labelAbbrev\r
         * @return\r
         */\r
-       protected Feature getFeature(STATE state, UUID uuid, String label, String text, String labelAbbrev){\r
+       protected Feature getFeature(STATE state, UUID uuid, String label, String text, String labelAbbrev, TermVocabulary<Feature> voc){\r
                if (uuid == null){\r
                        return null;\r
                }\r
                Feature feature = state.getFeature(uuid);\r
                if (feature == null){\r
                        feature = (Feature)getTermService().find(uuid);\r
-                       if (feature == null){\r
+                       if (feature == null && ! hasNoLabel(label, text, labelAbbrev)){\r
                                feature = Feature.NewInstance(text, label, labelAbbrev);\r
                                feature.setUuid(uuid);\r
                                feature.setSupportsTextData(true);\r
-                               //set vocabulary ; FIXME use another user-defined vocabulary\r
-                               UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8"); \r
-                               TermVocabulary<Feature> voc = getVocabularyService().find(uuidFeatureVoc);\r
+//                             UUID uuidFeatureVoc = UUID.fromString("b187d555-f06f-4d65-9e53-da7c93f8eaa8"); \r
+                               if (voc == null){\r
+                                       boolean isOrdered = false;\r
+                                       voc = getVocabulary(uuidUserDefinedFeatureVocabulary, "User defined vocabulary for features", "User Defined Features", null, null, isOrdered, feature);\r
+                               }\r
                                voc.addTerm(feature);\r
                                getTermService().save(feature);\r
                        }\r
@@ -223,6 +436,41 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                }\r
                return feature;\r
        }\r
+       \r
+       private boolean hasNoLabel(String label, String text, String labelAbbrev) {\r
+               return label == null && text == null && labelAbbrev == null;\r
+       }\r
+\r
+\r
+       /**\r
+        * Returns a presence term for a given uuid by first ...\r
+        * @param state\r
+        * @param uuid\r
+        * @param label\r
+        * @param text\r
+        * @param labelAbbrev\r
+        * @return\r
+        */\r
+       protected PresenceTerm getPresenceTerm(STATE state, UUID uuid, String label, String text, String labelAbbrev){\r
+               if (uuid == null){\r
+                       return null;\r
+               }\r
+               PresenceTerm presenceTerm = state.getPresenceTerm(uuid);\r
+               if (presenceTerm == null){\r
+                       presenceTerm = (PresenceTerm)getTermService().find(uuid);\r
+                       if (presenceTerm == null){\r
+                               presenceTerm = PresenceTerm.NewInstance(text, label, labelAbbrev);\r
+                               presenceTerm.setUuid(uuid);\r
+                               //set vocabulary ; FIXME use another user-defined vocabulary\r
+                               UUID uuidPresenceVoc = UUID.fromString("adbbbe15-c4d3-47b7-80a8-c7d104e53a05"); \r
+                               TermVocabulary<PresenceTerm> voc = getVocabularyService().find(uuidPresenceVoc);\r
+                               voc.addTerm(presenceTerm);\r
+                               getTermService().save(presenceTerm);\r
+                       }\r
+                       state.putPresenceTerm(presenceTerm);\r
+               }\r
+               return presenceTerm;\r
+       }\r
 \r
        /**\r
         * Returns a language for a given uuid by first ...\r
@@ -255,6 +503,27 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                return language;\r
        }\r
        \r
+\r
+       /**\r
+        * @param uuid \r
+        * @return\r
+        * \r
+        */\r
+       protected <T extends DefinedTermBase> TermVocabulary<T> getVocabulary(UUID uuid, String text, String label, String abbrev, URI termSourceUri, boolean isOrdered, T type) {\r
+               List<String> propPath = Arrays.asList(new String[]{"terms"});\r
+               TermVocabulary<T> voc = getVocabularyService().load(uuid, propPath);\r
+               if (voc == null){\r
+                       if (isOrdered){\r
+                               voc = OrderedTermVocabulary.NewInstance(text, label, abbrev, termSourceUri);\r
+                       }else{\r
+                               voc = TermVocabulary.NewInstance(text, label, abbrev, termSourceUri);\r
+                       }\r
+                       voc.setUuid(uuid);\r
+                       getVocabularyService().save(voc);\r
+               }\r
+               return voc;\r
+       }\r
+       \r
        /**\r
         * Adds an orginal source to a sourceable objects (implemented for Identifiable entity and description element.\r
         * If cdmBase is not sourceable nothing happens.\r
@@ -267,7 +536,7 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
         * @param citation\r
         * @throws SQLException\r
         */\r
-       public void addOriginalSource(CdmBase cdmBase, Object idAttributeValue, String namespace, ReferenceBase citation) throws SQLException {\r
+       public void addOriginalSource(CdmBase cdmBase, Object idAttributeValue, String namespace, Reference citation)  {\r
                if (cdmBase instanceof ISourceable ){\r
                        IOriginalSource source;\r
                        ISourceable sourceable = (ISourceable)cdmBase;\r
@@ -283,11 +552,15 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                                return;\r
                        }\r
                        sourceable.addSource(source);\r
+               }else if (cdmBase != null){\r
+                       logger.warn("Sourced object does not implement ISourceable: " + cdmBase.getClass() + "," + cdmBase.getUuid());\r
+               }else{\r
+                       logger.warn("Sourced object is null");\r
                }\r
        }\r
        \r
        /**\r
-        * @see #addOriginalSource(CdmBase, Object, String, ReferenceBase)\r
+        * @see #addOriginalSource(CdmBase, Object, String, Reference)\r
         * @param rs\r
         * @param cdmBase\r
         * @param dbIdAttribute\r
@@ -295,7 +568,7 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
         * @param citation\r
         * @throws SQLException\r
         */\r
-       public void addOriginalSource(ResultSet rs, CdmBase cdmBase, String dbIdAttribute, String namespace, ReferenceBase citation) throws SQLException {\r
+       public void addOriginalSource(ResultSet rs, CdmBase cdmBase, String dbIdAttribute, String namespace, Reference citation) throws SQLException {\r
                Object id = rs.getObject(dbIdAttribute);\r
                addOriginalSource(cdmBase, id, namespace, citation);\r
        }\r
@@ -337,4 +610,205 @@ public abstract class CdmImportBase<CONFIG extends IImportConfigurator, STATE ex
                }       \r
        }\r
        \r
+       /**\r
+        * Returns the taxon description for a taxon. If there are multiple taxon descriptions\r
+        * an arbitrary one is chosen.\r
+        * If no taxon description exists, a new one is created if <code>createNewIfNotExists</code>\r
+        * is <code>true</code>.\r
+        * @param createNewIfNotExists\r
+        * @param isImageGallery if true only taxon description being image galleries are considered.\r
+        * If false only taxon description being no image galleries are considered.\r
+        * @return\r
+        */\r
+       public TaxonDescription getTaxonDescription(Taxon taxon, boolean isImageGallery, boolean createNewIfNotExists) {\r
+               Reference ref = null;\r
+               return getTaxonDescription(taxon, ref, isImageGallery, createNewIfNotExists);\r
+       }\r
+       \r
+       /**\r
+        * Like {@link #getTaxonDescription(Taxon, boolean, boolean)}\r
+        * Only matches a description if the given reference is a source of the description.<BR>\r
+        * If a new description is created the given reference will be added as a source.\r
+        * \r
+        * @see #getTaxonDescription(Taxon, boolean, boolean)\r
+        */\r
+       public TaxonDescription getTaxonDescription(Taxon taxon, Reference ref, boolean isImageGallery, boolean createNewIfNotExists) {\r
+               TaxonDescription result = null;\r
+               Set<TaxonDescription> descriptions= taxon.getDescriptions();\r
+               for (TaxonDescription description : descriptions){\r
+                       if (description.isImageGallery() == isImageGallery){\r
+                               if (hasCorrespondingSource(ref, description)){\r
+                                       result = description;\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+               if (result == null && createNewIfNotExists){\r
+                       result = TaxonDescription.NewInstance(taxon);\r
+                       result.setImageGallery(isImageGallery);\r
+                       if (ref != null){\r
+                               result.addSource(null, null, ref, null);\r
+                       }\r
+               }\r
+               return result;\r
+       }\r
+       \r
+\r
+       /**\r
+        * Returns the textdata that holds general information about a feature for a taxon description.\r
+        * This is mainly necessary for descriptions that have more than one description element for\r
+        * a given feature such as 'distribution', 'description' or 'common name'. It may also hold\r
+        * for hierarchical features where no description element exists for a higher hierarchie level.\r
+        * Example: the description feature has subfeatures. But some information like authorship, figures,\r
+        * sources need to be added to the description itself.\r
+        * Currently a feature placeholder is marked by a marker of type 'feature placeholder'. Maybe in future\r
+        * there will be a boolean marker in the TextData class itself.\r
+        * @param state \r
+        * @param feature \r
+        * @param taxon\r
+        * @param ref\r
+        * @param createIfNotExists\r
+        * @return\r
+        */\r
+       protected TextData getFeaturePlaceholder(STATE state, DescriptionBase<?> description, Feature feature, boolean createIfNotExists) {\r
+               UUID featurePlaceholderUuid = MarkupTransformer.uuidFeaturePlaceholder;\r
+               for (DescriptionElementBase element : description.getElements()){\r
+                       if (element.isInstanceOf(TextData.class)){\r
+                               TextData textData = CdmBase.deproxy(element, TextData.class);\r
+                               if (textData.getFeature() == null || ! textData.getFeature().equals(feature)){\r
+                                       continue;\r
+                               }\r
+                               for (Marker marker : textData.getMarkers()){\r
+                                       MarkerType markerType = marker.getMarkerType();\r
+                                       if (markerType != null && \r
+                                                       markerType.getUuid().equals(featurePlaceholderUuid) && \r
+                                                       marker.getValue() == true){\r
+                                               return textData;\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+               if (createIfNotExists){\r
+                       TextData newPlaceholder = TextData.NewInstance(feature);\r
+                       MarkerType placeholderMarkerType = getMarkerType(state, featurePlaceholderUuid, "Feature Placeholder", "Feature Placeholder", null);\r
+                       Marker marker = Marker.NewInstance(placeholderMarkerType, true);\r
+                       newPlaceholder.addMarker(marker);\r
+                       description.addElement(newPlaceholder);\r
+                       return newPlaceholder;\r
+               }else{\r
+                       return null;\r
+               }\r
+       }\r
+\r
+\r
+\r
+       /**\r
+        * Returns true, if this description has a source with a citation equal to the given reference.\r
+        * Returns true if the given reference is null.\r
+        * @param ref\r
+        * @param description\r
+        */\r
+       private boolean hasCorrespondingSource(Reference ref, TaxonDescription description) {\r
+               if (ref != null){\r
+                       for (IdentifiableSource source : description.getSources()){\r
+                               if (ref.equals(source.getCitation())){\r
+                                       return true;\r
+                               }\r
+                       }\r
+                       return false;\r
+               }\r
+               return true;\r
+               \r
+       }\r
+       \r
+       \r
+       /**\r
+        * Returns the accepted taxon of a {@link TaxonBase taxon base}. <BR>\r
+        * If taxonBase is of type taxon the same object is returned. If taxonBase is of type\r
+        * synonym the accepted taxon is returned if one exists. If no accepted taxon exists\r
+        * <code>null</code> is returned. If multiple accepted taxa exist the one taxon with the \r
+        * same secundum reference is returned. If no such single taxon exists an \r
+        * {@link IllegalStateException illegal state exception} is thrown.  \r
+        * @param taxonBase\r
+        * @return\r
+        */\r
+       protected Taxon getAcceptedTaxon(TaxonBase<?> taxonBase) {\r
+               if (taxonBase == null){\r
+                       return null;\r
+               }else if(taxonBase.isInstanceOf(Taxon.class)){\r
+                       return CdmBase.deproxy(taxonBase, Taxon.class);\r
+               }else if(taxonBase.isInstanceOf(Synonym.class)){\r
+                       Synonym synonym = CdmBase.deproxy(taxonBase, Synonym.class);\r
+                       Set<Taxon> acceptedTaxa = synonym.getAcceptedTaxa();\r
+                       if (acceptedTaxa.size() == 0){\r
+                               return null;\r
+                       }else if (acceptedTaxa.size() == 1){\r
+                               return acceptedTaxa.iterator().next();\r
+                       }else{\r
+                               Reference sec = synonym.getSec();\r
+                               if (sec != null){\r
+                                       Set<Taxon> taxaWithSameSec = new HashSet<Taxon>();\r
+                                       for (Taxon taxon: acceptedTaxa){\r
+                                               if (sec.equals(taxon.getSec())){\r
+                                                       taxaWithSameSec.add(taxon);\r
+                                               }\r
+                                       }\r
+                                       if (taxaWithSameSec.size() == 1){\r
+                                               return taxaWithSameSec.iterator().next();\r
+                                       }\r
+                               }\r
+                               throw new IllegalStateException("Can't define the one accepted taxon for a synonym out of multiple accept taxa");\r
+                       }\r
+               }else{\r
+                       throw new IllegalStateException("Unknown TaxonBase subclass: " + taxonBase.getClass().getName());\r
+               }\r
+       }\r
+\r
+       \r
+\r
+       /**\r
+        * Creates \r
+        * @param uriString\r
+        * @param readDataFromUrl\r
+        * @see #READ_MEDIA_DATA\r
+        * @return\r
+        * @throws MalformedURLException\r
+        */\r
+       protected Media getImageMedia(String uriString, boolean readMediaData, boolean isFigure) throws MalformedURLException {\r
+               if( uriString == null){\r
+                       return null;\r
+               } else {\r
+                       ImageInfo imageInfo = null;\r
+                       URI uri;\r
+                       try {\r
+                               uri = new URI(uriString);\r
+                               try {\r
+                                       if (readMediaData){\r
+                                               imageInfo = ImageInfo.NewInstance(uri, 0);\r
+                                       }\r
+                               } catch (Exception e) {\r
+                                       String message = "An error occurred when trying to read image meta data: " +  e.getMessage();\r
+                                       logger.warn(message);\r
+                                       fireWarningEvent(message, "unknown location", 2, 0);\r
+                               }\r
+                               ImageFile imageFile = ImageFile.NewInstance(uri, null, imageInfo);\r
+                               MediaRepresentation representation = MediaRepresentation.NewInstance();\r
+                               if(imageInfo != null){\r
+                                       representation.setMimeType(imageInfo.getMimeType());\r
+                                       representation.setSuffix(imageInfo.getSuffix());\r
+                               }\r
+                               representation.addRepresentationPart(imageFile);\r
+                               Media media = isFigure ? Figure.NewInstance() : Media.NewInstance();\r
+                               media.addRepresentation(representation);\r
+                               return media;\r
+                       } catch (URISyntaxException e1) {\r
+                               String message = "An URISyntaxException occurred when trying to create uri from multimedia objcet string: " +  uriString;\r
+                               logger.warn(message);\r
+                               fireWarningEvent(message, "unknown location", 4, 0);\r
+                               return null;\r
+                       }\r
+               }\r
+       }\r
+\r
+       \r
 }\r