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
.algaterra
;
14 import java
.sql
.ResultSet
;
15 import java
.sql
.SQLException
;
17 import java
.util
.UUID
;
19 import org
.apache
.commons
.lang
.StringUtils
;
20 import org
.apache
.log4j
.Logger
;
21 import org
.springframework
.transaction
.TransactionStatus
;
23 import eu
.etaxonomy
.cdm
.api
.facade
.DerivedUnitFacade
;
24 import eu
.etaxonomy
.cdm
.io
.berlinModel
.in
.BerlinModelImportBase
;
25 import eu
.etaxonomy
.cdm
.io
.common
.ResultSetPartitioner
;
26 import eu
.etaxonomy
.cdm
.io
.common
.Source
;
27 import eu
.etaxonomy
.cdm
.model
.agent
.Team
;
28 import eu
.etaxonomy
.cdm
.model
.agent
.TeamOrPersonBase
;
29 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
30 import eu
.etaxonomy
.cdm
.model
.common
.TimePeriod
;
31 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
32 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
33 import eu
.etaxonomy
.cdm
.model
.description
.SpecimenDescription
;
34 import eu
.etaxonomy
.cdm
.model
.description
.State
;
35 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
36 import eu
.etaxonomy
.cdm
.model
.location
.NamedArea
;
37 import eu
.etaxonomy
.cdm
.model
.location
.Point
;
38 import eu
.etaxonomy
.cdm
.model
.location
.ReferenceSystem
;
39 import eu
.etaxonomy
.cdm
.model
.location
.TdwgArea
;
40 import eu
.etaxonomy
.cdm
.model
.location
.WaterbodyOrCountry
;
41 import eu
.etaxonomy
.cdm
.model
.occurrence
.Collection
;
42 import eu
.etaxonomy
.cdm
.model
.reference
.Reference
;
43 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
49 public abstract class AlgaTerraSpecimenImportBase
extends BerlinModelImportBase
{
50 private static final Logger logger
= Logger
.getLogger(AlgaTerraSpecimenImportBase
.class);
52 public static final String ECO_FACT_FIELD_OBSERVATION_NAMESPACE
= "EcoFact_FieldObservation";
53 public static final String ECO_FACT_DERIVED_UNIT_NAMESPACE
= "EcoFact_DerivedUnit";
54 public static final String TYPE_SPECIMEN_FIELD_OBSERVATION_NAMESPACE
= "TypeSpecimen_FieldObservation";
55 public static final String TYPE_SPECIMEN_DERIVED_UNIT_NAMESPACE
= "TypeSpecimen_DerivedUnit";
56 public static final String FACT_ECOLOGY_NAMESPACE
= "Fact(Ecology)";
59 public static final String TERMS_NAMESPACE
= "ALGA_TERRA_TERMS";
61 //TODO move to transformrer
62 final static UUID uuidMarkerAlkalinity
= UUID
.fromString("e52d0ea2-0c1f-4d95-ae6d-e21ab317c594");
63 final static UUID uuidRefSystemGps
= UUID
.fromString("c23e4928-c137-4e4a-b6ab-b430da3d0b94");
64 final static UUID uuidFeatureSpecimenCommunity
= UUID
.fromString("3ff5b1ab-3999-4b5a-b8f7-01fd2f6c12c7");
65 final static UUID uuidFeatureAdditionalData
= UUID
.fromString("0ac82ab8-2c2b-4953-98eb-a9f718eb9c57");
66 final static UUID uuidFeatureHabitatExplanation
= UUID
.fromString("6fe32295-61a3-44fc-9fcf-a85790ea888f");
68 final static UUID uuidVocAlgaTerraClimate
= UUID
.fromString("b0a677c6-8bb6-43f4-b1b8-fc377a10feb5");
69 final static UUID uuidVocAlgaTerraHabitat
= UUID
.fromString("06f30114-e19c-4e7d-a8e5-5488c41fcbc5");
70 final static UUID uuidVocAlgaTerraLifeForm
= UUID
.fromString("3c0b194e-809c-4b42-9498-6ff034066ed7");
72 final static UUID uuidFeatureAlgaTerraClimate
= UUID
.fromString("8754674c-9ab9-4f28-95f1-91eeee2314ee");
73 final static UUID uuidFeatureAlgaTerraHabitat
= UUID
.fromString("7def3fc2-cdc5-4739-8e13-62edbd053415");
74 final static UUID uuidFeatureAlgaTerraLifeForm
= UUID
.fromString("9b657901-1b0d-4a2a-8d21-dd8c1413e2e6");
76 final static UUID uuidVocParameter
= UUID
.fromString("45888b40-5bbb-4293-aa1e-02479796cd7c");
77 final static UUID uuidStatMeasureSingleValue
= UUID
.fromString("eb4c3d98-4d4b-4c37-8eb4-17315ce79920");
78 final static UUID uuidMeasurementValueModifier
= UUID
.fromString("0218a7a3-f6c0-4d06-a4f8-6b50b73aef5e");
80 final static UUID uuidModifierLowerThan
= UUID
.fromString("2b500085-6bef-4003-b6ea-e0ad0237d79d");
81 final static UUID uuidModifierGreaterThan
= UUID
.fromString("828df49d-c745-48f7-b083-0ada43356c34");
83 public AlgaTerraSpecimenImportBase(String tableName
, String pluralString
) {
84 super(tableName
, pluralString
);
88 * Creates the vocabularies and the features for Climate, Habitat and Lifeform
90 * @throws SQLException
92 protected void makeVocabulariesAndFeatures(AlgaTerraImportState state
) throws SQLException
{
93 String abbrevLabel
= null;
96 if (! state
.isSpecimenVocabulariesCreated()){
98 TransactionStatus txStatus
= this.startTransaction();
100 boolean isOrdered
= true;
101 OrderedTermVocabulary
<State
> climateVoc
= (OrderedTermVocabulary
)getVocabulary(uuidVocAlgaTerraClimate
, "Climate", "Climate", abbrevLabel
, uri
, isOrdered
, null);
102 OrderedTermVocabulary
<State
> habitatVoc
= (OrderedTermVocabulary
)getVocabulary(uuidVocAlgaTerraHabitat
, "Habitat", "Habitat", abbrevLabel
, uri
, isOrdered
, null);
103 OrderedTermVocabulary
<State
> lifeformVoc
= (OrderedTermVocabulary
)getVocabulary(uuidVocAlgaTerraLifeForm
, "Lifeform", "Lifeform", abbrevLabel
, uri
, isOrdered
, null);
106 Feature feature
= getFeature(state
, uuidFeatureAlgaTerraClimate
, "Climate","Climate", null, null);
107 feature
.setSupportsCategoricalData(true);
109 feature
= getFeature(state
, uuidFeatureAlgaTerraLifeForm
, "LifeForm","LifeForm", null, null);
110 feature
.setSupportsCategoricalData(true);
112 feature
= Feature
.HABITAT();
113 feature
.setSupportsCategoricalData(true);
114 getTermService().saveOrUpdate(feature
);
116 Source source
= state
.getAlgaTerraConfigurator().getSource();
118 String climateSql
= "SELECT * FROM EcoClimate";
119 ResultSet rs
= source
.getResultSet(climateSql
);
121 String climate
= rs
.getString("Climate");
122 String description
= rs
.getString("Description");
123 Integer id
= rs
.getInt("ClimateId");
124 UUID uuid
= UUID
.fromString(rs
.getString("UUID"));
125 State stateTerm
= getStateTerm(state
, uuid
, climate
, description
, null, climateVoc
);
126 addOriginalSource(stateTerm
, id
.toString(), "EcoClimate", state
.getTransactionalSourceReference());
127 getTermService().saveOrUpdate(stateTerm
);
130 String habitatSql
= "SELECT * FROM EcoHabitat";
131 rs
= source
.getResultSet(habitatSql
);
133 String habitat
= rs
.getString("Habitat");
134 String description
= rs
.getString("Description");
135 Integer id
= rs
.getInt("HabitatId");
136 UUID uuid
= UUID
.fromString(rs
.getString("UUID"));
137 State stateTerm
= getStateTerm(state
, uuid
, habitat
, description
, null, habitatVoc
);
138 addOriginalSource(stateTerm
, id
.toString(), "EcoHabitat", state
.getTransactionalSourceReference());
139 getTermService().saveOrUpdate(stateTerm
);
142 String lifeformSql
= "SELECT * FROM EcoLifeForm";
143 rs
= source
.getResultSet(lifeformSql
);
145 String lifeform
= rs
.getString("LifeForm");
146 String description
= rs
.getString("Description");
147 Integer id
= rs
.getInt("LifeFormId");
148 UUID uuid
= UUID
.fromString(rs
.getString("UUID"));
149 State stateTerm
= getStateTerm(state
, uuid
, lifeform
, description
, null, lifeformVoc
);
150 addOriginalSource(stateTerm
, id
.toString(), "EcoLifeForm", state
.getTransactionalSourceReference());
151 getTermService().saveOrUpdate(stateTerm
);
154 this.commitTransaction(txStatus
);
156 state
.setSpecimenVocabulariesCreated(true);
161 protected String
getLocalityString(){
165 protected void handleFieldObservationSpecimen(ResultSet rs
, DerivedUnitFacade facade
, AlgaTerraImportState state
, ResultSetPartitioner partitioner
) throws SQLException
{
166 //FIXME missing fields #3084, #3085, #3080
169 Integer unitId
= nullSafeInt(rs
, "unitId");
170 String locality
= rs
.getString(getLocalityString());
171 Double latitude
= nullSafeDouble(rs
, "Latitude");
172 Double longitude
= nullSafeDouble(rs
, "Longitude");
173 Integer errorRadius
= nullSafeInt(rs
,"Prec");
174 String geoCodeMethod
= rs
.getString("GeoCodeMethod");
176 Integer altitude
= nullSafeInt(rs
, "Altitude");
177 Integer lowerAltitude
= nullSafeInt(rs
,"AltitudeLowerValue");
178 String altitudeUnit
= rs
.getString("AltitudeUnit");
179 Double depth
= nullSafeDouble(rs
, "Depth");
180 Double depthLow
= nullSafeDouble(rs
, "DepthLow");
182 String collectorsNumber
= rs
.getString("CollectorsNumber");
183 Date collectionDateStart
= rs
.getDate("CollectionDate");
184 Date collectionDateEnd
= rs
.getDate("CollectionDateEnd");
187 facade
.setLocality(locality
);
190 ReferenceSystem referenceSystem
= makeRefrenceSystem(geoCodeMethod
, state
);
191 if (longitude
!= null || latitude
!= null || referenceSystem
!= null || errorRadius
!= null){
192 Point exactLocation
= Point
.NewInstance(longitude
, latitude
, referenceSystem
, errorRadius
);
193 facade
.setExactLocation(exactLocation
);
197 if (StringUtils
.isNotBlank(altitudeUnit
) && ! altitudeUnit
.trim().equalsIgnoreCase("m")){
198 logger
.warn("Altitude unit is not [m] but: " + altitudeUnit
);
200 if ( altitude
!= null){
201 if (lowerAltitude
== null){
202 facade
.setAbsoluteElevation(altitude
);
204 if (! facade
.isEvenDistance(lowerAltitude
, altitude
)){
205 //FIXME there is a ticket for this
206 altitude
= altitude
+ 1;
207 logger
.info("Current implementation of altitude does not allow uneven distances");
209 facade
.setAbsoluteElevationRange(lowerAltitude
,altitude
);
213 //FIXME needs model change to accept double #3072
214 Integer intDepth
= depth
.intValue();
215 if (depthLow
== null){
216 facade
.setDistanceToWaterSurface(intDepth
);
218 //FIXME range not yet in model #3074
219 facade
.setDistanceToWaterSurface(intDepth
);
224 facade
.setFieldNumber(collectorsNumber
);
225 TimePeriod gatheringPeriod
= TimePeriod
.NewInstance(collectionDateStart
, collectionDateEnd
);
226 facade
.setGatheringPeriod(gatheringPeriod
);
227 handleCollectorTeam(state
, facade
, rs
);
230 makeAreas(state
, rs
, facade
);
233 //TODO is this an annotation on field observation or on the derived unit?
235 //id, created, updated, notes
237 this.doIdCreatedUpdatedNotes(state
, facade
.innerFieldObservation(), rs
, unitId
, getFieldObservationNameSpace());
239 logger
.warn("FieldObservation has no unitId: " + facade
.innerFieldObservation() + ": " + getFieldObservationNameSpace());
241 } catch (Exception e
) {
242 throw new RuntimeException(e
);
247 protected void handleFirstDerivedSpecimen(ResultSet rs
, DerivedUnitFacade facade
, AlgaTerraImportState state
, ResultSetPartitioner partitioner
) throws SQLException
{
248 Integer unitId
= nullSafeInt(rs
, "unitId");
249 Integer collectionFk
= nullSafeInt(rs
,"CollectionFk");
252 if (collectionFk
!= null){
253 Collection subCollection
= state
.getRelatedObject(AlgaTerraCollectionImport
.NAMESPACE_SUBCOLLECTION
, String
.valueOf(collectionFk
), Collection
.class);
254 if (subCollection
!= null){
255 facade
.setCollection(subCollection
);
257 Collection collection
= state
.getRelatedObject(AlgaTerraCollectionImport
.NAMESPACE_COLLECTION
, String
.valueOf(collectionFk
), Collection
.class);
258 facade
.setCollection(collection
);
262 //TODO id, created for fact + ecoFact
263 // this.doIdCreatedUpdatedNotes(state, descriptionElement, rs, id, namespace);
265 this.doIdCreatedUpdatedNotes(state
, facade
.innerDerivedUnit(), rs
, unitId
, getDerivedUnitNameSpace());
267 logger
.warn("Specimen has no unitId: " + facade
.innerDerivedUnit() + ": " + getDerivedUnitNameSpace());
273 protected abstract String
getDerivedUnitNameSpace();
275 protected abstract String
getFieldObservationNameSpace();
278 protected DescriptionBase
getFieldObservationDescription(DerivedUnitFacade facade
) {
279 Set
<DescriptionBase
> descriptions
= facade
.innerFieldObservation().getDescriptions();
280 for (DescriptionBase desc
: descriptions
){
281 if (desc
.isImageGallery() == false){
285 SpecimenDescription specDesc
= SpecimenDescription
.NewInstance(facade
.innerFieldObservation());
286 descriptions
.add(specDesc
);
291 private void makeAreas(AlgaTerraImportState state
, ResultSet rs
, DerivedUnitFacade facade
) throws SQLException
{
292 Object gazetteerId
= rs
.getObject("GazetteerId");
293 if (gazetteerId
!= null){
296 String tdwg4
= rs
.getString("L4Code");
297 if (isNotBlank(tdwg4
)){
298 tdwgArea
= TdwgArea
.getAreaByTdwgAbbreviation(tdwg4
);
300 String tdwg3
= rs
.getString("L3Code");
301 if (isNotBlank(tdwg3
)){
302 tdwgArea
= TdwgArea
.getAreaByTdwgAbbreviation(tdwg3
);
304 Integer tdwg2
= rs
.getInt("L2Code");
305 tdwgArea
= TdwgArea
.getAreaByTdwgAbbreviation(String
.valueOf(tdwg2
));
308 if (tdwgArea
== null){
309 logger
.warn("TDWG area could not be defined for gazetterId: " + gazetteerId
);
311 facade
.addCollectingArea(tdwgArea
);
315 WaterbodyOrCountry country
= null;
316 String isoCountry
= rs
.getString("ISOCountry");
317 String countryStr
= rs
.getString("Country");
318 if (isNotBlank(isoCountry
)){
319 country
= WaterbodyOrCountry
.getWaterbodyOrCountryByIso3166A2(isoCountry
);
320 }else if (isNotBlank(countryStr
)){
321 logger
.warn("Country exists but no ISO code");
323 if (country
== null){
324 logger
.warn("Country does not exist for GazetteerID " + gazetteerId
);
326 facade
.setCountry(country
);
332 WaterbodyOrCountry waterbody
= null;
333 String waterbodyStr
= rs
.getString("WaterBody");
334 if (isNotBlank(waterbodyStr
)){
335 if (waterbodyStr
.equals("Atlantic Ocean")){
336 waterbody
= WaterbodyOrCountry
.ATLANTICOCEAN();
338 logger
.warn("Waterbody not recognized: " + waterbody
);
340 if (waterbody
!= null){
341 facade
.addCollectingArea(waterbody
);
347 //TODO -> SpecimenImport (not existing in TypeSpecimen)
353 private ReferenceSystem
makeRefrenceSystem(String geoCodeMethod
, AlgaTerraImportState state
) {
354 if (StringUtils
.isBlank(geoCodeMethod
)){
356 }else if(geoCodeMethod
.startsWith("GPS")){
357 getReferenceSystem(state
, uuidRefSystemGps
, "GPS", "GPS", "GPS", ReferenceSystem
.GOOGLE_EARTH().getVocabulary());
358 return ReferenceSystem
.WGS84();
359 }else if(geoCodeMethod
.startsWith("Google")){
360 return ReferenceSystem
.GOOGLE_EARTH();
361 }else if(geoCodeMethod
.startsWith("Map")){
362 logger
.warn("Reference system " + geoCodeMethod
+ " not yet supported.");
364 }else if(geoCodeMethod
.startsWith("WikiProjekt Georeferenzierung") || geoCodeMethod
.startsWith("http://toolserver.org/~geohack/geohack.php") ){
365 return ReferenceSystem
.WGS84();
367 logger
.warn("Reference system " + geoCodeMethod
+ " not yet supported.");
375 private void handleCollectorTeam(AlgaTerraImportState state
, DerivedUnitFacade facade
, ResultSet rs
) throws SQLException
{
376 String collector
= rs
.getString("Collector");
377 TeamOrPersonBase
<?
> author
= getAuthor(collector
);
378 facade
.setCollector(author
);
385 protected TeamOrPersonBase
<?
> getAuthor(String author
) {
386 // FIXME TODO parsen und deduplizieren
387 Team team
= Team
.NewTitledInstance(author
, author
);
393 * Use same TaxonDescription if two records belong to the same taxon
397 * @param oldDescription
401 protected TaxonDescription
getTaxonDescription(AlgaTerraImportState state
, Taxon taxon
, Reference
<?
> sourceSec
){
402 TaxonDescription result
= null;
403 Set
<TaxonDescription
> descriptionSet
= taxon
.getDescriptions();
404 if (descriptionSet
.size() > 0) {
405 result
= descriptionSet
.iterator().next();
407 result
= TaxonDescription
.NewInstance();
408 result
.setTitleCache(sourceSec
.getTitleCache(), true);
409 taxon
.addDescription(result
);