Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 4 additions & 25 deletions web/client/epics/featuregrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ const {query, QUERY_CREATE, QUERY_RESULT, LAYER_SELECTED_FOR_SEARCH, FEATURE_TYP
const {reset, QUERY_FORM_RESET} = require('../actions/queryform');
const {zoomToExtent} = require('../actions/map');
const {BROWSE_DATA} = require('../actions/layers');
const {parseString} = require('xml2js');
const {stripPrefix} = require('xml2js/lib/processors');

const {SORT_BY, CHANGE_PAGE, SAVE_CHANGES, SAVE_SUCCESS, DELETE_SELECTED_FEATURES, featureSaving, changePage,
saveSuccess, saveError, clearChanges, setLayer, clearSelection, toggleViewMode, toggleTool,
CLEAR_CHANGES, START_EDITING_FEATURE, TOGGLE_MODE, MODES, geometryChanged, DELETE_GEOMETRY, deleteGeometryFeature,
Expand All @@ -41,27 +40,7 @@ const {selectedFeaturesSelector, changesMapSelector, newFeaturesSelector, hasCha
const {error} = require('../actions/notifications');
const {describeSelector, isDescribeLoaded, getFeatureById, wfsURL, wfsFilter, featureCollectionResultSelector} = require('../selectors/query');
const drawSupportReset = () => changeDrawingStatus("clean", "", "featureGrid", [], {});
/**
* Intercept OGC Exception (200 response with exceptionReport) to throw error in the stream
* @param {observable} observable The observable that emits the server response
* @return {observable} The observable that returns the response or throws the error.
*/
const interceptOGCError = (observable) => observable.switchMap(response => {
if (typeof response.data === "string") {
if (response.data.indexOf("ExceptionReport") > 0) {
return Rx.Observable.bindNodeCallback( (data, callback) => parseString(data, {
tagNameProcessors: [stripPrefix],
explicitArray: false,
mergeAttrs: true
}, callback))(response.data).map(data => {
throw get(data, "ExceptionReport.Exception.ExceptionText") || "Undefined OGC Service Error";
});

}
}
return Rx.Observable.of(response);
});

const {interceptOGCError} = require('../utils/ObservableUtils');
const setupDrawSupport = (state, original) => {
const defaultFeatureProj = getDefaultFeatureProjection();
let drawOptions; let geomType;
Expand Down Expand Up @@ -260,7 +239,7 @@ module.exports = {
).map(() => saveSuccess())
.catch((e) => Rx.Observable.of(saveError(), error({
title: "featuregrid.errorSaving",
message: e,
message: e.message || "Unknown Exception",
uid: "saveError",
autoDismiss: 5
})))
Expand All @@ -283,7 +262,7 @@ module.exports = {
// close window
.catch((e) => Rx.Observable.of(saveError(), error({
title: "featuregrid.errorSaving",
message: e,
message: e.message || "Unknown Exception",
uid: "saveError"
}))).concat(Rx.Observable.of(
toggleTool("deleteConfirm"),
Expand Down
26 changes: 10 additions & 16 deletions web/client/epics/wfsquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const {paginationInfo, isDescribeLoaded, describeSelector} = require('../selecto
const FilterUtils = require('../utils/FilterUtils');
const assign = require('object-assign');

const {isString, isObject} = require('lodash');
const {isObject} = require('lodash');
const {interceptOGCError} = require('../utils/ObservableUtils');
// this is a workaround for https://osgeo-org.atlassian.net/browse/GEOS-7233. can be removed when fixed
const workaroundGEOS7233 = ({totalFeatures, features, ...rest}, {startIndex, maxFeatures}, originalSize) => {
if (originalSize > totalFeatures && originalSize === startIndex + features.length && totalFeatures === features.length) {
Expand Down Expand Up @@ -159,12 +160,6 @@ const getWFSFeature = (searchUrl, filterObj) => {
}));
};

const getWFSResponseException = (response, code) => {
const {unmarshaller} = require('../utils/ogc/WFS');
const json = isString(response.data) ? unmarshaller.unmarshalString(response.data) : null;
return json && json.value && json.value.exception && json.value.exception[0] && json.value.exception[0].TYPE_NAME === 'OWS_1_0_0.ExceptionType' && json.value.exception[0].exceptionCode === code;
};

const getFirstAttribute = (state)=> {
return state.query && state.query.featureTypes && state.query.featureTypes[state.query.typeName] && state.query.featureTypes[state.query.typeName].attributes && state.query.featureTypes[state.query.typeName].attributes[0] && state.query.featureTypes[state.query.typeName].attributes[0].attribute || null;
};
Expand All @@ -178,11 +173,11 @@ const retryWithForcedSortOptions = (action, store) => {
return getWFSFeature(action.searchUrl, assign(action.filterObj, {
sortOptions
}))
.let(interceptOGCError)
.map((newResponse) => {
const newError = getWFSResponseException(newResponse, 'NoApplicableCode');
const state = store.getState();
const data = workaroundGEOS7233(newResponse.data, action.filterObj.pagination, paginationInfo.totalFeatures(state));
return !newError ? querySearchResponse(data, action.searchUrl, action.filterObj) : queryError('No sortable request');
return querySearchResponse(data, action.searchUrl, action.filterObj);
})
.catch((e) => {
return Rx.Observable.of(queryError(e));
Expand Down Expand Up @@ -237,19 +232,18 @@ const wfsQueryEpic = (action$, store) =>
.switchMap(action => {
return Rx.Observable.merge(
getWFSFeature(action.searchUrl, action.filterObj)
.let(interceptOGCError)
.switchMap((response) => {
// try to guess if it was a missing id error and try to search again with forced sortOptions
const error = getWFSResponseException(response, 'NoApplicableCode');
if (error) {
return retryWithForcedSortOptions(action, store);
}
const state = store.getState();
const data = workaroundGEOS7233(response.data, action.filterObj.pagination, paginationInfo.totalFeatures(state));
return Rx.Observable.of(querySearchResponse(data, action.searchUrl, action.filterObj));
})
.startWith(featureLoading(true))
.catch((e) => {
return Rx.Observable.of(queryError(e));
.catch((error) => {
if (error.name === "OGCError" && error.code === 'NoApplicableCode') {
return retryWithForcedSortOptions(action, store);
}
return Rx.Observable.of(queryError(error));
})
.concat(Rx.Observable.of(featureLoading(false)))
);
Expand Down
38 changes: 38 additions & 0 deletions web/client/utils/ObservableUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const Rx = require('rxjs');
const {get} = require('lodash');
const {parseString} = require('xml2js');
const {stripPrefix} = require('xml2js/lib/processors');
class OGCError extends Error {
constructor(message, code) {
super(message);
this.name = 'OGCError';
this.code = code;
}
}
/**
* Intercept OGC Exception (200 response with exceptionReport) to throw error in the stream
* @param {observable} observable The observable that emits the server response
* @return {observable} The observable that returns the response or throws the error.
*/
const interceptOGCError = (observable) => observable.switchMap(response => {
if (typeof response.data === "string") {
if (response.data.indexOf("ExceptionReport") > 0) {
return Rx.Observable.bindNodeCallback( (data, callback) => parseString(data, {
tagNameProcessors: [stripPrefix],
explicitArray: false,
mergeAttrs: true
}, callback))(response.data).map(data => {
const message = get(data, "ExceptionReport.Exception.ExceptionText");
throw new OGCError(message || "Undefined OGC Service Error", get(data, "ExceptionReport.Exception.exceptionCode"));
});

}
}
return Rx.Observable.of(response);
});


module.exports = {
interceptOGCError

};