/* * AddLayer() */ void OGRNGWDataset::AddLayer( const CPLJSONObject &oResourceJsonObject, char **papszOptions, int nOpenFlagsIn ) { std::string osLayerResourceId; if( nOpenFlagsIn & GDAL_OF_VECTOR ) { OGRNGWLayer *poLayer = new OGRNGWLayer( this, oResourceJsonObject ); papoLayers = (OGRNGWLayer**) CPLRealloc(papoLayers, (nLayers + 1) * sizeof(OGRNGWLayer*)); papoLayers[nLayers++] = poLayer; osLayerResourceId = poLayer->GetResourceId(); } else { osLayerResourceId = oResourceJsonObject.GetString("resource/id"); } // Check styles exist and add them as rasters. if( nOpenFlagsIn & GDAL_OF_RASTER && oResourceJsonObject.GetBool( "resource/children", false ) ) { CPLJSONDocument oResourceChildReq; bool bResult = oResourceChildReq.LoadUrl( NGWAPI::GetChildren( osUrl, osLayerResourceId ), papszOptions ); if( bResult ) { CPLJSONArray oChildren( oResourceChildReq.GetRoot() ); for( int i = 0; i < oChildren.Size(); ++i ) { AddRaster( oChildren[i], papszOptions ); } } } }
/* * FillResources() */ bool OGRNGWDataset::FillResources( char **papszOptions, int nOpenFlagsIn ) { CPLJSONDocument oResourceDetailsReq; bool bResult = oResourceDetailsReq.LoadUrl( NGWAPI::GetChildren( osUrl, osResourceId ), papszOptions ); if( bResult ) { CPLJSONArray oChildren(oResourceDetailsReq.GetRoot()); for( int i = 0; i < oChildren.Size(); ++i ) { CPLJSONObject oChild = oChildren[i]; std::string osResourceType = oChild.GetString("resource/cls"); if( (osResourceType == "vector_layer" || osResourceType == "postgis_layer") ) { // Add vector layer. If failed, try next layer. AddLayer( oChild, papszOptions, nOpenFlagsIn ); } else if( (osResourceType == "raster_layer" || osResourceType == "wmsclient_layer") && nOpenFlagsIn & GDAL_OF_RASTER ) { AddRaster( oChild, papszOptions ); } // TODO: Add support for baselayers, webmap, wfsserver_service, wmsserver_service. } } return bResult; }
/* * AddRaster() */ void OGRNGWDataset::AddRaster( const CPLJSONObject &oRasterJsonObj, char **papszOptions ) { std::string osOutResourceId; std::string osOutResourceName; std::string osResourceType = oRasterJsonObj.GetString( "resource/cls" ); if( osResourceType == "mapserver_style" || osResourceType == "qgis_vector_style" || osResourceType == "raster_style" || osResourceType == "wmsclient_layer" ) { osOutResourceId = oRasterJsonObj.GetString( "resource/id" ); osOutResourceName = oRasterJsonObj.GetString( "resource/display_name" ); } else if( osResourceType == "raster_layer" ) { std::string osRasterResourceId = oRasterJsonObj.GetString( "resource/id" ); CPLJSONDocument oResourceRequest; bool bResult = oResourceRequest.LoadUrl( NGWAPI::GetChildren( osUrl, osRasterResourceId ), papszOptions ); if( bResult ) { CPLJSONArray oChildren(oResourceRequest.GetRoot()); for( int i = 0; i < oChildren.Size(); ++i ) { CPLJSONObject oChild = oChildren[i]; osResourceType = oChild.GetString("resource/cls"); if( osResourceType == "raster_style" ) { AddRaster( oChild, papszOptions ); } } } } if( !osOutResourceId.empty() ) { if( osOutResourceName.empty() ) { osOutResourceName = "raster_" + osOutResourceId; } CPLDebug("NGW", "Add raster %s: %s", osOutResourceId.c_str(), osOutResourceName.c_str()); GDALDataset::SetMetadataItem( CPLSPrintf("SUBDATASET_%d_NAME", nRasters), CPLSPrintf("NGW:%s/resource/%s", osUrl.c_str(), osOutResourceId.c_str()), "SUBDATASETS" ); GDALDataset::SetMetadataItem( CPLSPrintf("SUBDATASET_%d_DESC", nRasters), osOutResourceName.c_str(), "SUBDATASETS" ); nRasters++; } }
/* * FillCapabilities() */ void OGRNGWDataset::FillCapabilities( char **papszOptions ) { CPLJSONDocument oRouteReq; if( oRouteReq.LoadUrl( NGWAPI::GetRoute(osUrl), papszOptions ) ) { CPLJSONObject oRoot = oRouteReq.GetRoot(); if( oRoot.IsValid() ) { // TODO: check bHasFeaturePaging } } }
bool ConnectionFactory::createRemoteConnection(const enum ngsCatalogObjectType type, const std::string &path, const Options &options) { switch(type) { case CAT_CONTAINER_NGW: { std::string url = options.asString(KEY_URL); if(url.empty()) { return errorMessage(_("Missing required option 'url'")); } std::string login = options.asString(KEY_LOGIN); if(login.empty()) { login = "******"; } else { std::string oldLogin(login); login = CPLString(login).Trim(); if(!compare(oldLogin, login, true)) { warningMessage("Login was trimmed!"); } } std::string password = options.asString(KEY_PASSWORD); bool isGuest = options.asBool(KEY_IS_GUEST); CPLJSONDocument connectionFile; CPLJSONObject root = connectionFile.GetRoot(); root.Add(KEY_TYPE, type); root.Add(KEY_URL, url); root.Add(KEY_LOGIN, login); root.Add(KEY_IS_GUEST, isGuest); if(!password.empty()) { root.Add(KEY_PASSWORD, encrypt(password)); } return connectionFile.Save(path); } default: return errorMessage(_("Unsupported connection type %d"), type); } }
TEST(StoreTests, TestJSONSAXPArser) { char** options = nullptr; options = ngsListAddNameValue(options, "DEBUG_MODE", "ON"); options = ngsListAddNameValue(options, "SETTINGS_DIR", ngsFormFileName(ngsGetCurrentDirectory(), "tmp", nullptr)); EXPECT_EQ(ngsInit(options), COD_SUCCESS); ngsListFree(options); options = nullptr; options = ngsListAddNameValue(options, "MAX_RETRY", "20"); options = ngsListAddNameValue(options, "RETRY_DELAY", "5"); options = ngsListAddNameValue(options, "UNSAFESSL", "ON"); counter = 0; CPLJSONDocument doc; EXPECT_EQ(doc.LoadUrl("http://demo.nextgis.com/api/component/pyramid/pkg_version", options, ngsGDALProgressFunc, nullptr), true); ngsListFree(options); CPLJSONObject obj = doc.GetRoot(); CPLString ngwVersion = obj.GetString("nextgisweb", "0"); EXPECT_STRNE(ngwVersion, "0"); }
/* * Init() */ bool OGRNGWDataset::Init(int nOpenFlagsIn) { // NOTE: Skip check API version at that moment. We expected API v3. // Get resource details. CPLJSONDocument oResourceDetailsReq; char **papszHTTPOptions = GetHeaders(); bool bResult = oResourceDetailsReq.LoadUrl( NGWAPI::GetResource( osUrl, osResourceId ), papszHTTPOptions ); CPLDebug("NGW", "Get resource %s details %s", osResourceId.c_str(), bResult ? "success" : "failed"); if( bResult ) { CPLJSONObject oRoot = oResourceDetailsReq.GetRoot(); if( oRoot.IsValid() ) { std::string osResourceType = oRoot.GetString("resource/cls"); FillMetadata( oRoot ); if( osResourceType == "resource_group" ) { // Check feature paging. FillCapabilities( papszHTTPOptions ); if( oRoot.GetBool( "resource/children", false ) ) { // Get child resources. bResult = FillResources( papszHTTPOptions, nOpenFlagsIn ); } } else if( (osResourceType == "vector_layer" || osResourceType == "postgis_layer") ) { // Cehck feature paging. FillCapabilities( papszHTTPOptions ); // Add vector layer. AddLayer( oRoot, papszHTTPOptions, nOpenFlagsIn ); } else if( osResourceType == "mapserver_style" || osResourceType == "qgis_vector_style" || osResourceType == "raster_style" || osResourceType == "wmsclient_layer" ) { // GetExtent from parent. OGREnvelope stExtent; std::string osParentId = oRoot.GetString("resource/parent/id"); bool bExtentResult = NGWAPI::GetExtent(osUrl, osParentId, papszHTTPOptions, 3857, stExtent); if( !bExtentResult ) { // Set full extent for EPSG:3857. stExtent.MinX = -20037508.34; stExtent.MaxX = 20037508.34; stExtent.MinY = -20037508.34; stExtent.MaxY = 20037508.34; } CPLDebug("NGW", "Raster extent is: %f, %f, %f, %f", stExtent.MinX, stExtent.MinY, stExtent.MaxX, stExtent.MaxY); int nEPSG = 3857; // Get parent details. We can skip this as default SRS in NGW is 3857. if( osResourceType == "wmsclient_layer" ) { nEPSG = oRoot.GetInteger("wmsclient_layer/srs/id", nEPSG); } else { CPLJSONDocument oResourceReq; bResult = oResourceReq.LoadUrl( NGWAPI::GetResource( osUrl, osResourceId ), papszHTTPOptions ); if( bResult ) { CPLJSONObject oParentRoot = oResourceReq.GetRoot(); if( osResourceType == "mapserver_style" || osResourceType == "qgis_vector_style" ) { nEPSG = oParentRoot.GetInteger("vector_layer/srs/id", nEPSG); } else if( osResourceType == "raster_style") { nEPSG = oParentRoot.GetInteger("raster_layer/srs/id", nEPSG); } } } // Create raster dataset. std::string osRasterUrl = NGWAPI::GetTMS(osUrl, osResourceId); char* pszRasterUrl = CPLEscapeString(osRasterUrl.c_str(), -1, CPLES_XML); const char *pszConnStr = CPLSPrintf("<GDAL_WMS><Service name=\"TMS\">" "<ServerUrl>%s</ServerUrl></Service><DataWindow>" "<UpperLeftX>-20037508.34</UpperLeftX><UpperLeftY>20037508.34</UpperLeftY>" "<LowerRightX>20037508.34</LowerRightX><LowerRightY>-20037508.34</LowerRightY>" "<TileLevel>%d</TileLevel><TileCountX>1</TileCountX>" "<TileCountY>1</TileCountY><YOrigin>top</YOrigin></DataWindow>" "<Projection>EPSG:%d</Projection><BlockSizeX>256</BlockSizeX>" "<BlockSizeY>256</BlockSizeY><BandsCount>%d</BandsCount>" "<Cache><Type>file</Type><Expires>%d</Expires><MaxSize>%d</MaxSize>" "</Cache><ZeroBlockHttpCodes>204,404</ZeroBlockHttpCodes></GDAL_WMS>", pszRasterUrl, 22, // NOTE: We have no limit in zoom levels. nEPSG, // NOTE: Default SRS is EPSG:3857. 4, nCacheExpires, nCacheMaxSize); CPLFree( pszRasterUrl ); poRasterDS = reinterpret_cast<GDALDataset*>(GDALOpenEx(pszConnStr, GDAL_OF_READONLY | GDAL_OF_RASTER | GDAL_OF_INTERNAL, nullptr, nullptr, nullptr)); if( poRasterDS ) { bResult = true; nRasterXSize = poRasterDS->GetRasterXSize(); nRasterYSize = poRasterDS->GetRasterYSize(); for( int iBand = 1; iBand <= poRasterDS->GetRasterCount(); iBand++ ) { SetBand( iBand, new NGWWrapperRasterBand( poRasterDS->GetRasterBand( iBand )) ); } // Set pixel limits. bool bHasTransform = false; double geoTransform[6] = { 0.0 }; double invGeoTransform[6] = { 0.0 }; if(poRasterDS->GetGeoTransform(geoTransform) == CE_None) { bHasTransform = GDALInvGeoTransform(geoTransform, invGeoTransform) == TRUE; } if(bHasTransform) { GDALApplyGeoTransform(invGeoTransform, stExtent.MinX, stExtent.MinY, &stPixelExtent.MinX, &stPixelExtent.MaxY); GDALApplyGeoTransform(invGeoTransform, stExtent.MaxX, stExtent.MaxY, &stPixelExtent.MaxX, &stPixelExtent.MinY); CPLDebug("NGW", "Raster extent in px is: %f, %f, %f, %f", stPixelExtent.MinX, stPixelExtent.MinY, stPixelExtent.MaxX, stPixelExtent.MaxY); } else { stPixelExtent.MinX = 0.0; stPixelExtent.MinY = 0.0; stPixelExtent.MaxX = std::numeric_limits<double>::max(); stPixelExtent.MaxY = std::numeric_limits<double>::max(); } } else { bResult = false; } } else if( osResourceType == "raster_layer" ) //FIXME: Do we need this check? && nOpenFlagsIn & GDAL_OF_RASTER ) { AddRaster( oRoot, papszHTTPOptions ); } else { bResult = false; } // TODO: Add support for baselayers, webmap, wfsserver_service, wmsserver_service. } } CSLDestroy( papszHTTPOptions ); return bResult; }
bool ConnectionFactory::checkRemoteConnection(const enum ngsCatalogObjectType type, const Options &options) { resetError(); switch(type) { case CAT_CONTAINER_NGW: { std::string url = options.asString(KEY_URL); if(url.empty()) { return errorMessage(_("Missing required option 'url'")); } std::string login = options.asString(KEY_LOGIN); if(login.empty()) { login = "******"; } else { std::string oldLogin(login); login = CPLString(login).Trim(); if(!compare(oldLogin, login, true)) { warningMessage("Login was trimmed!"); } } std::string password = options.asString(KEY_PASSWORD); CPLStringList requestOptions; std::string headers = "Accept: */*"; Options authOptions; authOptions.add(KEY_TYPE, "basic"); authOptions.add(KEY_LOGIN, login); authOptions.add(KEY_PASSWORD, password); AuthStore::authAdd(url, authOptions); std::string auth = AuthStore::authHeader(url); AuthStore::authRemove(url); if(!auth.empty()) { headers += "\r\n"; headers += auth; } requestOptions.AddNameValue("HEADERS", headers.c_str()); CPLJSONDocument checkReq; if(!checkReq.LoadUrl(ngw::getCurrentUserUrl(url), requestOptions)) { return errorMessage(CPLGetLastErrorMsg()); } CPLJSONObject root = checkReq.GetRoot(); if(!root.IsValid()) { return errorMessage(_("Response is invalid")); } if(root.GetString("keyname") == login) { return true; } return errorMessage(_("User '%s' failed to connect to %s."), login.c_str(), url.c_str()); } default: return errorMessage(_("Unsupported connection type %d"), type); } }