1 /******************************************************************************
2 * $Id: ogrelasticlayer.cpp 28375 2015-01-30 12:06:11Z rouault $
3 *
4 * Project: ElasticSearch Translator
5 * Purpose:
6 * Author:
7 *
8 ******************************************************************************
9 * Copyright (c) 2011, Adam Estrada
10 * Copyright (c) 2012-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "ogr_elastic.h"
32 #include "cpl_conv.h"
33 #include "cpl_minixml.h"
34 #include "ogr_api.h"
35 #include "ogr_p.h"
36 #include <json.h> // JSON-C
37
38 CPL_CVSID("$Id: ogrelasticlayer.cpp 28375 2015-01-30 12:06:11Z rouault $");
39
40 /************************************************************************/
41 /* OGRElasticLayer() */
42 /************************************************************************/
43
OGRElasticLayer(CPL_UNUSED const char * pszFilename,const char * pszLayerName,OGRElasticDataSource * poDS,OGRSpatialReference * poSRSIn,CPL_UNUSED int bWriteMode)44 OGRElasticLayer::OGRElasticLayer(CPL_UNUSED const char* pszFilename,
45 const char* pszLayerName,
46 OGRElasticDataSource* poDS,
47 OGRSpatialReference *poSRSIn,
48 CPL_UNUSED int bWriteMode) {
49 this->pszLayerName = CPLStrdup(pszLayerName);
50 this->poDS = poDS;
51 this->pAttributes = NULL;
52
53 // If we are overwriting, then delete the current index if it exists
54 if (poDS->bOverwrite) {
55 poDS->DeleteIndex(CPLSPrintf("%s/%s", poDS->GetName(), pszLayerName));
56 }
57
58 // Create the index
59 poDS->UploadFile(CPLSPrintf("%s/%s", poDS->GetName(), pszLayerName), "");
60
61 // If we have a user specified mapping, then go ahead and update it now
62 if (poDS->pszMapping != NULL) {
63 poDS->UploadFile(CPLSPrintf("%s/%s/FeatureCollection/_mapping", poDS->GetName(), pszLayerName),
64 poDS->pszMapping);
65 }
66
67 poFeatureDefn = new OGRFeatureDefn(pszLayerName);
68 SetDescription( poFeatureDefn->GetName() );
69 poFeatureDefn->Reference();
70
71 poSRS = poSRSIn;
72 if (poSRS)
73 poSRS->Reference();
74
75 poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRS);
76
77 ResetReading();
78 return;
79 }
80
81 /************************************************************************/
82 /* ~OGRElasticLayer() */
83 /************************************************************************/
84
~OGRElasticLayer()85 OGRElasticLayer::~OGRElasticLayer() {
86 PushIndex();
87
88 CPLFree(pszLayerName);
89
90 poFeatureDefn->Release();
91
92 if (poSRS != NULL)
93 poSRS->Release();
94 }
95
96
97 /************************************************************************/
98 /* GetLayerDefn() */
99 /************************************************************************/
100
GetLayerDefn()101 OGRFeatureDefn * OGRElasticLayer::GetLayerDefn() {
102 return poFeatureDefn;
103 }
104
105 /************************************************************************/
106 /* ResetReading() */
107 /************************************************************************/
108
ResetReading()109 void OGRElasticLayer::ResetReading() {
110 return;
111 }
112
113 /************************************************************************/
114 /* GetNextFeature() */
115 /************************************************************************/
116
GetNextFeature()117 OGRFeature *OGRElasticLayer::GetNextFeature() {
118 CPLError(CE_Failure, CPLE_NotSupported,
119 "Cannot read features when writing a Elastic file");
120 return NULL;
121 }
122
123 /************************************************************************/
124 /* AppendGroup() */
125 /************************************************************************/
126
AppendGroup(json_object * parent,const CPLString & name)127 json_object *AppendGroup(json_object *parent, const CPLString &name) {
128 json_object *obj = json_object_new_object();
129 json_object *properties = json_object_new_object();
130 json_object_object_add(parent, name, obj);
131 json_object_object_add(obj, "properties", properties);
132 return properties;
133 }
134
135 /************************************************************************/
136 /* AddPropertyMap() */
137 /************************************************************************/
138
AddPropertyMap(const CPLString & type,const CPLString & format="")139 json_object *AddPropertyMap(const CPLString &type, const CPLString &format = "") {
140 json_object *obj = json_object_new_object();
141 json_object_object_add(obj, "store", json_object_new_string("yes"));
142 json_object_object_add(obj, "type", json_object_new_string(type.c_str()));
143 if (!format.empty()) {
144 json_object_object_add(obj, "format", json_object_new_string(format.c_str()));
145 }
146 return obj;
147 }
148
149 /************************************************************************/
150 /* BuildMap() */
151 /************************************************************************/
152
BuildMap()153 CPLString OGRElasticLayer::BuildMap() {
154 json_object *map = json_object_new_object();
155 json_object *properties = json_object_new_object();
156
157 json_object *Feature = AppendGroup(map, "FeatureCollection");
158 json_object_object_add(Feature, "type", AddPropertyMap("string"));
159 json_object_object_add(Feature, "properties", properties);
160 if (pAttributes) json_object_object_add(properties, "properties", (json_object *) pAttributes);
161 json_object *geometry = AppendGroup(Feature, "geometry");
162 json_object_object_add(geometry, "type", AddPropertyMap("string"));
163 json_object_object_add(geometry, "coordinates", AddPropertyMap("geo_point"));
164
165 CPLString jsonMap(json_object_to_json_string(map));
166 json_object_put(map);
167
168 // The attribute's were freed from the deletion of the map object
169 // because we added it as a child of one of the map object attributes
170 if (pAttributes) {
171 pAttributes = NULL;
172 }
173
174 return jsonMap;
175 }
176
177 /************************************************************************/
178 /* ICreateFeature() */
179 /************************************************************************/
180
ICreateFeature(OGRFeature * poFeature)181 OGRErr OGRElasticLayer::ICreateFeature(OGRFeature *poFeature) {
182
183 // Check to see if the user has elected to only write out the mapping file
184 // This method will only write out one layer from the vector file in cases where there are multiple layers
185 if (poDS->pszWriteMap != NULL) {
186 if (pAttributes) {
187 CPLString map = BuildMap();
188
189 // Write the map to a file
190 FILE *f = fopen(poDS->pszWriteMap, "wb");
191 if (f) {
192 fwrite(map.c_str(), 1, map.length(), f);
193 fclose(f);
194 }
195 }
196 return OGRERR_NONE;
197 }
198
199 // Check to see if we have any fields to upload to this index
200 if (poDS->pszMapping == NULL && pAttributes) {
201 poDS->UploadFile(CPLSPrintf("%s/%s/FeatureCollection/_mapping", poDS->GetName(), pszLayerName), BuildMap());
202 }
203
204 // Get the center point of the geometry
205 OGREnvelope env;
206 if (!poFeature->GetGeometryRef()) {
207 return OGRERR_FAILURE;
208 }
209 poFeature->GetGeometryRef()->getEnvelope(&env);
210
211 json_object *fieldObject = json_object_new_object();
212 json_object *geometry = json_object_new_object();
213 json_object *coordinates = json_object_new_array();
214 json_object *properties = json_object_new_object();
215
216 json_object_object_add(fieldObject, "geometry", geometry);
217 json_object_object_add(geometry, "type", json_object_new_string("POINT"));
218 json_object_object_add(geometry, "coordinates", coordinates);
219 json_object_array_add(coordinates, json_object_new_double((env.MaxX + env.MinX)*0.5));
220 json_object_array_add(coordinates, json_object_new_double((env.MaxY + env.MinY)*0.5));
221 json_object_object_add(fieldObject, "type", json_object_new_string("Feature"));
222 json_object_object_add(fieldObject, "properties", properties);
223
224 // For every field that
225 int fieldCount = poFeatureDefn->GetFieldCount();
226 for (int i = 0; i < fieldCount; i++) {
227 if(!poFeature->IsFieldSet( i ) ) {
228 continue;
229 }
230 switch (poFeatureDefn->GetFieldDefn(i)->GetType()) {
231 case OFTInteger:
232 json_object_object_add(properties,
233 poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
234 json_object_new_int(poFeature->GetFieldAsInteger(i)));
235 break;
236 case OFTReal:
237 json_object_object_add(properties,
238 poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
239 json_object_new_double(poFeature->GetFieldAsDouble(i)));
240 break;
241 default:
242 {
243 CPLString tmp = poFeature->GetFieldAsString(i);
244 json_object_object_add(properties,
245 poFeatureDefn->GetFieldDefn(i)->GetNameRef(),
246 json_object_new_string(tmp));
247 }
248 }
249 }
250
251 // Build the field string
252 CPLString fields(json_object_to_json_string(fieldObject));
253 json_object_put(fieldObject);
254
255 // Check to see if we're using bulk uploading
256 if (poDS->nBulkUpload > 0) {
257 sIndex += CPLSPrintf("{\"index\" :{\"_index\":\"%s\", \"_type\":\"FeatureCollection\"}}\n", pszLayerName) +
258 fields + "\n\n";
259
260 // Only push the data if we are over our bulk upload limit
261 if ((int) sIndex.length() > poDS->nBulkUpload) {
262 PushIndex();
263 }
264
265 } else { // Fall back to using single item upload for every feature
266 poDS->UploadFile(CPLSPrintf("%s/%s/FeatureCollection/", poDS->GetName(), pszLayerName), fields);
267 }
268
269 return OGRERR_NONE;
270 }
271
272 /************************************************************************/
273 /* PushIndex() */
274 /************************************************************************/
275
PushIndex()276 void OGRElasticLayer::PushIndex() {
277 if (sIndex.empty()) {
278 return;
279 }
280
281 poDS->UploadFile(CPLSPrintf("%s/_bulk", poDS->GetName()), sIndex);
282 sIndex.clear();
283 }
284
285 /************************************************************************/
286 /* CreateField() */
287 /************************************************************************/
288
CreateField(OGRFieldDefn * poFieldDefn,CPL_UNUSED int bApproxOK)289 OGRErr OGRElasticLayer::CreateField(OGRFieldDefn *poFieldDefn,
290 CPL_UNUSED int bApproxOK) {
291 if (!pAttributes) {
292 pAttributes = json_object_new_object();
293 }
294
295 switch (poFieldDefn->GetType()) {
296 case OFTInteger:
297 json_object_object_add((json_object *) pAttributes, poFieldDefn->GetNameRef(), AddPropertyMap("integer"));
298 break;
299 case OFTReal:
300 json_object_object_add((json_object *) pAttributes, poFieldDefn->GetNameRef(), AddPropertyMap("float"));
301 break;
302 case OFTString:
303 json_object_object_add((json_object *) pAttributes, poFieldDefn->GetNameRef(), AddPropertyMap("string"));
304 break;
305 case OFTDateTime:
306 case OFTDate:
307 json_object_object_add((json_object *) pAttributes, poFieldDefn->GetNameRef(), AddPropertyMap("date", "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd"));
308 break;
309 default:
310
311 // These types are mapped as strings and may not be correct
312 /*
313 OFTTime:
314 OFTIntegerList = 1,
315 OFTRealList = 3,
316 OFTStringList = 5,
317 OFTWideString = 6,
318 OFTWideStringList = 7,
319 OFTBinary = 8,
320 OFTMaxType = 11
321 */
322 json_object_object_add((json_object *) pAttributes, poFieldDefn->GetNameRef(), AddPropertyMap("string"));
323 }
324
325 poFeatureDefn->AddFieldDefn(poFieldDefn);
326 return OGRERR_NONE;
327 }
328
329 /************************************************************************/
330 /* TestCapability() */
331 /************************************************************************/
332
TestCapability(const char * pszCap)333 int OGRElasticLayer::TestCapability(const char * pszCap) {
334 if (EQUAL(pszCap, OLCFastFeatureCount))
335 return FALSE;
336
337 else if (EQUAL(pszCap, OLCStringsAsUTF8))
338 return TRUE;
339
340 else if (EQUAL(pszCap, OLCSequentialWrite))
341 return TRUE;
342 else if (EQUAL(pszCap, OLCCreateField))
343 return TRUE;
344 else
345 return FALSE;
346 }
347
348 /************************************************************************/
349 /* GetFeatureCount() */
350 /************************************************************************/
351
GetFeatureCount(CPL_UNUSED int bForce)352 GIntBig OGRElasticLayer::GetFeatureCount(CPL_UNUSED int bForce) {
353 CPLError(CE_Failure, CPLE_NotSupported,
354 "Cannot read features when writing a Elastic file");
355 return 0;
356 }
357