wiki:MapGuideRfc157

Version 4 (modified by jng, 8 months ago) (diff)

--

MapGuide RFC 157 - Support creating MgMap? instances with initial display parameters

This page contains a change request (RFC) for the MapGuide Open Source project. More MapGuide RFCs can be found on the RFCs page.

Status

RFC Template Version(1.0)
Submission Date9 Feb 2017
Last Modified11 Apr 2017
AuthorJackie Ng
RFC StatusAdopted
Implementation StatusCompleted
Proposed Milestone3.3
Assigned PSC guide(s)(when determined)
Voting History(vote date)
+1Jackie,Crispin,Gordon
+0
-0
-1
no vote

Overview

This RFC proposes to add a new overload of MgMap?.Create() that allows for initial display parameters (width/height/dpi/center/scale)

to be set, allowing them to be used for certain MgRenderingService? operations without a session id.

Motivation

A key roadblock of MapGuide scalability is the current use of session repositories. Using session repositories imposes an upper limit when vertically scaling up MapGuide. Each MapGuide session adds memory and administrative burden on the MapGuide Server. A truly scalable solution would be to completely do away with the notion of session repositories and support stateless rendering of map selection and querying. A stateless map viewer would then be responsible for the management of map selections and view state, leaving the MapGuide Server solely responsible for rendering and querying of feature data.

However, the current building blocks to enable the above scenario simply do not exist in the MapGuide Web API in its current form.

There are a certain set of APIs in the MgRenderingService? that can accept an MgMap? object. However, these APIs implicitly assume the MgMap? object is to be opened from an existing session repository.

It is currently not possible to create an MgMap? using MgMap?.Create() and immediately use this MgMap? in any of the following operations:

These operations require a MgMap? instance that was opened from an existing session repository via a mapname/session pair, thus a MapGuide session must always be involved when using any of these operations.

It is not possible to use the above APIs in a "stateless" manner without needing to create or use a MapGuide session ID/repository.

The reason these operations don't work in a "stateless" context is because such operations expect the MgMap?'s display properties to be already set:

  • Display Width
  • Display Height
  • DPI
  • View Center
  • View Scale

However, these properties are immutable and can only be modified through the mapagent-only GETDYNAMICMAPOVERLAYIMAGE API via:

  • SETDISPLAYWIDTH
  • SETDISPLAYHEIGHT
  • SETDISPLAYDPI
  • SETVIEWCENTERX
  • SETVIEWCENTERY
  • SETVIEWSCALE

This API also requires a SESSION/MAPNAME pair meaning once again you have to have created and saved a MgMap? and MgSelection? into a session repository.

The immutability of these display parameters hinders our ability to use certain MgRenderingService? operations in a "stateless" manner without a MapGuide session id. Without the ability to use these MgRenderingService? operations in a stateless manner, we do not have the required pieces to build a stateless map viewer.

Proposed Solution

To remove these limitations, we will introduce an overload of MgMap?.Create() that allows these display parameters to be set as part of map creation.

class MG_MAPGUIDE_API MgMap : public MgSerializable
{
PUBLISHED_API:
    //////////////////////////////////////////////////////////////////
    /// \brief
    /// Initializes a new MgMap object given a map definition or tile set
    /// definition and a name for the map with initial display parameters set. 
    /// This method is used for MapGuide Viewers or for offline map production.
    ///
    /// \remarks
    /// If creating a MgMap object from a tile set definition, only "Default" is the
    /// acceptable tile provider. Any other provider will cause this method to
    /// throw a MgUnsupportedTileProviderException
    ///
    /// <!-- Syntax in .Net, Java, and PHP -->
    /// \htmlinclude DotNetSyntaxTop.html
    /// void Create(MgResourceIdentifier mapDefinition, string mapName, int displayWidth, int displayHeight, double x, double y, double scale, int dpi);
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude JavaSyntaxTop.html
    /// void Create(MgResourceIdentifier mapDefinition, String mapName, int displayWidth, int displayHeight, double x, double y, double scale, int dpi);
    /// \htmlinclude SyntaxBottom.html
    /// \htmlinclude PHPSyntaxTop.html
    /// void Create(MgResourceIdentifier mapDefinition, string mapName, int displayWidth, int displayHeight, double x, double y, double scale, int dpi);
    /// \htmlinclude SyntaxBottom.html
    ///
    /// \param resource
    /// An MgResourceIdentifier that specifies the
    /// location of the map definition in a resource
    /// repository.
    /// \param mapName
    /// A string that specifies the name of the map.
    /// \param displayWidth
    /// The display width to initially set for the map
    /// \param displayHeight
    /// The display height to initially set for the map
    /// \param x
    /// The view center X coordinate to initially set for the map
    /// \param y
    /// The view center Y coordinate to initially set for the map
    /// \param scale
    /// The view scale to initially set for the map
    /// \param dpi
    /// The display DPI to initially set for the map
    ///
    /// \return
    /// Returns nothing.
    ///
    /// <!-- Example (PHP) -->
    /// \htmlinclude PHPExampleTop.html
    /// \code
    /// // Assuming the site connection has already been intialized
    /// $resourceID = new  MgResourceIdentifier('Library://Calgary/Maps/Calgary.MapDefinition');
    /// $map = new MgMap($site);
    /// // Initializes the map to be centered on the Calgary CBD at 1:5000 scale with a DPI of 96
    /// $map->Create($resourceID, 'Calgary', 640, 480, -114.054565, 51.068369, 5000.0, 96);
    /// \endcode
    /// \htmlinclude ExampleBottom.html
    ///
    virtual void Create(MgResourceIdentifier* resource, CREFSTRING mapName, INT32 displayWidth, INT32 displayheight, double x, double y, double scale, INT32 dpi);
};

Any MgMap? instance created by this new API can immediately be used for any MgRenderingService? API that accepts an MgMap? without requiring it be loaded from an existing session repository.

Implications

This is a new API addition. Existing forms of MgMap::Create() work as before.

Test Plan

Create MgMap? instances using the new overload API and verify they can be used immediately with the following MgRenderingService?

operations without errors:

Funding / Resources

Community

Addendum, 11 April 2017

It has been discovered using QueryFeatures, that the MgFeatureInformation returned has a MgSelection that cannot be interrogated in detail (ie. GetLayers on this selection will throw)

The reason is the selection object is "disconnected" in that it has no internal reference to the MgMap it was initialized from (due to the (de)serialization of the MgFeatureInformation from server to web tier). There is a method SetMap that allows one to "attach" the original MgMap instance to the selection so that methods like GetLayers will work again, but this method is not part of the public API.

To enable the selection within a MgFeatureInformation to be interrogated, the SetMap method will be promoted to EXTERNAL_API