20#include <nlohmann/json.hpp>
34#include <QNetworkRequest>
37#include "moc_qgssensorthingsprovider.cpp"
39using namespace Qt::StringLiterals;
43QgsSensorThingsProvider::QgsSensorThingsProvider(
const QString &uri,
const ProviderOptions &options,
Qgis::DataProviderReadFlags flags )
46 mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
48 const QUrl url( QgsSensorThingsSharedData::parseUrl( mSharedData->mRootUri ) );
50 QNetworkRequest request = QNetworkRequest( url );
52 mSharedData->mHeaders.updateNetworkRequest( request );
55 networkRequest.
setAuthCfg( mSharedData->mAuthCfg );
57 switch ( networkRequest.
get( request ) )
73 auto rootContent = json::parse( content.
content().toStdString() );
74 if ( !rootContent.contains(
"value" ) )
76 appendError(
QgsErrorMessage( tr(
"No 'value' array in response" ), u
"SensorThings"_s ) );
80 bool foundMatchingEntity =
false;
81 for (
const auto &valueJson : rootContent[
"value"] )
83 if ( valueJson.contains(
"name" ) && valueJson.contains(
"url" ) )
85 const QString name = QString::fromStdString( valueJson[
"name"].get<std::string>() );
87 if ( entityType == mSharedData->mEntityType )
89 const QString url = QString::fromStdString( valueJson[
"url"].get<std::string>() );
92 foundMatchingEntity =
true;
93 mSharedData->mEntityBaseUri = url;
101 ( void ) mSharedData->featureCount();
107 if ( !foundMatchingEntity )
109 switch ( mSharedData->mEntityType )
126 appendError(
QgsErrorMessage( tr(
"MultiDatastreams are not supported by this connection" ), u
"SensorThings"_s ) );
134 catch (
const json::parse_error &ex )
136 appendError(
QgsErrorMessage( tr(
"Error parsing response: %1" ).arg( ex.what() ), u
"SensorThings"_s ) );
143QString QgsSensorThingsProvider::storageType()
const
147 return u
"OGC SensorThings API"_s;
154 return new QgsSensorThingsFeatureSource( mSharedData );
161 return new QgsSensorThingsFeatureIterator(
new QgsSensorThingsFeatureSource( mSharedData ),
true, request );
168 return mSharedData->mGeometryType;
171long long QgsSensorThingsProvider::featureCount()
const
180 const long long count = mSharedData->featureCount();
181 if ( !mSharedData->error().isEmpty() )
182 pushError( mSharedData->error() );
187QgsFields QgsSensorThingsProvider::fields()
const
191 return mSharedData->mFields;
198 return mLayerMetadata;
201QString QgsSensorThingsProvider::htmlMetadata()
const
209 metadata += u
"<tr><td class=\"highlight\">"_s % tr(
"Entity Type" ) % u
"</td><td>%1"_s.arg(
qgsEnumValueToKey( mSharedData->mEntityType ) ) % u
"</td></tr>\n"_s;
210 metadata += u
"<tr><td class=\"highlight\">"_s % tr(
"Endpoint" ) % u
"</td><td><a href=\"%1\">%1</a>"_s.arg( mSharedData->mEntityBaseUri ) % u
"</td></tr>\n"_s;
233bool QgsSensorThingsProvider::supportsSubsetString()
const
239QString QgsSensorThingsProvider::subsetStringDialect()
const
241 return tr(
"OGC SensorThings filter" );
244QString QgsSensorThingsProvider::subsetStringHelpUrl()
const
246 return u
"https://docs.ogc.org/is/18-088/18-088.html#filter"_s;
249QString QgsSensorThingsProvider::subsetString()
const
252 return mSharedData->subsetString();
255bool QgsSensorThingsProvider::setSubsetString(
const QString &subset,
bool )
259 const QString trimmedSubset = subset.trimmed();
260 if ( trimmedSubset == mSharedData->subsetString() )
265 const QString baseUri = mSharedData->mEntityBaseUri;
268 uri.
setSql( trimmedSubset );
269 setDataSourceUri( uri.
uri(
false ) );
271 mSharedData->mEntityBaseUri = baseUri;
280void QgsSensorThingsProvider::setDataSourceUri(
const QString &uri )
284 mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
292 return mSharedData->mSourceCRS;
298 return mSharedData->extent();
301QString QgsSensorThingsProvider::name()
const
305 return SENSORTHINGS_PROVIDER_KEY;
308QString QgsSensorThingsProvider::providerKey()
310 return SENSORTHINGS_PROVIDER_KEY;
315 mSharedData = qobject_cast<QgsSensorThingsProvider *>( source )->mSharedData;
318QString QgsSensorThingsProvider::description()
const
320 return SENSORTHINGS_PROVIDER_DESCRIPTION;
323bool QgsSensorThingsProvider::renderInPreview(
const PreviewContext & )
329void QgsSensorThingsProvider::reloadProviderData()
332 mSharedData->clearCache();
340QgsSensorThingsProviderMetadata::QgsSensorThingsProviderMetadata():
341 QgsProviderMetadata( QgsSensorThingsProvider::SENSORTHINGS_PROVIDER_KEY, QgsSensorThingsProvider::SENSORTHINGS_PROVIDER_DESCRIPTION )
345QIcon QgsSensorThingsProviderMetadata::icon()
const
350QList<QgsDataItemProvider *> QgsSensorThingsProviderMetadata::dataItemProviders()
const
352 return {
new QgsSensorThingsDataItemProvider() };
355QVariantMap QgsSensorThingsProviderMetadata::decodeUri(
const QString &uri )
const
359 QVariantMap components;
360 components.insert( u
"url"_s, dsUri.
param( u
"url"_s ) );
364 components.insert( u
"authcfg"_s, dsUri.
authConfigId() );
368 components.insert( u
"username"_s, dsUri.
username() );
372 components.insert( u
"password"_s, dsUri.
password() );
380 if ( !dsUri.
param( u
"referer"_s ).isEmpty() )
382 components.insert( u
"referer"_s, dsUri.
param( u
"referer"_s ) );
384 if ( !dsUri.
param( u
"http-header:referer"_s ).isEmpty() )
386 components.insert( u
"referer"_s, dsUri.
param( u
"http-header:referer"_s ) );
389 const QString entityParam = dsUri.
param( u
"entity"_s );
397 const QStringList expandToParam = dsUri.
param( u
"expandTo"_s ).split(
';', Qt::SkipEmptyParts );
398 if ( !expandToParam.isEmpty() )
400 QVariantList expandParts;
401 for (
const QString &expandString : expandToParam )
406 expandParts.append( QVariant::fromValue( definition ) );
409 if ( !expandParts.isEmpty() )
411 components.insert( u
"expandTo"_s, expandParts );
416 const int maxPageSizeParam = dsUri.
param( u
"pageSize"_s ).toInt( &ok );
419 components.insert( u
"pageSize"_s, maxPageSizeParam );
423 const int featureLimitParam = dsUri.
param( u
"featureLimit"_s ).toInt( &ok );
426 components.insert( u
"featureLimit"_s, featureLimitParam );
433 components.insert( u
"geometryType"_s, u
"multipoint"_s );
435 components.insert( u
"geometryType"_s, u
"point"_s );
438 components.insert( u
"geometryType"_s, u
"line"_s );
441 components.insert( u
"geometryType"_s, u
"polygon"_s );
449 const QStringList bbox = dsUri.
param( u
"bbox"_s ).split(
',' );
450 if ( bbox.size() == 4 )
461 if ( xminOk && yminOk && xmaxOk && ymaxOk )
462 components.insert( u
"bounds"_s, r );
465 if ( !dsUri.
sql().isEmpty() )
466 components.insert( u
"sql"_s, dsUri.
sql() );
471QString QgsSensorThingsProviderMetadata::encodeUri(
const QVariantMap &parts )
const
474 dsUri.
setParam( u
"url"_s, parts.value( u
"url"_s ).toString() );
476 if ( !parts.value( u
"authcfg"_s ).toString().isEmpty() )
480 if ( !parts.value( u
"username"_s ).toString().isEmpty() )
482 dsUri.
setUsername( parts.value( u
"username"_s ).toString() );
484 if ( !parts.value( u
"password"_s ).toString().isEmpty() )
486 dsUri.
setPassword( parts.value( u
"password"_s ).toString() );
488 if ( !parts.value( u
"referer"_s ).toString().isEmpty() )
490 dsUri.
setParam( u
"referer"_s, parts.value( u
"referer"_s ).toString() );
494 parts.value( u
"entity"_s ).toString() );
504 const QVariantList expandToParam = parts.value( u
"expandTo"_s ).toList();
505 if ( !expandToParam.isEmpty() )
507 QStringList expandToStringList;
508 for (
const QVariant &expansion : expandToParam )
511 if ( !expansionDefinition.
isValid() )
514 expandToStringList.append( expansionDefinition.
toString() );
516 if ( !expandToStringList.isEmpty() )
518 dsUri.
setParam( u
"expandTo"_s, expandToStringList.join(
';' ) );
523 const int maxPageSizeParam = parts.value( u
"pageSize"_s ).toInt( &ok );
526 dsUri.
setParam( u
"pageSize"_s, QString::number( maxPageSizeParam ) );
530 const int featureLimitParam = parts.value( u
"featureLimit"_s ).toInt( &ok );
533 dsUri.
setParam( u
"featureLimit"_s, QString::number( featureLimitParam ) );
536 const QString geometryType = parts.value( u
"geometryType"_s ).toString();
537 if ( geometryType.compare(
"point"_L1, Qt::CaseInsensitive ) == 0 )
541 else if ( geometryType.compare(
"multipoint"_L1, Qt::CaseInsensitive ) == 0 )
545 else if ( geometryType.compare(
"line"_L1, Qt::CaseInsensitive ) == 0 )
549 else if ( geometryType.compare(
"polygon"_L1, Qt::CaseInsensitive ) == 0 )
554 if ( parts.contains( u
"bounds"_s ) && parts.value( u
"bounds"_s ).userType() == qMetaTypeId<QgsRectangle>() )
560 if ( !parts.value( u
"sql"_s ).toString().isEmpty() )
561 dsUri.
setSql( parts.value( u
"sql"_s ).toString() );
563 return dsUri.
uri(
false );
568 return new QgsSensorThingsProvider( uri, options, flags );
571QList<Qgis::LayerType> QgsSensorThingsProviderMetadata::supportedLayerTypes()
const
576QMap<QString, QgsAbstractProviderConnection *> QgsSensorThingsProviderMetadata::connections(
bool cached )
578 return connectionsProtected<QgsSensorThingsProviderConnection, QgsSensorThingsProviderConnection>( cached );
586void QgsSensorThingsProviderMetadata::deleteConnection(
const QString &name )
588 deleteConnectionProtected<QgsSensorThingsProviderConnection>( name );
593 saveConnectionProtected( connection, name );
@ SelectAtId
Fast access to features using their ID.
@ ReloadData
Provider is able to force reload data.
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
QFlags< DataProviderFlag > DataProviderFlags
Data provider flags.
@ FastExtent2D
Provider's 2D extent retrieval via QgsDataProvider::extent() is always guaranteed to be trivial/fast ...
SensorThingsEntity
OGC SensorThings API entity types.
@ Sensor
A Sensor is an instrument that observes a property or phenomenon with the goal of producing an estima...
@ MultiDatastream
A MultiDatastream groups a collection of Observations and the Observations in a MultiDatastream have ...
@ ObservedProperty
An ObservedProperty specifies the phenomenon of an Observation.
@ Invalid
An invalid/unknown entity.
@ FeatureOfInterest
In the context of the Internet of Things, many Observations’ FeatureOfInterest can be the Location of...
@ Datastream
A Datastream groups a collection of Observations measuring the same ObservedProperty and produced by ...
@ Observation
An Observation is the act of measuring or otherwise determining the value of a property.
@ Location
A Location entity locates the Thing or the Things it associated with. A Thing’s Location entity is de...
@ Thing
A Thing is an object of the physical world (physical things) or the information world (virtual things...
@ HistoricalLocation
A Thing’s HistoricalLocation entity set provides the times of the current (i.e., last known) and prev...
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
QFlags< VectorProviderCapability > VectorProviderCapabilities
Vector data provider capabilities.
@ SkipFeatureCount
Make featureCount() return -1 to indicate unknown, and subLayers() to return a unknown feature count ...
WkbType
The WKB type describes the number of dimensions a geometry has.
@ MultiPointZ
MultiPointZ.
@ MultiLineStringZ
MultiLineStringZ.
@ MultiPolygonZ
MultiPolygonZ.
Base class that can be used for any class that is capable of returning features.
An interface for data provider connections.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
void setAuthCfg(const QString &authCfg)
Sets the authentication config id which should be used during the request.
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
@ NetworkError
A network error occurred.
@ ServerExceptionError
An exception was raised by the server.
@ NoError
No error was encountered.
@ TimeoutError
Timeout was reached before a reply was received.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
Represents a coordinate reference system (CRS).
virtual void setDataSourceUri(const QString &uri)
Set the data source specification.
Stores the component parts of a data source URI (e.g.
void setSql(const QString &sql)
Sets the sql filter for the URI.
void setAuthConfigId(const QString &authcfg)
Sets the authentication configuration ID for the URI.
QString uri(bool expandAuthConfig=true) const
Returns the complete URI as a string.
void setUsername(const QString &username)
Sets the username for the URI.
QString param(const QString &key) const
Returns a generic parameter value corresponding to the specified key.
QString username() const
Returns the username stored in the URI.
Qgis::WkbType wkbType() const
Returns the WKB type associated with the URI.
void setWkbType(Qgis::WkbType type)
Sets the WKB type associated with the URI.
void setParam(const QString &key, const QString &value)
Sets a generic parameter value on the URI.
QString password() const
Returns the password stored in the URI.
QString authConfigId() const
Returns any associated authentication configuration ID stored in the URI.
QString sql() const
Returns the SQL filter stored in the URI, if set.
void setPassword(const QString &password)
Sets the password for the URI.
Represents a single error message.
Wrapper for iterator of features from vector data provider or vector layer.
Wraps a request for features to a vector layer (or directly its vector data provider).
Container of fields for a vector layer.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QByteArray content() const
Returns the reply content.
A convenience class that simplifies locking and unlocking QReadWriteLocks.
A rectangle specified with double values.
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
Encapsulates information about how relationships in a SensorThings API service should be expanded.
static QgsSensorThingsExpansionDefinition fromString(const QString &string)
Returns a QgsSensorThingsExpansionDefinition from a string representation.
QString toString() const
Returns a string encapsulation of the expansion definition.
bool isValid() const
Returns true if the definition is valid.
Represents connections to SensorThings data sources.
static Qgis::SensorThingsEntity stringToEntity(const QString &type)
Converts a string value to a Qgis::SensorThingsEntity type.
static Qgis::SensorThingsEntity entitySetStringToEntity(const QString &type)
Converts a string value corresponding to a SensorThings entity set to a Qgis::SensorThingsEntity type...
Base class for vector data providers.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Q_INVOKABLE bool isMultiType(Qgis::WkbType type)
Returns true if the WKB type is a multi type.
@ UnknownCount
Provider returned an unknown feature count.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
#define QgsSetRequestInitiatorClass(request, _class)
#define QGIS_PROTECT_QOBJECT_THREAD_ACCESS
Setting options for creating vector data providers.