1 /***************************************************************************
2                               qgswfsprovider.h
3                               -------------------
4   begin                : July 25, 2006
5   copyright            : (C) 2006 by Marco Hugentobler
6                          (C) 2016 by Even Rouault
7   email                : marco dot hugentobler at karto dot baug dot ethz dot ch
8                          even.rouault at spatialys.com
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 #ifndef QGSWFSPROVIDER_H
21 #define QGSWFSPROVIDER_H
22 
23 #include "qgis.h"
24 #include "qgsrectangle.h"
25 #include "qgscoordinatereferencesystem.h"
26 #include "qgsvectordataprovider.h"
27 #include "qgswfscapabilities.h"
28 #include "qgswfsfeatureiterator.h"
29 #include "qgswfsdatasourceuri.h"
30 
31 #include "qgsprovidermetadata.h"
32 
33 class QgsRectangle;
34 class QgsWFSSharedData;
35 
36 
37 /**
38  * \ingroup WFSProvider
39  *
40  * \brief A provider reading/write features from/into a WFS server.
41  *
42  * Below quick design notes on the whole provider.
43  *
44  * QgsWFSProvider class purpose:
45  *
46  * - in constructor, do a GetCapabilities request to determine server-side feature limit,
47      paging capabilities, WFS version, edition capabilities. Do a DescribeFeatureType request
48      to determine fields, geometry name and type.
49  * - in other methods, mostly WFS-T related operations.
50  *
51  * QgsWFSSharedData class purpose:
52  *
53  * - contains logic shared by QgsWFSProvider, QgsWFSFeatureIterator and QgsWFSFeatureDownloader.
54  * - one of its main function is to maintain a on-disk cache of the features retrieved
55  *   from the server. This cache is a SpatiaLite database.
56  *
57  * QgsWFSRequest class purpose: abstract base class to create WFS network requests,
58  * such as QgsWFSCapabilities, QgsWFSDescribeFeatureType, QgsWFSFeatureDownloader,
59  * QgsWFSFeatureHitsAsyncRequest, QgsWFSFeatureHitsRequest, QgsWFSTransactionRequest
60  *
61  * QgsWFSDataSourceURI class purpose: wrapper above QgsDataSourceUri to get/set
62  * the specific attributes of a WFS URI.
63  *
64  */
65 class QgsWFSProvider final: public QgsVectorDataProvider
66 {
67     Q_OBJECT
68   public:
69 
70     static const QString WFS_PROVIDER_KEY;
71     static const QString WFS_PROVIDER_DESCRIPTION;
72 
73     explicit QgsWFSProvider( const QString &uri, const QgsDataProvider::ProviderOptions &providerOptions, const QgsWfsCapabilities::Capabilities &caps = QgsWfsCapabilities::Capabilities() );
74     ~QgsWFSProvider() override;
75 
76     /* Inherited from QgsVectorDataProvider */
77 
78     QgsAbstractFeatureSource *featureSource() const override;
79 
80     QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override;
81 
82     QgsWkbTypes::Type wkbType() const override;
83     long featureCount() const override;
84 
85     QgsFields fields() const override;
86 
87     QgsCoordinateReferenceSystem crs() const override;
88 
89     QString subsetString() const override;
90     bool setSubsetString( const QString &theSQL, bool updateFeatureCount = true ) override;
91 
supportsSubsetString()92     bool supportsSubsetString() const override { return true; }
93 
94     /* Inherited from QgsDataProvider */
95 
96     QgsRectangle extent() const override;
97     bool isValid() const override;
98     QString name() const override;
99     QString description() const override;
100 
101     QgsVectorDataProvider::Capabilities capabilities() const override;
102 
storageType()103     QString storageType() const override { return QStringLiteral( "OGC WFS (Web Feature Service)" ); }
104 
105     /* new functions */
106 
107     QString geometryAttribute() const;
108 
processSQLErrorMsg()109     const QString processSQLErrorMsg() const { return mProcessSQLErrorMsg; }
110 
processSQLWarningMsg()111     const QString processSQLWarningMsg() const { return mProcessSQLWarningMsg; }
112 
113     //Editing operations
114 
115     bool addFeatures( QgsFeatureList &flist, QgsFeatureSink::Flags flags = QgsFeatureSink::Flags() ) override;
116     bool deleteFeatures( const QgsFeatureIds &id ) override;
117     bool changeGeometryValues( const QgsGeometryMap &geometry_map ) override;
118     bool changeAttributeValues( const QgsChangedAttributesMap &attr_map ) override;
119     QVariantMap metadata() const override;
120     QString translateMetadataKey( const QString &mdKey ) const override;
121     QString translateMetadataValue( const QString &mdKey, const QVariant &value ) const override;
122 
123     bool empty() const override;
124 
125   private slots:
126 
127     void featureReceivedAnalyzeOneFeature( QVector<QgsFeatureUniqueIdPair> );
128 
129     void pushErrorSlot( const QString &errorMsg );
130 
131 
132   private:
133     //! Mutable data shared between provider and feature sources
134     std::shared_ptr<QgsWFSSharedData> mShared;
135 
136     /**
137      * Invalidates cache of shared object
138     */
139     void reloadProviderData() override;
140 
141     friend class QgsWFSFeatureSource;
142 
143     /**
144      * Create the geometry element
145      */
146     QDomElement geometryElement( const QgsGeometry &geometry, QDomDocument &transactionDoc );
147 
148   protected:
149 
150     //! String used to define a subset of the layer
151     QString mSubsetString;
152 
153     //! Flag if provider is valid
154     bool mValid = true;
155     //! Namespace URL of the server (comes from DescribeFeatureDocument)
156     QString mApplicationNamespace;
157     //! Server capabilities for this layer (generated from capabilities document)
158     QgsVectorDataProvider::Capabilities mCapabilities = QgsVectorDataProvider::Capabilities();
159     //! Fields of this typename. Might be different from mShared->mFields in case of SELECT
160     QgsFields mThisTypenameFields;
161 
162     QString mProcessSQLErrorMsg;
163     QString mProcessSQLWarningMsg;
164 
165     /**
166      * Collects information about the field types. Is called internally from QgsWFSProvider ctor.
167      * The method gives back the name of
168      * the geometry attribute and the thematic attributes with their types.
169     */
170     bool describeFeatureType( QString &geometryAttribute,
171                               QgsFields &fields, QgsWkbTypes::Type &geomType );
172 
173     /**
174      * For a given typename, reads the name of the geometry attribute, the
175      * thematic attributes and their types from a dom document. Returns true in case of success.
176     */
177     bool readAttributesFromSchema( QDomDocument &schemaDoc,
178                                    const QString &prefixedTypename,
179                                    QString &geometryAttribute,
180                                    QgsFields &fields, QgsWkbTypes::Type &geomType, QString &errorMsg );
181 
182     //helper methods for WFS-T
183 
184     /**
185      * Sends the transaction document to the server using HTTP POST
186      * \returns true if transmission to the server succeeded, otherwise false
187      * \note true does not automatically mean that the transaction succeeded
188     */
189     bool sendTransactionDocument( const QDomDocument &doc, QDomDocument &serverResponse );
190 
191     //! Creates a transaction element and adds it (normally as first element) to the document
192     QDomElement createTransactionElement( QDomDocument &doc ) const;
193 
194     //! True if the server response means success
195     bool transactionSuccess( const QDomDocument &serverResponse ) const;
196     //! Returns the inserted ids
197     QStringList insertedFeatureIds( const QDomDocument &serverResponse ) const;
198     //! Retrieve version and capabilities for this layer from GetCapabilities document (will be stored in mCapabilities)
199     bool getCapabilities();
200     //! Records provider error
201     void handleException( const QDomDocument &serverResponse );
202     //! Converts DescribeFeatureType schema geometry property type to WKBType
203     QgsWkbTypes::Type geomTypeFromPropertyType( const QString &attName, const QString &propType );
204     //! Convert the value to its appropriate XML representation
205     QString convertToXML( const QVariant &value );
206 
207     bool processSQL( const QString &sqlString, QString &errorMsg, QString &warningMsg );
208 };
209 
210 class QgsWfsProviderMetadata final: public QgsProviderMetadata
211 {
212   public:
213     QgsWfsProviderMetadata();
214     QList<QgsDataItemProvider *> dataItemProviders() const override;
215     QgsWFSProvider *createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() ) override;
216 };
217 
218 
219 #endif /* QGSWFSPROVIDER_H */
220