GeoTools : MapLayerArchitecture - 3_Concepts

Specific proposed concepts

This section shall hold our more specific(technical) thoughts and whishes for the new architecture.

Which object interfaces should exist?

There exist several possible concepts:

  1. Map and map layer. This is the current approach in GeoTools. Grouping map layers is not supported.
  2. Only layers. This seems to be the GeoAPI approach (in my understanding). A hierarchical structure where one and the same interface represents a branch (if it has child objects) or a leaf (if it has geodata). This would allow for deep nesting, which might however introduce problems trying to visualize this structure in a legend widget. Also it is slightly harder for newbys to understand this concept.
    I'm sceptical. Matthias
  3. Map, map layer group and map layer. Here the hierarchy is: Map contains map layers AND/OR contains map layer groups, which contain the map layers. Nothing very exotic. Quite easy to understand. Getting all layers within a map requires querying the layers from each map layer group plus the layers that are direct children of the map.
  4. Map with grouping function and map layers. Here the grouping is managed within the map interface, so there exist only two interfaces. The map would return on request either all map layers or the map layers within a specified group. This might be easier to implement than #3, but on the other side it might be more consistent to have a map layer group actually represented by an own object. Note also that this approach limits grouping to one level. (Might or might not be desired.)

First preliminary results show that #3 gives "cleaner", easier interfaces, although the number of interfaces is significantly higher (3 object interfaces + 2 "helper" interfaces in my approach, instead of just two interfaces).
Matthias: So I guess I prefer #3.
Jesse: I like # 3 for map/layer interfaces.

See the UML diagram on the next page for our current solution.

Interface and implementation relationships

It looks as if a strikt separation between Object interfaces and UI interfaces is not possible, or at least not possible without a big effort without any obvious advantage.
Example: It would be possible to create pure object interfaces for MapLayerGroup and MapLayer. In order to use them in a UI things like icons and listeners need to be added. It proved much easier to inherit MapLayerGroup and MapLayer from a common base class that already cares about the icon and some listeners.

So this issue collapses basically to the trivial note that uDig's application interfaces should extend the general interfaces provided by GeoTools.

How do the interfaces play together for rendering?

Note: This discussion should move to MapLayerArchitecture - 5_Rendering .
See (and comment) this page for rendering specific issues and ideas.

The tight bidirectional referencing of map, render manager, viewport, display and the like to each other in uDig seems unfamilar to me. I would expect following workflow when a map must be rendered:

  1. A new rendering manager is created, which gets the map as its data and the display widget as its destination.
  2. The rendering manager parses the map's layer list to find suitable renderers
  3. The rendering manager fetches the viewport model and the graphics context from the display widget.
  4. The rendering manager starts rendering these layers. It gives each renderer the geodata(or its handle) to render and the viewport model, which should contain enough information in order for the renderer to know which area to render.

Pending: Not sure a rendering manager should take this task. One idea is that there is something like a "MapRenderer" (similar to the CompositeRenderer in uDig), that delegates the work to "LayerRenderer"s or "MultiLayerRenderer"s, depending on the layer's data.
But see more on this on the following page:
MapLayerArchitecture - 5_Rendering

This means, that the map does not need to know anything about the rendering manager, nor does it need to know the display(s) it is currently painted on or the like.
Does the viewport model (i.e. a map canvas) need to know which map is painted on it? Probably yes, to update the map when the component is resized.

Objections?, Comments?

Maps and map layers

Implement any specification?

Should the new map/map layer architecture implement any specification such as the WMS spec.?
Matthias: For me a strict implementation is not necessary, but how do others think about this?

What information should the object interfaces hold?

Let's check what would be needed if map layer group were to be a separate interface:

  • Contains:
    • List of layers directly in map and
    • List of map layer groups (both kept in one list?)
    • Map CRS (the CRS in which the map is displayed)
    • Visibility flag
  • Returns:
    • List of all(!) layers (incl. the ones in groups)
    • BBox of all layers. In map CRS coordinates?
  • Metadata: Title. Probably abstract/description. What else?
  • Editing functions: Add/move/remove children, change metadata+visibility
  • Listeners: MapLayerListListener, MapBoundsListener and PropertyChangeListener as in GeoTools

Map layer group: (Groups layers into logical groups)

  • Contains:
    • list of child layers
    • Visibility flag
  • Returns:
    • BBox of all child layers. So it is known which area has to be redrawn if the group is switched to be visible.
  • Metadata: Title (It is merely a means of grouping.)
  • Editing functions: Add/move/remove children, change metadata+visibility
  • Listeners: MapLayerListListener, MapBoundsListener

Map layer: (Describes ONE data set, possibly from multiple local or remote sources)

  • Contains:
    • geographic data or proxy to the data
    • Style
    • A Query
    • Layer CRS
    • Visibility flag
  • Returns:
    • Data's BBox? (or query that from the data/proxy?)
    • Icon(glyph) in a requested size (e.g. 16x16) for display in a legend.
  • Metadata:
    • Title,
    • Source(s), e.g. URL(s) (or query that from the data/proxy?)
    • Image returned by WMS as "legend image", whatever size it is.
    • IsOpaque flag? Minimum and maximum map scale to show layer?
  • Editing functions: Change style, Change query?, Change metadata+visibility
  • Listeners: MapLayerListener (or PropertyChangeListener?)

Do you find there's something missing? This question is especially directed towards the uDig developers ... Would it be possible to use the above objects as a basis in uDig as well? If not, why not?

Helper interfaces:

In case it is agreed to have map layer groups as separate objects, it seems might be favourable to have:

  • a common interface for children of a map (MapLayerCollection to be exact, see below), so they can be kept in ONE list, which simplyfies ordering. I call this interface MapElement for the moment.
  • a common interface for objects that can contain such {{MapElement}}s. I call it
    MapLayerCollection for the moment.

See the UML diagram above. To be created.

The MapElement interface theoretially needs no specific methods or functions. It could contain shared functions of its two extensions (MapLayerGroup and MapLayer), such as getTitle() or isVisible(). But that seems rather a cosmetical question.

The MapLayerCollection interface would need all functions to maintain and edit the list of {{MapElement}}s, including adding and removing listeners.

Metadata storage

From the three evaluated map/maplayer architectures it already becomes clear that the amount of metadata seen as "required" varies widely between different users and use cases.
Simple applications might care only about a map's or map layers's title, sophisticated applications might want to store creation date, last editing date, source URLs, specification URL's, vendor, description and the like.

It is therefore that I propose to use an open metadata framework. That is, it should not be hardcoded in the interfaces which metadata they contain (e.g. getTitle, getVendor, getAuthority, getSourceURL, ...), but rather there should be a property-value mapping of some sort, which allows to store metadata with a set of predefined keys, with additional keys being possible in application interfaces. An API user could then just query if an object for the type of metadata required, exists or not.
(Actually a simple java.util.Map would imho do the job.)

I'm quite sure there exist approaches for this in GeoTools/GeoAPI - I just don't know them yet. Matthias

Locking and immutable objects

Since we talk about interfaces that support editing of content and metadata, we might consider following facts:

  • An implementation might not want to allow editing of, lets say, a map layer.
  • A user might want to temporary lock a layer to protect it against changes. Not every application might support this notion however.

I'm currently testing a small interface that does just this. It has three functions:

  • isContentEditable() (default: true)
  • isMetadataEditable() (default: true)
    These functions are set at construction timeand do not change over time. They determine if the object (or the implementation class used) is immutable concerning the content and or the metadata.
  • isLocked() (default: false)
    An application supporting locking could offer this choice to the end user somewhere in its UI. If not, the object is editable by default. The above two restrictions apply, however: If a layer is not editable the "isLocked" flag is simply ignored.

If an edit method is called, but editing is not supported for one of the above reasons, a specific exception is thrown.

Undoable editing

Undoable "commands" (deprecated) or "operations" (Eclipse 3.1) are essential for a good application. But do the object interfaces need to know about this? I don't think so.

For instance, the object interface MapContext might offer the plain methods
public boolean addLayer(MapLayer layer, int index)
public boolean removeLayer(MapLayer layer)
without any notion that these two could be undone/redone. An application interface, within uDig f.e., could add support for MapCommands, which would than wrap these plain edit methods in a way that "addLayer" can be undone by "removeLayer" and so on.

Any objections? Is there anybody who thinks this will not work?. If so, why?

Data access

It is common to all existing layer interfaces that they contain the data or a handle to the data. uDig's concept is that a IGeoResource is a proxy to the geodata, that is, the geodata is requested by a the function:
public abstract <T> T resolve(Class<T> adaptee, ...)
Furthermore there exists a status flag, which is set to "BROKEN" if the connection to a the data is not available currently.

Now, I wonder if it isn't possible to hide the facts from the high level API, that

  • the resource is remote and the data has to be streamed over the internet.
  • the resource might have multiple sources (URLs f.e.), so if one source is unavailable the data is fetched from a mirror
    I could imagine the following:
  • A High level interface which behaves the same for ALL sorts of geodata, local and remote. It would have a flag that shows the status of the data (available/unavailable/unknown or so).
  • Low level interface extending the above for (A) local data (B) remote data.
    (Note: What about data that is available local and remote?)
    As an alternative it could be up to the implementation (e.g. some abstract classes) to care about the details, that is, from where to fetch which data when.

At David Zwiers: Do you see a problem with the above? Why does the IGeoResource expose the fact that the resource must be "resolved" to the user of the interface? What advantage does uDig gain through that?
Maybe the following: IGeoResource extends IResolve and ...

... Your instance of IResolve could also implement IAdaptable (we ensured that no method names would conflict).

This desired compatibility should be kept in mind if/when designing a new interface.

One interface to rule them all?

I quote a sentence from the uDig documentation on the IGeoResource interface:

The IGeoResource implementation does not place any restrictions on the interface used to represent the external resource.

What this means, is, that a GeoResource can contain data of almost any class. This contrasts to the GeoTools approach, where there is one interface for the data in a layer: FeatureSource, with its FeatureStore extension:

FeatureSource getFeatureSource();

Given that the rendering framework should allow to select renderers according to the data type (class) of the georesource, this allows a great flexibility. Is there any drawback, i.e. is there the need that all georesources that are resolved by IGeoResource share some functions and/or methods? I don'k know any yet.