31#include <QNetworkRequest>
32#include <nlohmann/json.hpp>
36QgsSensorThingsProvider::QgsSensorThingsProvider(
const QString &uri,
const ProviderOptions &options,
QgsDataProvider::ReadFlags flags )
39 mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
41 const QUrl url( QgsSensorThingsSharedData::parseUrl( mSharedData->mRootUri ) );
43 QNetworkRequest request = QNetworkRequest( url );
45 mSharedData->mHeaders.updateNetworkRequest( request );
48 networkRequest.setAuthCfg( mSharedData->mAuthCfg );
50 switch ( networkRequest.get( request ) )
58 appendError(
QgsErrorMessage( tr(
"Connection failed: %1" ).arg( networkRequest.
errorMessage() ), QStringLiteral(
"SensorThings" ) ) );
66 auto rootContent = json::parse( content.
content().toStdString() );
67 if ( !rootContent.contains(
"value" ) )
69 appendError(
QgsErrorMessage( tr(
"No 'value' array in response" ), QStringLiteral(
"SensorThings" ) ) );
73 bool foundMatchingEntity =
false;
74 for (
const auto &valueJson : rootContent[
"value"] )
76 if ( valueJson.contains(
"name" ) && valueJson.contains(
"url" ) )
78 const QString name = QString::fromStdString( valueJson[
"name"].get<std::string>() );
80 if ( entityType == mSharedData->mEntityType )
82 const QString url = QString::fromStdString( valueJson[
"url"].get<std::string>() );
85 foundMatchingEntity =
true;
86 mSharedData->mEntityBaseUri = url;
94 ( void ) mSharedData->featureCount();
100 if ( !foundMatchingEntity )
102 switch ( mSharedData->mEntityType )
119 appendError(
QgsErrorMessage( tr(
"MultiDatastreams are not supported by this connection" ), QStringLiteral(
"SensorThings" ) ) );
127 catch (
const json::parse_error &ex )
129 appendError(
QgsErrorMessage( tr(
"Error parsing response: %1" ).arg( ex.what() ), QStringLiteral(
"SensorThings" ) ) );
136QString QgsSensorThingsProvider::storageType()
const
140 return QStringLiteral(
"OGC SensorThings API" );
147 return new QgsSensorThingsFeatureSource( mSharedData );
154 return new QgsSensorThingsFeatureIterator(
new QgsSensorThingsFeatureSource( mSharedData ),
true, request );
161 return mSharedData->mGeometryType;
164long long QgsSensorThingsProvider::featureCount()
const
173 const long long count = mSharedData->featureCount();
174 if ( !mSharedData->error().isEmpty() )
175 pushError( mSharedData->error() );
180QgsFields QgsSensorThingsProvider::fields()
const
184 return mSharedData->mFields;
191 return mLayerMetadata;
194QString QgsSensorThingsProvider::htmlMetadata()
const
202 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Entity Type" ) % QStringLiteral(
"</td><td>%1" ).arg(
qgsEnumValueToKey( mSharedData->mEntityType ) ) % QStringLiteral(
"</td></tr>\n" );
203 metadata += QStringLiteral(
"<tr><td class=\"highlight\">" ) % tr(
"Endpoint" ) % QStringLiteral(
"</td><td><a href=\"%1\">%1</a>" ).arg( mSharedData->mEntityBaseUri ) % QStringLiteral(
"</td></tr>\n" );
226bool QgsSensorThingsProvider::supportsSubsetString()
const
232QString QgsSensorThingsProvider::subsetString()
const
235 return mSharedData->subsetString();
238bool QgsSensorThingsProvider::setSubsetString(
const QString &subset,
bool )
242 const QString trimmedSubset = subset.trimmed();
243 if ( trimmedSubset == mSharedData->subsetString() )
248 const QString baseUri = mSharedData->mEntityBaseUri;
251 uri.
setSql( trimmedSubset );
252 setDataSourceUri( uri.
uri(
false ) );
254 mSharedData->mEntityBaseUri = baseUri;
263void QgsSensorThingsProvider::setDataSourceUri(
const QString &uri )
267 mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
275 return mSharedData->mSourceCRS;
281 return mSharedData->extent();
284QString QgsSensorThingsProvider::name()
const
288 return SENSORTHINGS_PROVIDER_KEY;
291QString QgsSensorThingsProvider::providerKey()
293 return SENSORTHINGS_PROVIDER_KEY;
298 mSharedData = qobject_cast<QgsSensorThingsProvider *>( source )->mSharedData;
301QString QgsSensorThingsProvider::description()
const
303 return SENSORTHINGS_PROVIDER_DESCRIPTION;
306bool QgsSensorThingsProvider::renderInPreview(
const PreviewContext & )
312void QgsSensorThingsProvider::reloadProviderData()
315 mSharedData->clearCache();
323QgsSensorThingsProviderMetadata::QgsSensorThingsProviderMetadata():
324 QgsProviderMetadata( QgsSensorThingsProvider::SENSORTHINGS_PROVIDER_KEY, QgsSensorThingsProvider::SENSORTHINGS_PROVIDER_DESCRIPTION )
328QIcon QgsSensorThingsProviderMetadata::icon()
const
333QList<QgsDataItemProvider *> QgsSensorThingsProviderMetadata::dataItemProviders()
const
335 return {
new QgsSensorThingsDataItemProvider() };
338QVariantMap QgsSensorThingsProviderMetadata::decodeUri(
const QString &uri )
const
342 QVariantMap components;
343 components.insert( QStringLiteral(
"url" ), dsUri.
param( QStringLiteral(
"url" ) ) );
347 components.insert( QStringLiteral(
"authcfg" ), dsUri.
authConfigId() );
351 components.insert( QStringLiteral(
"username" ), dsUri.
username() );
355 components.insert( QStringLiteral(
"password" ), dsUri.
password() );
363 if ( !dsUri.
param( QStringLiteral(
"referer" ) ).isEmpty() )
365 components.insert( QStringLiteral(
"referer" ), dsUri.
param( QStringLiteral(
"referer" ) ) );
367 if ( !dsUri.
param( QStringLiteral(
"http-header:referer" ) ).isEmpty() )
369 components.insert( QStringLiteral(
"referer" ), dsUri.
param( QStringLiteral(
"http-header:referer" ) ) );
372 const QString entityParam = dsUri.
param( QStringLiteral(
"entity" ) );
380 const QStringList expandToParam = dsUri.
param( QStringLiteral(
"expandTo" ) ).split(
';', Qt::SkipEmptyParts );
381 if ( !expandToParam.isEmpty() )
383 QVariantList expandParts;
384 for (
const QString &expandString : expandToParam )
389 expandParts.append( QVariant::fromValue( definition ) );
392 if ( !expandParts.isEmpty() )
394 components.insert( QStringLiteral(
"expandTo" ), expandParts );
399 const int maxPageSizeParam = dsUri.
param( QStringLiteral(
"pageSize" ) ).toInt( &ok );
402 components.insert( QStringLiteral(
"pageSize" ), maxPageSizeParam );
406 const int featureLimitParam = dsUri.
param( QStringLiteral(
"featureLimit" ) ).toInt( &ok );
409 components.insert( QStringLiteral(
"featureLimit" ), featureLimitParam );
416 components.insert( QStringLiteral(
"geometryType" ), QStringLiteral(
"multipoint" ) );
418 components.insert( QStringLiteral(
"geometryType" ), QStringLiteral(
"point" ) );
421 components.insert( QStringLiteral(
"geometryType" ), QStringLiteral(
"line" ) );
424 components.insert( QStringLiteral(
"geometryType" ), QStringLiteral(
"polygon" ) );
432 const QStringList bbox = dsUri.
param( QStringLiteral(
"bbox" ) ).split(
',' );
433 if ( bbox.size() == 4 )
444 if ( xminOk && yminOk && xmaxOk && ymaxOk )
445 components.insert( QStringLiteral(
"bounds" ), r );
448 if ( !dsUri.
sql().isEmpty() )
449 components.insert( QStringLiteral(
"sql" ), dsUri.
sql() );
454QString QgsSensorThingsProviderMetadata::encodeUri(
const QVariantMap &parts )
const
457 dsUri.
setParam( QStringLiteral(
"url" ), parts.value( QStringLiteral(
"url" ) ).toString() );
459 if ( !parts.value( QStringLiteral(
"authcfg" ) ).toString().isEmpty() )
461 dsUri.
setAuthConfigId( parts.value( QStringLiteral(
"authcfg" ) ).toString() );
463 if ( !parts.value( QStringLiteral(
"username" ) ).toString().isEmpty() )
465 dsUri.
setUsername( parts.value( QStringLiteral(
"username" ) ).toString() );
467 if ( !parts.value( QStringLiteral(
"password" ) ).toString().isEmpty() )
469 dsUri.
setPassword( parts.value( QStringLiteral(
"password" ) ).toString() );
471 if ( !parts.value( QStringLiteral(
"referer" ) ).toString().isEmpty() )
473 dsUri.
setParam( QStringLiteral(
"referer" ), parts.value( QStringLiteral(
"referer" ) ).toString() );
477 parts.value( QStringLiteral(
"entity" ) ).toString() );
483 dsUri.
setParam( QStringLiteral(
"entity" ),
487 const QVariantList expandToParam = parts.value( QStringLiteral(
"expandTo" ) ).toList();
488 if ( !expandToParam.isEmpty() )
490 QStringList expandToStringList;
491 for (
const QVariant &expansion : expandToParam )
494 if ( !expansionDefinition.
isValid() )
497 expandToStringList.append( expansionDefinition.
toString() );
499 if ( !expandToStringList.isEmpty() )
501 dsUri.
setParam( QStringLiteral(
"expandTo" ), expandToStringList.join(
';' ) );
506 const int maxPageSizeParam = parts.value( QStringLiteral(
"pageSize" ) ).toInt( &ok );
509 dsUri.
setParam( QStringLiteral(
"pageSize" ), QString::number( maxPageSizeParam ) );
513 const int featureLimitParam = parts.value( QStringLiteral(
"featureLimit" ) ).toInt( &ok );
516 dsUri.
setParam( QStringLiteral(
"featureLimit" ), QString::number( featureLimitParam ) );
519 const QString geometryType = parts.value( QStringLiteral(
"geometryType" ) ).toString();
520 if ( geometryType.compare( QLatin1String(
"point" ), Qt::CaseInsensitive ) == 0 )
524 else if ( geometryType.compare( QLatin1String(
"multipoint" ), Qt::CaseInsensitive ) == 0 )
528 else if ( geometryType.compare( QLatin1String(
"line" ), Qt::CaseInsensitive ) == 0 )
532 else if ( geometryType.compare( QLatin1String(
"polygon" ), Qt::CaseInsensitive ) == 0 )
537 if ( parts.contains( QStringLiteral(
"bounds" ) ) && parts.value( QStringLiteral(
"bounds" ) ).userType() == QMetaType::type(
"QgsRectangle" ) )
539 const QgsRectangle bBox = parts.value( QStringLiteral(
"bounds" ) ).value< QgsRectangle >();
543 if ( !parts.value( QStringLiteral(
"sql" ) ).toString().isEmpty() )
544 dsUri.
setSql( parts.value( QStringLiteral(
"sql" ) ).toString() );
546 return dsUri.
uri(
false );
551 return new QgsSensorThingsProvider( uri, options, flags );
554QList<Qgis::LayerType> QgsSensorThingsProviderMetadata::supportedLayerTypes()
const
559QMap<QString, QgsAbstractProviderConnection *> QgsSensorThingsProviderMetadata::connections(
bool cached )
561 return connectionsProtected<QgsSensorThingsProviderConnection, QgsSensorThingsProviderConnection>( cached );
569void QgsSensorThingsProviderMetadata::deleteConnection(
const QString &name )
571 deleteConnectionProtected<QgsSensorThingsProviderConnection>( name );
576 saveConnectionProtected( connection, name );
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...
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.
The QgsAbstractProviderConnection provides 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...
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
@ 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...
This class represents a coordinate reference system (CRS).
@ SkipFeatureCount
Make featureCount() return -1 to indicate unknown, and subLayers() to return a unknown feature count ...
QFlags< ReadFlag > ReadFlags
virtual void setDataSourceUri(const QString &uri)
Set the data source specification.
Class for storing the component parts of a RDBMS 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.
QgsErrorMessage represents single error message.
Wrapper for iterator of features from vector data provider or vector layer.
This class 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)
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.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
void setYMinimum(double y)
Set the minimum y value.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
void setXMinimum(double x)
Set the minimum x value.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
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...
This is the base class for vector data providers.
@ ReadLayerMetadata
Provider can read layer metadata from data store. Since QGIS 3.0. See QgsDataProvider::layerMetadata(...
@ SelectAtId
Fast access to features using their ID.
@ ReloadData
Provider is able to force reload data.
QFlags< Capability > Capabilities
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 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.