19#include "moc_qgssensorthingsprovider.cpp" 
   32#include <QNetworkRequest> 
   33#include <nlohmann/json.hpp> 
   37QgsSensorThingsProvider::QgsSensorThingsProvider( 
const QString &uri, 
const ProviderOptions &options, 
Qgis::DataProviderReadFlags flags )
 
   40  mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
 
   42  const QUrl url( QgsSensorThingsSharedData::parseUrl( mSharedData->mRootUri ) );
 
   44  QNetworkRequest request = QNetworkRequest( url );
 
   46  mSharedData->mHeaders.updateNetworkRequest( request );
 
   49  networkRequest.setAuthCfg( mSharedData->mAuthCfg );
 
   51  switch ( networkRequest.get( request ) )
 
   59      appendError( 
QgsErrorMessage( tr( 
"Connection failed: %1" ).arg( networkRequest.
errorMessage() ), QStringLiteral( 
"SensorThings" ) ) );
 
   67    auto rootContent = json::parse( content.
content().toStdString() );
 
   68    if ( !rootContent.contains( 
"value" ) )
 
   70      appendError( 
QgsErrorMessage( tr( 
"No 'value' array in response" ), QStringLiteral( 
"SensorThings" ) ) );
 
   74    bool foundMatchingEntity = 
false;
 
   75    for ( 
const auto &valueJson : rootContent[
"value"] )
 
   77      if ( valueJson.contains( 
"name" ) && valueJson.contains( 
"url" ) )
 
   79        const QString name = QString::fromStdString( valueJson[
"name"].get<std::string>() );
 
   81        if ( entityType == mSharedData->mEntityType )
 
   83          const QString url = QString::fromStdString( valueJson[
"url"].get<std::string>() );
 
   86            foundMatchingEntity = 
true;
 
   87            mSharedData->mEntityBaseUri = url;
 
   95            ( void ) mSharedData->featureCount();
 
  101    if ( !foundMatchingEntity )
 
  103      switch ( mSharedData->mEntityType )
 
  120          appendError( 
QgsErrorMessage( tr( 
"MultiDatastreams are not supported by this connection" ), QStringLiteral( 
"SensorThings" ) ) );
 
  128  catch ( 
const json::parse_error &ex )
 
  130    appendError( 
QgsErrorMessage( tr( 
"Error parsing response: %1" ).arg( ex.what() ), QStringLiteral( 
"SensorThings" ) ) );
 
  137QString QgsSensorThingsProvider::storageType()
 const 
  141  return QStringLiteral( 
"OGC SensorThings API" );
 
  148  return new QgsSensorThingsFeatureSource( mSharedData );
 
  155  return new QgsSensorThingsFeatureIterator( 
new QgsSensorThingsFeatureSource( mSharedData ), 
true, request );
 
  162  return mSharedData->mGeometryType;
 
  165long long QgsSensorThingsProvider::featureCount()
 const 
  174  const long long count = mSharedData->featureCount();
 
  175  if ( !mSharedData->error().isEmpty() )
 
  176    pushError( mSharedData->error() );
 
  181QgsFields QgsSensorThingsProvider::fields()
 const 
  185  return mSharedData->mFields;
 
  192  return mLayerMetadata;
 
  195QString QgsSensorThingsProvider::htmlMetadata()
 const 
  203  metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Entity Type" ) % QStringLiteral( 
"</td><td>%1" ).arg( 
qgsEnumValueToKey( mSharedData->mEntityType ) ) % QStringLiteral( 
"</td></tr>\n" );
 
  204  metadata += QStringLiteral( 
"<tr><td class=\"highlight\">" ) % tr( 
"Endpoint" ) % QStringLiteral( 
"</td><td><a href=\"%1\">%1</a>" ).arg( mSharedData->mEntityBaseUri ) % QStringLiteral( 
"</td></tr>\n" );
 
  227bool QgsSensorThingsProvider::supportsSubsetString()
 const 
  233QString QgsSensorThingsProvider::subsetStringDialect()
 const 
  235  return tr( 
"OGC SensorThings filter" );
 
  238QString QgsSensorThingsProvider::subsetStringHelpUrl()
 const 
  240  return QStringLiteral( 
"https://docs.ogc.org/is/18-088/18-088.html#filter" );
 
  243QString QgsSensorThingsProvider::subsetString()
 const 
  246  return mSharedData->subsetString();
 
  249bool QgsSensorThingsProvider::setSubsetString( 
const QString &subset, 
bool )
 
  253  const QString trimmedSubset = subset.trimmed();
 
  254  if ( trimmedSubset == mSharedData->subsetString() )
 
  259  const QString baseUri = mSharedData->mEntityBaseUri;
 
  262  uri.
setSql( trimmedSubset );
 
  263  setDataSourceUri( uri.
uri( 
false ) );
 
  265  mSharedData->mEntityBaseUri = baseUri;
 
  274void QgsSensorThingsProvider::setDataSourceUri( 
const QString &uri )
 
  278  mSharedData = std::make_shared< QgsSensorThingsSharedData >( uri );
 
  286  return mSharedData->mSourceCRS;
 
  292  return mSharedData->extent();
 
  295QString QgsSensorThingsProvider::name()
 const 
  299  return SENSORTHINGS_PROVIDER_KEY;
 
  302QString QgsSensorThingsProvider::providerKey()
 
  304  return SENSORTHINGS_PROVIDER_KEY;
 
  309  mSharedData = qobject_cast<QgsSensorThingsProvider *>( source )->mSharedData;
 
  312QString QgsSensorThingsProvider::description()
 const 
  314  return SENSORTHINGS_PROVIDER_DESCRIPTION;
 
  317bool QgsSensorThingsProvider::renderInPreview( 
const PreviewContext & )
 
  323void QgsSensorThingsProvider::reloadProviderData()
 
  326  mSharedData->clearCache();
 
  334QgsSensorThingsProviderMetadata::QgsSensorThingsProviderMetadata():
 
  335  QgsProviderMetadata( QgsSensorThingsProvider::SENSORTHINGS_PROVIDER_KEY, QgsSensorThingsProvider::SENSORTHINGS_PROVIDER_DESCRIPTION )
 
  339QIcon QgsSensorThingsProviderMetadata::icon()
 const 
  344QList<QgsDataItemProvider *> QgsSensorThingsProviderMetadata::dataItemProviders()
 const 
  346  return { 
new QgsSensorThingsDataItemProvider() };
 
  349QVariantMap QgsSensorThingsProviderMetadata::decodeUri( 
const QString &uri )
 const 
  353  QVariantMap components;
 
  354  components.insert( QStringLiteral( 
"url" ), dsUri.
param( QStringLiteral( 
"url" ) ) );
 
  358    components.insert( QStringLiteral( 
"authcfg" ), dsUri.
authConfigId() );
 
  362    components.insert( QStringLiteral( 
"username" ), dsUri.
username() );
 
  366    components.insert( QStringLiteral( 
"password" ), dsUri.
password() );
 
  374  if ( !dsUri.
param( QStringLiteral( 
"referer" ) ).isEmpty() )
 
  376    components.insert( QStringLiteral( 
"referer" ), dsUri.
param( QStringLiteral( 
"referer" ) ) );
 
  378  if ( !dsUri.
param( QStringLiteral( 
"http-header:referer" ) ).isEmpty() )
 
  380    components.insert( QStringLiteral( 
"referer" ), dsUri.
param( QStringLiteral( 
"http-header:referer" ) ) );
 
  383  const QString entityParam = dsUri.
param( QStringLiteral( 
"entity" ) );
 
  391  const QStringList expandToParam = dsUri.
param( QStringLiteral( 
"expandTo" ) ).split( 
';', Qt::SkipEmptyParts );
 
  392  if ( !expandToParam.isEmpty() )
 
  394    QVariantList expandParts;
 
  395    for ( 
const QString &expandString : expandToParam )
 
  400        expandParts.append( QVariant::fromValue( definition ) );
 
  403    if ( !expandParts.isEmpty() )
 
  405      components.insert( QStringLiteral( 
"expandTo" ), expandParts );
 
  410  const int maxPageSizeParam = dsUri.
param( QStringLiteral( 
"pageSize" ) ).toInt( &ok );
 
  413    components.insert( QStringLiteral( 
"pageSize" ), maxPageSizeParam );
 
  417  const int featureLimitParam = dsUri.
param( QStringLiteral( 
"featureLimit" ) ).toInt( &ok );
 
  420    components.insert( QStringLiteral( 
"featureLimit" ), featureLimitParam );
 
  427        components.insert( QStringLiteral( 
"geometryType" ), QStringLiteral( 
"multipoint" ) );
 
  429        components.insert( QStringLiteral( 
"geometryType" ), QStringLiteral( 
"point" ) );
 
  432      components.insert( QStringLiteral( 
"geometryType" ), QStringLiteral( 
"line" ) );
 
  435      components.insert( QStringLiteral( 
"geometryType" ), QStringLiteral( 
"polygon" ) );
 
  443  const QStringList bbox = dsUri.
param( QStringLiteral( 
"bbox" ) ).split( 
',' );
 
  444  if ( bbox.size() == 4 )
 
  455    if ( xminOk && yminOk && xmaxOk && ymaxOk )
 
  456      components.insert( QStringLiteral( 
"bounds" ), r );
 
  459  if ( !dsUri.
sql().isEmpty() )
 
  460    components.insert( QStringLiteral( 
"sql" ), dsUri.
sql() );
 
  465QString QgsSensorThingsProviderMetadata::encodeUri( 
const QVariantMap &parts )
 const 
  468  dsUri.
setParam( QStringLiteral( 
"url" ), parts.value( QStringLiteral( 
"url" ) ).toString() );
 
  470  if ( !parts.value( QStringLiteral( 
"authcfg" ) ).toString().isEmpty() )
 
  472    dsUri.
setAuthConfigId( parts.value( QStringLiteral( 
"authcfg" ) ).toString() );
 
  474  if ( !parts.value( QStringLiteral( 
"username" ) ).toString().isEmpty() )
 
  476    dsUri.
setUsername( parts.value( QStringLiteral( 
"username" ) ).toString() );
 
  478  if ( !parts.value( QStringLiteral( 
"password" ) ).toString().isEmpty() )
 
  480    dsUri.
setPassword( parts.value( QStringLiteral( 
"password" ) ).toString() );
 
  482  if ( !parts.value( QStringLiteral( 
"referer" ) ).toString().isEmpty() )
 
  484    dsUri.
setParam( QStringLiteral( 
"referer" ), parts.value( QStringLiteral( 
"referer" ) ).toString() );
 
  488                                      parts.value( QStringLiteral( 
"entity" ) ).toString() );
 
  494    dsUri.
setParam( QStringLiteral( 
"entity" ),
 
  498  const QVariantList expandToParam = parts.value( QStringLiteral( 
"expandTo" ) ).toList();
 
  499  if ( !expandToParam.isEmpty() )
 
  501    QStringList expandToStringList;
 
  502    for ( 
const QVariant &expansion : expandToParam )
 
  505      if ( !expansionDefinition.
isValid() )
 
  508      expandToStringList.append( expansionDefinition.
toString() );
 
  510    if ( !expandToStringList.isEmpty() )
 
  512      dsUri.
setParam( QStringLiteral( 
"expandTo" ), expandToStringList.join( 
';' ) );
 
  517  const int maxPageSizeParam = parts.value( QStringLiteral( 
"pageSize" ) ).toInt( &ok );
 
  520    dsUri.
setParam( QStringLiteral( 
"pageSize" ), QString::number( maxPageSizeParam ) );
 
  524  const int featureLimitParam = parts.value( QStringLiteral( 
"featureLimit" ) ).toInt( &ok );
 
  527    dsUri.
setParam( QStringLiteral( 
"featureLimit" ), QString::number( featureLimitParam ) );
 
  530  const QString geometryType = parts.value( QStringLiteral( 
"geometryType" ) ).toString();
 
  531  if ( geometryType.compare( QLatin1String( 
"point" ), Qt::CaseInsensitive ) == 0 )
 
  535  else if ( geometryType.compare( QLatin1String( 
"multipoint" ), Qt::CaseInsensitive ) == 0 )
 
  539  else if ( geometryType.compare( QLatin1String( 
"line" ), Qt::CaseInsensitive ) == 0 )
 
  543  else if ( geometryType.compare( QLatin1String( 
"polygon" ), Qt::CaseInsensitive ) == 0 )
 
  548  if ( parts.contains( QStringLiteral( 
"bounds" ) ) && parts.value( QStringLiteral( 
"bounds" ) ).userType() == qMetaTypeId<QgsRectangle>() )
 
  550    const QgsRectangle bBox = parts.value( QStringLiteral( 
"bounds" ) ).value< QgsRectangle >();
 
  554  if ( !parts.value( QStringLiteral( 
"sql" ) ).toString().isEmpty() )
 
  555    dsUri.
setSql( parts.value( QStringLiteral( 
"sql" ) ).toString() );
 
  557  return dsUri.
uri( 
false );
 
  562  return new QgsSensorThingsProvider( uri, options, flags );
 
  565QList<Qgis::LayerType> QgsSensorThingsProviderMetadata::supportedLayerTypes()
 const 
  570QMap<QString, QgsAbstractProviderConnection *> QgsSensorThingsProviderMetadata::connections( 
bool cached )
 
  572  return connectionsProtected<QgsSensorThingsProviderConnection, QgsSensorThingsProviderConnection>( cached );
 
  580void QgsSensorThingsProviderMetadata::deleteConnection( 
const QString &name )
 
  582  deleteConnectionProtected<QgsSensorThingsProviderConnection>( name );
 
  587  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...
 
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...
 
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.