AlgaTerra categorical data and flat classifications
authorAndreas Müller <a.mueller@bgbm.org>
Sat, 8 Sep 2012 22:18:53 +0000 (22:18 +0000)
committerAndreas Müller <a.mueller@bgbm.org>
Sat, 8 Sep 2012 22:18:53 +0000 (22:18 +0000)
app-import/src/main/java/eu/etaxonomy/cdm/app/berlinModelImport/AlgaTerraActivator.java
app-import/src/main/java/eu/etaxonomy/cdm/io/algaterra/AlgaTerraImportState.java
app-import/src/main/java/eu/etaxonomy/cdm/io/algaterra/AlgaTerraSpecimenImport.java

index 8f341dff7a9fa389b9724cc53990066c3fdb37c8..09415f15db76f81bebd64500f16209d16139ed7a 100644 (file)
@@ -58,6 +58,8 @@ public class AlgaTerraActivator {
        static final CHECK check = CHECK.IMPORT_WITHOUT_CHECK;\r
 \r
        private boolean ignoreNull = true;\r
+       \r
+       private boolean includeFlatClassifications = true;\r
 \r
        //NomeclaturalCode\r
        static final NomenclaturalCode nomenclaturalCode = NomenclaturalCode.ICBN;\r
@@ -100,7 +102,7 @@ public class AlgaTerraActivator {
 //     \r
 //     //taxa\r
 //     static final boolean doTaxa = true;\r
-//     static final boolean doRelTaxa = false;\r
+//     static final boolean doRelTaxa = true;\r
 //     static final boolean doFacts = false;\r
 //     static final boolean doOccurences = false;\r
 //     static final boolean doCommonNames = false;\r
@@ -139,6 +141,8 @@ public class AlgaTerraActivator {
                config.setSourceRefUuid(sourceRefUuid);\r
                config.setIgnoreNull(ignoreNull);\r
                \r
+               config.setIncludeFlatClassifications(includeFlatClassifications);\r
+               \r
                config.setDbSchemaValidation(hbm2dll);\r
 \r
                config.setCheck(check);\r
index 9df4332c14a3a1bb71f109586860cfc30c96eda8..68be738fe89b655da378460ba2be0b45542edebf 100644 (file)
@@ -24,6 +24,8 @@ public class AlgaTerraImportState extends BerlinModelImportState{
        @SuppressWarnings("unused")\r
        private static final Logger logger = Logger.getLogger(AlgaTerraImportState.class);\r
 \r
+       private boolean specimenVocabulariesCreated = false;\r
+       \r
        public AlgaTerraImportState(AlgaTerraImportConfigurator config) {\r
                super(config);\r
        }\r
@@ -31,5 +33,14 @@ public class AlgaTerraImportState extends BerlinModelImportState{
        public AlgaTerraImportConfigurator getAlgaTerraConfigurator(){\r
                return (AlgaTerraImportConfigurator)getConfig();\r
        }\r
+\r
+       public boolean isSpecimenVocabulariesCreated() {\r
+               return specimenVocabulariesCreated;\r
+       }\r
+\r
+       public void setSpecimenVocabulariesCreated(boolean specimenVocabulariesCreated) {\r
+               this.specimenVocabulariesCreated = specimenVocabulariesCreated;\r
+       }\r
+\r
     \r
 }\r
index 4879bc3fdc36b6025549aea1d3b7c154c8bafdf0..6fe5e03a2f567f290d8ff6d5695ec8904a112f93 100644 (file)
@@ -9,16 +9,20 @@
 \r
 package eu.etaxonomy.cdm.io.algaterra;\r
 \r
+import java.net.URI;\r
+import java.sql.Date;\r
 import java.sql.ResultSet;\r
 import java.sql.SQLException;\r
 import java.util.HashMap;\r
 import java.util.HashSet;\r
 import java.util.Map;\r
 import java.util.Set;\r
+import java.util.UUID;\r
 \r
 import org.apache.commons.lang.StringUtils;\r
 import org.apache.log4j.Logger;\r
 import org.springframework.stereotype.Component;\r
+import org.springframework.transaction.TransactionStatus;\r
 \r
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;\r
 import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade.DerivedUnitType;\r
@@ -29,12 +33,31 @@ import eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportState;
 import eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelTaxonImport;\r
 import eu.etaxonomy.cdm.io.common.IOValidator;\r
 import eu.etaxonomy.cdm.io.common.ResultSetPartitioner;\r
+import eu.etaxonomy.cdm.io.common.Source;\r
+import eu.etaxonomy.cdm.model.agent.Team;\r
 import eu.etaxonomy.cdm.model.common.CdmBase;\r
+import eu.etaxonomy.cdm.model.common.DefinedTermBase;\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.TimePeriod;\r
+import eu.etaxonomy.cdm.model.description.CategoricalData;\r
+import eu.etaxonomy.cdm.model.description.DescriptionBase;\r
 import eu.etaxonomy.cdm.model.description.Feature;\r
 import eu.etaxonomy.cdm.model.description.IndividualsAssociation;\r
+import eu.etaxonomy.cdm.model.description.SpecimenDescription;\r
+import eu.etaxonomy.cdm.model.description.State;\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.Point;\r
 import eu.etaxonomy.cdm.model.location.ReferenceSystem;\r
+import eu.etaxonomy.cdm.model.location.TdwgArea;\r
+import eu.etaxonomy.cdm.model.location.WaterbodyOrCountry;\r
+import eu.etaxonomy.cdm.model.name.BotanicalName;\r
+import eu.etaxonomy.cdm.model.name.Rank;\r
+import eu.etaxonomy.cdm.model.occurrence.FieldObservation;\r
 import eu.etaxonomy.cdm.model.reference.Reference;\r
 import eu.etaxonomy.cdm.model.taxon.Taxon;\r
 import eu.etaxonomy.cdm.model.taxon.TaxonBase;\r
@@ -49,7 +72,23 @@ import eu.etaxonomy.cdm.model.taxon.TaxonBase;
 public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {\r
        private static final Logger logger = Logger.getLogger(AlgaTerraSpecimenImport.class);\r
 \r
-       public static final String NAMESPACE = "Occurrence";\r
+       public static final String FIELD_OBSERVATION_NAMESPACE = "FieldObservation";\r
+       public static final String TERMS_NAMESPACE = "ALGA_TERRA_TERMS";\r
+       \r
+       //move to transformrer\r
+       final static UUID uuidMarkerAlkalinity = UUID.fromString("e52d0ea2-0c1f-4d95-ae6d-e21ab317c594");  \r
+       final static UUID uuidRefSystemGps = UUID.fromString("c23e4928-c137-4e4a-b6ab-b430da3d0b94");  \r
+       final static UUID uuidFeatureSpecimenCommunity = UUID.fromString("3ff5b1ab-3999-4b5a-b8f7-01fd2f6c12c7");\r
+       final static UUID uuidFeatureAdditionalData = UUID.fromString("0ac82ab8-2c2b-4953-98eb-a9f718eb9c57");\r
+       \r
+       final static UUID uuidVocAlgaTerraClimate = UUID.fromString("b0a677c6-8bb6-43f4-b1b8-fc377a10feb5");\r
+       final static UUID uuidVocAlgaTerraHabitat = UUID.fromString("06f30114-e19c-4e7d-a8e5-5488c41fcbc5");\r
+       final static UUID uuidVocAlgaTerraLifeForm = UUID.fromString("3c0b194e-809c-4b42-9498-6ff034066ed7");\r
+       \r
+       final static UUID uuidFeatureAlgaTerraClimate = UUID.fromString("8754674c-9ab9-4f28-95f1-91eeee2314ee");\r
+       final static UUID uuidFeatureAlgaTerraHabitat = UUID.fromString("7def3fc2-cdc5-4739-8e13-62edbd053415");\r
+       final static UUID uuidFeatureAlgaTerraLifeForm = UUID.fromString("9b657901-1b0d-4a2a-8d21-dd8c1413e2e6");\r
+       \r
        \r
        \r
        private static int modCount = 5000;\r
@@ -61,15 +100,19 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
                super();\r
        }\r
        \r
+       \r
+       \r
        /* (non-Javadoc)\r
         * @see eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportBase#getIdQuery()\r
         */\r
        @Override\r
        protected String getIdQuery(BerlinModelImportState state) {\r
                String result = " SELECT factId " + \r
-                               " FROM " + getTableName() + " INNER JOIN PTaxon ON Fact.PTNameFk = PTaxon.PTNameFk AND Fact.PTRefFk = PTaxon.PTRefFk "\r
+                               " FROM Fact " +\r
+                                       " INNER JOIN EcoFact ON Fact.ExtensionFk = EcoFact.EcoFactId " +\r
+                                       "INNER JOIN PTaxon ON Fact.PTNameFk = PTaxon.PTNameFk AND Fact.PTRefFk = PTaxon.PTRefFk "\r
                                + " WHERE FactCategoryFk = 202 "\r
-                               + " ORDER BY PTaxon.RIdentifier, Fact.FactId ";\r
+                               + " ORDER BY EcoFact.EcoFactId, PTaxon.RIdentifier, Fact.FactId ";\r
                return result;\r
        }\r
 \r
@@ -79,12 +122,18 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
        @Override\r
        protected String getRecordQuery(BerlinModelImportConfigurator config) {\r
                        String strQuery =   //DISTINCT because otherwise emOccurrenceSource creates multiple records for a single distribution \r
-            " SELECT PTaxon.RIdentifier as taxonId, Fact.FactId, Fact.RecordBasis, EcoFact.* " + \r
+            " SELECT PTaxon.RIdentifier as taxonId, Fact.FactId, Fact.RecordBasis, EcoFact.*, " + \r
+               " tg.ID AS GazetteerId, tg.L2Code, tg.L3Code, tg.L4Code, tg.Country, tg.ISOCountry, " +\r
+               " ec.UUID as climateUuid, eh.UUID as habitatUuid, elf.UUID as lifeFormUuid" +\r
             " FROM Fact " + \r
                  " INNER JOIN EcoFact ON Fact.ExtensionFk = EcoFact.EcoFactId " +\r
                  " INNER JOIN PTaxon ON dbo.Fact.PTNameFk = dbo.PTaxon.PTNameFk AND dbo.Fact.PTRefFk = dbo.PTaxon.PTRefFk " +\r
-            " WHERE Fact.FactCategoryFk = 202 AND (Fact.FactId IN (" + ID_LIST_TOKEN + ")  )"  \r
-            + " ORDER BY PTaxon.RIdentifier, Fact.FactId "\r
+                 " LEFT OUTER JOIN TDWGGazetteer tg ON EcoFact.TDWGGazetteerFk = tg.ID " +\r
+                 " LEFT OUTER JOIN EcoClimate  ec  ON EcoFact.ClimateFk  = ec.ClimateId " +\r
+                 " LEFT OUTER JOIN EcoHabitat  eh  ON EcoFact.HabitatFk  = eh.HabitatId " +\r
+                 " LEFT OUTER JOIN EcoLifeForm elf ON EcoFact.LifeFormFk = elf.LifeFormId " +\r
+              " WHERE Fact.FactCategoryFk = 202 AND (Fact.FactId IN (" + ID_LIST_TOKEN + ")  )"  \r
+            + " ORDER BY EcoFact.EcoFactId, PTaxon.RIdentifier, Fact.FactId "\r
             ;\r
                return strQuery;\r
        }\r
@@ -92,20 +141,27 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
        /* (non-Javadoc)\r
         * @see eu.etaxonomy.cdm.io.berlinModel.in.IPartitionedIO#doPartition(eu.etaxonomy.cdm.io.berlinModel.in.ResultSetPartitioner, eu.etaxonomy.cdm.io.berlinModel.in.BerlinModelImportState)\r
         */\r
-       public boolean doPartition(ResultSetPartitioner partitioner, BerlinModelImportState state) {\r
+       public boolean doPartition(ResultSetPartitioner partitioner, BerlinModelImportState bmState) {\r
                boolean success = true;\r
+               \r
+               AlgaTerraImportState state = (AlgaTerraImportState)bmState;\r
+               try {\r
+                       makeVocabulariesAndFeatures(state);\r
+               } catch (SQLException e1) {\r
+                       logger.warn("Exception occurred when trying to create Ecofact vocabularies: " + e1.getMessage());\r
+                       e1.printStackTrace();\r
+               }\r
                Set<TaxonBase> taxaToSave = new HashSet<TaxonBase>();\r
                \r
                Map<String, TaxonBase> taxonMap = (Map<String, TaxonBase>) partitioner.getObjectMap(BerlinModelTaxonImport.NAMESPACE);\r
-                       \r
+               Map<String, FieldObservation> fieldObservationMap = (Map<String, FieldObservation>) partitioner.getObjectMap(FIELD_OBSERVATION_NAMESPACE);\r
+               \r
                ResultSet rs = partitioner.getResultSet();\r
 \r
                try {\r
-                       int oldTaxonId = -1;\r
-                       TaxonDescription oldDescription = null;\r
+                       \r
                        int i = 0;\r
-                       int countDescriptions = 0;\r
-                       int countSpecimen = 0;\r
+\r
                        //for each reference\r
             while (rs.next()){\r
                 \r
@@ -113,30 +169,33 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
                                \r
                                int newTaxonId = rs.getInt("taxonId");\r
                                int factId = rs.getInt("FactId");\r
+                               int ecoFactId = rs.getInt("EcoFactId");\r
+                               String recordBasis = rs.getString("RecordBasis");\r
+                               \r
                                try {\r
-                                                       \r
-                                       String recordBasis = rs.getString("RecordBasis");\r
                                        \r
+                                       //source ref\r
                                        Reference<?> sourceRef = state.getTransactionalSourceReference();\r
-                                       //create description(elements)\r
-                                       TaxonDescription taxonDescription = getTaxonDescription(newTaxonId, oldTaxonId, oldDescription, taxonMap, factId, sourceRef);\r
-\r
+                               \r
+                                       //facade\r
+                                       FieldObservation fieldObservation = getFieldObservation(ecoFactId, fieldObservationMap);\r
                                        DerivedUnitType type = makeDerivedUnitType(recordBasis);\r
-                                       DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(type);\r
-                                       \r
-                                       handleSingleSpecimen(rs, facade);\r
+                                       DerivedUnitFacade facade = DerivedUnitFacade.NewInstance(type, fieldObservation);\r
+\r
+                                       //field observation\r
+                                       handleSingleSpecimen(rs, facade, state);\r
                                        \r
+                                       //description element\r
+                                       TaxonDescription taxonDescription = getTaxonDescription(state, newTaxonId, taxonMap, factId, sourceRef);\r
                                        IndividualsAssociation indAssociation = IndividualsAssociation.NewInstance();\r
                                        Feature feature = makeFeature(type);\r
                                        indAssociation.setAssociatedSpecimenOrObservation(facade.innerDerivedUnit());\r
                                        indAssociation.setFeature(feature);\r
                                        taxonDescription.addElement(indAssociation);\r
                                        \r
-                                       if (taxonDescription != oldDescription){ \r
-                                               taxaToSave.add(taxonDescription.getTaxon()); \r
-                                               oldDescription = taxonDescription; \r
-                                               countDescriptions++; \r
-                                       }\r
+                                       taxaToSave.add(taxonDescription.getTaxon()); \r
+                                       \r
+\r
                                } catch (Exception e) {\r
                                        logger.warn("Exception in ecoFact: FactId " + factId + ". " + e.getMessage());\r
 //                                     e.printStackTrace();\r
@@ -144,7 +203,7 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
                 \r
             }\r
            \r
-            logger.warn("Specimen: " + countSpecimen + ", Descriptions: " + countDescriptions );\r
+//            logger.warn("Specimen: " + countSpecimen + ", Descriptions: " + countDescriptions );\r
 \r
                        logger.warn("Taxa to save: " + taxaToSave.size());\r
                        getTaxonService().save(taxaToSave);     \r
@@ -157,39 +216,332 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
        }\r
 \r
 \r
-       private void handleSingleSpecimen(ResultSet rs, DerivedUnitFacade facade) throws SQLException {\r
-               //TDWGGazetteerFK, CollectionFk, Collector, GeoCodeMethod, Prec, AltitudeMethod, Depth,\r
-       //ISOCountrySub, CollectionDate/End, WaterBody, \r
-       //CreatedWhen/Who/Updated/who\r
-       \r
-       //P1-10Value/Unit/Parameter/Method\r
 \r
-//             int factId = rs.getInt("factId");\r
-        String locality = rs.getString("Locality");\r
-        Double latitude = rs.getDouble("Latitude");\r
-        Double longitude = rs.getDouble("Longitude");\r
-        int errorRadius = rs.getInt("Prec");\r
-       Integer altitude = rs.getInt("Altitude");\r
-       String altitudeUnit = rs.getString("AltitudeUnit");\r
-       String collectorsNumber = rs.getString("CollectorsNumber");\r
-       \r
-       //location\r
-       facade.setLocality(locality);\r
-               \r
-       //exact location\r
-       ReferenceSystem referenceSystem = null;\r
-       Point exactLocation = Point.NewInstance(longitude, latitude, referenceSystem, errorRadius);\r
-       facade.setExactLocation(exactLocation);\r
+\r
+       /**\r
+        * Creates the vocabularies and the features for Climate, Habitat and Lifeform\r
+        * @param state\r
+        * @throws SQLException\r
+        */\r
+       private void makeVocabulariesAndFeatures(AlgaTerraImportState state) throws SQLException {\r
+               String abbrevLabel = null;\r
+               URI uri = null;\r
+               \r
+               if (! state.isSpecimenVocabulariesCreated()){\r
+                       \r
+                       TransactionStatus txStatus = this.startTransaction();\r
+               \r
+                       boolean isOrdered = true;\r
+                       OrderedTermVocabulary<State> climateVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraClimate, "Climate", "Climate", abbrevLabel, uri, isOrdered, null);\r
+                       OrderedTermVocabulary<State> habitatVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraHabitat, "Habitat", "Habitat", abbrevLabel, uri, isOrdered, null);\r
+                       OrderedTermVocabulary<State> lifeformVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraLifeForm, "Lifeform", "Lifeform", abbrevLabel, uri, isOrdered, null);\r
+                       \r
+                       \r
+                       Feature feature = getFeature(state, uuidFeatureAlgaTerraClimate, "Climate","Climate", null, null);\r
+                       feature.setSupportsCategoricalData(true);\r
+                       \r
+                       feature = getFeature(state, uuidFeatureAlgaTerraLifeForm, "LifeForm","LifeForm", null, null);\r
+                       feature.setSupportsCategoricalData(true);\r
+                       \r
+                       feature = Feature.HABITAT();\r
+                       feature.setSupportsCategoricalData(true);\r
+                       getTermService().saveOrUpdate(feature);\r
+                       \r
+                       Source source = state.getAlgaTerraConfigurator().getSource();\r
+                       \r
+                       String climateSql = "SELECT * FROM EcoClimate";\r
+                       ResultSet rs = source.getResultSet(climateSql);\r
+                       while (rs.next()){\r
+                               String climate = rs.getString("Climate");\r
+                               String description = rs.getString("Description");\r
+                               Integer id = rs.getInt("ClimateId");\r
+                               UUID uuid = UUID.fromString(rs.getString("UUID"));\r
+                               State stateTerm = getStateTerm(state, uuid, climate, description, null, climateVoc);\r
+                               addOriginalSource(stateTerm, id.toString(), "EcoClimate", state.getConfig().getSourceReference());\r
+                               getTermService().saveOrUpdate(stateTerm);\r
+                       }\r
+                       \r
+                       String habitatSql = "SELECT * FROM EcoHabitat";\r
+                       rs = source.getResultSet(habitatSql);\r
+                       while (rs.next()){\r
+                               String habitat = rs.getString("Habitat");\r
+                               String description = rs.getString("Description");\r
+                               Integer id = rs.getInt("HabitatId");\r
+                               UUID uuid = UUID.fromString(rs.getString("UUID"));\r
+                               State stateTerm = getStateTerm(state, uuid, habitat, description, null, habitatVoc);\r
+                               addOriginalSource(stateTerm, id.toString(), "EcoHabitat", state.getConfig().getSourceReference());\r
+                               getTermService().saveOrUpdate(stateTerm);\r
+                       }\r
+                       \r
+                       String lifeformSql = "SELECT * FROM EcoLifeForm";\r
+                       rs = source.getResultSet(lifeformSql);\r
+                       while (rs.next()){\r
+                               String lifeform = rs.getString("LifeForm");\r
+                               String description = rs.getString("Description");\r
+                               Integer id = rs.getInt("LifeFormId");\r
+                               UUID uuid = UUID.fromString(rs.getString("UUID"));\r
+                               State stateTerm = getStateTerm(state, uuid, lifeform, description, null, lifeformVoc);\r
+                               addOriginalSource(stateTerm, id.toString(), "EcoLifeForm", state.getConfig().getSourceReference());\r
+                               getTermService().saveOrUpdate(stateTerm);\r
+                       }\r
+                       \r
+                       this.commitTransaction(txStatus);\r
+                       \r
+                       state.setSpecimenVocabulariesCreated(true);\r
+               }\r
+               \r
+       }\r
+\r
+\r
+\r
+       private void handleSingleSpecimen(ResultSet rs, DerivedUnitFacade facade, AlgaTerraImportState state) throws SQLException {\r
+               //CollectionFk, Collector, AltitudeMethod, \r
+       //ISOCountrySub, CreatedWhen/Who/Updated/who\r
        \r
-       //altitude\r
-       if (StringUtils.isNotBlank(altitudeUnit) && ! altitudeUnit.trim().equalsIgnoreCase("m")){\r
-               logger.warn("Altitude unit is not [m] but: " +  altitudeUnit);\r
-       }\r
-       facade.setAbsoluteElevationRange(altitude, altitude);  //TODO\r
+       //P1-10Value/Unit/Parameter/Method\r
+               \r
+               try {\r
+                       Object alkalinityFlag = rs.getBoolean("AlkalinityFlag");\r
+                       \r
+                       String locality = rs.getString("Locality");\r
+                       Double latitude = nullSafeDouble(rs, "Latitude");\r
+                       Double longitude = nullSafeDouble(rs, "Longitude");\r
+                       Integer errorRadius = nullSafeInt(rs,"Prec");\r
+                       String geoCodeMethod = rs.getString("GeoCodeMethod");\r
+                       \r
+                       Integer altitude = nullSafeInt(rs, "Altitude");\r
+                       Integer lowerAltitude = nullSafeInt(rs,"AltitudeLowerValue");\r
+                       String altitudeUnit = rs.getString("AltitudeUnit");\r
+                       Double depth = nullSafeDouble(rs, "Depth");\r
+                       Double depthLow = nullSafeDouble(rs, "DepthLow");\r
+                               \r
+                       String collectorsNumber = rs.getString("CollectorsNumber");\r
+                       Date collectionDateStart = rs.getDate("CollectionDate");\r
+                       Date collectionDateEnd = rs.getDate("CollectionDateEnd");\r
+                       \r
+                       String climateUuid = rs.getString("climateUuid");\r
+                       String habitatUuid = rs.getString("habitatUuid");\r
+                       String lifeFormUuid = rs.getString("lifeFormUuid");\r
+                       \r
+                       String habitat = rs.getString("HabitatExplanation");\r
+                       String community = rs.getString("Comunity");\r
+                       String additionalData = rs.getString("AdditionalData");\r
+                       \r
+                       \r
+                       \r
+                       FieldObservation fieldObservation = facade.innerFieldObservation();\r
+                       \r
+                       //alkalinity marker\r
+                       if (alkalinityFlag != null){\r
+                               MarkerType alkalinityMarkerType = getMarkerType(state, uuidMarkerAlkalinity, "Alkalinity", "Alkalinity", null);\r
+                               boolean alkFlag = Boolean.valueOf(alkalinityFlag.toString());\r
+                               Marker alkalinityMarker = Marker.NewInstance(alkalinityMarkerType, alkFlag);\r
+                               fieldObservation.addMarker(alkalinityMarker);\r
+                       }\r
+                       \r
+                       //location\r
+                       facade.setLocality(locality);\r
+                               \r
+                       //exact location\r
+                       ReferenceSystem referenceSystem = makeRefrenceSystem(geoCodeMethod, state);\r
+                       Point exactLocation = Point.NewInstance(longitude, latitude, referenceSystem, errorRadius);\r
+                       facade.setExactLocation(exactLocation);\r
+                       \r
+                       //altitude, depth\r
+                       if (StringUtils.isNotBlank(altitudeUnit) && ! altitudeUnit.trim().equalsIgnoreCase("m")){\r
+                               logger.warn("Altitude unit is not [m] but: " +  altitudeUnit);\r
+                       }\r
+                       if ( altitude != null){\r
+                               if (lowerAltitude == null){\r
+                                       facade.setAbsoluteElevation(altitude);\r
+                               }else{\r
+                                       if (! facade.isEvenDistance(lowerAltitude, altitude)){\r
+                                               //FIXME there is a ticket for this\r
+                                               altitude = altitude + 1;\r
+                                               logger.warn("Current implementation of altitude does not allow uneven distances");\r
+                                       }\r
+                                       facade.setAbsoluteElevationRange(lowerAltitude,altitude);\r
+                               }\r
+                       }\r
+                       if ( depth != null){\r
+                               //FIXME needs model change to accept double #3072\r
+                               Integer intDepth = depth.intValue();\r
+                               if (depthLow == null){\r
+                                       facade.setDistanceToWaterSurface(intDepth);\r
+                               }else{\r
+                                       //FIXME range not yet in model #3074\r
+                                       facade.setDistanceToWaterSurface(intDepth);\r
+                               }\r
+                       }\r
+                       \r
+                       //habitat, ecology, community, etc.\r
+                       DescriptionBase<?> fieldDescription = getFieldObservationDescription(facade);\r
+                       addCategoricalValue(state, fieldDescription, climateUuid, uuidFeatureAlgaTerraClimate);\r
+                       addCategoricalValue(state, fieldDescription, habitatUuid, Feature.HABITAT().getUuid());\r
+                       addCategoricalValue(state, fieldDescription, lifeFormUuid, uuidFeatureAlgaTerraLifeForm);\r
+                       \r
+                       if (isNotBlank(habitat)){\r
+                               //FIXME\r
+                               facade.setEcology(habitat);  //or use an own feature ??\r
+                       }\r
+                       if (isNotBlank(community)){\r
+                               Feature communityFeature = getFeature(state, uuidFeatureSpecimenCommunity, "Community", "The community of a specimen (e.g. other algae in the same sample)", null, null);\r
+                               TextData textData = TextData.NewInstance(communityFeature);\r
+                               textData.putText(Language.DEFAULT(), community);\r
+                               getFieldObservationDescription(facade).addElement(textData);\r
+                       }\r
+                       if (isNotBlank(additionalData)){  //or handle it as Annotation ??\r
+                               Feature additionalDataFeature = getFeature(state, uuidFeatureAdditionalData, "Additional Data", "Additional Data", null, null);\r
+                               TextData textData = TextData.NewInstance(additionalDataFeature);\r
+                               textData.putText(Language.DEFAULT(), additionalData);\r
+                               getFieldObservationDescription(facade).addElement(textData);\r
+                       }\r
+                       \r
+                       //field\r
+                       facade.setFieldNumber(collectorsNumber);\r
+                       TimePeriod gatheringPeriod = TimePeriod.NewInstance(collectionDateStart, collectionDateEnd);\r
+                       facade.setGatheringPeriod(gatheringPeriod);\r
+                       handleCollectorTeam(state, facade, rs);\r
+                       \r
+                       //areas\r
+                       makeAreas(state, rs, facade);\r
+                       \r
+                       //parameters\r
+                       //TODO\r
+                       \r
+                       //notes\r
+                       //TODO is this an annotation on field observation or on the derived unit?\r
+                       \r
+                       //TODO id, created for fact +  ecoFact\r
+                       //      this.doIdCreatedUpdatedNotes(state, descriptionElement, rs, id, namespace);\r
+               \r
+               } catch (IllegalArgumentException e) {\r
+                       throw e;\r
+               }\r
        \r
-       //field\r
-       facade.setFieldNumber(collectorsNumber);\r
-       \r
+       }\r
+\r
+\r
+       private void addCategoricalValue(AlgaTerraImportState importState, DescriptionBase description, String uuidTerm, UUID featureUuid) {\r
+               if (uuidTerm != null){\r
+                       State state = this.getStateTerm(importState, UUID.fromString(uuidTerm));\r
+                       Feature feature = getFeature(importState, featureUuid);\r
+                       CategoricalData categoricalData = CategoricalData.NewInstance(state, feature);\r
+                       description.addElement(categoricalData);\r
+               }\r
+       }\r
+\r
+\r
+       private void handleCollectorTeam(AlgaTerraImportState state, DerivedUnitFacade facade, ResultSet rs) throws SQLException {\r
+               // FIXME parsen\r
+               String collector = rs.getString("Collector");\r
+               Team team = Team.NewTitledInstance(collector, collector);\r
+               facade.setCollector(team);\r
+               \r
+               \r
+               \r
+       }\r
+\r
+       private void makeAreas(AlgaTerraImportState state, ResultSet rs, DerivedUnitFacade facade) throws SQLException {\r
+               Object gazetteerId = rs.getObject("GazetteerId");\r
+               if (gazetteerId != null){\r
+                       //TDWG\r
+                       NamedArea tdwgArea;\r
+                       String tdwg4 = rs.getString("L4Code");\r
+                       if (isNotBlank(tdwg4)){\r
+                               tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(tdwg4);\r
+                       }else{\r
+                               String tdwg3 = rs.getString("L3Code");\r
+                               if (isNotBlank(tdwg3)){\r
+                                       tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(tdwg3);\r
+                               }else{\r
+                                       Integer tdwg2 = rs.getInt("L2Code");                            \r
+                                       tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(String.valueOf(tdwg2));\r
+                               }\r
+                       }\r
+                       if (tdwgArea == null){\r
+                               logger.warn("TDWG area could not be defined for gazetterId: " + gazetteerId);\r
+                       }else{\r
+                               facade.addCollectingArea(tdwgArea);\r
+                       }\r
+                       \r
+                       //Countries\r
+                       WaterbodyOrCountry country = null;\r
+                       String isoCountry = rs.getString("ISOCountry");\r
+                       String countryStr = rs.getString("Country");\r
+                       if (isNotBlank(isoCountry)){\r
+                               country = WaterbodyOrCountry.getWaterbodyOrCountryByIso3166A2(isoCountry);\r
+                       }else if (isNotBlank(countryStr)){\r
+                               logger.warn("Country exists but no ISO code");\r
+                       }\r
+                       if (country == null){\r
+                               logger.warn("Country does not exist for GazetteerID " + gazetteerId);\r
+                       }else{\r
+                               facade.setCountry(country);\r
+                       }\r
+                       \r
+               }\r
+           \r
+               //Waterbody\r
+               WaterbodyOrCountry waterbody = null;\r
+               String waterbodyStr = rs.getString("WaterBody");\r
+               if (isNotBlank(waterbodyStr)){\r
+                       if (waterbodyStr.equals("Atlantic Ocean")){\r
+                               waterbody = WaterbodyOrCountry.ATLANTICOCEAN();\r
+                       }else{\r
+                               logger.warn("Waterbody not recognized: " + waterbody);\r
+                       }\r
+                       if (waterbody != null){\r
+                               facade.addCollectingArea(waterbody);\r
+                       }\r
+               }\r
+\r
+               \r
+               //countries sub\r
+               //TODO\r
+       }\r
+\r
+       private DescriptionBase getFieldObservationDescription(DerivedUnitFacade facade) {\r
+               Set<DescriptionBase> descriptions = facade.innerFieldObservation().getDescriptions();\r
+               for (DescriptionBase desc : descriptions){\r
+                       if (desc.isImageGallery() == false){\r
+                               return desc;\r
+                       }\r
+               }\r
+               SpecimenDescription specDesc = SpecimenDescription.NewInstance(facade.innerFieldObservation());\r
+               descriptions.add(specDesc);\r
+               return specDesc;\r
+       }\r
+\r
+       private ReferenceSystem makeRefrenceSystem(String geoCodeMethod, AlgaTerraImportState state) {\r
+               if (StringUtils.isBlank(geoCodeMethod)){\r
+                       return null;\r
+               }else if(geoCodeMethod.startsWith("GPS")){\r
+                       getReferenceSystem(state, uuidRefSystemGps, "GPS", "GPS", "GPS", ReferenceSystem.GOOGLE_EARTH().getVocabulary());\r
+                       return ReferenceSystem.WGS84(); \r
+               }else if(geoCodeMethod.startsWith("Google")){\r
+                       return ReferenceSystem.GOOGLE_EARTH();\r
+               }else if(geoCodeMethod.startsWith("Map")){\r
+                       logger.warn("Reference system " +  geoCodeMethod +  " not yet supported.");\r
+                       return null;\r
+               }else if(geoCodeMethod.startsWith("WikiProjekt Georeferenzierung") || geoCodeMethod.startsWith("http://toolserver.org/~geohack/geohack.php") ){\r
+                       return ReferenceSystem.WGS84();\r
+               }else {\r
+                       logger.warn("Reference system " +  geoCodeMethod +  " not yet supported.");\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       private FieldObservation getFieldObservation(int ecoFactId, Map<String, FieldObservation> fieldObservationMap) {\r
+               String key = String.valueOf(ecoFactId);\r
+               FieldObservation fieldObservation = fieldObservationMap.get(key);\r
+               if (fieldObservation == null){\r
+                       fieldObservation = FieldObservation.NewInstance();\r
+                       \r
+                       fieldObservationMap.put(key, fieldObservation);\r
+               }\r
+               \r
+               return fieldObservation;\r
        }\r
        \r
        private Feature makeFeature(DerivedUnitType type) {\r
@@ -238,8 +590,15 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
                \r
                try{\r
                        Set<String> taxonIdSet = new HashSet<String>();\r
+                       Set<String> fieldObservationIdSet = new HashSet<String>();\r
+                       Set<String> termsIdSet = new HashSet<String>();\r
+                       \r
                        while (rs.next()){\r
                                handleForeignKey(rs, taxonIdSet, "taxonId");\r
+                               handleForeignKey(rs, fieldObservationIdSet, "ecoFactId");\r
+                               handleForeignKey(rs, termsIdSet, "ClimateFk");\r
+                               handleForeignKey(rs, termsIdSet, "HabitatFk");\r
+                               handleForeignKey(rs, termsIdSet, "LifeFormFk");\r
                        }\r
                        \r
                        //taxon map\r
@@ -249,6 +608,23 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
                        Map<String, TaxonBase> objectMap = (Map<String, TaxonBase>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);\r
                        result.put(nameSpace, objectMap);\r
 \r
+                       //field observation map map\r
+                       nameSpace = AlgaTerraSpecimenImport.FIELD_OBSERVATION_NAMESPACE;\r
+                       cdmClass = FieldObservation.class;\r
+                       idSet = taxonIdSet;\r
+                       Map<String, FieldObservation> fieldObservationMap = (Map<String, FieldObservation>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);\r
+                       result.put(nameSpace, fieldObservationMap);\r
+\r
+                       //terms\r
+                       nameSpace = AlgaTerraSpecimenImport.TERMS_NAMESPACE;\r
+                       cdmClass = FieldObservation.class;\r
+                       idSet = taxonIdSet;\r
+                       Map<String, DefinedTermBase> termMap = (Map<String, DefinedTermBase>)getCommonService().getSourcedObjectsByIdInSource(cdmClass, idSet, nameSpace);\r
+                       result.put(nameSpace, termMap);\r
+\r
+               \r
+                       \r
+                       \r
                } catch (SQLException e) {\r
                        throw new RuntimeException(e);\r
                }\r
@@ -258,38 +634,39 @@ public class AlgaTerraSpecimenImport  extends BerlinModelImportBase {
 \r
        /**\r
         * Use same TaxonDescription if two records belong to the same taxon \r
+        * @param state \r
         * @param newTaxonId\r
         * @param oldTaxonId\r
         * @param oldDescription\r
         * @param taxonMap\r
         * @return\r
         */\r
-       private TaxonDescription getTaxonDescription(int newTaxonId, int oldTaxonId, TaxonDescription oldDescription, Map<String, TaxonBase> taxonMap, int factId, Reference<?> sourceSec){\r
+       private TaxonDescription getTaxonDescription(AlgaTerraImportState state, int newTaxonId, Map<String, TaxonBase> taxonMap, int factId, Reference<?> sourceSec){\r
                TaxonDescription result = null;\r
-               if (oldDescription == null || newTaxonId != oldTaxonId){\r
-                       TaxonBase<?> taxonBase = taxonMap.get(String.valueOf(newTaxonId));\r
-                       //TODO for testing\r
-                       //TaxonBase taxonBase = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
-                       Taxon taxon;\r
-                       if ( taxonBase instanceof Taxon ) {\r
-                               taxon = (Taxon) taxonBase;\r
-                       } else if (taxonBase != null) {\r
-                               logger.warn("TaxonBase for Fact(Specimen) with factId" + factId + " was not of type Taxon but: " + taxonBase.getClass().getSimpleName());\r
-                               return null;\r
-                       } else {\r
-                               logger.warn("TaxonBase for Fact(Specimen) " + factId + " is null.");\r
-                               return null;\r
-                       }               \r
-                       Set<TaxonDescription> descriptionSet= taxon.getDescriptions();\r
-                       if (descriptionSet.size() > 0) {\r
-                               result = descriptionSet.iterator().next(); \r
-                       }else{\r
-                               result = TaxonDescription.NewInstance();\r
-                               result.setTitleCache(sourceSec.getTitleCache(), true);\r
-                               taxon.addDescription(result);\r
-                       }\r
+               TaxonBase<?> taxonBase = taxonMap.get(String.valueOf(newTaxonId));\r
+               \r
+               //TODO for testing\r
+               if (taxonBase == null && ! state.getConfig().isDoTaxa()){\r
+                       taxonBase = Taxon.NewInstance(BotanicalName.NewInstance(Rank.SPECIES()), null);\r
+               }\r
+               \r
+               Taxon taxon;\r
+               if ( taxonBase instanceof Taxon ) {\r
+                       taxon = (Taxon) taxonBase;\r
+               } else if (taxonBase != null) {\r
+                       logger.warn("TaxonBase for Fact(Specimen) with factId" + factId + " was not of type Taxon but: " + taxonBase.getClass().getSimpleName());\r
+                       return null;\r
+               } else {\r
+                       logger.warn("TaxonBase for Fact(Specimen) " + factId + " is null.");\r
+                       return null;\r
+               }               \r
+               Set<TaxonDescription> descriptionSet= taxon.getDescriptions();\r
+               if (descriptionSet.size() > 0) {\r
+                       result = descriptionSet.iterator().next(); \r
                }else{\r
-                       result = oldDescription;\r
+                       result = TaxonDescription.NewInstance();\r
+                       result.setTitleCache(sourceSec.getTitleCache(), true);\r
+                       taxon.addDescription(result);\r
                }\r
                return result;\r
        }\r