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.
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).
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.
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...
This is the 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 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.