Project

General

Profile

Download (12 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2014 EDIT
4
* European Distributed Institute of Taxonomy
5
* http://www.e-taxonomy.eu
6
*
7
* The contents of this file are subject to the Mozilla Public License Version 1.1
8
* See LICENSE.TXT at the top of this package for the full license terms.
9
*/
10
package eu.etaxonomy.cdm.ext.occurrence.gbif;
11

    
12
import java.io.IOException;
13
import java.io.InputStream;
14
import java.io.StringWriter;
15
import java.net.MalformedURLException;
16
import java.net.URI;
17
import java.net.URISyntaxException;
18
import java.net.URL;
19
import java.text.ParseException;
20
import java.util.ArrayList;
21
import java.util.Collection;
22

    
23
import net.sf.json.JSONArray;
24
import net.sf.json.JSONObject;
25

    
26
import org.apache.commons.io.IOUtils;
27
import org.apache.log4j.Logger;
28

    
29
import eu.etaxonomy.cdm.api.facade.DerivedUnitFacade;
30
import eu.etaxonomy.cdm.common.UriUtils;
31
import eu.etaxonomy.cdm.model.agent.Person;
32
import eu.etaxonomy.cdm.model.common.TimePeriod;
33
import eu.etaxonomy.cdm.model.location.Country;
34
import eu.etaxonomy.cdm.model.location.Point;
35
import eu.etaxonomy.cdm.model.location.ReferenceSystem;
36
import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationType;
37

    
38
/**
39
 * Utility class which provides the functionality to convert a JSON response
40
 * resulting from a GBIF query for occurrences to the corresponding CDM entities.
41
 * @author pplitzner
42
 * @date 22.05.2014
43
 *
44
 */
45
public class GbifJsonOccurrenceParser {
46

    
47
    private static final Logger logger = Logger.getLogger(GbifJsonOccurrenceParser.class);
48

    
49
    private static final String DATASET_KEY = "datasetKey";
50
    private static final String DATASET_PROTOCOL = "protocol";
51

    
52
    private static final String KEY = "key";
53
    private static final String URL = "url";
54
    private static final String TYPE = "type";
55

    
56
    private static final String COUNTRY_CODE = "countryCode";
57
    private static final String LOCALITY = "locality";
58
    private static final String LONGITUDE = "decimalLongitude";
59
    private static final String LATITUDE = "decimalLatitude";
60
    private static final String GEOREFERENCE_PROTOCOL = "georeferenceProtocol";//reference system
61
    private static final String ELEVATION = "verbatimElevation";
62
    private static final String YEAR = "year";
63
    private static final String MONTH = "month";
64
    private static final String DAY = "day";
65
    private static final String EVENT_DATE= "eventDate";
66
    private static final String RECORDED_BY= "recordedBy";//collector
67
    private static final String RECORD_NUMBER = "recordNumber";//collector number
68
    private static final String FIELD_NUMBER = "fieldNumber";//collector number
69
    private static final String EVENT_REMARKS = "eventRemarks";//gathering event description
70
    private static final String OCCURRENCE_REMARKS = "occurrenceRemarks";//ecology
71
    private static final String COLLECTION_CODE = "collectionCode";
72
    private static final String CATALOG_NUMBER = "catalogNumber";//accession number
73

    
74

    
75
    /**
76
     * Parses the given {@link String} for occurrences.<br>
77
     * Note: The data structure of the GBIF response should not be changed.
78
     * @param jsonString JSON data as a String
79
     * @return the found occurrences as a collection of {@link GbifResponse}
80
     */
81
    public static Collection<GbifResponse> parseJsonRecords(String jsonString) {
82
        return parseJsonRecords(JSONObject.fromObject(jsonString));
83
    }
84

    
85
    /**
86
     * Parses the given {@link InputStream} for occurrences.
87
     * @param jsonString JSON data as an InputStream
88
     * @return the found occurrences as a collection of {@link GbifResponse}
89
     */
90
    public static Collection<GbifResponse> parseJsonRecords(InputStream inputStream) throws IOException{
91
        StringWriter stringWriter = new StringWriter();
92
        IOUtils.copy(inputStream, stringWriter);
93
        return parseJsonRecords(stringWriter.toString());
94
    }
95

    
96
    /**
97
     * Parses the given {@link JSONObject} for occurrences.<br>
98
     * Note: The data structure of the GBIF response should not be changed.
99
     * @param jsonString JSON data as an JSONObject
100
     * @return the found occurrences as a collection of {@link GbifResponse}
101
     */
102
    public static Collection<GbifResponse> parseJsonRecords(JSONObject jsonObject){
103
        return parseJsonRecords(jsonObject.getJSONArray("results"));
104
    }
105

    
106
    /**
107
     * Parses the given {@link JSONArray} for occurrences.
108
     * @param jsonString JSON data as an {@link JSONArray}
109
     * @return the found occurrences as a collection of {@link GbifResponse}
110
     */
111
    private static Collection<GbifResponse> parseJsonRecords(JSONArray jsonArray) {
112
        Collection<GbifResponse> results = new ArrayList<GbifResponse>();
113
        for(Object o:jsonArray){
114
            //parse every record
115
            if(o instanceof JSONObject){
116
                String dataSetKey = null;
117
                GbifDataSetProtocol dataSetProtocol = null;
118
                DerivedUnitFacade derivedUnitFacade = DerivedUnitFacade.NewInstance(SpecimenOrObservationType.PreservedSpecimen);
119
                JSONObject record = (JSONObject)o;
120

    
121
                if(record.has(DATASET_PROTOCOL)){
122
                    dataSetProtocol = GbifDataSetProtocol.parseProtocol(record.getString(DATASET_PROTOCOL));
123
                }
124
                if(record.has(DATASET_KEY)){
125
                    dataSetKey = record.getString(DATASET_KEY);
126
                }
127
                if(record.has(COUNTRY_CODE)){
128
                    String string = record.getString(COUNTRY_CODE);
129
                    Country country = Country.getCountryByIso3166A2(string);
130
                    if(country!=null){
131
                        derivedUnitFacade.setCountry(country);
132
                    }
133
                }
134
                if(record.has(LOCALITY)){
135
                    String string = record.getString(LOCALITY);
136
                    derivedUnitFacade.setLocality(string);
137
                }
138

    
139
                // GPS location
140
                Point location = Point.NewInstance();
141
                derivedUnitFacade.setExactLocation(location);
142
                try {
143
                    if(record.has(LATITUDE)){
144
                        String lat = record.getString(LATITUDE);
145
                        location.setLatitudeByParsing(lat);
146
                    }
147
                    if(record.has(LONGITUDE)){
148
                        String lon = record.getString(LONGITUDE);
149
                        location.setLongitudeByParsing(lon);
150
                    }
151
                } catch (ParseException e) {
152
                    logger.error("Could not parse GPS coordinates", e);
153
                }
154
                if(record.has(GEOREFERENCE_PROTOCOL)){
155
                    String geo = record.getString(GEOREFERENCE_PROTOCOL);
156
                    ReferenceSystem referenceSystem = null;
157
                    //TODO: Is there another way than string comparison
158
                    //to check which reference system is used?
159
                    if(ReferenceSystem.WGS84().getLabel().contains(geo)){
160
                        referenceSystem = ReferenceSystem.WGS84();
161
                    }
162
                    else if(ReferenceSystem.GOOGLE_EARTH().getLabel().contains(geo)){
163
                        referenceSystem = ReferenceSystem.GOOGLE_EARTH();
164
                    }
165
                    else if(ReferenceSystem.GAZETTEER().getLabel().contains(geo)){
166
                        referenceSystem = ReferenceSystem.GAZETTEER();
167
                    }
168
                    location.setReferenceSystem(referenceSystem);
169
                }
170

    
171
                if(record.has(ELEVATION)){
172
                    try {
173
                        //parse integer and strip of unit
174
                        String string = record.getString(ELEVATION);
175
                        int length = string.length();
176
                        StringBuilder builder = new StringBuilder();
177
                        for(int i=0;i<length;i++){
178
                            if(Character.isDigit(string.charAt(i))){
179
                                builder.append(string.charAt(i));
180
                            }
181
                            else{
182
                                break;
183
                            }
184
                        }
185
                        derivedUnitFacade.setAbsoluteElevation(Integer.parseInt(builder.toString()));
186
                    } catch (NumberFormatException e) {
187
                        logger.warn("Could not parse elevation", e);
188
                    }
189
                }
190

    
191
                //Date (Gathering Period)
192
                TimePeriod timePeriod = TimePeriod.NewInstance();
193
                derivedUnitFacade.setGatheringPeriod(timePeriod);
194
                //TODO what happens with eventDate??
195
                if(record.has(YEAR)){
196
                    timePeriod.setStartYear(record.getInt(YEAR));
197
                }
198
                if(record.has(MONTH)){
199
                    timePeriod.setStartMonth(record.getInt(MONTH));
200
                }
201
                if(record.has(DAY)){
202
                    timePeriod.setStartDay(record.getInt(DAY));
203
                }
204
                if(record.has(RECORDED_BY)){
205
                    Person person = Person.NewTitledInstance(record.getString(RECORDED_BY));
206
                    //FIXME check data base if collector already present
207
                    derivedUnitFacade.setCollector(person);
208
                }
209

    
210
                //collector number (fieldNumber OR recordNumber)
211
                if(record.has(FIELD_NUMBER)){
212
                    derivedUnitFacade.setFieldNumber(record.getString(FIELD_NUMBER));
213
                }
214
                //collector number (fieldNumber OR recordNumber)
215
                if(record.has(RECORD_NUMBER)){
216
                    derivedUnitFacade.setFieldNumber(record.getString(RECORD_NUMBER));
217
                }
218

    
219
                if(record.has(EVENT_REMARKS)){
220
                    derivedUnitFacade.setGatheringEventDescription(record.getString(EVENT_REMARKS));
221
                }
222
                if(record.has(OCCURRENCE_REMARKS)){
223
                    derivedUnitFacade.setEcology(record.getString(OCCURRENCE_REMARKS));
224
                }
225
                if(record.has(COLLECTION_CODE)){
226
                    String collectionCode = record.getString(COLLECTION_CODE);
227
                    //FIXME: check data base for existing collections
228
                    eu.etaxonomy.cdm.model.occurrence.Collection collection = eu.etaxonomy.cdm.model.occurrence.Collection.NewInstance();
229
                    collection.setCode(collectionCode);
230
                    derivedUnitFacade.setCollection(collection);
231
                }
232
                if(record.has(CATALOG_NUMBER)){
233
                    derivedUnitFacade.setAccessionNumber(record.getString(CATALOG_NUMBER));
234
                }
235
                // create dataset URL
236
                URI uri = null;
237
                try {
238
                    uri = UriUtils.createUri(new URL(GbifQueryServiceWrapper.BASE_URL), "/v1/dataset/"+dataSetKey+"/endpoint", null, null);
239
                } catch (MalformedURLException e) {
240
                    logger.error("Endpoint URI could not be created!", e);
241
                } catch (URISyntaxException e) {
242
                    logger.error("Endpoint URI could not be created!", e);
243
                }
244
                results.add(new GbifResponse(derivedUnitFacade, uri, dataSetProtocol));
245
            }
246
        }
247
        return results;
248
    }
249

    
250
    public static DataSetResponse parseOriginalDataSetUri(InputStream inputStream) throws IOException {
251
        StringWriter stringWriter = new StringWriter();
252
        IOUtils.copy(inputStream, stringWriter);
253
        return parseOriginalDataSetUri(stringWriter.toString());
254
    }
255

    
256
    public static DataSetResponse parseOriginalDataSetUri(String jsonString) {
257
        DataSetResponse response = new DataSetResponse();
258
        JSONArray jsonArray = JSONArray.fromObject(jsonString);
259
        Object next = jsonArray.iterator().next();
260
        if(next instanceof JSONObject){
261
            JSONObject jsonObject = (JSONObject)next;
262
            if(jsonObject.has(URL)){
263
                response.setEndpoint(URI.create(jsonObject.getString(URL)));
264
            }
265
            if(jsonObject.has(TYPE)){
266
                response.setProtocol(GbifDataSetProtocol.parseProtocol(jsonObject.getString(TYPE)));
267
            }
268
        }
269
        return response;
270
    }
271

    
272
}
(3-3/6)