[mapguide-commits] r9243 - in sandbox/jng/ogc: Common/MapGuideCommon/Services Common/PlatformBase/Services Server/src/Services/Feature Web/src/HttpHandler

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Fri Oct 6 06:49:24 PDT 2017


Author: jng
Date: 2017-10-06 06:49:24 -0700 (Fri, 06 Oct 2017)
New Revision: 9243

Added:
   sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.cpp
   sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.h
Modified:
   sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
   sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.h
   sandbox/jng/ogc/Common/PlatformBase/Services/FeatureService.h
   sandbox/jng/ogc/Server/src/Services/Feature/FeatureOperationFactory.cpp
   sandbox/jng/ogc/Server/src/Services/Feature/Makefile.am
   sandbox/jng/ogc/Server/src/Services/Feature/OpGetWfsReader.cpp
   sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.cpp
   sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.h
   sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj
   sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
   sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/HttpWfsGetFeature.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
   sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.h
Log:
Remove the MgLimitingFeatureReader. The reader pooling mechanism that applies to any MgFeatureReader kind of throws a monkey wrench of wanting to limit reader iterations on the server-tier. It is easier to limit the iterations on the web tier instead and just let the server-tier pre-buffer however many configuration-defined results upfront as it already does. As a result, for WFS GetFeature responses in GeoJSON, we now simply house the MgFeatureReader from MgFeatureService::GetWfsReader into a MgReaderByteSourceImpl and add support in this class for max iterations via SetMaxFeatures. This means the maxfeatures parameter of WFS GetFeature now works for GeoJSON output format.

This submission also unifies the base WFS GetFeature reader acquisition logic into a new MgWfsQueryAdapter class. Both GetWfsFeature and GetWfsReader have been refactored to use MgWfsQueryAdapter to set up the base feature reader instead of doing this themselves.

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.cpp
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -1478,14 +1478,13 @@
                                                      MgStringCollection* requiredProperties,
                                                      CREFSTRING srs,
                                                      CREFSTRING filter,
-                                                     INT32 maxFeatures,
                                                      CREFSTRING sortCriteria)
 {
     MgCommand cmd;
     cmd.ExecuteCommand(m_connProp,                                  // Connection
                        MgCommand::knObject,                         // Return type expected
                        MgFeatureServiceOpId::GetWfsReader_Id,       // Command Code
-                       7,                                           // No of arguments
+                       6,                                           // No of arguments
                        Feature_Service,                             // Service Id
                        BUILD_VERSION(3,3,0),                        // Operation version
                        MgCommand::knObject, featureSourceId,        // Argument#1
@@ -1493,8 +1492,7 @@
                        MgCommand::knObject, requiredProperties,     // Argument#3
                        MgCommand::knString, &srs,                   // Argument#4
                        MgCommand::knString, &filter,                // Argument#5
-                       MgCommand::knInt32, maxFeatures,             // Argument#6
-                       MgCommand::knString, &sortCriteria,          // Argument#7
+                       MgCommand::knString, &sortCriteria,          // Argument#6
                        MgCommand::knNone);                          // End of argument
 
     SetWarning(cmd.GetWarningObject());

Modified: sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.h
===================================================================
--- sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.h	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Common/MapGuideCommon/Services/ProxyFeatureService.h	2017-10-06 13:49:24 UTC (rev 9243)
@@ -1561,7 +1561,6 @@
                                   MgStringCollection* requiredProperties,
                                   CREFSTRING srs,
                                   CREFSTRING filter,
-                                  INT32 maxFeatures,
                                   CREFSTRING sortCriteria);
 
     ////////////////////////////////////////////////////////////////////////////////

Modified: sandbox/jng/ogc/Common/PlatformBase/Services/FeatureService.h
===================================================================
--- sandbox/jng/ogc/Common/PlatformBase/Services/FeatureService.h	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Common/PlatformBase/Services/FeatureService.h	2017-10-06 13:49:24 UTC (rev 9243)
@@ -2068,9 +2068,6 @@
     /// The spatial reference system in which to return feature geometries
     /// \param filter (String/string)
     /// An XML string containing the definition for an OGC filter
-    /// \param maxFeatures (int)
-    /// The maximum number of features to retrieve. If the value is less
-    /// than or equal to zero, all features will be retrieved.
     /// \param sortCriteria (String/string)
     /// A string identifying the sort criteria
     ///
@@ -2093,7 +2090,6 @@
                                           MgStringCollection* requiredProperties,
                                           CREFSTRING srs,
                                           CREFSTRING filter,
-                                          INT32 maxFeatures,
                                           CREFSTRING sortCriteria) = 0;
 
     ////////////////////////////////////////////////////////////////////////////////

Modified: sandbox/jng/ogc/Server/src/Services/Feature/FeatureOperationFactory.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/FeatureOperationFactory.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/FeatureOperationFactory.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -690,11 +690,11 @@
         }
         break;
 
-	case MgFeatureServiceOpId::AddSavePoint_Id:
-		switch (VERSION_NO_PHASE(operationVersion))
+    case MgFeatureServiceOpId::AddSavePoint_Id:
+        switch (VERSION_NO_PHASE(operationVersion))
         {
         case VERSION_SUPPORTED(1,0):
-			handler.reset(new MgOpAddSavePoint());
+            handler.reset(new MgOpAddSavePoint());
             break;
         default:
             throw new MgInvalidOperationVersionException(
@@ -706,7 +706,7 @@
         switch (VERSION_NO_PHASE(operationVersion))
         {
         case VERSION_SUPPORTED(1,0):
-	        handler.reset(new MgOpRollbackSavePoint());
+            handler.reset(new MgOpRollbackSavePoint());
             break;
         default:
             throw new MgInvalidOperationVersionException(
@@ -715,7 +715,7 @@
         break;
 
     case MgFeatureServiceOpId::ReleaseSavePoint_Id:
-		switch (VERSION_NO_PHASE(operationVersion))
+        switch (VERSION_NO_PHASE(operationVersion))
         {
         case VERSION_SUPPORTED(1,0):
             handler.reset(new MgOpReleaseSavePoint());

Modified: sandbox/jng/ogc/Server/src/Services/Feature/Makefile.am
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/Makefile.am	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/Makefile.am	2017-10-06 13:49:24 UTC (rev 9243)
@@ -107,6 +107,7 @@
   OpGetWfsFeature.cpp \
   OpGetWfsReader.cpp \
   FilterUtil.cpp \
+  WfsQueryAdapter.cpp \
   OpEnumerateDataStores.cpp \
   OpGetSchemaMapping.cpp \
   ServerEnumerateDataStores.cpp \
@@ -219,6 +220,7 @@
   OpGetWfsFeature.h \
   OpGetWfsReader.h \
   FilterUtil.h \
+  WfsQueryAdapter.h \
   OpEnumerateDataStores.h \
   OpGetSchemaMapping.h \
   ServerEnumerateDataStores.h \

Modified: sandbox/jng/ogc/Server/src/Services/Feature/OpGetWfsReader.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/OpGetWfsReader.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/OpGetWfsReader.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -62,7 +62,7 @@
 
     ACE_ASSERT(m_stream != NULL);
 
-    if (7 == m_packet.m_NumArguments)
+    if (6 == m_packet.m_NumArguments)
     {
         // Get the feature source
         Ptr<MgResourceIdentifier> featureSourceId = (MgResourceIdentifier*)m_stream->GetObject();
@@ -82,10 +82,6 @@
         STRING filter;
         m_stream->GetString(filter);
 
-        // Get the max features to return
-        INT32 maxFeatures;
-        m_stream->GetInt32(maxFeatures);
-
         // Get the sort criteria
         STRING sortCriteria;
         m_stream->GetString(sortCriteria);
@@ -103,15 +99,13 @@
         MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
         MG_LOG_OPERATION_MESSAGE_ADD_STRING(filter.c_str());
         MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
-        MG_LOG_OPERATION_MESSAGE_ADD_INT32(maxFeatures);
-        MG_LOG_OPERATION_MESSAGE_ADD_SEPARATOR();
         MG_LOG_OPERATION_MESSAGE_ADD_STRING(sortCriteria.c_str());
         MG_LOG_OPERATION_MESSAGE_PARAMETERS_END();
 
         Validate();
 
         // Execute the operation
-        Ptr<MgFeatureReader> fr = m_service->GetWfsReader(featureSourceId, featureClass, requiredProperties, srs, filter, maxFeatures, sortCriteria);
+        Ptr<MgFeatureReader> fr = m_service->GetWfsReader(featureSourceId, featureClass, requiredProperties, srs, filter, sortCriteria);
 
         // Write the response
         EndExecution(fr);

Modified: sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -48,6 +48,7 @@
 #include "ServerSqlDataReader.h"
 #include "ServerFeatureTransaction.h"
 #include "TransformedGeometryFeatureReader.h"
+#include "WfsQueryAdapter.h"
 
 #include <Fdo/Xml/FeatureSerializer.h>
 #include <Fdo/Xml/FeatureWriter.h>
@@ -2048,172 +2049,20 @@
                                                       MgStringCollection* propNames,
                                                       CREFSTRING srs,
                                                       CREFSTRING wfsFilter,
-                                                      INT32 maxFeatures,
                                                       CREFSTRING sortCriteria)
 {
+    MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::GetWfsReader()");
+
     Ptr<MgFeatureReader> mgfReader;
-    TransformCacheMap transformCache;
 
     MG_FEATURE_SERVICE_TRY()
 
-        STRING lfeatureName = featureClass;
-    STRING schemaName, className;
-    MgUtil::ParseQualifiedClassName(lfeatureName, schemaName, className);
+    MgWfsQueryAdapter wfsQuery(this);
+    wfsQuery.SetOptions(fs, featureClass, propNames, srs, wfsFilter, sortCriteria);
+    mgfReader = wfsQuery.GetWfsReader();
 
-    bool hashed = (0 == schemaName.find_first_of(
-        MG_SCHEMA_NAME_HASH_PREFIX.c_str(), 0, MG_SCHEMA_NAME_HASH_PREFIX.length()));
-    Ptr<MgStringCollection> classNames = new MgStringCollection();
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(fs, L"MgServerFeatureService.GetWfsReader")
 
-    if (!className.empty())
-    {
-        classNames->Add(className);
-    }
-
-    // Find the needed class definition.
-    Ptr<MgFeatureSchemaCollection> fsc = DescribeSchema(
-        fs, hashed ? L"" : schemaName, classNames);
-    Ptr<MgFeatureSchema> schema;
-    Ptr<MgClassDefinition> fc;
-    STRING schemaHash;
-
-    FindClassDefinition(fsc, schemaName, className, schemaHash, schema, fc);
-
-    if (hashed && NULL != schema.p)
-    {
-        MgUtil::FormatQualifiedClassName(schema->GetName(), className, lfeatureName);
-    }
-
-    MgCoordinateSystemFactory fact;
-    std::wstring wkt = srs;
-    if (wkt.empty())
-    {
-        //If there is no coordinate system pass in, get the default one in resource header.
-        MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-        assert(NULL != serviceMan);
-        Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(serviceMan->RequestService(MgServiceType::ResourceService));
-        assert(resourceService != NULL);
-        Ptr<MgByteReader> byteReaderHeader = resourceService->GetResourceHeader(fs);
-        Ptr<MgByteSink> byteSinkHeader = new MgByteSink(byteReaderHeader);
-        std::string resourceHeader;
-        byteSinkHeader->ToStringUtf8(resourceHeader);
-        //parse for default SRS of this WFS, the format is:
-        //<Property xsi:noNamespaceSchemaLocation="Property-1.0.0.xsd">
-        //  <Name>_PrimarySRS</Name>
-        //  <Value>EPSG:4326</Value>
-        //</Property>
-        std::string primary("<Name>_PrimarySRS</Name>");
-        std::size_t primaryPos = resourceHeader.find(primary);
-        if (primaryPos != std::string::npos)
-        {
-            std::string begin("<Value>EPSG:");
-            std::size_t beginPos = resourceHeader.find(begin, primaryPos);
-            if (beginPos != std::string::npos)
-            {
-                std::size_t endPos = resourceHeader.find("</Value>", beginPos);
-                if (endPos != std::string::npos)
-                {
-                    std::string primarySRS = resourceHeader.substr(beginPos + begin.length(), endPos - beginPos - begin.length());
-                    int epsgCode = atoi(primarySRS.c_str());
-                    wkt = fact.ConvertEpsgCodeToWkt(epsgCode);
-                }
-            }
-        }
-    }
-
-    Ptr<MgCoordinateSystem> mapCs = NULL;
-    if (!wkt.empty())
-    {
-        MG_TRY();
-        mapCs = fact.Create(wkt);
-        MG_CATCH_AND_RELEASE();
-    }
-
-    //get a transform from feature space to mapping space
-    TransformCache* item = TransformCache::GetLayerToMapTransform(transformCache, lfeatureName, fs, mapCs, &fact, this, false);
-    Ptr<MgCoordinateSystemTransform> trans = item ? item->GetMgTransform() : NULL;
-
-    assert(fc != NULL);
-    if (fc == NULL)
-        return NULL;
-
-    //execute the spatial query
-    Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
-
-    //add the properties we need from FDO
-    if (propNames)
-    {
-        for (int i = 0; i<propNames->GetCount(); i++)
-            options->AddFeatureProperty(propNames->GetItem(i));
-    }
-
-    //convert the WFS filter to an FDO filter
-    //and set it to the FDO feature query
-    if (!wfsFilter.empty())
-    {
-        STRING GEOM_PROP_TAG = L"%MG_GEOM_PROP%"; //NOXLATE
-        STRING fdoFilterString = L""; //NOXLATE
-
-        Ptr<MgPropertyDefinitionCollection> properties = fc->GetProperties();
-        MgOgcFilterUtil u;
-
-        for (int i = 0; i<properties->GetCount(); i++)
-        {
-            Ptr<MgPropertyDefinition> prop = properties->GetItem(i);
-            if (prop->GetPropertyType() == MgFeaturePropertyType::GeometricProperty)
-            {
-                STRING ogcFilter = wfsFilter;
-
-                if (wfsFilter.find(GEOM_PROP_TAG, 0) != STRING::npos)
-                {
-                    ogcFilter = MgUtil::ReplaceString(wfsFilter, GEOM_PROP_TAG.c_str(), prop->GetName().c_str());
-                }
-                if (!fdoFilterString.empty())
-                {
-                    fdoFilterString += L" OR "; //NOXLATE
-                }
-                TransformCache* itemFilter = TransformCache::GetLayerToMapTransform(transformCache, lfeatureName, fs, mapCs, &fact, this, true);
-                Ptr<MgCoordinateSystemTransform> transFilter = itemFilter ? itemFilter->GetMgTransform() : NULL;
-                fdoFilterString += u.Ogc2FdoFilter(ogcFilter, transFilter, prop->GetName(), properties);
-            }
-        }
-
-        options->SetFilter(fdoFilterString);
-    }
-
-    if (!sortCriteria.empty())
-    {
-        Ptr<MgStringCollection> orderByProperties = new MgStringCollection();
-        int orderOption = MgOrderingOption::Ascending;
-
-        STRING sSortCriteria = sortCriteria;
-        STRING::size_type pos = sSortCriteria.find_last_of(L" ");
-        if (pos != STRING::npos)
-        {
-            STRING sSortByProperty = sSortCriteria.substr(0, pos);
-            orderByProperties->Add(sSortByProperty);
-
-            STRING sSortOption = MgUtil::ToUpper(sSortCriteria.substr(pos + 1));
-            if (sSortOption == L"D")
-            {
-                orderOption = MgOrderingOption::Descending;
-            }
-        }
-        else
-        {
-            orderByProperties->Add(sortCriteria);
-        }
-
-        options->SetOrderingFilter(orderByProperties, orderOption);
-    }
-    // TODO: can FeatureName be an extension name rather than a FeatureClass?
-    mgfReader = SelectFeatures(fs, lfeatureName, options);
-
-    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH(fs, L"MgServerFeatureService.GetWfsReader")
-
-    TransformCache::Clear(transformCache);
-
-    MG_FEATURE_SERVICE_THROW()
-
     return mgfReader.Detach();
 }
 
@@ -2284,162 +2133,17 @@
     MG_LOG_TRACE_ENTRY(L"MgServerFeatureService::GetWfsFeature()");
 
     Ptr<MgByteReader> byteReader;
-    TransformCacheMap transformCache;
 
     MG_FEATURE_SERVICE_TRY()
 
-    STRING lfeatureName = featureClass;
-    STRING schemaName, className;
-    MgUtil::ParseQualifiedClassName(lfeatureName, schemaName, className);
+    MgWfsQueryAdapter wfsQuery(this);
+    wfsQuery.SetOptions(fs, featureClass, propNames, srs, wfsFilter, sortCriteria);
 
-    bool hashed = (0 == schemaName.find_first_of(
-        MG_SCHEMA_NAME_HASH_PREFIX.c_str(), 0, MG_SCHEMA_NAME_HASH_PREFIX.length()));
-    Ptr<MgStringCollection> classNames = new MgStringCollection();
+    Ptr<MgFeatureReader> mgfReader = wfsQuery.GetWfsReader();
+    Ptr<MgCoordinateSystemTransform> trans = wfsQuery.GetTransform();
+    Ptr<MgCoordinateSystem> mapCs = wfsQuery.GetMapCs();
+    Ptr<MgClassDefinition> fc = wfsQuery.GetClassDefinition();
 
-    if (!className.empty())
-    {
-        classNames->Add(className);
-    }
-
-    // Find the needed class definition.
-    Ptr<MgFeatureSchemaCollection> fsc = DescribeSchema(
-        fs, hashed ? L"" : schemaName, classNames);
-    Ptr<MgFeatureSchema> schema;
-    Ptr<MgClassDefinition> fc;
-    STRING schemaHash;
-
-    FindClassDefinition(fsc, schemaName, className, schemaHash, schema, fc);
-
-    if (hashed && NULL != schema.p)
-    {
-        MgUtil::FormatQualifiedClassName(schema->GetName(), className, lfeatureName);
-    }
-
-    MgCoordinateSystemFactory fact;
-    std::wstring wkt = srs;
-    if (wkt.empty())
-    {
-        //If there is no coordinate system pass in, get the default one in resource header.
-        MgServiceManager* serviceMan = MgServiceManager::GetInstance();
-        assert(NULL != serviceMan);
-        Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(serviceMan->RequestService(MgServiceType::ResourceService));
-        assert(resourceService != NULL);
-        Ptr<MgByteReader> byteReaderHeader = resourceService->GetResourceHeader(fs);
-        Ptr<MgByteSink> byteSinkHeader = new MgByteSink(byteReaderHeader);
-        std::string resourceHeader;
-        byteSinkHeader->ToStringUtf8(resourceHeader);
-        //parse for default SRS of this WFS, the format is:
-        //<Property xsi:noNamespaceSchemaLocation="Property-1.0.0.xsd">
-        //  <Name>_PrimarySRS</Name>
-        //  <Value>EPSG:4326</Value>
-        //</Property>
-        std::string primary("<Name>_PrimarySRS</Name>");
-        std::size_t primaryPos = resourceHeader.find(primary);
-        if (primaryPos != std::string::npos)
-        {
-            std::string begin("<Value>EPSG:");
-            std::size_t beginPos = resourceHeader.find(begin, primaryPos);
-            if (beginPos != std::string::npos)
-            {
-                std::size_t endPos = resourceHeader.find("</Value>", beginPos);
-                if (endPos != std::string::npos)
-                {
-                    std::string primarySRS = resourceHeader.substr(beginPos+begin.length(), endPos-beginPos-begin.length());
-                    int epsgCode = atoi(primarySRS.c_str());
-                    wkt = fact.ConvertEpsgCodeToWkt(epsgCode);
-                }
-            }
-        }
-    }
-
-    Ptr<MgCoordinateSystem> mapCs = NULL;
-    if (!wkt.empty())
-    {
-        MG_TRY();
-            mapCs = fact.Create(wkt);
-        MG_CATCH_AND_RELEASE();
-    }
-
-    //get a transform from feature space to mapping space
-    TransformCache* item = TransformCache::GetLayerToMapTransform(transformCache, lfeatureName, fs, mapCs, &fact, this, false);
-    Ptr<MgCoordinateSystemTransform> trans = item? item->GetMgTransform() : NULL;
-
-    assert(fc != NULL);
-    if (fc == NULL)
-        return NULL;
-
-    //execute the spatial query
-    Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
-
-    //add the properties we need from FDO
-    if (propNames)
-    {
-        for (int i=0; i<propNames->GetCount(); i++)
-            options->AddFeatureProperty(propNames->GetItem(i));
-    }
-
-    //convert the WFS filter to an FDO filter
-    //and set it to the FDO feature query
-    if (!wfsFilter.empty())
-    {
-        STRING GEOM_PROP_TAG = L"%MG_GEOM_PROP%"; //NOXLATE
-        STRING fdoFilterString = L""; //NOXLATE
-
-        Ptr<MgPropertyDefinitionCollection> properties = fc->GetProperties();
-        MgOgcFilterUtil u;
-        
-        for(int i = 0; i<properties->GetCount(); i++)
-        {
-            Ptr<MgPropertyDefinition> prop = properties->GetItem(i);
-            if(prop->GetPropertyType() == MgFeaturePropertyType::GeometricProperty)
-            {
-                STRING ogcFilter = wfsFilter;
-
-                if(wfsFilter.find(GEOM_PROP_TAG, 0) != STRING::npos)
-                {
-                    ogcFilter = MgUtil::ReplaceString(wfsFilter,GEOM_PROP_TAG.c_str(),prop->GetName().c_str());
-                }
-                if(!fdoFilterString.empty())
-                {
-                    fdoFilterString += L" OR "; //NOXLATE
-                }
-                TransformCache* itemFilter = TransformCache::GetLayerToMapTransform(transformCache, lfeatureName, fs, mapCs, &fact, this, true);
-                Ptr<MgCoordinateSystemTransform> transFilter = itemFilter? itemFilter->GetMgTransform() : NULL;
-                fdoFilterString += u.Ogc2FdoFilter(ogcFilter, transFilter, prop->GetName(), properties);
-            }
-        }
-
-        options->SetFilter(fdoFilterString);
-    }
-
-    if(!sortCriteria.empty())
-    {
-        Ptr<MgStringCollection> orderByProperties = new MgStringCollection();
-        int orderOption = MgOrderingOption::Ascending;
-
-        STRING sSortCriteria = sortCriteria;
-        STRING::size_type pos = sSortCriteria.find_last_of(L" ");
-        if(pos != STRING::npos)
-        {
-            STRING sSortByProperty = sSortCriteria.substr(0, pos);
-            orderByProperties->Add(sSortByProperty);
-
-            STRING sSortOption  = MgUtil::ToUpper(sSortCriteria.substr(pos+1));
-            if(sSortOption == L"D")
-            {
-                orderOption = MgOrderingOption::Descending;
-            }
-        }
-        else
-        {
-            orderByProperties->Add(sortCriteria);
-        }
-
-        options->SetOrderingFilter(orderByProperties,orderOption);
-    }
-    // TODO: can FeatureName be an extension name rather than a FeatureClass?
-    Ptr<MgFeatureReader> mgfReader = SelectFeatures(fs, lfeatureName, options);
-
     FdoPtr<MgGMLCsTransform> transform = new MgGMLCsTransform(trans);
 
     //get underlying FDO feature reader
@@ -2569,12 +2273,8 @@
     src->SetMimeType(MgMimeType::Xml);
     byteReader = src->GetReader();
 
-    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH(fs, L"MgServerFeatureService.GetWfsFeature")
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(fs, L"MgServerFeatureService.GetWfsFeature")
 
-    TransformCache::Clear(transformCache);
-
-    MG_FEATURE_SERVICE_THROW()
-
     return byteReader.Detach();
 }
 

Modified: sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.h
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.h	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.h	2017-10-06 13:49:24 UTC (rev 9243)
@@ -23,8 +23,12 @@
 
 #include <set>
 
+class MgWfsQueryAdapter;
+
 class MG_SERVER_FEATURE_API MgServerFeatureService : public MgFeatureService
 {
+    friend class MgWfsQueryAdapter;
+
     DECLARE_CLASSNAME(MgServerFeatureService)
 
 public:
@@ -946,7 +950,6 @@
                                   MgStringCollection* requiredProperties,
                                   CREFSTRING srs,
                                   CREFSTRING filter,
-                                  INT32 maxFeatures,
                                   CREFSTRING sortCriteria);
 
     ////////////////////////////////////////////////////////////////////////////////

Modified: sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj	2017-10-06 13:49:24 UTC (rev 9243)
@@ -822,6 +822,12 @@
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
     </ClCompile>
+    <ClCompile Include="WfsQueryAdapter.cpp">
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
+      <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FdoForcedOneToOneFeatureReader.h" />
@@ -892,6 +898,7 @@
     <ClInclude Include="FeatureStringFunctions.h" />
     <ClInclude Include="FilterUtil.h" />
     <ClInclude Include="GeometryDataReaderCreator.h" />
+    <ClInclude Include="WfsQueryAdapter.h" />
     <CustomBuildStep Include="GwsConnectionPool.h">
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>

Modified: sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureService.vcxproj.filters	2017-10-06 13:49:24 UTC (rev 9243)
@@ -204,6 +204,7 @@
     <ClCompile Include="OpGetWfsReader.cpp">
       <Filter>Ops</Filter>
     </ClCompile>
+    <ClCompile Include="WfsQueryAdapter.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="FeatureOperation.h">
@@ -417,6 +418,7 @@
     <ClInclude Include="OpGetWfsReader.h">
       <Filter>Ops</Filter>
     </ClInclude>
+    <ClInclude Include="WfsQueryAdapter.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ServerFeatureService.rc" />

Modified: sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Server/src/Services/Feature/ServerFeatureServiceBuild.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -88,6 +88,7 @@
 #include "OpGetWfsFeature.cpp"
 #include "OpGetWfsReader.cpp"
 #include "FilterUtil.cpp"
+#include "WfsQueryAdapter.cpp"
 #include "ServerGwsFeatureReader.cpp"
 #include "GwsConnectionPool.cpp"
 #include "OpEnumerateDataStores.cpp"
@@ -112,4 +113,4 @@
 #include "OpInsertFeaturesBatched.cpp"
 #include "OpUpdateMatchingFeatures.cpp"
 #include "OpDeleteFeatures.cpp"
-#include "TransformedGeometryFeatureReader.cpp"
+#include "TransformedGeometryFeatureReader.cpp"
\ No newline at end of file

Added: sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.cpp
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.cpp	                        (rev 0)
+++ sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -0,0 +1,216 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#include "ServerFeatureServiceDefs.h"
+#include "WfsQueryAdapter.h"
+
+MgWfsQueryAdapter::MgWfsQueryAdapter(MgServerFeatureService* featSvc)
+{
+    m_featSvc = SAFE_ADDREF(featSvc);
+}
+
+MgWfsQueryAdapter::~MgWfsQueryAdapter()
+{
+    TransformCache::Clear(m_transformCache);
+    m_classDef = NULL;
+    m_fs = NULL;
+    m_options = NULL;
+    m_featSvc = NULL;
+    m_mapCs = NULL;
+    m_xform = NULL;
+}
+
+bool MgWfsQueryAdapter::SetOptions(MgResourceIdentifier* fs,
+                                   CREFSTRING featureClass,
+                                   MgStringCollection* propNames,
+                                   CREFSTRING srs,
+                                   CREFSTRING wfsFilter,
+                                   CREFSTRING sortCriteria)
+{
+    m_fs = SAFE_ADDREF(fs);
+    m_className = featureClass;
+    STRING schemaName, className;
+    MgUtil::ParseQualifiedClassName(m_className, schemaName, className);
+
+    bool hashed = (0 == schemaName.find_first_of(MG_SCHEMA_NAME_HASH_PREFIX.c_str(), 0, MG_SCHEMA_NAME_HASH_PREFIX.length()));
+    Ptr<MgStringCollection> classNames = new MgStringCollection();
+
+    if (!className.empty())
+    {
+        classNames->Add(className);
+    }
+
+    // Find the needed class definition.
+    Ptr<MgFeatureSchemaCollection> fsc = m_featSvc->DescribeSchema(m_fs, hashed ? L"" : schemaName, classNames);
+    Ptr<MgFeatureSchema> schema;
+    STRING schemaHash;
+
+    m_featSvc->FindClassDefinition(fsc, schemaName, className, schemaHash, schema, m_classDef);
+
+    if (hashed && NULL != schema.p)
+    {
+        MgUtil::FormatQualifiedClassName(schema->GetName(), className, m_className);
+    }
+
+    MgCoordinateSystemFactory fact;
+    std::wstring wkt = srs;
+    if (wkt.empty())
+    {
+        //If there is no coordinate system pass in, get the default one in resource header.
+        MgServiceManager* serviceMan = MgServiceManager::GetInstance();
+        assert(NULL != serviceMan);
+        Ptr<MgResourceService> resourceService = dynamic_cast<MgResourceService*>(serviceMan->RequestService(MgServiceType::ResourceService));
+        assert(resourceService != NULL);
+        Ptr<MgByteReader> byteReaderHeader = resourceService->GetResourceHeader(m_fs);
+        Ptr<MgByteSink> byteSinkHeader = new MgByteSink(byteReaderHeader);
+        std::string resourceHeader;
+        byteSinkHeader->ToStringUtf8(resourceHeader);
+        //parse for default SRS of this WFS, the format is:
+        //<Property xsi:noNamespaceSchemaLocation="Property-1.0.0.xsd">
+        //  <Name>_PrimarySRS</Name>
+        //  <Value>EPSG:4326</Value>
+        //</Property>
+        std::string primary("<Name>_PrimarySRS</Name>");
+        std::size_t primaryPos = resourceHeader.find(primary);
+        if (primaryPos != std::string::npos)
+        {
+            std::string begin("<Value>EPSG:");
+            std::size_t beginPos = resourceHeader.find(begin, primaryPos);
+            if (beginPos != std::string::npos)
+            {
+                std::size_t endPos = resourceHeader.find("</Value>", beginPos);
+                if (endPos != std::string::npos)
+                {
+                    std::string primarySRS = resourceHeader.substr(beginPos + begin.length(), endPos - beginPos - begin.length());
+                    int epsgCode = atoi(primarySRS.c_str());
+                    wkt = fact.ConvertEpsgCodeToWkt(epsgCode);
+                }
+            }
+        }
+    }
+
+    if (!wkt.empty())
+    {
+        MG_TRY();
+        m_mapCs = fact.Create(wkt);
+        MG_CATCH_AND_RELEASE();
+    }
+
+    //get a transform from feature space to mapping space
+    TransformCache* item = TransformCache::GetLayerToMapTransform(m_transformCache, m_className, m_fs, m_mapCs, &fact, m_featSvc, false);
+    m_xform = item ? item->GetMgTransform() : NULL;
+
+    assert(m_classDef.p != NULL);
+    if (NULL == m_classDef.p)
+        return false;
+
+    //execute the spatial query
+    Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
+
+    //add the properties we need from FDO
+    if (propNames)
+    {
+        for (int i = 0; i<propNames->GetCount(); i++)
+            options->AddFeatureProperty(propNames->GetItem(i));
+    }
+
+    //convert the WFS filter to an FDO filter
+    //and set it to the FDO feature query
+    if (!wfsFilter.empty())
+    {
+        STRING GEOM_PROP_TAG = L"%MG_GEOM_PROP%"; //NOXLATE
+        STRING fdoFilterString = L""; //NOXLATE
+
+        Ptr<MgPropertyDefinitionCollection> properties = m_classDef->GetProperties();
+        MgOgcFilterUtil u;
+
+        for (int i = 0; i<properties->GetCount(); i++)
+        {
+            Ptr<MgPropertyDefinition> prop = properties->GetItem(i);
+            if (prop->GetPropertyType() == MgFeaturePropertyType::GeometricProperty)
+            {
+                STRING ogcFilter = wfsFilter;
+
+                if (wfsFilter.find(GEOM_PROP_TAG, 0) != STRING::npos)
+                {
+                    ogcFilter = MgUtil::ReplaceString(wfsFilter, GEOM_PROP_TAG.c_str(), prop->GetName().c_str());
+                }
+                if (!fdoFilterString.empty())
+                {
+                    fdoFilterString += L" OR "; //NOXLATE
+                }
+                TransformCache* itemFilter = TransformCache::GetLayerToMapTransform(m_transformCache, m_className, m_fs, m_mapCs, &fact, m_featSvc, true);
+                Ptr<MgCoordinateSystemTransform> transFilter = itemFilter ? itemFilter->GetMgTransform() : NULL;
+                fdoFilterString += u.Ogc2FdoFilter(ogcFilter, transFilter, prop->GetName(), properties);
+            }
+        }
+
+        options->SetFilter(fdoFilterString);
+    }
+
+    if (!sortCriteria.empty())
+    {
+        Ptr<MgStringCollection> orderByProperties = new MgStringCollection();
+        int orderOption = MgOrderingOption::Ascending;
+
+        STRING sSortCriteria = sortCriteria;
+        STRING::size_type pos = sSortCriteria.find_last_of(L" ");
+        if (pos != STRING::npos)
+        {
+            STRING sSortByProperty = sSortCriteria.substr(0, pos);
+            orderByProperties->Add(sSortByProperty);
+
+            STRING sSortOption = MgUtil::ToUpper(sSortCriteria.substr(pos + 1));
+            if (sSortOption == L"D")
+            {
+                orderOption = MgOrderingOption::Descending;
+            }
+        }
+        else
+        {
+            orderByProperties->Add(sortCriteria);
+        }
+
+        options->SetOrderingFilter(orderByProperties, orderOption);
+    }
+    return true;
+}
+
+MgClassDefinition* MgWfsQueryAdapter::GetClassDefinition()
+{
+    return SAFE_ADDREF(m_classDef.p);
+}
+
+MgCoordinateSystemTransform* MgWfsQueryAdapter::GetTransform()
+{
+    return SAFE_ADDREF(m_xform.p);
+}
+
+MgCoordinateSystem* MgWfsQueryAdapter::GetMapCs()
+{
+    return SAFE_ADDREF(m_mapCs.p);
+}
+
+MgFeatureReader* MgWfsQueryAdapter::GetWfsReader()
+{
+    Ptr<MgFeatureReader> fr;
+    MG_FEATURE_SERVICE_TRY()
+    // TODO: can FeatureName be an extension name rather than a FeatureClass?
+    fr = m_featSvc->SelectFeatures(m_fs, m_className, m_options);
+    MG_FEATURE_SERVICE_CHECK_CONNECTION_CATCH_AND_THROW(m_fs, L"MgWfsQueryAdapter.GetWfsReader")
+    return fr.Detach();
+}
\ No newline at end of file

Added: sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.h
===================================================================
--- sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.h	                        (rev 0)
+++ sandbox/jng/ogc/Server/src/Services/Feature/WfsQueryAdapter.h	2017-10-06 13:49:24 UTC (rev 9243)
@@ -0,0 +1,52 @@
+//
+//  Copyright (C) 2004-2017 by Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+#ifndef _MG_WFS_QUERY_ADAPTER_H_
+#define _MG_WFS_QUERY_ADAPTER_H_
+
+class MgServerFeatureService;
+
+// This is a helper class that contains most of the boilerplate for translating WFS GetFeature request parameters
+// to our feature service queries
+class MgWfsQueryAdapter 
+{
+public:
+    MgWfsQueryAdapter(MgServerFeatureService* featSvc);
+    ~MgWfsQueryAdapter();
+    bool SetOptions(MgResourceIdentifier* fs,
+                    CREFSTRING featureClass,
+                    MgStringCollection* propNames,
+                    CREFSTRING srs,
+                    CREFSTRING wfsFilter,
+                    CREFSTRING sortCriteria);
+    MgFeatureReader* GetWfsReader();
+    MgCoordinateSystem* GetMapCs();
+    MgCoordinateSystemTransform* GetTransform();
+    MgClassDefinition* GetClassDefinition();
+
+private:
+    Ptr<MgClassDefinition> m_classDef;
+    Ptr<MgResourceIdentifier> m_fs;
+    Ptr<MgFeatureQueryOptions> m_options;
+    Ptr<MgServerFeatureService> m_featSvc;
+    Ptr<MgCoordinateSystem> m_mapCs;
+    Ptr<MgCoordinateSystemTransform> m_xform;
+    STRING m_className;
+    TransformCacheMap m_transformCache;
+};
+
+#endif
\ No newline at end of file

Modified: sandbox/jng/ogc/Web/src/HttpHandler/HttpWfsGetFeature.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/HttpWfsGetFeature.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Web/src/HttpHandler/HttpWfsGetFeature.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -297,10 +297,11 @@
                                 // NOTE: This API doesn't accept WFS version, format and XML namepaces because these are GML-isms baked into the GetWfsFeature API itself, making
                                 // it unsuitable for non-GML output, hence the need for this new GetWfsReader API
                                 Ptr<MgFeatureReader> fr = featureService->GetWfsReader(featureSourceId, ((sSchemaHash.size() == 0) ? sClass : sSchemaHash + _(":") + sClass),
-                                    requiredProperties, m_getFeatureParams->GetSrs(), filter, numFeaturesToRetrieve - 1, sSortCriteria);
+                                    requiredProperties, m_getFeatureParams->GetSrs(), filter, sSortCriteria);
                                 
                                 //MgByteSource owns this and will clean it up when done
-                                ByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(fr, MgMimeType::Json, true, false, -1);
+                                MgReaderByteSourceImpl* bsImpl = new MgReaderByteSourceImpl(fr, MgMimeType::Json, true, false, -1);
+                                bsImpl->SetMaxFeatures(numFeaturesToRetrieve - 1);
                                 Ptr<MgByteSource> bs = new MgByteSource(bsImpl);
                                 resultReader = bs->GetReader();
                             }

Modified: sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.cpp
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.cpp	2017-10-06 13:49:24 UTC (rev 9243)
@@ -18,6 +18,8 @@
 #include "PlatformBase.h"
 
 MgReaderByteSourceImpl::MgReaderByteSourceImpl(MgReader* reader, CREFSTRING format, bool bCleanJson, bool bEnablePrecision, INT32 precision)
+    : m_maxFeatures(-1),
+      m_featureIndex(-1)
 {
     m_reader = SAFE_ADDREF(reader);
     m_format = format;
@@ -40,6 +42,24 @@
     m_reader = NULL;
 }
 
+void MgReaderByteSourceImpl::SetMaxFeatures(INT32 maxFeatures)
+{
+    m_maxFeatures = maxFeatures;
+}
+
+bool MgReaderByteSourceImpl::ReadNextInternal()
+{
+    if (m_maxFeatures < 0 || m_featureIndex < m_maxFeatures)
+    {
+        m_featureIndex++;
+        return m_reader->ReadNext();
+    }
+    else
+    {
+        return false;
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 /// \brief
 /// Reads a buffer
@@ -161,7 +181,7 @@
 
     if (m_bInternalReaderHasMore && bAdvanceReader)
     {
-        m_bInternalReaderHasMore = m_reader->ReadNext();
+        m_bInternalReaderHasMore = ReadNextInternal();
         if (m_bInternalReaderHasMore)
         {
             if (m_format == MgMimeType::Json)

Modified: sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.h
===================================================================
--- sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.h	2017-10-02 22:12:57 UTC (rev 9242)
+++ sandbox/jng/ogc/Web/src/HttpHandler/ReaderByteSourceImpl.h	2017-10-06 13:49:24 UTC (rev 9243)
@@ -80,7 +80,10 @@
     ///
     virtual void Rewind();
 
+    void SetMaxFeatures(INT32 maxFeatures);
+
 private:
+    bool ReadNextInternal();
     INT32 ReadInternalBuffer(BYTE_ARRAY_OUT buffer, INT32 fromIndex, INT32 length);
 
     Ptr<MgReader> m_reader;
@@ -90,6 +93,8 @@
     bool m_bInternalReaderHasMore;
     bool m_bFirstRecord;
     bool m_bEnablePrecision;
+    INT32 m_maxFeatures;
+    INT32 m_featureIndex;
 
     std::string m_buf;
     INT32 m_bufOffset;



More information about the mapguide-commits mailing list