Skip to content

Commit

Permalink
Better error reporting when things go wrong in ArcGIS MapServer provi…
Browse files Browse the repository at this point in the history
…der rendering
  • Loading branch information
nyalldawson committed May 30, 2019
1 parent 323fae2 commit d383073
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 17 deletions.
73 changes: 59 additions & 14 deletions src/providers/arcgisrest/qgsamsprovider.cpp
Expand Up @@ -59,6 +59,8 @@ void QgsAmsLegendFetcher::start()

void QgsAmsLegendFetcher::handleError( const QString &errorTitle, const QString &errorMsg )
{
mErrorTitle = errorTitle;
mError = errorMsg;
emit error( errorTitle + ": " + errorMsg );
}

Expand Down Expand Up @@ -256,7 +258,7 @@ QString QgsAmsProvider::htmlMetadata()
return dumpVariantMap( mServiceInfo, tr( "Service Info" ) ) + dumpVariantMap( mLayerInfo, tr( "Layer Info" ) );
}

void QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int pixelHeight )
void QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int pixelHeight, QgsRasterBlockFeedback *feedback )
{
if ( !mCachedImage.isNull() && mCachedImageExtent == viewExtent )
{
Expand Down Expand Up @@ -287,7 +289,6 @@ void QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int p
if ( lodEntries.isEmpty() )
{
mCachedImage = QImage();
mCachedImage.fill( Qt::transparent );
return;
}
int level = 0;
Expand Down Expand Up @@ -355,11 +356,49 @@ void QgsAmsProvider::draw( const QgsRectangle &viewExtent, int pixelWidth, int p
requestUrl.addQueryItem( QStringLiteral( "layers" ), QStringLiteral( "show:%1" ).arg( dataSource.param( QStringLiteral( "layer" ) ) ) );
requestUrl.addQueryItem( QStringLiteral( "transparent" ), QStringLiteral( "true" ) );
requestUrl.addQueryItem( QStringLiteral( "f" ), QStringLiteral( "image" ) );
QByteArray reply = QgsArcGisRestUtils::queryService( requestUrl, authcfg, mErrorTitle, mError );
mCachedImage = QImage::fromData( reply, dataSource.param( QStringLiteral( "format" ) ).toLatin1() );
if ( mCachedImage.format() != QImage::Format_ARGB32 )
mError.clear();
mErrorTitle.clear();
QString contentType;
QByteArray reply = QgsArcGisRestUtils::queryService( requestUrl, authcfg, mErrorTitle, mError, QgsStringMap(), feedback, &contentType );
if ( !mError.isEmpty() )
{
mCachedImage = mCachedImage.convertToFormat( QImage::Format_ARGB32 );
mCachedImage = QImage();
if ( feedback )
feedback->appendError( QStringLiteral( "%1: %2" ).arg( mErrorTitle, mError ) );
}
else if ( contentType.startsWith( QLatin1String( "application/json" ) ) )
{
// if we get a JSON response, something went wrong (e.g. authentication error)
mCachedImage = QImage();

QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson( reply, &err );
if ( doc.isNull() )
{
mErrorTitle = QObject::tr( "Error" );
mError = reply;
}
else
{
const QVariantMap res = doc.object().toVariantMap();
if ( res.contains( QStringLiteral( "error" ) ) )
{
const QVariantMap error = res.value( QStringLiteral( "error" ) ).toMap();
mError = error.value( QStringLiteral( "message" ) ).toString();
mErrorTitle = QObject::tr( "Error %1" ).arg( error.value( QStringLiteral( "code" ) ).toString() );
}
}

if ( feedback )
feedback->appendError( QStringLiteral( "%1: %2" ).arg( mErrorTitle, mError ) );
}
else
{
mCachedImage = QImage::fromData( reply, dataSource.param( QStringLiteral( "format" ) ).toLatin1() );
if ( mCachedImage.format() != QImage::Format_ARGB32 )
{
mCachedImage = mCachedImage.convertToFormat( QImage::Format_ARGB32 );
}
}
}
}
Expand Down Expand Up @@ -459,20 +498,26 @@ QgsRasterIdentifyResult QgsAmsProvider::identify( const QgsPointXY &point, QgsRa

bool QgsAmsProvider::readBlock( int /*bandNo*/, const QgsRectangle &viewExtent, int width, int height, void *data, QgsRasterBlockFeedback *feedback )
{
Q_UNUSED( feedback ) // TODO: make use of the feedback object

// TODO: optimize to avoid writing to QImage
draw( viewExtent, width, height );
if ( mCachedImage.width() != width || mCachedImage.height() != height )
draw( viewExtent, width, height, feedback );
if ( mCachedImage.isNull() )
{
return false;
}
else if ( mCachedImage.width() != width || mCachedImage.height() != height )
{
const QString error = tr( "Unexpected image size for block. Expected %1x%2, got %3x%4" ).arg( width ).arg( height ).arg( mCachedImage.width() ).arg( mCachedImage.height() );
if ( feedback )
feedback->appendError( tr( "Unexpected image size for block" ) );
feedback->appendError( error );

QgsDebugMsg( QStringLiteral( "Unexpected image size for block" ) );
QgsDebugMsg( error );
return false;
}
std::memcpy( data, mCachedImage.constBits(), mCachedImage.bytesPerLine() * mCachedImage.height() );
return true;
else
{
std::memcpy( data, mCachedImage.constBits(), mCachedImage.bytesPerLine() * mCachedImage.height() );
return true;
}
}

#ifdef HAVE_GUI
Expand Down
2 changes: 1 addition & 1 deletion src/providers/arcgisrest/qgsamsprovider.h
Expand Up @@ -88,7 +88,7 @@ class QgsAmsProvider : public QgsRasterDataProvider
protected:
bool readBlock( int bandNo, const QgsRectangle &viewExtent, int width, int height, void *data, QgsRasterBlockFeedback *feedback = nullptr ) override;

void draw( const QgsRectangle &viewExtent, int pixelWidth, int pixelHeight );
void draw( const QgsRectangle &viewExtent, int pixelWidth, int pixelHeight, QgsRasterBlockFeedback *feedback = nullptr );

private:
bool mValid = false;
Expand Down
4 changes: 3 additions & 1 deletion src/providers/arcgisrest/qgsarcgisrestutils.cpp
Expand Up @@ -490,7 +490,7 @@ QList<quint32> QgsArcGisRestUtils::getObjectIdsByExtent( const QString &layerurl
return ids;
}

QByteArray QgsArcGisRestUtils::queryService( const QUrl &u, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders, QgsFeedback *feedback )
QByteArray QgsArcGisRestUtils::queryService( const QUrl &u, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders, QgsFeedback *feedback, QString *contentType )
{
QUrl url = parseUrl( u );

Expand Down Expand Up @@ -518,6 +518,8 @@ QByteArray QgsArcGisRestUtils::queryService( const QUrl &u, const QString &authc
}

const QgsNetworkReplyContent content = networkRequest.reply();
if ( contentType )
*contentType = content.rawHeader( "Content-Type" );
return content.content();
}

Expand Down
2 changes: 1 addition & 1 deletion src/providers/arcgisrest/qgsarcgisrestutils.h
Expand Up @@ -64,7 +64,7 @@ class QgsArcGisRestUtils
bool fetchGeometry, const QStringList &fetchAttributes, bool fetchM, bool fetchZ,
const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static QList<quint32> getObjectIdsByExtent( const QString &layerurl, const QgsRectangle &filterRect, QString &errorTitle, QString &errorText, const QString &authcfg, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static QByteArray queryService( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );
static QByteArray queryService( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr, QString *contentType = nullptr );
static QVariantMap queryServiceJSON( const QUrl &url, const QString &authcfg, QString &errorTitle, QString &errorText, const QgsStringMap &requestHeaders = QgsStringMap(), QgsFeedback *feedback = nullptr );

static std::unique_ptr< QgsPoint > parsePoint( const QVariantList &coordList, QgsWkbTypes::Type pointType );
Expand Down

0 comments on commit d383073

Please sign in to comment.