1 /*******************************************************************************
2 * Project: NextGIS Web Driver
3 * Purpose: Implements NextGIS Web Driver
4 * Author: Dmitry Baryshnikov, dmitry.baryshnikov@nextgis.com
5 * Language: C++
6 *******************************************************************************
7 * The MIT License (MIT)
8 *
9 * Copyright (c) 2018-2020, NextGIS <info@nextgis.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in all
19 * copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 *******************************************************************************/
29
30 #include "ogr_ngw.h"
31
32 /*
33 * CheckRequestResult()
34 */
CheckRequestResult(bool bResult,const CPLJSONObject & oRoot,const std::string & osErrorMessage)35 static bool CheckRequestResult(bool bResult, const CPLJSONObject &oRoot,
36 const std::string &osErrorMessage)
37 {
38 if( !bResult )
39 {
40 if( oRoot.IsValid() )
41 {
42 std::string osErrorMessageInt = oRoot.GetString("message");
43 if( !osErrorMessageInt.empty() )
44 {
45 CPLError(CE_Failure, CPLE_AppDefined, "%s",
46 osErrorMessageInt.c_str());
47 return false;
48 }
49 }
50 CPLError(CE_Failure, CPLE_AppDefined, "%s", osErrorMessage.c_str());
51
52 return false;
53 }
54
55 if( !oRoot.IsValid() )
56 {
57 CPLError(CE_Failure, CPLE_AppDefined, "%s", osErrorMessage.c_str());
58 return false;
59 }
60
61 return true;
62 }
63
64 /*
65 * OGRGeometryToWKT()
66 */
OGRGeometryToWKT(OGRGeometry * poGeom)67 static std::string OGRGeometryToWKT( OGRGeometry *poGeom )
68 {
69 std::string osOut;
70 if( nullptr == poGeom )
71 {
72 return osOut;
73 }
74
75 char *pszWkt = nullptr;
76 if( poGeom->exportToWkt( &pszWkt ) == OGRERR_NONE )
77 {
78 osOut = pszWkt;
79 }
80 CPLFree(pszWkt);
81
82 return osOut;
83 }
84
85 /*
86 * JSONToFeature()
87 */
JSONToFeature(const CPLJSONObject & featureJson,OGRFeatureDefn * poFeatureDefn,bool bCheckIgnoredFields=false,bool bStoreExtensionData=false)88 static OGRFeature *JSONToFeature( const CPLJSONObject &featureJson,
89 OGRFeatureDefn *poFeatureDefn, bool bCheckIgnoredFields = false,
90 bool bStoreExtensionData = false )
91 {
92 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
93 poFeature->SetFID( featureJson.GetLong("id") );
94 CPLJSONObject oFields = featureJson.GetObj("fields");
95 for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField )
96 {
97 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
98 if( bCheckIgnoredFields && poFieldDefn->IsIgnored() )
99 {
100 continue;
101 }
102 CPLJSONObject oJSONField = oFields[poFieldDefn->GetNameRef()];
103 if( oJSONField.IsValid() && oJSONField.GetType() != CPLJSONObject::Type::Null )
104 {
105 switch( poFieldDefn->GetType() )
106 {
107 case OFTInteger:
108 poFeature->SetField( iField, oJSONField.ToInteger() );
109 break;
110 case OFTInteger64:
111 poFeature->SetField( iField, oJSONField.ToLong() );
112 break;
113 case OFTReal:
114 poFeature->SetField( iField, oJSONField.ToDouble() );
115 break;
116 case OFTBinary:
117 // Not supported.
118 break;
119 case OFTString:
120 case OFTIntegerList:
121 case OFTInteger64List:
122 case OFTRealList:
123 case OFTStringList:
124 poFeature->SetField( iField, oJSONField.ToString().c_str() );
125 break;
126 case OFTDate:
127 case OFTTime:
128 case OFTDateTime:
129 {
130 int nYear = oJSONField.GetInteger("year");
131 int nMonth = oJSONField.GetInteger("month");
132 int nDay = oJSONField.GetInteger("day");
133 int nHour = oJSONField.GetInteger("hour");
134 int nMinute = oJSONField.GetInteger("minute");
135 int nSecond = oJSONField.GetInteger("second");
136 poFeature->SetField( iField, nYear, nMonth, nDay, nHour,
137 nMinute, float(nSecond) );
138 break;
139 }
140 default:
141 break;
142 }
143 }
144 }
145
146 bool bFillGeometry = !( bCheckIgnoredFields &&
147 poFeatureDefn->IsGeometryIgnored() );
148
149 if( bFillGeometry )
150 {
151 OGRGeometry *poGeometry = nullptr;
152 OGRGeometryFactory::createFromWkt( featureJson.GetString("geom").c_str(),
153 nullptr, &poGeometry );
154 if( poGeometry != nullptr )
155 {
156 OGRSpatialReference *poSpatialRef =
157 poFeatureDefn->GetGeomFieldDefn( 0 )->GetSpatialRef();
158 if( poSpatialRef != nullptr)
159 {
160 poGeometry->assignSpatialReference( poSpatialRef );
161 }
162 poFeature->SetGeomFieldDirectly( 0, poGeometry );
163 }
164 }
165
166 // Get extensions key and store it in native data.
167 if( bStoreExtensionData )
168 {
169 CPLJSONObject oExtensions = featureJson.GetObj("extensions");
170 if( oExtensions.IsValid() && oExtensions.GetType() != CPLJSONObject::Type::Null )
171 {
172 poFeature->SetNativeData(oExtensions.Format(CPLJSONObject::PrettyFormat::Plain).c_str());
173 poFeature->SetNativeMediaType("application/json");
174 }
175 }
176
177 return poFeature;
178 }
179
180 /*
181 * FeatureToJson()
182 */
FeatureToJson(OGRFeature * poFeature)183 static CPLJSONObject FeatureToJson(OGRFeature *poFeature)
184 {
185 CPLJSONObject oFeatureJson;
186 if( poFeature == nullptr )
187 {
188 // Should not happen.
189 return oFeatureJson;
190 }
191
192 if( poFeature->GetFID() >= 0 )
193 {
194 oFeatureJson.Add("id", poFeature->GetFID());
195 }
196
197 OGRGeometry *poGeom = poFeature->GetGeometryRef();
198 std::string osGeomWKT = OGRGeometryToWKT( poGeom );
199 if( !osGeomWKT.empty() )
200 {
201 oFeatureJson.Add("geom", osGeomWKT);
202 }
203
204 OGRFeatureDefn *poFeatureDefn = poFeature->GetDefnRef();
205 CPLJSONObject oFieldsJson("fields", oFeatureJson);
206 for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField )
207 {
208 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
209 if( poFeature->IsFieldNull(iField) == TRUE )
210 {
211 oFieldsJson.AddNull(poFieldDefn->GetNameRef());
212 continue;
213 }
214
215 if( poFeature->IsFieldSet(iField) == TRUE )
216 {
217 switch( poFieldDefn->GetType() )
218 {
219 case OFTInteger:
220 oFieldsJson.Add( poFieldDefn->GetNameRef(),
221 poFeature->GetFieldAsInteger(iField) );
222 break;
223 case OFTInteger64:
224 oFieldsJson.Add( poFieldDefn->GetNameRef(),
225 static_cast<GInt64>(
226 poFeature->GetFieldAsInteger64(iField)) );
227 break;
228 case OFTReal:
229 oFieldsJson.Add( poFieldDefn->GetNameRef(),
230 poFeature->GetFieldAsDouble(iField) );
231 break;
232 case OFTBinary:
233 // Not supported.
234 break;
235 case OFTString:
236 case OFTIntegerList:
237 case OFTInteger64List:
238 case OFTRealList:
239 case OFTStringList:
240 oFieldsJson.Add( poFieldDefn->GetNameRef(),
241 poFeature->GetFieldAsString(iField) );
242 break;
243 case OFTDate:
244 case OFTTime:
245 case OFTDateTime:
246 {
247 int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZFlag;
248 if( poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth,
249 &nDay, &nHour, &nMinute, &nSecond, &nTZFlag) == TRUE)
250 {
251 // TODO: Convert timestamp to UTC.
252 if( nTZFlag == 0 || nTZFlag == 100 )
253 {
254 CPLJSONObject oDateJson(poFieldDefn->GetNameRef(),
255 oFieldsJson);
256
257 oDateJson.Add("year", nYear);
258 oDateJson.Add("month", nMonth);
259 oDateJson.Add("day", nDay);
260 oDateJson.Add("hour", nHour);
261 oDateJson.Add("minute", nMinute);
262 oDateJson.Add("second", nSecond);
263 }
264 }
265 break;
266 }
267 default:
268 break;
269 }
270 }
271 }
272
273 if( poFeature->GetNativeData() )
274 {
275 CPLJSONDocument oExtensions;
276 if( oExtensions.LoadMemory(poFeature->GetNativeData()) )
277 {
278 oFeatureJson.Add("extensions", oExtensions.GetRoot());
279 }
280 }
281
282 return oFeatureJson;
283 }
284
285 /*
286 * FeatureToJsonString()
287 */
FeatureToJsonString(OGRFeature * poFeature)288 static std::string FeatureToJsonString(OGRFeature *poFeature)
289 {
290 return FeatureToJson(poFeature).Format(CPLJSONObject::PrettyFormat::Plain);
291 }
292
293 /*
294 * FreeMap()
295 */
FreeMap(std::map<GIntBig,OGRFeature * > & moFeatures)296 static void FreeMap( std::map<GIntBig, OGRFeature*> &moFeatures )
297 {
298 for( auto &oPair: moFeatures )
299 {
300 OGRFeature::DestroyFeature( oPair.second );
301 }
302
303 moFeatures.clear();
304 }
305
CheckFieldNameUnique(OGRFeatureDefn * poFeatureDefn,int iField,const char * pszFieldName)306 static bool CheckFieldNameUnique( OGRFeatureDefn *poFeatureDefn, int iField,
307 const char *pszFieldName )
308 {
309 for( int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
310 {
311 if( i == iField)
312 {
313 continue;
314 }
315
316 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
317 if( poFieldDefn && EQUAL(poFieldDefn->GetNameRef(), pszFieldName) )
318 {
319 CPLError( CE_Failure, CPLE_NotSupported,
320 "Field name %s already present in field %d.",
321 pszFieldName, i );
322 return false;
323 }
324 }
325 return true;
326 }
327
GetUniqueFieldName(OGRFeatureDefn * poFeatureDefn,int iField,const char * pszBaseName,int nAdd=0,int nMax=100)328 static std::string GetUniqueFieldName( OGRFeatureDefn *poFeatureDefn, int iField,
329 const char *pszBaseName, int nAdd = 0, int nMax = 100 )
330 {
331 const char *pszNewName = CPLSPrintf("%s%d", pszBaseName, nAdd);
332 for( int i = 0; i < poFeatureDefn->GetFieldCount(); ++i)
333 {
334 if( i == iField)
335 {
336 continue;
337 }
338
339 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( i );
340 if( poFieldDefn && EQUAL(poFieldDefn->GetNameRef(), pszNewName) )
341 {
342 if( nAdd + 1 == nMax)
343 {
344 CPLError( CE_Failure, CPLE_NotSupported,
345 "Too many field names like '%s' + number.",
346 pszBaseName);
347
348 return pszBaseName; // Let's solve this on server side.
349 }
350 return GetUniqueFieldName( poFeatureDefn, iField, pszBaseName, nAdd + 1 );
351 }
352 }
353
354 return pszNewName;
355 }
356
NormalizeFieldName(OGRFeatureDefn * poFeatureDefn,int iField,OGRFieldDefn * poFieldDefn)357 static void NormalizeFieldName( OGRFeatureDefn *poFeatureDefn, int iField,
358 OGRFieldDefn *poFieldDefn )
359 {
360 if( EQUAL(poFieldDefn->GetNameRef(), "id"))
361 {
362 std::string osNewFieldName = GetUniqueFieldName(poFeatureDefn, iField,
363 poFieldDefn->GetNameRef(), 0);
364 CPLError( CE_Warning, CPLE_NotSupported,
365 "Normalized/laundered field name: '%s' to '%s'",
366 poFieldDefn->GetNameRef(),
367 osNewFieldName.c_str() );
368
369 // Set field name with normalized value.
370 poFieldDefn->SetName( osNewFieldName.c_str() );
371 }
372 }
373
374 /*
375 * TranslateSQLToFilter()
376 */
TranslateSQLToFilter(swq_expr_node * poNode)377 std::string OGRNGWLayer::TranslateSQLToFilter( swq_expr_node *poNode )
378 {
379 if( nullptr == poNode )
380 {
381 return "";
382 }
383
384 if( poNode->eNodeType == SNT_OPERATION )
385 {
386 if ( poNode->nOperation == SWQ_AND && poNode->nSubExprCount == 2 )
387 {
388 std::string osFilter1 = TranslateSQLToFilter(poNode->papoSubExpr[0]);
389 std::string osFilter2 = TranslateSQLToFilter(poNode->papoSubExpr[1]);
390
391 if(osFilter1.empty() || osFilter2.empty())
392 {
393 return "";
394 }
395 return osFilter1 + "&" + osFilter2;
396 }
397 else if ( (poNode->nOperation == SWQ_EQ || poNode->nOperation == SWQ_NE ||
398 poNode->nOperation == SWQ_GE || poNode->nOperation == SWQ_LE ||
399 poNode->nOperation == SWQ_LT || poNode->nOperation == SWQ_GT ||
400 poNode->nOperation == SWQ_LIKE || poNode->nOperation == SWQ_ILIKE) &&
401 poNode->nSubExprCount == 2 &&
402 poNode->papoSubExpr[0]->eNodeType == SNT_COLUMN &&
403 poNode->papoSubExpr[1]->eNodeType == SNT_CONSTANT )
404 {
405 if( poNode->papoSubExpr[0]->string_value == nullptr )
406 {
407 return "";
408 }
409 char *pszNameEncoded = CPLEscapeString(
410 poNode->papoSubExpr[0]->string_value, -1, CPLES_URL);
411 std::string osFieldName = "fld_" + std::string(pszNameEncoded);
412 CPLFree(pszNameEncoded);
413
414 switch(poNode->nOperation)
415 {
416 case SWQ_EQ:
417 osFieldName += "__eq";
418 break;
419 case SWQ_NE:
420 osFieldName += "__ne";
421 break;
422 case SWQ_GE:
423 osFieldName += "__ge";
424 break;
425 case SWQ_LE:
426 osFieldName += "__le";
427 break;
428 case SWQ_LT:
429 osFieldName += "__lt";
430 break;
431 case SWQ_GT:
432 osFieldName += "__gt";
433 break;
434 case SWQ_LIKE:
435 osFieldName += "__like";
436 break;
437 case SWQ_ILIKE:
438 osFieldName += "__ilike";
439 break;
440 default:
441 CPLAssert(false);
442 break;
443 }
444
445 std::string osVal;
446 switch(poNode->papoSubExpr[1]->field_type)
447 {
448 case SWQ_INTEGER64:
449 case SWQ_INTEGER:
450 osVal = std::to_string(poNode->papoSubExpr[1]->int_value);
451 break;
452 case SWQ_FLOAT:
453 osVal = std::to_string(poNode->papoSubExpr[1]->float_value);
454 break;
455 case SWQ_STRING:
456 if(poNode->papoSubExpr[1]->string_value)
457 {
458 char *pszValueEncoded = CPLEscapeString(
459 poNode->papoSubExpr[1]->string_value, -1, CPLES_URL);
460 osVal = pszValueEncoded;
461 CPLFree(pszValueEncoded);
462 }
463 break;
464 case SWQ_DATE:
465 case SWQ_TIME:
466 case SWQ_TIMESTAMP:
467 if(poNode->papoSubExpr[1]->string_value)
468 {
469 char *pszValueEncoded = CPLEscapeString(
470 poNode->papoSubExpr[1]->string_value, -1, CPLES_URL);
471 osVal = pszValueEncoded;
472 CPLFree(pszValueEncoded);
473 }
474 break;
475 default:
476 break;
477 }
478 if(osFieldName.empty() || osVal.empty())
479 {
480 CPLDebug("NGW", "Unsupported filter operation for server side");
481 return "";
482 }
483
484 return osFieldName + "=" + osVal;
485 }
486 else
487 {
488 CPLDebug("NGW", "Unsupported filter operation for server side");
489 return "";
490 }
491 }
492 return "";
493 }
494
495 /*
496 * OGRNGWLayer()
497 */
OGRNGWLayer(OGRNGWDataset * poDSIn,const CPLJSONObject & oResourceJsonObject)498 OGRNGWLayer::OGRNGWLayer( OGRNGWDataset *poDSIn,
499 const CPLJSONObject &oResourceJsonObject ) :
500 osResourceId(oResourceJsonObject.GetString("resource/id", "-1")),
501 poDS(poDSIn),
502 bFetchedPermissions(false),
503 nFeatureCount(-1),
504 oNextPos(moFeatures.begin()),
505 nPageStart(0),
506 bNeedSyncData(false),
507 bNeedSyncStructure(false),
508 bClientSideAttributeFilter(false)
509 {
510 std::string osName = oResourceJsonObject.GetString("resource/display_name");
511 poFeatureDefn = new OGRFeatureDefn( osName.c_str() );
512 poFeatureDefn->Reference();
513
514 poFeatureDefn->SetGeomType( NGWAPI::NGWGeomTypeToOGRGeomType(
515 oResourceJsonObject.GetString("vector_layer/geometry_type")) );
516
517 OGRSpatialReference *poSRS = new OGRSpatialReference;
518 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
519 int nEPSG = oResourceJsonObject.GetInteger("vector_layer/srs/id", 3857); // Default NGW SRS is Web mercator EPSG:3857.
520 if( poSRS->importFromEPSG( nEPSG ) == OGRERR_NONE )
521 {
522 if( poFeatureDefn->GetGeomFieldCount() != 0 )
523 {
524 poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef( poSRS );
525 }
526 }
527 poSRS->Release();
528
529 CPLJSONArray oFields = oResourceJsonObject.GetArray("feature_layer/fields");
530 FillFields( oFields );
531 FillMetadata( oResourceJsonObject );
532
533 SetDescription( poFeatureDefn->GetName() );
534 }
535
536 /*
537 * OGRNGWLayer()
538 */
OGRNGWLayer(const std::string & osResourceIdIn,OGRNGWDataset * poDSIn,const NGWAPI::Permissions & stPermissionsIn,OGRFeatureDefn * poFeatureDefnIn,GIntBig nFeatureCountIn,const OGREnvelope & stExtentIn)539 OGRNGWLayer::OGRNGWLayer( const std::string &osResourceIdIn, OGRNGWDataset *poDSIn,
540 const NGWAPI::Permissions &stPermissionsIn, OGRFeatureDefn *poFeatureDefnIn,
541 GIntBig nFeatureCountIn, const OGREnvelope &stExtentIn ) :
542 osResourceId(osResourceIdIn),
543 poDS(poDSIn),
544 stPermissions(stPermissionsIn),
545 bFetchedPermissions(true),
546 poFeatureDefn(poFeatureDefnIn),
547 nFeatureCount(nFeatureCountIn),
548 stExtent(stExtentIn),
549 oNextPos(moFeatures.begin()),
550 nPageStart(0),
551 bNeedSyncData(false),
552 bNeedSyncStructure(false),
553 bClientSideAttributeFilter(false)
554 {
555 poFeatureDefn->Reference();
556 SetDescription( poFeatureDefn->GetName() );
557 }
558
559 /*
560 * OGRNGWLayer()
561 */
OGRNGWLayer(OGRNGWDataset * poDSIn,const std::string & osNameIn,OGRSpatialReference * poSpatialRef,OGRwkbGeometryType eGType,const std::string & osKeyIn,const std::string & osDescIn)562 OGRNGWLayer::OGRNGWLayer( OGRNGWDataset *poDSIn, const std::string &osNameIn,
563 OGRSpatialReference *poSpatialRef, OGRwkbGeometryType eGType,
564 const std::string &osKeyIn, const std::string &osDescIn ) :
565 osResourceId("-1"),
566 poDS(poDSIn),
567 bFetchedPermissions(false),
568 nFeatureCount(0),
569 oNextPos(moFeatures.begin()),
570 nPageStart(0),
571 bNeedSyncData(false),
572 bNeedSyncStructure(false),
573 bClientSideAttributeFilter(false)
574 {
575 poFeatureDefn = new OGRFeatureDefn( osNameIn.c_str() );
576 poFeatureDefn->Reference();
577
578 poFeatureDefn->SetGeomType( eGType );
579
580 if( poSpatialRef )
581 {
582 if( poFeatureDefn->GetGeomFieldCount() != 0 )
583 {
584 poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef( poSpatialRef );
585 }
586 }
587
588 if( !osDescIn.empty() )
589 {
590 OGRLayer::SetMetadataItem( "description", osDescIn.c_str() );
591 }
592 if( !osKeyIn.empty() )
593 {
594 OGRLayer::SetMetadataItem( "keyname", osKeyIn.c_str() );
595 }
596
597 SetDescription( poFeatureDefn->GetName() );
598 }
599
600 /*
601 * ~OGRNGWLayer()
602 */
~OGRNGWLayer()603 OGRNGWLayer::~OGRNGWLayer()
604 {
605 FreeFeaturesCache(true);
606 if( poFeatureDefn != nullptr )
607 {
608 poFeatureDefn->Release();
609 }
610 }
611
612 /*
613 * FreeFeaturesCache()
614 */
FreeFeaturesCache(bool bForce)615 void OGRNGWLayer::FreeFeaturesCache( bool bForce )
616 {
617 if( !soChangedIds.empty() )
618 {
619 bNeedSyncData = true;
620 }
621
622 if( SyncFeatures() == OGRERR_NONE || bForce ) // Try sync first
623 {
624 // Free only if synced with server successfully or executed from destructor.
625 FreeMap(moFeatures);
626 }
627 }
628
629 /*
630 * GetResourceId()
631 */
GetResourceId() const632 std::string OGRNGWLayer::GetResourceId() const
633 {
634 return osResourceId;
635 }
636
637 /*
638 * Delete()
639 */
Delete()640 bool OGRNGWLayer::Delete()
641 {
642 if( osResourceId == "-1")
643 {
644 return true;
645 }
646
647 // Headers free in DeleteResource method.
648 return NGWAPI::DeleteResource(poDS->GetUrl(), osResourceId, poDS->GetHeaders());
649 }
650
651 /*
652 * Rename()
653 */
Rename(const std::string & osNewName)654 bool OGRNGWLayer::Rename( const std::string &osNewName)
655 {
656 bool bResult = true;
657 if( osResourceId != "-1")
658 {
659 bResult = NGWAPI::RenameResource(poDS->GetUrl(), osResourceId,
660 osNewName, poDS->GetHeaders());
661 }
662 if( bResult )
663 {
664 poFeatureDefn->SetName( osNewName.c_str() );
665 SetDescription( poFeatureDefn->GetName() );
666 }
667 else
668 {
669 CPLError(CE_Failure, CPLE_AppDefined, "Rename layer to %s failed", osNewName.c_str());
670 }
671 return bResult;
672 }
673
674 /*
675 * ResetReading()
676 */
ResetReading()677 void OGRNGWLayer::ResetReading()
678 {
679 SyncToDisk();
680 if( poDS->GetPageSize() > 0 )
681 {
682 FreeFeaturesCache();
683 nPageStart = 0;
684 }
685 oNextPos = moFeatures.begin();
686 }
687
688 /*
689 * FillFeatures()
690 */
FillFeatures(const std::string & osUrl)691 bool OGRNGWLayer::FillFeatures(const std::string &osUrl)
692 {
693 CPLDebug("NGW", "GetNextFeature: Url: %s", osUrl.c_str());
694
695 CPLErrorReset();
696 CPLJSONDocument oFeatureReq;
697 char **papszHTTPOptions = poDS->GetHeaders();
698 bool bResult = oFeatureReq.LoadUrl( osUrl, papszHTTPOptions );
699 CSLDestroy( papszHTTPOptions );
700
701 CPLJSONObject oRoot = oFeatureReq.GetRoot();
702 if( !CheckRequestResult(bResult, oRoot, "GetFeatures request failed") )
703 {
704 return false;
705 }
706
707 CPLJSONArray aoJSONFeatures = oRoot.ToArray();
708 for( int i = 0; i < aoJSONFeatures.Size(); ++i)
709 {
710 OGRFeature *poFeature = JSONToFeature( aoJSONFeatures[i],
711 poFeatureDefn, true, poDS->IsExtInNativeData() );
712 moFeatures[poFeature->GetFID()] = poFeature;
713 }
714
715 return true;
716 }
717
718 /*
719 * SetNextByIndex()
720 */
SetNextByIndex(GIntBig nIndex)721 OGRErr OGRNGWLayer::SetNextByIndex( GIntBig nIndex )
722 {
723 SyncToDisk();
724 if( nIndex < 0)
725 {
726 CPLError(CE_Failure, CPLE_AppDefined,
727 "Feature index must be greater or equal 0. Got " CPL_FRMT_GIB, nIndex);
728 return OGRERR_FAILURE;
729 }
730 if( poDS->GetPageSize() > 0 )
731 {
732 // Check if index is in current cache
733 if( nPageStart > nIndex && nIndex <= nPageStart - poDS->GetPageSize() )
734 {
735 if( moFeatures.empty() ||
736 static_cast<GIntBig>( moFeatures.size() ) <= nIndex )
737 {
738 oNextPos = moFeatures.end();
739 }
740 else
741 {
742 oNextPos = moFeatures.begin();
743 std::advance(oNextPos, static_cast<size_t>(nIndex));
744 }
745 }
746 else
747 {
748 ResetReading();
749 nPageStart = nIndex;
750 }
751 }
752 else
753 {
754 if( moFeatures.empty() && GetMaxFeatureCount(false) > 0 )
755 {
756 std::string osUrl;
757 if( poDS->HasFeaturePaging() )
758 {
759 osUrl = NGWAPI::GetFeaturePage( poDS->GetUrl(), osResourceId, 0, 0,
760 osFields, osWhere, osSpatialFilter, poDS->Extensions(),
761 poFeatureDefn->IsGeometryIgnored() == TRUE);
762 }
763 else
764 {
765 osUrl = NGWAPI::GetFeature( poDS->GetUrl(), osResourceId );
766 }
767
768 FillFeatures(osUrl);
769 }
770
771 if( moFeatures.empty() ||
772 static_cast<GIntBig>( moFeatures.size() ) <= nIndex )
773 {
774 oNextPos = moFeatures.end();
775 }
776 else
777 {
778 oNextPos = moFeatures.begin();
779 std::advance(oNextPos, static_cast<size_t>(nIndex));
780 }
781 }
782 return OGRERR_NONE;
783 }
784
785 /*
786 * GetNextFeature()
787 */
GetNextFeature()788 OGRFeature *OGRNGWLayer::GetNextFeature()
789 {
790 std::string osUrl;
791
792 if( poDS->GetPageSize() > 0 )
793 {
794 if( oNextPos == moFeatures.end() && nPageStart < GetMaxFeatureCount(false) )
795 {
796 FreeFeaturesCache();
797
798 osUrl = NGWAPI::GetFeaturePage( poDS->GetUrl(), osResourceId,
799 nPageStart, poDS->GetPageSize(), osFields, osWhere,
800 osSpatialFilter, poDS->Extensions(),
801 poFeatureDefn->IsGeometryIgnored() == TRUE);
802 nPageStart += poDS->GetPageSize();
803 }
804 }
805 else if( moFeatures.empty() && GetMaxFeatureCount(false) > 0 )
806 {
807 if( poDS->HasFeaturePaging() )
808 {
809 osUrl = NGWAPI::GetFeaturePage( poDS->GetUrl(), osResourceId, 0, 0,
810 osFields, osWhere, osSpatialFilter, poDS->Extensions(),
811 poFeatureDefn->IsGeometryIgnored() == TRUE);
812 }
813 else
814 {
815 osUrl = NGWAPI::GetFeature( poDS->GetUrl(), osResourceId );
816 }
817 }
818
819 bool bFinalRead = true;
820 if( !osUrl.empty() )
821 {
822 if( !FillFeatures(osUrl) )
823 {
824 return nullptr;
825 }
826
827 oNextPos = moFeatures.begin();
828
829 if( poDS->GetPageSize() < 1 )
830 {
831 // Without paging we read all features at once.
832 m_nFeaturesRead = moFeatures.size();
833 }
834 else
835 {
836 if(poDS->GetPageSize() - moFeatures.size() == 0)
837 {
838 m_nFeaturesRead = nPageStart;
839 bFinalRead = false;
840 }
841 else
842 {
843 m_nFeaturesRead = nPageStart - poDS->GetPageSize() +
844 moFeatures.size();
845 }
846 }
847 }
848
849 while( oNextPos != moFeatures.end() )
850 {
851 OGRFeature *poFeature = oNextPos->second;
852 ++oNextPos;
853
854 if( poFeature == nullptr ) // Feature may be deleted.
855 {
856 continue;
857 }
858
859 // Check local filters only for new features which not send to server yet
860 // or if attribute filter process on client side.
861 if( poFeature->GetFID() < 0 || bClientSideAttributeFilter )
862 {
863 if( ( m_poFilterGeom == nullptr
864 || FilterGeometry(poFeature->GetGeometryRef()) )
865 && ( m_poAttrQuery == nullptr
866 || m_poAttrQuery->Evaluate(poFeature) ) )
867 {
868 return poFeature->Clone();
869 }
870 }
871 else
872 {
873 return poFeature->Clone();
874 }
875 }
876
877 if( poDS->GetPageSize() > 0 && !bFinalRead )
878 {
879 return GetNextFeature();
880 }
881 return nullptr;
882 }
883
884 /*
885 * GetFeature()
886 */
GetFeature(GIntBig nFID)887 OGRFeature *OGRNGWLayer::GetFeature( GIntBig nFID )
888 {
889 // Check feature in cache.
890 if( moFeatures[nFID] != nullptr )
891 {
892 return moFeatures[nFID]->Clone();
893 }
894 std::string osUrl = NGWAPI::GetFeature( poDS->GetUrl(), osResourceId) +
895 std::to_string(nFID);
896 CPLErrorReset();
897 CPLJSONDocument oFeatureReq;
898 char **papszHTTPOptions = poDS->GetHeaders();
899 bool bResult = oFeatureReq.LoadUrl( osUrl, papszHTTPOptions );
900 CSLDestroy( papszHTTPOptions );
901
902 CPLJSONObject oRoot = oFeatureReq.GetRoot();
903 if( !CheckRequestResult(bResult, oRoot, "GetFeature " + std::to_string(nFID) +
904 " response is invalid") )
905 {
906 return nullptr;
907 }
908
909 // Don't store feature in cache. This can broke sequence read.
910 return JSONToFeature( oRoot, poFeatureDefn, true, poDS->IsExtInNativeData() );
911 }
912
913 /*
914 * GetLayerDefn()
915 */
GetLayerDefn()916 OGRFeatureDefn *OGRNGWLayer::GetLayerDefn()
917 {
918 return poFeatureDefn;
919 }
920
921 /*
922 * TestCapability()
923 */
TestCapability(const char * pszCap)924 int OGRNGWLayer::TestCapability( const char *pszCap )
925 {
926 FetchPermissions();
927 if( EQUAL(pszCap, OLCRandomRead) )
928 return TRUE;
929 else if( EQUAL(pszCap, OLCSequentialWrite) )
930 return stPermissions.bDataCanWrite && poDS->IsUpdateMode();
931 else if( EQUAL(pszCap, OLCRandomWrite) )
932 return stPermissions.bDataCanWrite && poDS->IsUpdateMode();
933 else if( EQUAL(pszCap, OLCFastFeatureCount) )
934 return m_poFilterGeom == nullptr && m_poAttrQuery == nullptr;
935 else if( EQUAL(pszCap, OLCFastGetExtent) )
936 return TRUE;
937 else if( EQUAL(pszCap, OLCAlterFieldDefn) ) // Only field name and alias can be altered.
938 return stPermissions.bDatastructCanWrite && poDS->IsUpdateMode();
939 else if( EQUAL(pszCap, OLCDeleteFeature) )
940 return stPermissions.bDataCanWrite && poDS->IsUpdateMode();
941 else if( EQUAL(pszCap, OLCStringsAsUTF8) )
942 return TRUE;
943 else if( EQUAL(pszCap, OLCFastSetNextByIndex) )
944 return TRUE;
945 else if( EQUAL(pszCap,OLCCreateField) )
946 return osResourceId == "-1" && poDS->IsUpdateMode(); // Can create fields only in new layer not synced with server.
947 else if( EQUAL(pszCap, OLCIgnoreFields) )
948 return poDS->HasFeaturePaging(); // Ignore fields, paging support and attribute/spatial filters were introduced in NGW v3.1
949 else if( EQUAL(pszCap, OLCFastSpatialFilter) )
950 return poDS->HasFeaturePaging();
951 return FALSE;
952 }
953
954 /*
955 * FillMetadata()
956 */
FillMetadata(const CPLJSONObject & oRootObject)957 void OGRNGWLayer::FillMetadata( const CPLJSONObject &oRootObject )
958 {
959 std::string osCreateDate = oRootObject.GetString("resource/creation_date");
960 if( !osCreateDate.empty() )
961 {
962 OGRLayer::SetMetadataItem( "creation_date", osCreateDate.c_str() );
963 }
964 std::string osDescription = oRootObject.GetString("resource/description");
965 if( !osDescription.empty() )
966 {
967 OGRLayer::SetMetadataItem( "description", osDescription.c_str() );
968 }
969 std::string osKeyName = oRootObject.GetString("resource/keyname");
970 if( !osKeyName.empty() )
971 {
972 OGRLayer::SetMetadataItem( "keyname", osKeyName.c_str() );
973 }
974 std::string osResourceType = oRootObject.GetString("resource/cls");
975 if( !osResourceType.empty() )
976 {
977 OGRLayer::SetMetadataItem( "resource_type", osResourceType.c_str() );
978 }
979 std::string osResourceParentId = oRootObject.GetString("resource/parent/id");
980 if( !osResourceParentId.empty() )
981 {
982 OGRLayer::SetMetadataItem( "parent_id", osResourceParentId.c_str() );
983 }
984 OGRLayer::SetMetadataItem( "id", osResourceId.c_str() );
985
986 std::vector<CPLJSONObject> items =
987 oRootObject.GetObj("resmeta/items").GetChildren();
988
989 for( const CPLJSONObject &item : items )
990 {
991 std::string osSuffix = NGWAPI::GetResmetaSuffix( item.GetType() );
992 OGRLayer::SetMetadataItem( (item.GetName() + osSuffix).c_str(),
993 item.ToString().c_str(), "NGW" );
994 }
995 }
996
997 /*
998 * FillFields()
999 */
FillFields(const CPLJSONArray & oFields)1000 void OGRNGWLayer::FillFields( const CPLJSONArray &oFields )
1001 {
1002 for( int i = 0; i < oFields.Size(); ++i )
1003 {
1004 CPLJSONObject oField = oFields[i];
1005 std::string osFieldName = oField.GetString("keyname");
1006 OGRFieldType eFieldtype = NGWAPI::NGWFieldTypeToOGRFieldType(
1007 oField.GetString("datatype"));
1008 OGRFieldDefn oFieldDefn(osFieldName.c_str(), eFieldtype);
1009 std::string osFieldId = oField.GetString("id");
1010 std::string osFieldAlias = oField.GetString("display_name");
1011 oFieldDefn.SetAlternativeName(osFieldAlias.c_str());
1012 poFeatureDefn->AddFieldDefn(&oFieldDefn);
1013 std::string osFieldIsLabel = oField.GetString("label_field");
1014 std::string osFieldGridVisible = oField.GetString("grid_visibility");
1015
1016 std::string osFieldAliasName = "FIELD_" + std::to_string(i) + "_ALIAS";
1017 std::string osFieldIdName = "FIELD_" + std::to_string(i) + "_ID";
1018 std::string osFieldIsLabelName = "FIELD_" + std::to_string(i) + "_LABEL_FIELD";
1019 std::string osFieldGridVisibleName = "FIELD_" + std::to_string(i) + "_GRID_VISIBILITY";
1020
1021 OGRLayer::SetMetadataItem(osFieldAliasName.c_str(),
1022 osFieldAlias.c_str(), "");
1023 OGRLayer::SetMetadataItem(osFieldIdName.c_str(),
1024 osFieldId.c_str(), "");
1025 OGRLayer::SetMetadataItem(osFieldIsLabelName.c_str(),
1026 osFieldIsLabel.c_str(), "");
1027 OGRLayer::SetMetadataItem(osFieldGridVisibleName.c_str(),
1028 osFieldGridVisible.c_str(), "");
1029 }
1030 }
1031
1032 /*
1033 * GetMaxFeatureCount()
1034 */
GetMaxFeatureCount(bool bForce)1035 GIntBig OGRNGWLayer::GetMaxFeatureCount( bool bForce )
1036 {
1037 if( nFeatureCount < 0 || bForce )
1038 {
1039 CPLErrorReset();
1040 CPLJSONDocument oCountReq;
1041 char **papszHTTPOptions = poDS->GetHeaders();
1042 bool bResult = oCountReq.LoadUrl( NGWAPI::GetFeatureCount( poDS->GetUrl(),
1043 osResourceId ), papszHTTPOptions );
1044 CSLDestroy( papszHTTPOptions );
1045 if( bResult )
1046 {
1047 CPLJSONObject oRoot = oCountReq.GetRoot();
1048 if( oRoot.IsValid() )
1049 {
1050 nFeatureCount = oRoot.GetLong("total_count");
1051 nFeatureCount += GetNewFeaturesCount();
1052 }
1053 }
1054 }
1055 return nFeatureCount;
1056 }
1057
1058 /*
1059 * GetFeatureCount()
1060 */
GetFeatureCount(int bForce)1061 GIntBig OGRNGWLayer::GetFeatureCount( int bForce )
1062 {
1063 if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
1064 {
1065 return GetMaxFeatureCount( CPL_TO_BOOL(bForce) );
1066 }
1067 else
1068 {
1069 return OGRLayer::GetFeatureCount( bForce );
1070 }
1071 }
1072
1073 /*
1074 * GetExtent()
1075 */
GetExtent(OGREnvelope * psExtent,int bForce)1076 OGRErr OGRNGWLayer::GetExtent( OGREnvelope *psExtent, int bForce )
1077 {
1078 if( !stExtent.IsInit() || CPL_TO_BOOL(bForce) )
1079 {
1080 char **papszHTTPOptions = poDS->GetHeaders();
1081 bool bResult = NGWAPI::GetExtent(poDS->GetUrl(), osResourceId,
1082 papszHTTPOptions, 3857, stExtent);
1083 CSLDestroy( papszHTTPOptions );
1084 if( !bResult )
1085 {
1086 return OGRERR_FAILURE;
1087 }
1088 }
1089 *psExtent = stExtent;
1090 return OGRERR_NONE;
1091 }
1092
1093 /*
1094 * GetExtent()
1095 */
GetExtent(int iGeomField,OGREnvelope * psExtent,int bForce)1096 OGRErr OGRNGWLayer::GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce)
1097 {
1098 return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
1099 }
1100
1101 /*
1102 * FetchPermissions()
1103 */
FetchPermissions()1104 void OGRNGWLayer::FetchPermissions()
1105 {
1106 if( bFetchedPermissions || osResourceId == "-1" )
1107 {
1108 return;
1109 }
1110
1111 if( poDS->IsUpdateMode() )
1112 {
1113 char **papszHTTPOptions = poDS->GetHeaders();
1114 stPermissions = NGWAPI::CheckPermissions( poDS->GetUrl(), osResourceId,
1115 papszHTTPOptions, poDS->IsUpdateMode() );
1116 CSLDestroy( papszHTTPOptions );
1117 }
1118 else
1119 {
1120 stPermissions.bDataCanRead = true;
1121 stPermissions.bResourceCanRead = true;
1122 stPermissions.bDatastructCanRead = true;
1123 stPermissions.bMetadataCanRead = true;
1124 }
1125 bFetchedPermissions = true;
1126 }
1127
1128 /*
1129 * CreateField()
1130 */
CreateField(OGRFieldDefn * poField,CPL_UNUSED int bApproxOK)1131 OGRErr OGRNGWLayer::CreateField( OGRFieldDefn *poField, CPL_UNUSED int bApproxOK )
1132 {
1133 CPLAssert( nullptr != poField );
1134
1135 if( osResourceId == "-1" ) // Can create field only on new layers (not synced with server).
1136 {
1137 if( !CheckFieldNameUnique(poFeatureDefn, -1, poField->GetNameRef()) )
1138 {
1139 return OGRERR_FAILURE;
1140 }
1141 // Field name 'id' is forbidden.
1142 OGRFieldDefn oModFieldDefn(poField);
1143 NormalizeFieldName(poFeatureDefn, -1, &oModFieldDefn);
1144 poFeatureDefn->AddFieldDefn( &oModFieldDefn );
1145 return OGRERR_NONE;
1146 }
1147 return OGRLayer::CreateField( poField, bApproxOK );
1148 }
1149
1150 /*
1151 * DeleteField()
1152 */
DeleteField(int iField)1153 OGRErr OGRNGWLayer::DeleteField( int iField )
1154 {
1155 if( osResourceId == "-1" ) // Can delete field only on new layers (not synced with server).
1156 {
1157 return poFeatureDefn->DeleteFieldDefn( iField );
1158 }
1159 return OGRLayer::DeleteField( iField );
1160 }
1161
1162 /*
1163 * ReorderFields()
1164 */
ReorderFields(int * panMap)1165 OGRErr OGRNGWLayer::ReorderFields( int *panMap )
1166 {
1167 if( osResourceId == "-1" ) // Can reorder fields only on new layers (not synced with server).
1168 {
1169 return poFeatureDefn->ReorderFieldDefns( panMap );
1170 }
1171 return OGRLayer::ReorderFields( panMap );
1172 }
1173
1174 /*
1175 * AlterFieldDefn()
1176 */
AlterFieldDefn(int iField,OGRFieldDefn * poNewFieldDefn,int nFlagsIn)1177 OGRErr OGRNGWLayer::AlterFieldDefn( int iField, OGRFieldDefn *poNewFieldDefn,
1178 int nFlagsIn )
1179 {
1180 CPLAssert( nullptr != poNewFieldDefn );
1181
1182 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( iField );
1183 if( poFieldDefn )
1184 {
1185 // Check new field name is not equal for another fields.
1186 if( !CheckFieldNameUnique(poFeatureDefn, iField, poNewFieldDefn->GetNameRef()) )
1187 {
1188 return OGRERR_FAILURE;
1189 }
1190 if( osResourceId == "-1" ) // Can alter field only on new layers (not synced with server).
1191 {
1192 // Field name 'id' forbidden.
1193 OGRFieldDefn oModFieldDefn(poNewFieldDefn);
1194 NormalizeFieldName(poFeatureDefn, iField, &oModFieldDefn);
1195
1196 poFieldDefn->SetName( oModFieldDefn.GetNameRef() );
1197 poFieldDefn->SetType( oModFieldDefn.GetType() );
1198 poFieldDefn->SetSubType( oModFieldDefn.GetSubType() );
1199 poFieldDefn->SetWidth( oModFieldDefn.GetWidth() );
1200 poFieldDefn->SetPrecision( oModFieldDefn.GetPrecision() );
1201 }
1202 else if( nFlagsIn & ALTER_NAME_FLAG ) // Can only rename field, not change it type.
1203 {
1204 // Field name 'id' forbidden.
1205 OGRFieldDefn oModFieldDefn(poNewFieldDefn);
1206 NormalizeFieldName(poFeatureDefn, iField, &oModFieldDefn);
1207
1208 bNeedSyncStructure = true;
1209 poFieldDefn->SetName( oModFieldDefn.GetNameRef() );
1210 }
1211 }
1212 return OGRLayer::AlterFieldDefn( iField, poNewFieldDefn, nFlagsIn );
1213 }
1214
1215 /*
1216 * SetMetadata()
1217 */
SetMetadata(char ** papszMetadata,const char * pszDomain)1218 CPLErr OGRNGWLayer::SetMetadata(char **papszMetadata, const char *pszDomain)
1219 {
1220 bNeedSyncStructure = true;
1221 return OGRLayer::SetMetadata(papszMetadata, pszDomain);
1222 }
1223
1224 /*
1225 * SetMetadataItem()
1226 */
SetMetadataItem(const char * pszName,const char * pszValue,const char * pszDomain)1227 CPLErr OGRNGWLayer::SetMetadataItem(const char *pszName, const char *pszValue,
1228 const char *pszDomain)
1229 {
1230 bNeedSyncStructure = true;
1231 return OGRLayer::SetMetadataItem(pszName, pszValue, pszDomain);
1232 }
1233
1234 /*
1235 * CreateNGWResourceJson()
1236 */
CreateNGWResourceJson()1237 std::string OGRNGWLayer::CreateNGWResourceJson()
1238 {
1239 CPLJSONObject oResourceJson;
1240
1241 // Add resource json item.
1242 CPLJSONObject oResource("resource", oResourceJson);
1243 oResource.Add("cls", "vector_layer");
1244 CPLJSONObject oResourceParent("parent", oResource);
1245 oResourceParent.Add("id", static_cast<GIntBig>(std::stol( poDS->GetResourceId() )));
1246 oResource.Add("display_name", GetName());
1247 const char *pszKeyName = GetMetadataItem( "keyname" );
1248 if( pszKeyName )
1249 {
1250 oResource.Add("keyname", pszKeyName);
1251 }
1252 const char *pszDescription = GetMetadataItem( "description" );
1253 if( pszDescription )
1254 {
1255 oResource.Add("description", pszDescription);
1256 }
1257
1258 // Add vector_layer json item.
1259 CPLJSONObject oVectorLayer("vector_layer", oResourceJson);
1260 CPLJSONObject oVectorLayerSrs("srs", oVectorLayer);
1261
1262 OGRSpatialReference *poSpatialRef = GetSpatialRef();
1263 int nEPSG = 3857;
1264 if( poSpatialRef )
1265 {
1266 poSpatialRef->AutoIdentifyEPSG();
1267 const char *pszEPSG = poSpatialRef->GetAuthorityCode( nullptr );
1268 if( pszEPSG != nullptr )
1269 {
1270 nEPSG = atoi( pszEPSG );
1271 }
1272 }
1273 oVectorLayerSrs.Add("id", nEPSG);
1274 // In OGRNGWDataset::ICreateLayer we limit supported geometry types.
1275 oVectorLayer.Add("geometry_type", NGWAPI::OGRGeomTypeToNGWGeomType(
1276 GetGeomType() ));
1277 CPLJSONArray oVectorLayerFields;
1278 for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField )
1279 {
1280 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn( iField );
1281
1282 CPLJSONObject oField;
1283 oField.Add("keyname", poFieldDefn->GetNameRef());
1284 oField.Add("datatype", NGWAPI::OGRFieldTypeToNGWFieldType(
1285 poFieldDefn->GetType() ));
1286 std::string osFieldAliasName = poFieldDefn->GetAlternativeNameRef();
1287 // Get alias from metadata.
1288 if( osFieldAliasName.empty() )
1289 {
1290 osFieldAliasName = "FIELD_" + std::to_string(iField) + "_ALIAS";
1291 const char *pszFieldAlias = GetMetadataItem( osFieldAliasName.c_str() );
1292 if( pszFieldAlias )
1293 {
1294 oField.Add("display_name", pszFieldAlias);
1295 }
1296 }
1297 else
1298 {
1299 oField.Add("display_name", osFieldAliasName);
1300 }
1301 oVectorLayerFields.Add(oField);
1302 }
1303 oVectorLayer.Add("fields", oVectorLayerFields);
1304
1305 // Add resmeta json item.
1306 NGWAPI::FillResmeta(oResourceJson, GetMetadata("NGW"));
1307
1308 return oResourceJson.Format(CPLJSONObject::PrettyFormat::Plain);
1309 }
1310
1311 /*
1312 * SyncFeatures()
1313 */
SyncFeatures()1314 OGRErr OGRNGWLayer::SyncFeatures()
1315 {
1316 if( !bNeedSyncData )
1317 {
1318 return OGRERR_NONE;
1319 }
1320
1321 CPLJSONArray oFeatureJsonArray;
1322 std::vector<GIntBig> aoPatchedFIDs;
1323 for(GIntBig nFID : soChangedIds)
1324 {
1325 if( moFeatures[nFID] != nullptr )
1326 {
1327 oFeatureJsonArray.Add( FeatureToJson( moFeatures[nFID] ) );
1328 aoPatchedFIDs.push_back(nFID);
1329 }
1330 }
1331
1332 if( !aoPatchedFIDs.empty() )
1333 {
1334 auto osIDs = NGWAPI::PatchFeatures( poDS->GetUrl(), osResourceId,
1335 oFeatureJsonArray.Format(CPLJSONObject::PrettyFormat::Plain), poDS->GetHeaders() );
1336 if( !osIDs.empty() )
1337 {
1338 bNeedSyncData = false;
1339 nFeatureCount += GetNewFeaturesCount();
1340 soChangedIds.clear();
1341 if( osIDs.size() != aoPatchedFIDs.size() ) // Expected equal identifier count.
1342 {
1343 CPLDebug("ngw", "Patched feature count is not equal. Reload features from server.");
1344 FreeMap(moFeatures);
1345 }
1346 else // Just update identifiers.
1347 {
1348 int nCounter = 0;
1349 for(GIntBig nFID : aoPatchedFIDs)
1350 {
1351 GIntBig nNewFID = osIDs[nCounter++];
1352 OGRFeature *poFeature = moFeatures[nFID];
1353 poFeature->SetFID(nNewFID);
1354 moFeatures.erase(nFID);
1355 moFeatures[nNewFID] = poFeature;
1356 }
1357 }
1358 }
1359 else
1360 {
1361 // Error message should set in NGWAPI::PatchFeatures function.
1362 if( CPLGetLastErrorNo() != 0 )
1363 {
1364 return OGRERR_FAILURE;
1365 }
1366 }
1367 }
1368 return OGRERR_NONE;
1369 }
1370
1371 /*
1372 * SyncToDisk()
1373 */
SyncToDisk()1374 OGRErr OGRNGWLayer::SyncToDisk()
1375 {
1376 if( osResourceId == "-1" ) // Create vector layer at NextGIS Web.
1377 {
1378 bNeedSyncData = !moFeatures.empty();
1379 std::string osResourceIdInt = NGWAPI::CreateResource( poDS->GetUrl(),
1380 CreateNGWResourceJson(), poDS->GetHeaders() );
1381 if( osResourceIdInt == "-1" )
1382 {
1383 // Error message should set in CreateResource.
1384 return OGRERR_FAILURE;
1385 }
1386 osResourceId = osResourceIdInt;
1387 OGRLayer::SetMetadataItem( "id", osResourceId.c_str() );
1388 FetchPermissions();
1389 bNeedSyncStructure = false;
1390 }
1391 else if( bNeedSyncStructure ) // Update vector layer at NextGIS Web.
1392 {
1393 if( !NGWAPI::UpdateResource( poDS->GetUrl(), GetResourceId(),
1394 CreateNGWResourceJson(), poDS->GetHeaders() ) )
1395 {
1396 // Error message should set in UpdateResource.
1397 return OGRERR_FAILURE;
1398 }
1399 bNeedSyncStructure = false;
1400 }
1401
1402 // Sync features.
1403 return SyncFeatures();
1404 }
1405
1406 /*
1407 * DeleteFeature()
1408 */
DeleteFeature(GIntBig nFID)1409 OGRErr OGRNGWLayer::DeleteFeature(GIntBig nFID)
1410 {
1411 CPLErrorReset();
1412 if( nFID < 0 )
1413 {
1414 if( moFeatures[nFID] != nullptr )
1415 {
1416 OGRFeature::DestroyFeature( moFeatures[nFID] );
1417 moFeatures[nFID] = nullptr;
1418 nFeatureCount--;
1419 soChangedIds.erase(nFID);
1420 return OGRERR_NONE;
1421 }
1422 CPLError(CE_Failure, CPLE_AppDefined,
1423 "Feature with id " CPL_FRMT_GIB " not found.", nFID);
1424 return OGRERR_FAILURE;
1425 }
1426 else
1427 {
1428 FetchPermissions();
1429 if( stPermissions.bDataCanWrite && poDS->IsUpdateMode() )
1430 {
1431 bool bResult = NGWAPI::DeleteFeature(poDS->GetUrl(), osResourceId,
1432 std::to_string(nFID), poDS->GetHeaders());
1433 if( bResult )
1434 {
1435 if( moFeatures[nFID] != nullptr )
1436 {
1437 OGRFeature::DestroyFeature( moFeatures[nFID] );
1438 moFeatures[nFID] = nullptr;
1439 }
1440 nFeatureCount--;
1441 soChangedIds.erase(nFID);
1442 return OGRERR_NONE;
1443 }
1444 return OGRERR_FAILURE;
1445 }
1446 CPLError(CE_Failure, CPLE_AppDefined,
1447 "Delete feature " CPL_FRMT_GIB " operation is not permitted.", nFID);
1448 return OGRERR_FAILURE;
1449 }
1450 }
1451
1452 /*
1453 * DeleteAllFeatures()
1454 */
DeleteAllFeatures()1455 bool OGRNGWLayer::DeleteAllFeatures()
1456 {
1457 if( osResourceId == "-1" )
1458 {
1459 soChangedIds.clear();
1460 bNeedSyncData = false;
1461 FreeFeaturesCache();
1462 nFeatureCount = 0;
1463 return true;
1464 }
1465 else
1466 {
1467 FetchPermissions();
1468 if( stPermissions.bDataCanWrite && poDS->IsUpdateMode() )
1469 {
1470 bool bResult = NGWAPI::DeleteFeature(poDS->GetUrl(), osResourceId, "",
1471 poDS->GetHeaders());
1472 if( bResult )
1473 {
1474 soChangedIds.clear();
1475 bNeedSyncData = false;
1476 FreeFeaturesCache();
1477 nFeatureCount = 0;
1478 }
1479 return bResult;
1480 }
1481 }
1482 CPLErrorReset();
1483 CPLError(CE_Failure, CPLE_AppDefined,
1484 "Delete all features operation is not permitted.");
1485 return false;
1486 }
1487
1488 /*
1489 * ISetFeature()
1490 */
ISetFeature(OGRFeature * poFeature)1491 OGRErr OGRNGWLayer::ISetFeature(OGRFeature *poFeature)
1492 {
1493 if( poDS->IsBatchMode() )
1494 {
1495 if( moFeatures[poFeature->GetFID()] == nullptr )
1496 {
1497 if(poFeature->GetFID() < 0)
1498 {
1499 CPLError(CE_Failure, CPLE_AppDefined,
1500 "Cannot update not existing feature " CPL_FRMT_GIB,
1501 poFeature->GetFID());
1502 return OGRERR_FAILURE;
1503 }
1504 }
1505 else
1506 {
1507 OGRFeature::DestroyFeature( moFeatures[poFeature->GetFID()] );
1508 }
1509 moFeatures[poFeature->GetFID()] = poFeature->Clone();
1510 soChangedIds.insert(poFeature->GetFID());
1511
1512 if( soChangedIds.size() > static_cast<size_t>(poDS->GetBatchSize()) )
1513 {
1514 bNeedSyncData = true;
1515 }
1516
1517 return SyncToDisk();
1518 }
1519 else
1520 {
1521 OGRErr eResult = SyncToDisk(); // For create new layer if not yet created.
1522 if(eResult == OGRERR_NONE)
1523 {
1524 if(poFeature->GetFID() < 0)
1525 {
1526 CPLError(CE_Failure, CPLE_AppDefined,
1527 "Cannot update not existing feature " CPL_FRMT_GIB,
1528 poFeature->GetFID());
1529 return OGRERR_FAILURE;
1530 }
1531
1532 bool bResult = NGWAPI::UpdateFeature(poDS->GetUrl(), osResourceId,
1533 std::to_string(poFeature->GetFID()),
1534 FeatureToJsonString(poFeature), poDS->GetHeaders());
1535 if( bResult )
1536 {
1537 CPLDebug("NGW", "ISetFeature with FID " CPL_FRMT_GIB, poFeature->GetFID());
1538
1539 OGRFeature::DestroyFeature( moFeatures[poFeature->GetFID()] );
1540 moFeatures[poFeature->GetFID()] = poFeature->Clone();
1541 return OGRERR_NONE;
1542 }
1543 else
1544 {
1545 // CPLError should be set in NGWAPI::UpdateFeature.
1546 return OGRERR_FAILURE;
1547 }
1548 }
1549 else
1550 {
1551 return eResult;
1552 }
1553 }
1554 }
1555
1556 /*
1557 * ICreateFeature()
1558 */
ICreateFeature(OGRFeature * poFeature)1559 OGRErr OGRNGWLayer::ICreateFeature(OGRFeature *poFeature)
1560 {
1561 if( poDS->IsBatchMode() )
1562 {
1563 GIntBig nNewFID = -1;
1564 if( !soChangedIds.empty() )
1565 {
1566 nNewFID = *(soChangedIds.begin()) - 1;
1567 }
1568 poFeature->SetFID(nNewFID);
1569 moFeatures[nNewFID] = poFeature->Clone();
1570 soChangedIds.insert(nNewFID);
1571 nFeatureCount++;
1572
1573 if( soChangedIds.size() > static_cast<size_t>(poDS->GetBatchSize()) )
1574 {
1575 bNeedSyncData = true;
1576 }
1577
1578 return SyncToDisk();
1579 }
1580 else
1581 {
1582 OGRErr eResult = SyncToDisk(); // For create new layer if not yet created.
1583 if(eResult == OGRERR_NONE)
1584 {
1585 GIntBig nNewFID = NGWAPI::CreateFeature(poDS->GetUrl(), osResourceId,
1586 FeatureToJsonString(poFeature), poDS->GetHeaders());
1587 if(nNewFID >= 0)
1588 {
1589 poFeature->SetFID(nNewFID);
1590 moFeatures[nNewFID] = poFeature->Clone();
1591 nFeatureCount++;
1592 return OGRERR_NONE;
1593 }
1594 else
1595 {
1596 // CPLError should be set in NGWAPI::CreateFeature.
1597 return OGRERR_FAILURE;
1598 }
1599 }
1600 else
1601 {
1602 return eResult;
1603 }
1604 }
1605 }
1606
1607 /*
1608 * SetIgnoredFields()
1609 */
SetIgnoredFields(const char ** papszFields)1610 OGRErr OGRNGWLayer::SetIgnoredFields( const char **papszFields )
1611 {
1612 OGRErr eResult = OGRLayer::SetIgnoredFields( papszFields );
1613 if( eResult != OGRERR_NONE )
1614 {
1615 return eResult;
1616 }
1617
1618 if( nullptr == papszFields )
1619 {
1620 osFields.clear();
1621 }
1622 else
1623 {
1624 for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField )
1625 {
1626 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
1627 if( poFieldDefn->IsIgnored() )
1628 {
1629 continue;
1630 }
1631
1632 if( osFields.empty() )
1633 {
1634 osFields = poFieldDefn->GetNameRef();
1635 }
1636 else
1637 {
1638 osFields += "," + std::string(poFieldDefn->GetNameRef());
1639 }
1640 }
1641
1642 if( !osFields.empty() )
1643 {
1644 char *pszValuesEncoded = CPLEscapeString(osFields.c_str(),
1645 static_cast<int>(osFields.size()), CPLES_URL);
1646 osFields = pszValuesEncoded;
1647 CPLFree(pszValuesEncoded);
1648 }
1649 }
1650
1651 if( poDS->GetPageSize() < 1 )
1652 {
1653 FreeFeaturesCache();
1654 }
1655 ResetReading();
1656 return OGRERR_NONE;
1657 }
1658
1659 /*
1660 * SetSpatialFilter()
1661 */
SetSpatialFilter(OGRGeometry * poGeom)1662 void OGRNGWLayer::SetSpatialFilter( OGRGeometry *poGeom )
1663 {
1664 OGRLayer::SetSpatialFilter( poGeom );
1665
1666 if( nullptr == m_poFilterGeom )
1667 {
1668 CPLDebug("NGW", "Spatial filter unset");
1669 osSpatialFilter.clear();
1670 }
1671 else
1672 {
1673 OGREnvelope sEnvelope;
1674 m_poFilterGeom->getEnvelope(&sEnvelope);
1675
1676 OGREnvelope sBigEnvelope;
1677 sBigEnvelope.MinX = -40000000.0;
1678 sBigEnvelope.MinY = -40000000.0;
1679 sBigEnvelope.MaxX = 40000000.0;
1680 sBigEnvelope.MaxY = 40000000.0;
1681
1682 // Case for infinity filter
1683 if(sEnvelope.Contains( sBigEnvelope ) == TRUE )
1684 {
1685 CPLDebug("NGW", "Spatial filter unset as filter envelope covers whole features.");
1686 osSpatialFilter.clear();
1687 }
1688 else
1689 {
1690 if( sEnvelope.MinX == sEnvelope.MaxX && sEnvelope.MinY == sEnvelope.MaxY )
1691 {
1692 OGRPoint p(sEnvelope.MinX, sEnvelope.MinY);
1693 InstallFilter(&p);
1694 }
1695
1696 osSpatialFilter = OGRGeometryToWKT( m_poFilterGeom );
1697 CPLDebug("NGW", "Spatial filter: %s", osSpatialFilter.c_str());
1698 char *pszSpatFilterEncoded = CPLEscapeString(osSpatialFilter.c_str(),
1699 static_cast<int>(osSpatialFilter.size()), CPLES_URL);
1700 osSpatialFilter = pszSpatFilterEncoded;
1701 CPLFree(pszSpatFilterEncoded);
1702 }
1703 }
1704
1705 if( poDS->GetPageSize() < 1 )
1706 {
1707 FreeFeaturesCache();
1708 }
1709 ResetReading();
1710 }
1711
1712 /*
1713 * SetSpatialFilter()
1714 */
SetSpatialFilter(int iGeomField,OGRGeometry * poGeom)1715 void OGRNGWLayer::SetSpatialFilter( int iGeomField, OGRGeometry *poGeom )
1716 {
1717 OGRLayer::SetSpatialFilter( iGeomField, poGeom );
1718 }
1719
1720 /*
1721 * SetAttributeFilter()
1722 */
SetAttributeFilter(const char * pszQuery)1723 OGRErr OGRNGWLayer::SetAttributeFilter( const char *pszQuery )
1724 {
1725 OGRErr eResult = OGRERR_NONE;
1726 if( nullptr == pszQuery )
1727 {
1728 eResult = OGRLayer::SetAttributeFilter( pszQuery );
1729 osWhere.clear();
1730 bClientSideAttributeFilter = false;
1731 }
1732 else if( STARTS_WITH_CI(pszQuery, "NGW:") ) // Already formatted for NGW REST API
1733 {
1734 osWhere = pszQuery + strlen("NGW:");
1735 bClientSideAttributeFilter = false;
1736 }
1737 else
1738 {
1739 eResult = OGRLayer::SetAttributeFilter( pszQuery );
1740 if( eResult == OGRERR_NONE && m_poAttrQuery != nullptr )
1741 {
1742 swq_expr_node *poNode =
1743 reinterpret_cast<swq_expr_node*>( m_poAttrQuery->GetSWQExpr() );
1744 std::string osWhereIn = TranslateSQLToFilter( poNode );
1745 if( osWhereIn.empty() )
1746 {
1747 osWhere.clear();
1748 bClientSideAttributeFilter = true;
1749 CPLDebug("NGW",
1750 "Attribute filter '%s' will be evaluated on client side.",
1751 pszQuery);
1752 }
1753 else
1754 {
1755 bClientSideAttributeFilter = false;
1756 CPLDebug("NGW", "Attribute filter: %s", osWhereIn.c_str());
1757 osWhere = osWhereIn;
1758 }
1759 }
1760 }
1761
1762 if( poDS->GetPageSize() < 1 )
1763 {
1764 FreeFeaturesCache();
1765 }
1766 ResetReading();
1767 return eResult;
1768 }
1769
1770 /*
1771 * SetSelectedFields()
1772 */
SetSelectedFields(const std::set<std::string> & aosFields)1773 OGRErr OGRNGWLayer::SetSelectedFields(const std::set<std::string> &aosFields)
1774 {
1775 CPLStringList aosIgnoreFields;
1776 for( int iField = 0; iField < poFeatureDefn->GetFieldCount(); ++iField )
1777 {
1778 OGRFieldDefn *poFieldDefn = poFeatureDefn->GetFieldDefn(iField);
1779 if( aosFields.find( poFieldDefn->GetNameRef() ) != aosFields.end() )
1780 {
1781 continue;
1782 }
1783 aosIgnoreFields.AddString( poFieldDefn->GetNameRef() );
1784 }
1785 return SetIgnoredFields( const_cast<const char**>(aosIgnoreFields.List()) );
1786 }
1787
1788 /*
1789 * Clone()
1790 */
Clone() const1791 OGRNGWLayer *OGRNGWLayer::Clone() const
1792 {
1793 return new OGRNGWLayer( osResourceId, poDS, stPermissions,
1794 poFeatureDefn->Clone(), nFeatureCount, stExtent );
1795 }
1796
1797 /*
1798 * GetNewFeaturesCount()
1799 */
GetNewFeaturesCount() const1800 GIntBig OGRNGWLayer::GetNewFeaturesCount() const
1801 {
1802 if( soChangedIds.empty() )
1803 {
1804 return 0;
1805 }
1806
1807 if( *soChangedIds.begin() >= 0 )
1808 {
1809 return 0;
1810 }
1811
1812 // The lowest negative identifier equal new feature count
1813 return *soChangedIds.begin() * -1;
1814 }
1815