minor
[cdmlib-apps.git] / app-import / src / main / java / eu / etaxonomy / cdm / io / algaterra / AlgaTerraSpecimenImportBase.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
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.
8 */
9
10 package eu.etaxonomy.cdm.io.algaterra;
11
12 import java.net.URI;
13 import java.sql.Date;
14 import java.sql.ResultSet;
15 import java.sql.SQLException;
16 import java.util.Set;
17 import java.util.UUID;
18
19 import org.apache.commons.lang.StringUtils;
20 import org.apache.log4j.Logger;
21 import org.springframework.transaction.TransactionStatus;
22
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.common.OrderedTermVocabulary;
29 import eu.etaxonomy.cdm.model.common.TimePeriod;
30 import eu.etaxonomy.cdm.model.description.DescriptionBase;
31 import eu.etaxonomy.cdm.model.description.Feature;
32 import eu.etaxonomy.cdm.model.description.SpecimenDescription;
33 import eu.etaxonomy.cdm.model.description.State;
34 import eu.etaxonomy.cdm.model.location.NamedArea;
35 import eu.etaxonomy.cdm.model.location.Point;
36 import eu.etaxonomy.cdm.model.location.ReferenceSystem;
37 import eu.etaxonomy.cdm.model.location.TdwgArea;
38 import eu.etaxonomy.cdm.model.location.WaterbodyOrCountry;
39 import eu.etaxonomy.cdm.model.occurrence.Collection;
40
41 /**
42 * @author a.mueller
43 * @created 12.09.2012
44 */
45 public abstract class AlgaTerraSpecimenImportBase extends BerlinModelImportBase{
46 private static final Logger logger = Logger.getLogger(AlgaTerraSpecimenImportBase.class);
47
48 public static final String ECO_FACT_FIELD_OBSERVATION_NAMESPACE = "EcoFact";
49 public static final String ECO_FACT_DERIVED_UNIT_NAMESPACE = "EcoFact";
50 public static final String TYPE_SPECIMEN_FIELD_OBSERVATION_NAMESPACE = "TypeSpecimen_FieldObservation";
51 public static final String TYPE_SPECIMEN_DERIVED_UNIT_NAMESPACE = "TypeSpecimen_DerivedUnit";
52
53 public static final String TERMS_NAMESPACE = "ALGA_TERRA_TERMS";
54
55 //TODO move to transformrer
56 final static UUID uuidMarkerAlkalinity = UUID.fromString("e52d0ea2-0c1f-4d95-ae6d-e21ab317c594");
57 final static UUID uuidRefSystemGps = UUID.fromString("c23e4928-c137-4e4a-b6ab-b430da3d0b94");
58 final static UUID uuidFeatureSpecimenCommunity = UUID.fromString("3ff5b1ab-3999-4b5a-b8f7-01fd2f6c12c7");
59 final static UUID uuidFeatureAdditionalData = UUID.fromString("0ac82ab8-2c2b-4953-98eb-a9f718eb9c57");
60 final static UUID uuidFeatureHabitatExplanation = UUID.fromString("6fe32295-61a3-44fc-9fcf-a85790ea888f");
61
62 final static UUID uuidVocAlgaTerraClimate = UUID.fromString("b0a677c6-8bb6-43f4-b1b8-fc377a10feb5");
63 final static UUID uuidVocAlgaTerraHabitat = UUID.fromString("06f30114-e19c-4e7d-a8e5-5488c41fcbc5");
64 final static UUID uuidVocAlgaTerraLifeForm = UUID.fromString("3c0b194e-809c-4b42-9498-6ff034066ed7");
65
66 final static UUID uuidFeatureAlgaTerraClimate = UUID.fromString("8754674c-9ab9-4f28-95f1-91eeee2314ee");
67 final static UUID uuidFeatureAlgaTerraHabitat = UUID.fromString("7def3fc2-cdc5-4739-8e13-62edbd053415");
68 final static UUID uuidFeatureAlgaTerraLifeForm = UUID.fromString("9b657901-1b0d-4a2a-8d21-dd8c1413e2e6");
69
70 final static UUID uuidVocParameter = UUID.fromString("45888b40-5bbb-4293-aa1e-02479796cd7c");
71 final static UUID uuidStatMeasureSingleValue = UUID.fromString("eb4c3d98-4d4b-4c37-8eb4-17315ce79920");
72 final static UUID uuidMeasurementValueModifier = UUID.fromString("0218a7a3-f6c0-4d06-a4f8-6b50b73aef5e");
73
74 final static UUID uuidModifierLowerThan = UUID.fromString("2b500085-6bef-4003-b6ea-e0ad0237d79d");
75 final static UUID uuidModifierGreaterThan = UUID.fromString("828df49d-c745-48f7-b083-0ada43356c34");
76
77
78 /**
79 * Creates the vocabularies and the features for Climate, Habitat and Lifeform
80 * @param state
81 * @throws SQLException
82 */
83 protected void makeVocabulariesAndFeatures(AlgaTerraImportState state) throws SQLException {
84 String abbrevLabel = null;
85 URI uri = null;
86
87 if (! state.isSpecimenVocabulariesCreated()){
88
89 TransactionStatus txStatus = this.startTransaction();
90
91 boolean isOrdered = true;
92 OrderedTermVocabulary<State> climateVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraClimate, "Climate", "Climate", abbrevLabel, uri, isOrdered, null);
93 OrderedTermVocabulary<State> habitatVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraHabitat, "Habitat", "Habitat", abbrevLabel, uri, isOrdered, null);
94 OrderedTermVocabulary<State> lifeformVoc = (OrderedTermVocabulary)getVocabulary(uuidVocAlgaTerraLifeForm, "Lifeform", "Lifeform", abbrevLabel, uri, isOrdered, null);
95
96
97 Feature feature = getFeature(state, uuidFeatureAlgaTerraClimate, "Climate","Climate", null, null);
98 feature.setSupportsCategoricalData(true);
99
100 feature = getFeature(state, uuidFeatureAlgaTerraLifeForm, "LifeForm","LifeForm", null, null);
101 feature.setSupportsCategoricalData(true);
102
103 feature = Feature.HABITAT();
104 feature.setSupportsCategoricalData(true);
105 getTermService().saveOrUpdate(feature);
106
107 Source source = state.getAlgaTerraConfigurator().getSource();
108
109 String climateSql = "SELECT * FROM EcoClimate";
110 ResultSet rs = source.getResultSet(climateSql);
111 while (rs.next()){
112 String climate = rs.getString("Climate");
113 String description = rs.getString("Description");
114 Integer id = rs.getInt("ClimateId");
115 UUID uuid = UUID.fromString(rs.getString("UUID"));
116 State stateTerm = getStateTerm(state, uuid, climate, description, null, climateVoc);
117 addOriginalSource(stateTerm, id.toString(), "EcoClimate", state.getTransactionalSourceReference());
118 getTermService().saveOrUpdate(stateTerm);
119 }
120
121 String habitatSql = "SELECT * FROM EcoHabitat";
122 rs = source.getResultSet(habitatSql);
123 while (rs.next()){
124 String habitat = rs.getString("Habitat");
125 String description = rs.getString("Description");
126 Integer id = rs.getInt("HabitatId");
127 UUID uuid = UUID.fromString(rs.getString("UUID"));
128 State stateTerm = getStateTerm(state, uuid, habitat, description, null, habitatVoc);
129 addOriginalSource(stateTerm, id.toString(), "EcoHabitat", state.getTransactionalSourceReference());
130 getTermService().saveOrUpdate(stateTerm);
131 }
132
133 String lifeformSql = "SELECT * FROM EcoLifeForm";
134 rs = source.getResultSet(lifeformSql);
135 while (rs.next()){
136 String lifeform = rs.getString("LifeForm");
137 String description = rs.getString("Description");
138 Integer id = rs.getInt("LifeFormId");
139 UUID uuid = UUID.fromString(rs.getString("UUID"));
140 State stateTerm = getStateTerm(state, uuid, lifeform, description, null, lifeformVoc);
141 addOriginalSource(stateTerm, id.toString(), "EcoLifeForm", state.getTransactionalSourceReference());
142 getTermService().saveOrUpdate(stateTerm);
143 }
144
145 this.commitTransaction(txStatus);
146
147 state.setSpecimenVocabulariesCreated(true);
148 }
149
150 }
151
152 protected String getLocalityString(){
153 return "Locality";
154 }
155
156 protected void handleSingleSpecimen(ResultSet rs, DerivedUnitFacade facade, AlgaTerraImportState state, ResultSetPartitioner partitioner) throws SQLException {
157 //FIXME missing fields #3084, #3085, #3080
158 try {
159
160 Integer unitId = nullSafeInt(rs, "unitId");
161 String locality = rs.getString(getLocalityString());
162 Double latitude = nullSafeDouble(rs, "Latitude");
163 Double longitude = nullSafeDouble(rs, "Longitude");
164 Integer errorRadius = nullSafeInt(rs,"Prec");
165 String geoCodeMethod = rs.getString("GeoCodeMethod");
166
167 Integer altitude = nullSafeInt(rs, "Altitude");
168 Integer lowerAltitude = nullSafeInt(rs,"AltitudeLowerValue");
169 String altitudeUnit = rs.getString("AltitudeUnit");
170 Double depth = nullSafeDouble(rs, "Depth");
171 Double depthLow = nullSafeDouble(rs, "DepthLow");
172
173 String collectorsNumber = rs.getString("CollectorsNumber");
174 Date collectionDateStart = rs.getDate("CollectionDate");
175 Date collectionDateEnd = rs.getDate("CollectionDateEnd");
176
177 Integer collectionFk = nullSafeInt(rs,"CollectionFk");
178
179
180 //location
181 facade.setLocality(locality);
182
183 //exact location
184 ReferenceSystem referenceSystem = makeRefrenceSystem(geoCodeMethod, state);
185 if (longitude != null || latitude != null || referenceSystem != null || errorRadius != null){
186 Point exactLocation = Point.NewInstance(longitude, latitude, referenceSystem, errorRadius);
187 facade.setExactLocation(exactLocation);
188 }
189
190 //altitude, depth
191 if (StringUtils.isNotBlank(altitudeUnit) && ! altitudeUnit.trim().equalsIgnoreCase("m")){
192 logger.warn("Altitude unit is not [m] but: " + altitudeUnit);
193 }
194 if ( altitude != null){
195 if (lowerAltitude == null){
196 facade.setAbsoluteElevation(altitude);
197 }else{
198 if (! facade.isEvenDistance(lowerAltitude, altitude)){
199 //FIXME there is a ticket for this
200 altitude = altitude + 1;
201 logger.info("Current implementation of altitude does not allow uneven distances");
202 }
203 facade.setAbsoluteElevationRange(lowerAltitude,altitude);
204 }
205 }
206 if ( depth != null){
207 //FIXME needs model change to accept double #3072
208 Integer intDepth = depth.intValue();
209 if (depthLow == null){
210 facade.setDistanceToWaterSurface(intDepth);
211 }else{
212 //FIXME range not yet in model #3074
213 facade.setDistanceToWaterSurface(intDepth);
214 }
215 }
216
217 //field
218 facade.setFieldNumber(collectorsNumber);
219 TimePeriod gatheringPeriod = TimePeriod.NewInstance(collectionDateStart, collectionDateEnd);
220 facade.setGatheringPeriod(gatheringPeriod);
221 handleCollectorTeam(state, facade, rs);
222
223 //areas
224 makeAreas(state, rs, facade);
225
226 //collection
227 if (collectionFk != null){
228 Collection subCollection = state.getRelatedObject(AlgaTerraCollectionImport.NAMESPACE_SUBCOLLECTION, String.valueOf(collectionFk), Collection.class);
229 if (subCollection != null){
230 facade.setCollection(subCollection);
231 }else{
232 Collection collection = state.getRelatedObject(AlgaTerraCollectionImport.NAMESPACE_COLLECTION, String.valueOf(collectionFk), Collection.class);
233 facade.setCollection(collection);
234 }
235 }
236
237 //notes
238 //TODO is this an annotation on field observation or on the derived unit?
239
240 //TODO id, created for fact + ecoFact
241 // this.doIdCreatedUpdatedNotes(state, descriptionElement, rs, id, namespace);
242 if (unitId != null){
243 this.doIdCreatedUpdatedNotes(state, facade.innerDerivedUnit(), rs, unitId, getDerivedUnitNameSpace());
244 }else{
245 logger.warn("Specimen has no unitId: " + facade.innerDerivedUnit() + ": " + getDerivedUnitNameSpace());
246 }
247
248
249 } catch (Exception e) {
250 throw new RuntimeException(e);
251 }
252
253 }
254
255 protected abstract String getDerivedUnitNameSpace();
256
257 protected DescriptionBase getFieldObservationDescription(DerivedUnitFacade facade) {
258 Set<DescriptionBase> descriptions = facade.innerFieldObservation().getDescriptions();
259 for (DescriptionBase desc : descriptions){
260 if (desc.isImageGallery() == false){
261 return desc;
262 }
263 }
264 SpecimenDescription specDesc = SpecimenDescription.NewInstance(facade.innerFieldObservation());
265 descriptions.add(specDesc);
266 return specDesc;
267 }
268
269
270 private void makeAreas(AlgaTerraImportState state, ResultSet rs, DerivedUnitFacade facade) throws SQLException {
271 Object gazetteerId = rs.getObject("GazetteerId");
272 if (gazetteerId != null){
273 //TDWG
274 NamedArea tdwgArea;
275 String tdwg4 = rs.getString("L4Code");
276 if (isNotBlank(tdwg4)){
277 tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(tdwg4);
278 }else{
279 String tdwg3 = rs.getString("L3Code");
280 if (isNotBlank(tdwg3)){
281 tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(tdwg3);
282 }else{
283 Integer tdwg2 = rs.getInt("L2Code");
284 tdwgArea = TdwgArea.getAreaByTdwgAbbreviation(String.valueOf(tdwg2));
285 }
286 }
287 if (tdwgArea == null){
288 logger.warn("TDWG area could not be defined for gazetterId: " + gazetteerId);
289 }else{
290 facade.addCollectingArea(tdwgArea);
291 }
292
293 //Countries
294 WaterbodyOrCountry country = null;
295 String isoCountry = rs.getString("ISOCountry");
296 String countryStr = rs.getString("Country");
297 if (isNotBlank(isoCountry)){
298 country = WaterbodyOrCountry.getWaterbodyOrCountryByIso3166A2(isoCountry);
299 }else if (isNotBlank(countryStr)){
300 logger.warn("Country exists but no ISO code");
301 }
302 if (country == null){
303 logger.warn("Country does not exist for GazetteerID " + gazetteerId);
304 }else{
305 facade.setCountry(country);
306 }
307
308 }
309
310 //Waterbody
311 WaterbodyOrCountry waterbody = null;
312 String waterbodyStr = rs.getString("WaterBody");
313 if (isNotBlank(waterbodyStr)){
314 if (waterbodyStr.equals("Atlantic Ocean")){
315 waterbody = WaterbodyOrCountry.ATLANTICOCEAN();
316 }else{
317 logger.warn("Waterbody not recognized: " + waterbody);
318 }
319 if (waterbody != null){
320 facade.addCollectingArea(waterbody);
321 }
322 }
323
324
325 //countries sub
326 //TODO -> SpecimenImport (not existing in TypeSpecimen)
327 }
328
329
330
331
332 private ReferenceSystem makeRefrenceSystem(String geoCodeMethod, AlgaTerraImportState state) {
333 if (StringUtils.isBlank(geoCodeMethod)){
334 return null;
335 }else if(geoCodeMethod.startsWith("GPS")){
336 getReferenceSystem(state, uuidRefSystemGps, "GPS", "GPS", "GPS", ReferenceSystem.GOOGLE_EARTH().getVocabulary());
337 return ReferenceSystem.WGS84();
338 }else if(geoCodeMethod.startsWith("Google")){
339 return ReferenceSystem.GOOGLE_EARTH();
340 }else if(geoCodeMethod.startsWith("Map")){
341 logger.warn("Reference system " + geoCodeMethod + " not yet supported.");
342 return null;
343 }else if(geoCodeMethod.startsWith("WikiProjekt Georeferenzierung") || geoCodeMethod.startsWith("http://toolserver.org/~geohack/geohack.php") ){
344 return ReferenceSystem.WGS84();
345 }else {
346 logger.warn("Reference system " + geoCodeMethod + " not yet supported.");
347 return null;
348 }
349 }
350
351
352
353
354 private void handleCollectorTeam(AlgaTerraImportState state, DerivedUnitFacade facade, ResultSet rs) throws SQLException {
355 // FIXME parsen
356 String collector = rs.getString("Collector");
357 Team team = Team.NewTitledInstance(collector, collector);
358 facade.setCollector(team);
359 }
360
361
362
363
364 }