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 );
54 networkRequest.
setAuthCfg( mSharedData->mAuthCfg );
56 switch ( networkRequest.
get( request ) )
72 auto rootContent = json::parse( content.
content().toStdString() );
73 if ( !rootContent.contains(
"value" ) )
75 appendError(
QgsErrorMessage( tr(
"No 'value' array in response" ), u
"SensorThings"_s ) );
79 bool foundMatchingEntity =
false;
80 for (
const auto &valueJson : rootContent[
"value"] )
82 if ( valueJson.contains(
"name" ) && valueJson.contains(
"url" ) )
84 const QString name = QString::fromStdString( valueJson[
"name"].get<std::string>() );
86 if ( entityType == mSharedData->mEntityType )
88 const QString url = QString::fromStdString( valueJson[
"url"].get<std::string>() );
91 foundMatchingEntity =
true;
92 mSharedData->mEntityBaseUri = url;
100 ( void ) mSharedData->featureCount();
106 if ( !foundMatchingEntity )
108 switch ( mSharedData->mEntityType )
124 appendError(
QgsErrorMessage( tr(
"MultiDatastreams are not supported by this connection" ), u
"SensorThings"_s ) );
132 catch (
const json::parse_error &ex )
134 appendError(
QgsErrorMessage( tr(
"Error parsing response: %1" ).arg( ex.what() ), u
"SensorThings"_s ) );
141QString QgsSensorThingsProvider::storageType()
const
145 return u
"OGC SensorThings API"_s;
152 return new QgsSensorThingsFeatureSource( mSharedData );
159 return new QgsSensorThingsFeatureIterator(
new QgsSensorThingsFeatureSource( mSharedData ),
true, request );
166 return mSharedData->mGeometryType;
169long long QgsSensorThingsProvider::featureCount()
const
178 const long long count = mSharedData->featureCount();
179 if ( !mSharedData->error().isEmpty() )
180 pushError( mSharedData->error() );
185QgsFields QgsSensorThingsProvider::fields()
const
189 return mSharedData->mFields;
196 return mLayerMetadata;
199QString QgsSensorThingsProvider::htmlMetadata()
const
207 metadata += u
"<tr><td class=\"highlight\">"_s % tr(
"Entity Type" ) % u
"</td><td>%1"_s.arg(
qgsEnumValueToKey( mSharedData->mEntityType ) ) % u
"</td></tr>\n"_s;
208 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;
229bool QgsSensorThingsProvider::supportsSubsetString()
const
235QString QgsSensorThingsProvider::subsetStringDialect()
const
237 return tr(
"OGC SensorThings filter" );
240QString QgsSensorThingsProvider::subsetStringHelpUrl()
const
242 return u
"https://docs.ogc.org/is/18-088/18-088.html#filter"_s;
245QString QgsSensorThingsProvider::subsetString()
const
248 return mSharedData->subsetString();
251bool QgsSensorThingsProvider::setSubsetString(
const QString &subset,
bool )
255 const QString trimmedSubset = subset.trimmed();
256 if ( trimmedSubset == mSharedData->subsetString() )
261 const QString baseUri = mSharedData->mEntityBaseUri;
264 uri.
setSql( trimmedSubset );
265 setDataSourceUri( uri.
uri(
false ) );
267 mSharedData->mEntityBaseUri = baseUri;
276void QgsSensorThingsProvider::setDataSourceUri(
const QString &uri )
280 mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
288 return mSharedData->mSourceCRS;
294 return mSharedData->extent();
297QString QgsSensorThingsProvider::name()
const
301 return SENSORTHINGS_PROVIDER_KEY;
304QString QgsSensorThingsProvider::providerKey()
306 return SENSORTHINGS_PROVIDER_KEY;
311 mSharedData = qobject_cast<QgsSensorThingsProvider *>( source )->mSharedData;
314QString QgsSensorThingsProvider::description()
const
316 return SENSORTHINGS_PROVIDER_DESCRIPTION;
319bool QgsSensorThingsProvider::renderInPreview(
const PreviewContext & )
325void QgsSensorThingsProvider::reloadProviderData()
328 mSharedData->clearCache();
336QgsSensorThingsProviderMetadata::QgsSensorThingsProviderMetadata()
337 :
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() );
502 const QVariantList expandToParam = parts.value( u
"expandTo"_s ).toList();
503 if ( !expandToParam.isEmpty() )
505 QStringList expandToStringList;
506 for (
const QVariant &expansion : expandToParam )
509 if ( !expansionDefinition.
isValid() )
512 expandToStringList.append( expansionDefinition.
toString() );
514 if ( !expandToStringList.isEmpty() )
516 dsUri.
setParam( u
"expandTo"_s, expandToStringList.join(
';' ) );
521 const int maxPageSizeParam = parts.value( u
"pageSize"_s ).toInt( &ok );
524 dsUri.
setParam( u
"pageSize"_s, QString::number( maxPageSizeParam ) );
528 const int featureLimitParam = parts.value( u
"featureLimit"_s ).toInt( &ok );
531 dsUri.
setParam( u
"featureLimit"_s, QString::number( featureLimitParam ) );
534 const QString geometryType = parts.value( u
"geometryType"_s ).toString();
535 if ( geometryType.compare(
"point"_L1, Qt::CaseInsensitive ) == 0 )
539 else if ( geometryType.compare(
"multipoint"_L1, Qt::CaseInsensitive ) == 0 )
543 else if ( geometryType.compare(
"line"_L1, Qt::CaseInsensitive ) == 0 )
547 else if ( geometryType.compare(
"polygon"_L1, Qt::CaseInsensitive ) == 0 )
552 if ( parts.contains( u
"bounds"_s ) && parts.value( u
"bounds"_s ).userType() == qMetaTypeId<QgsRectangle>() )
558 if ( !parts.value( u
"sql"_s ).toString().isEmpty() )
559 dsUri.
setSql( parts.value( u
"sql"_s ).toString() );
561 return dsUri.
uri(
false );
566 return new QgsSensorThingsProvider( uri, options, flags );
569QList<Qgis::LayerType> QgsSensorThingsProviderMetadata::supportedLayerTypes()
const
574QMap<QString, QgsAbstractProviderConnection *> QgsSensorThingsProviderMetadata::connections(
bool cached )
576 return connectionsProtected<QgsSensorThingsProviderConnection, QgsSensorThingsProviderConnection>( cached );
584void QgsSensorThingsProviderMetadata::deleteConnection(
const QString &name )
586 deleteConnectionProtected<QgsSensorThingsProviderConnection>( name );
591 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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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.