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