Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(WMS): call getCapabilities during layer preprocessing #594

Closed
wants to merge 4 commits into from

Conversation

autra
Copy link
Contributor

@autra autra commented Dec 6, 2017

Description

Add GetCapabilities query for WMS layers. This PR implement the fetching of capabilities and set or check the following informations:

  • projection
  • extent
  • format

BREAKING CHANGE:

  • WMS layer will now query getCapabilities. If you want to disable this behaviour (because you already provide all the informations in the json object), you need to set layer.disableGetCap to true.

  • previously we had layer.format and layer.options.mimetype coexisting, with no clear difference in role. This commit removes layer.options.mimetype to only keep layer.format. This is needed to reliably check configured format.

Motivation and Context

Supporting getCapabilities in our providers is a necessary step to present a usable SIG application for the outside world, let's start this.

Moreover, if we want itowns to be able to display a layer from its url only, we need to be able to query capabilities from these layers.

Work that would need to follow this PR:

  • support getCapabilities for WFS and WMTS
  • add the possibility to create an entire scene (view + layers) with just a WMS/WMTS/WFS url.

This is a first pass at fixing #285.

@autra
Copy link
Contributor Author

autra commented Dec 6, 2017

@iTowns/reviewers please r?

Copy link
Contributor

@gchoqueux gchoqueux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to valid the default value of layer.disableGetCap.

Why you change options.mimetype to format?
You have to support both if you make this type of change. (and tag to deprecated)

@autra
Copy link
Contributor Author

autra commented Dec 6, 2017

Why you change options.mimetype to format?

From the description

previously we had layer.format and layer.options.mimetype coexisting, with no clear difference in role. This commit removes layer.options.mimetype to only keep layer.format. This is needed to reliably check configured format.

2 option for the same thing is not needed. I picked the better.

You have to support both if you make this type of change. (and tag to deprecated)

For such a simple thing? Deprecation process is necessary if the change will notably impact client, preventing them to work before extensive work is done to adapt themselves to a new version. It is not necessary to go into such a process for a simple renaming. As the commit is annotated with a BREAKING CHANGE, it'll appear automatically in the release note. I'll make sure it is clearly visible.

We need to valid the default value of layer.disableGetCap.

It is very surprising that itowns managed to do without getCap this far honestly :-) Every SIG app I'm aware of do that by default. Of course we'll keep a way to bypass it (hence the disableGetCap, the name can be changed btw). It is very useful in some case I agree (for instance for Lyon data, their getCap takes 17 sec :-/ )

I believe this will make iTowns a lot simpler to use, especially for WMTS layers.

@autra
Copy link
Contributor Author

autra commented Dec 11, 2017

We need to valid the default value of layer.disableGetCap.

Ok let's validate it. What's your thoughts about it?

@@ -10,6 +10,8 @@ import mE from '../Math/MathExtended';
import Ellipsoid from '../Math/Ellipsoid';

proj4.defs('EPSG:4978', '+proj=geocent +datum=WGS84 +units=m +no_defs');
// used in some protocol
proj4.defs('CRS:84', proj4.defs('EPSG:4326'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add comment?

// CRS:84 is equivalent to EPSG:4326 - ie, basic WGS84 degrees.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the point of this comment. This line is pretty self-explanatory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not for the WGS84

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean, but I'm not sure this is the place to explain CRS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to watch on the internet for explanations CRS:84, so it's a good place to explain to the developers. Why it makes sense to add this equivalence because we try to support wgs84 in itowns. It's better to be generous in commentary and it'sn't much to add

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

let supportedCrs = [];
const crsPropName = version === '1.3.0' ? 'CRS' : 'SRS';

for (const childElem of xmlLayer.children) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Searching for items by tag name is often used. It could be factoring.

Otherwise, it will not be easier to transform the xml object js?
I also found lib js that turns the capes into json.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Searching for items by tag name is often used. It could be factoring.

I've hesitated to do so, but each time it's a bit different. So I decided against it because:

  • It will only abstract the for loop in the general case (the if part is always a bit different)
  • it is less readable than the current code. And it's better to optimize for the reader of our code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise, it will not be easier to transform the xml object js?

In my opinion, not worthy the extra lib. It won't save me the for loop anyway, and it adds a layer of abstraction that doesn't bring a lot of value here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To elaborate, as we already have everything we need to query and parse xml in js, I think we can do without. It will avoid growing itowns.js.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

}

function parseGeoBounds(version, xmlLayer) {
const geoTagName = version === '1.3.0' ? 'EX_GeographicBoundingBox' : 'LatLonBoundingBox';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could group in private functions

getCrsPNByVersion(version)...

getGeoPNByVersion(version)...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You want a function for a one-liner?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's just to group the constants
you can suggest something else

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. Yes, a function should be better than constants here I guess.

});
};

WMS_Provider.prototype.findXmlLayer = function findXMLLayer(name, xml) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add documentation on new functions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oups I forgot! yes will do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I did better: I only expose them through a _testing export, which avoid polluting the prototype of the provider with private functions.

return new Set(_parseSupportedCrs(version, xmlLayer));
};

WMS_Provider.prototype.parseSupportedFormats = function parseSupportedFormats(version, xmlCapa) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a difference between xmlLayer and xmlCapa

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

options.style = options.style || 'normal';
options.projection = options.projection || 'EPSG:3857';
let newBaseUrl = `${layer.url}` +
`?LAYER=${options.name}` +
`&FORMAT=${options.mimetype}` +
`&FORMAT=${layer.format}` +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

options.mimetype to layer.format to be in another PR, both must be supported with a deprecated message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can put that in another PR if you want, but I still don't see the need for a depreciation message. I did give my reasons, but you didn't give yours.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it breaks the users cases

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but what about my suggestion in my previous comment? If it's clearly documented in the release notes, as it is a trivial change to do, user won't have any difficulty right? They would upgrade their itowns lib, and in the same commit rename this property.

Anyway, I'll see if I can remove this from this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As it breaks the user cases, it's better, we have to support both and put a deprecated message

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here it is: #597

src/Core/View.js Outdated
// if we still haven't any validExtent after getCapabilities, we assume
// it is the same as the configured extent
if (!layer.validExtent) {
layer.validExtent = layer.extent;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and if layer.extent is undefined?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally it shouldn't happen: if disableGetCap is true, we check for it. Otherwise the parseExtent method has several fallbacks that cannot reasonably fail.

@autra
Copy link
Contributor Author

autra commented Dec 11, 2017

@gchoqueux updated.

This now depends on #597

@autra
Copy link
Contributor Author

autra commented Mar 7, 2018

@iTowns/reviewers updated and rebased :-)

examples/wfs.js Outdated
@@ -31,6 +31,7 @@ view.addLayer({
networkOptions: { crossOrigin: 'anonymous' },
type: 'color',
protocol: 'wms',
disableGetCap: true, // their getCap call is too slow
Copy link
Contributor

@peppsac peppsac Mar 7, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't this be implicit? If the user supplies all needed paramaters (format, version?) then you assume that the GetCapabilities query is not needed.
WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's an interesting idea. The advantage of disableGetCap is that it explicitly ensure getCap won't be called. If it's implicit, it can still be called if you forget something. Maybe we can cover both use cases ? if we have all the parameters, we disable it. If we have disableGetCap, we check the needed parameters and throw if one is missing. WDYT?

Also, WDYT about disableGetCap naming? The more I see it, the more I prefer disableGetCapabilities.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your suggestion seems fine.

And I prefer disableGetCapabilities (or noGetCapabilities?)

@autra
Copy link
Contributor Author

autra commented Mar 9, 2018

@peppsac updated

autra added 3 commits July 13, 2018 18:48
WMS provider call get capabilities and set or check the following information:
- projection
- extent
- format

BREAKING CHANGE:

WMS layer will now query getCapabilities. If you want to disable this
behaviour (because you already provide all the informations in the json
object), you need to set layer.disableGetCap to true.
@gchoqueux gchoqueux added this to the 2.xx.x milestone Feb 1, 2019
@autra autra closed this Jun 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants