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 )
340QIcon QgsSensorThingsProviderMetadata::icon()
const
345QList<QgsDataItemProvider *> QgsSensorThingsProviderMetadata::dataItemProviders()
const
347 return {
new QgsSensorThingsDataItemProvider() };
350QVariantMap QgsSensorThingsProviderMetadata::decodeUri(
const QString &uri )
const
354 QVariantMap components;
355 components.insert( u
"url"_s, dsUri.
param( u
"url"_s ) );
359 components.insert( u
"authcfg"_s, dsUri.
authConfigId() );
363 components.insert( u
"username"_s, dsUri.
username() );
367 components.insert( u
"password"_s, dsUri.
password() );
375 if ( !dsUri.
param( u
"referer"_s ).isEmpty() )
377 components.insert( u
"referer"_s, dsUri.
param( u
"referer"_s ) );
379 if ( !dsUri.
param( u
"http-header:referer"_s ).isEmpty() )
381 components.insert( u
"referer"_s, dsUri.
param( u
"http-header:referer"_s ) );
384 const QString entityParam = dsUri.
param( u
"entity"_s );
392 const QStringList expandToParam = dsUri.
param( u
"expandTo"_s ).split(
';', Qt::SkipEmptyParts );
393 if ( !expandToParam.isEmpty() )
395 QVariantList expandParts;
396 for (
const QString &expandString : expandToParam )
401 expandParts.append( QVariant::fromValue( definition ) );
404 if ( !expandParts.isEmpty() )
406 components.insert( u
"expandTo"_s, expandParts );
411 const int maxPageSizeParam = dsUri.
param( u
"pageSize"_s ).toInt( &ok );
414 components.insert( u
"pageSize"_s, maxPageSizeParam );
418 const int featureLimitParam = dsUri.
param( u
"featureLimit"_s ).toInt( &ok );
421 components.insert( u
"featureLimit"_s, featureLimitParam );
428 components.insert( u
"geometryType"_s, u
"multipoint"_s );
430 components.insert( u
"geometryType"_s, u
"point"_s );
433 components.insert( u
"geometryType"_s, u
"line"_s );
436 components.insert( u
"geometryType"_s, u
"polygon"_s );
444 const QStringList bbox = dsUri.
param( u
"bbox"_s ).split(
',' );
445 if ( bbox.size() == 4 )
456 if ( xminOk && yminOk && xmaxOk && ymaxOk )
457 components.insert( u
"bounds"_s, r );
460 if ( !dsUri.
sql().isEmpty() )
461 components.insert( u
"sql"_s, dsUri.
sql() );
466QString QgsSensorThingsProviderMetadata::encodeUri(
const QVariantMap &parts )
const
469 dsUri.
setParam( u
"url"_s, parts.value( u
"url"_s ).toString() );
471 if ( !parts.value( u
"authcfg"_s ).toString().isEmpty() )
475 if ( !parts.value( u
"username"_s ).toString().isEmpty() )
477 dsUri.
setUsername( parts.value( u
"username"_s ).toString() );
479 if ( !parts.value( u
"password"_s ).toString().isEmpty() )
481 dsUri.
setPassword( parts.value( u
"password"_s ).toString() );
483 if ( !parts.value( u
"referer"_s ).toString().isEmpty() )
485 dsUri.
setParam( u
"referer"_s, parts.value( u
"referer"_s ).toString() );
497 const QVariantList expandToParam = parts.value( u
"expandTo"_s ).toList();
498 if ( !expandToParam.isEmpty() )
500 QStringList expandToStringList;
501 for (
const QVariant &expansion : expandToParam )
504 if ( !expansionDefinition.
isValid() )
507 expandToStringList.append( expansionDefinition.
toString() );
509 if ( !expandToStringList.isEmpty() )
511 dsUri.
setParam( u
"expandTo"_s, expandToStringList.join(
';' ) );
516 const int maxPageSizeParam = parts.value( u
"pageSize"_s ).toInt( &ok );
519 dsUri.
setParam( u
"pageSize"_s, QString::number( maxPageSizeParam ) );
523 const int featureLimitParam = parts.value( u
"featureLimit"_s ).toInt( &ok );
526 dsUri.
setParam( u
"featureLimit"_s, QString::number( featureLimitParam ) );
529 const QString geometryType = parts.value( u
"geometryType"_s ).toString();
530 if ( geometryType.compare(
"point"_L1, Qt::CaseInsensitive ) == 0 )
534 else if ( geometryType.compare(
"multipoint"_L1, Qt::CaseInsensitive ) == 0 )
538 else if ( geometryType.compare(
"line"_L1, Qt::CaseInsensitive ) == 0 )
542 else if ( geometryType.compare(
"polygon"_L1, Qt::CaseInsensitive ) == 0 )
547 if ( parts.contains( u
"bounds"_s ) && parts.value( u
"bounds"_s ).userType() == qMetaTypeId<QgsRectangle>() )
553 if ( !parts.value( u
"sql"_s ).toString().isEmpty() )
554 dsUri.
setSql( parts.value( u
"sql"_s ).toString() );
556 return dsUri.
uri(
false );
561 return new QgsSensorThingsProvider( uri, options, flags );
564QList<Qgis::LayerType> QgsSensorThingsProviderMetadata::supportedLayerTypes()
const
569QMap<QString, QgsAbstractProviderConnection *> QgsSensorThingsProviderMetadata::connections(
bool cached )
571 return connectionsProtected<QgsSensorThingsProviderConnection, QgsSensorThingsProviderConnection>( cached );
579void QgsSensorThingsProviderMetadata::deleteConnection(
const QString &name )
581 deleteConnectionProtected<QgsSensorThingsProviderConnection>( name );
586 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.