Wednesday 30 April 2014

Announcing: MapGuide Maestro 6.0 Alpha 1

It has been 4 years since I took over development of MapGuide Maestro. In those 4 years, Maestro has evolved to the point where I now believe that for a MapGuide Server authoring application, the design space of Maestro in my opinion, has been mostly fully explored. There isn't really much left for me to do

So as I see it, 6.0 will be my final major release of Maestro. Since this is going to be my final release, we should release early and often so that when 6.0 does finally drop, it will be what I consider to be complete and finished. The road to MapGuide Maestro 6.0 will be my "farewell tour" for this piece of software.

So with that said, here's the first alpha release of MapGuide Maestro 6.0. Here's what's new

New Grid-based Style Editor

A new grid-based style editor replaces the existing control-based style editor.


The old control-based style editor can be restored through the Maestro options. Note: In my tests on Mono, the new grid-based editor does not work, so you'll have to revert back to the old style editor.



Web Layout v2.6.0

The new Web Layout schema has specialized editor support in anticipation of the release of MapGuide Open Source 2.6.



Theming improvements

You can now generate themes based on values from an external Class Definition (eg. A lookup table)



Also, you can now also generate LOOKUP() theme expressions via the Expression Editor. This can be accessed from the Tools menu of the Expression Editor and uses the existing Theme Builder UI.




You can also generate themes for composite styles as well (in most cases).

Advanced Stylization improvements

Thanks to the grid-based style editor, you can now see such style previews inline.



Also we've made the mega-verbose Composite Symbolization dialog a bit more accessible.

Component Symbol Definitions of a Composite Symbolization now also have previews so you can see how the component Symbol Definitions are assembled to the final preview.



Secondly, you can edit the XML of the Composite Symbolization if you know what you're doing and the existing UI is a bit too hard for you to navigate through.



Other improvements

MgCooker now provides you the ability to auto-calculate the meters-per-unit value required for tile generation via the official method.


Calculation uses the following methods based on availability:


Bad Feature Source, Feature Class and Geometry fields are flagged when you open a bad Layer Definition


The XML diff UI has been tweaked to combine the source/target views so you can scroll thorough both sides in sync.


A new context menu command is available that lets you diff 2 different resources of the same type using the refined Diff UI.


A new context menu command is available to let you get the spatial context information for a Layer Definition



A new context menu command is available to let you create image-based Symbol Definitions from a Symbol Library.


The resource picker has some extra navigation shortcuts


And if you're picking Symbol Definitions, you can now preview them inline



Finally, we leverage the new-found use of Watermarks to inject useful debugging information to most resource previews.



Download

Tuesday 15 April 2014

Announcing: mapguide-rest 0.7

Before we continue our blogging journey into the rest of mapguide-rest's data publishing framework, here's the second release of mapguide-rest.

Here's what this new release offers

ACLs for published data sources

We now let you have some level of control as to what users and groups can access a given published data sources, which is important if you are exposing representations that support POST/PUT/DELETE operations and even more important if this is on a public-facing site. You don't want Joe Anonymous MapGuide user to be able to POST/PUT/DELETE to your data sources willy nilly unless you have configured such data sources to allow for such things to happen.

Consider this example from a recent post

{
    "Source": {
        "Type": "MapGuide",
        "FeatureSource": "Library://Samples/Sheboygan/Data/Parcels.FeatureSource",
        "FeatureClass": "SHP_Schema:Parcels"
    },
    "Representations": {
        "xml": {
            "Adapter": "FeatureSetXml",
            "Methods": {
                "GET": {
                    "MaxCount": 500
                },
                "POST": {},
                "PUT": {},
                "DELETE": {}
            }
        }
    }
}

This configuration will now deny all users because no ACLs have been defined for it. A configuration like this

{
    "Source": {
        "Type": "MapGuide",
        "FeatureSource": "Library://Samples/Sheboygan/Data/Parcels.FeatureSource",
        "FeatureClass": "SHP_Schema:Parcels"
    },
    "Representations": {
        "xml": {
            "Adapter": "FeatureSetXml",
            "Methods": {
                "GET": {
                    "MaxCount": 500,
                    "AllowGroups": ["Everyone"]
                },
                "POST": {
                    "AllowUsers": ["Administrator", "Author"]
                },
                "PUT": {
                    "AllowUsers": ["Administrator", "Author"]
                },
                "DELETE": {
                    "AllowUsers": ["Administrator", "Author"]
                }
            }
        }
    }
}

This will define the following access rules:
  • GET: Anybody can access the data source
  • POST: Only the Administrator and Author users (and related session IDs) can access the data source. Everyone else will be denied access.
  • PUT: Only the Administrator and Author users (and related session IDs) can access the data source. Everyone else will be denied access.
  • DELETE: Only the Administrator and Author users (and related session IDs) can access the data source. Everyone else will be denied access.
Auto-API documentation for published data sources

Thanks to the integration of Swagger UI for our REST API documentation needs, and the fact that all published data sources will offer a "fixed" REST API to interact with it, we now can provide automatic REST API documentation for any published data source.

Simply append a doc/index.html to access a data source's API documentation



New REST API routes

This release includes plenty of new routes to play with
  • GET /library/{resourcePath}.WebLayout/viewer (Load the given Web Layout into the AJAX viewer)
  • GET /library/{resourcePath}.ApplicationDefinition/viewer/{template} (Load the given Flexible Layout in Fusion with the given template)
  • POST /library (Load a package file into the repository)
  • GET /services/getschemamapping.{type} (Get the schema mapping for a given FDO provider and partial connection string)
  • GET /library/{resourcePath}.FeatureSource/preview (Launch a schema report preview on the given Feature Source)
  • GET /library/{resourcePath}.LayerDefinition/preview (Launch a AJAX viewer preview of the given Layer Definition)
  • GET /library/{resourcePath}.MapDefinition/preview (Launch a AJAX viewer preview of the given Map Definition)
  • GET /library/{resourcePath}.SymbolDefinition/preview (Render a preview of the given Symbol Definition)
  • GET /library/{resourcePath}.WatermarkDefinition/preview (Launch a AJAX viewer preview of the given Watermark Definition)
  • GET /session/{sessionId}/{resourceName}.WebLayout/viewer (Load the given Web Layout into the AJAX viewer)
  • GET /session/{sessionId}/{resourceName}.ApplicationDefinition/viewer/{template} (Load the given Flexible Layout in Fusion with the given template)
  • GET /session/{sessionId}/{resourceName}.FeatureSource/preview (Launch a schema report preview on the given Feature Source)
  • GET /session/{sessionId}/{resourceName}.LayerDefinition/preview (Launch a AJAX viewer preview of the given Layer Definition)
  • GET /session/{sessionId}/{resourceName}.MapDefinition/preview (Launch a AJAX viewer preview of the given Map Definition)
  • GET /session/{sessionId}/{resourceName}.SymbolDefinition/preview (Render a preview of the given Symbol Definition)
  • GET /session/{sessionId}/{resourceName}.WatermarkDefinition/preview (Launch a AJAX viewer preview of the given Watermark Definition)
You can use the provided interactive REST API documentation to find out more information about these new routes

Improved HTML representation of the site repository

The default HTML representation of the site repository is very bare-bones and primitive.

With the power of Bootstrap 3, we've brought the HTML representation into the 21st century :)


Most of the resource options now show their results inline




Any Web Layout or Application Definition resources now expose new options for you to launch them in their respective AJAX or Fusion viewer



This is still experimental code, so standard disclaimer: use in production at your own risk.

Download

Tuesday 1 April 2014

GeoREST as re-imagined by mapguide-rest: Part 2 - The XML adapter

For this post, we are going to talk about one of the adapters provided by mapguide-rest: The XML adapter.

This won't be a comprehensive guide, you can consult the adapter documentation in the github wiki for all the gritty details. This will just be a basic overview of the adapter

The XML adapter lets you provide an XML representation of feature data from any MapGuide Feature Source. The name of this adapter is FeatureSetXml. When reading XML via this adapter (using HTTP GET), the XML is the same format as the XML data returned by a SELECTFEATURES operation from the mapagent.

While the value of consuming MapGuide feature data in this format may be debatable, what the XML adapter special and where it is most valuable is that it is the only adapter to support CRUD through the quartet of HTTP verbs:
  • GET: For reading one or more features
  • POST: For inserting one or more features
  • PUT: For updating one or more features
  • DELETE: For deleting one or more features
All other adapters only provide GET support (to "read" feature data as a particular format). This is the only adapter to support feature manipulation.

Configuration

To enable XML representation support for your feature source, your restcfg.json should look like this:

{
    "Source": {
        "Type": "MapGuide",
        "FeatureSource": "Library://Samples/Sheboygan/Data/Parcels.FeatureSource",
        "FeatureClass": "SHP_Schema:Parcels"
    },
    "Representations": {
        "xml": {
            "Adapter": "FeatureSetXml",
            "Methods": {
                "GET": {
                    "MaxCount": 500
                },
                "POST": {},
                "PUT": {},
                "DELETE": {}
            }
        }
    }
}

The above configuration will enable support for all 4 HTTP methods. If you do not want to support a particular method on this Feature Source, then simply remove the corresponding method key from the Methods section of the above configuration. Attempts to make requests to this data source using such un-configured methods will return HTTP 405 (method not allowed).

Reading XML Features

Assume the above restcfg.json resides in /conf/data/property/restcfg.json

To get the XML of this data source is simply to issue a GET request like this:

GET http://servername/mapguide/rest/data/property/.xml


The number of features in this result will be capped at 500 due to the MaxCount property in the configuration.

You can also request the XML of a single feature by putting the actual ID value of the feature into the URL like so

GET http://servername/mapguide/rest/data/property/45.xml


Inserting XML Features

Assume the above restcfg.json resides in /conf/data/property/restcfg.json

Inserting a new feature requires a HTTP POST to the multiple results URL. Your XML body should be structured as follows:

  • A top-level FeatureSet element
  • With a Features element
  • With a Feature element for each feature you want to insert.
  • Each Feature element should have one or more Property elements
  • Each Property element should have a Name element containing the property name and a Value element containing the property value. Geometry values must be in WKT format

A successful request will return an XML envelope containing the ID values for the inserted feature.



Updating XML Features

There are 2 ways to update features.

  • A PUT request to the multiple results URL
  • A PUT request to the single result URL
Your XML request body must be structured as follows
  • A top-level UpdateOperation element
  • With a Filter element which is the FDO filter for features to be updated. If issuing a PUT request to a single results URL, this element is not required as the filter can be inferred from the URL itself.
  • Also with a UpdateProperties element
  • Containing one or more Property elements
  • Each Property element should have a Name element containing the property name and a Value element containing the property value. Geometry values must be in WKT format. Null values can be specified by omitting the Value element.
Note that on IIS, PUT requests is probably not allowed by default, so you'll probably have to use a POST request and include a X-HTTP-Method-Override = PUT request header.

Sending the request will return an XML envelope indicating the number of features updated by this request.


Deleting Features

Like updating, there are 2 ways to delete features
  • A DELETE request to the multiple results URL
  • A DELETE request to the single result URL
No XML request body is required. You just have to specify a filter parameter that indicates what features will be deleted. If the request is to a single result URL, this parameter is not required as the filter will be inferred from the URL itself.

Like PUT, DELETE is probably not allowed on IIS by default, so you can work around that by using a POST request and include a X-HTTP-Method-Override = DELETE request header.

Sending the request will return an XML envelope indicating the number of features deleted by this request


Transaction Support

For providers that support it, you can configure such CRUD operations to use transactions by specifying UseTransaction: true in the relevant methods in restcfg.json

{
    ...
    "Representations": {
        "xml": {
            "Adapter": "FeatureSetXml",
            "Methods": {
                "GET": {
                    "MaxCount": 500
                },
                "POST": {
                    "UseTransaction": true
                },
                "PUT": {
                    "UseTransaction": true
}, "DELETE": {
                    "UseTransaction": true
                }
} } } }

In Summary

The XML adapter is useful for doing CRUD operations using standard HTTP requests and the specially crafted XML request envelopes as described in this post. No special code or APIs required!

GeoREST as re-imagined by mapguide-rest: Part 1

So after a little tour of the REST API, we now come to the other half of mapguide-rest: The re-imagined GeoREST-style data publishing framework.

If you have used GeoREST before, most of what I will be showing here should be familiar to you conceptually.

Introduction

If you've never used GeoREST before, it is a framework for publishing spatial data (from a MapGuide Feature Source or a raw FDO connection) in one or more various formats and representations, such as:
  • GeoJSON
  • XML
  • OData
  • PNG
  • HTML (via templates)
  • KML (via templates)
  • GeoRSS (via templates)
  • CSV (via templates)
Published spatial data sources follow RESTful principles for interaction and data access.
  • Clients use HTTP GET to "read" features from the data source
  • Clients use HTTP POST to "create" features in the data source
  • Clients use HTTP PUT to "update" features in the data source
  • Clients use HTTP DELETE to "delete" features in the data source
GeoREST enables CRUD for certain Feature Sources without needing to know specifics of the MapGuide API. Accessing this data does not require the use any specialized client libraries and APIs or knowledge of SOAP or other specialized RPC mechanisms. Only knowledge of how to make HTTP requests is required. Based on the type of representation and what's configured for the data source, certain operations may or may not be supported.

The other major feature is that access to such data will generally have clean URLs which assists in bookmark-ability and makes such published data easy to access by humans and machines alike.

While GeoREST offers something unique, for mapguide-rest I wanted to go back to the drawing board on this idea for reasons already stated.

Differences from GeoREST

The main differences in mapguide-rest that distinguish it from GeoREST are:
  • Configuration is done by JSON files instead of XML files
  • Because mapguide-rest is in PHP, it also works in Linux versions of MapGuide/AIMS where GeoREST is windows-only.
  • mapguide-rest is not tied to a specific version of MapGuide/AIMS and can work on any version of MapGuide/AIMS that bundles PHP 5.3 or newer (though we recommend using it on the latest releases).
  • Also because of PHP, mapguide-rest uses the more powerful and flexible Smarty template engine for any template-based representations instead of GeoREST's ctemplate engine allowing for more expressive content templates.
  • The base URL where data sources in mapguide-rest can be accessed is strictly based on the relative location of its configuration file and not based on the value of uripart in restcfg.xml for GeoREST.
  • mapguide-rest provides an easy API to extend it with your own custom formats/representations or geometry/datetime formatters for templated content.
  • mapguide-rest provides coordinate transformation capabilities out of the box.
  • mapguide-rest in its current iteration is yet to support OData like GeoREST currently does.
  • mapguide-rest does not support raw FDO connections as a data source. Only MapGuide Feature Sources are supported.
Configuration

Configuration files are JSON-based and reside under the /conf/data subdirectory of your mapguide-rest installation. These files can reside any levels deep within this folder. These configuration files are named restcfg.json and its relative location determines the base URL in which to access that particular configured data source.

Here's a basic example restcfg.json

{
    "Source": {
        "Type": "MapGuide",
        "FeatureSource": "Library://Samples/Sheboygan/Data/Parcels.FeatureSource",
        "FeatureClass": "SHP_Schema:Parcels"
    },
    "Representations": {
        "xml": {
            "Adapter": "FeatureSetXml",
            "Methods": {
                "GET": {
                    "PageSize": 100,
                    "MaxCount": 500
                }
            }
        },
        "html": {
            "Adapter": "Template",
            "Methods": {
                "GET": {
                    "PageSize": 100,
                    "MaxCount": 500,
                    "MimeType": "text/html",
                    "Templates": {
                        "Single": "property_html_single.tpl",
                        "Many": "property_html_many.tpl",
                        "None": "property_html_none.tpl",
                        "Error": "property_html_error.tpl"
                    }
                }
            }
        }
    }
}

As you can see, the structure of restcfg.json is easy to follow:
  • There is a top-level Source property that indicates the MapGuide Feature Source that we want to make available for RESTful access
  • There is a top-level Representations property that contains one or more supported data formats that specifies the Adapter that will handle this particular representation along with adapter-specific configuration options for each HTTP method that you want to allow through that particular representation (and is supported by the given adapter)
The above restcfg.json enables the Parcels Feature Source to be accessible:
  • As XML data
  • As a set of web pages with master-detail type of navigation
URL Conventions

All URLs follow the following forms:
  • Multiple results: http://servername/mapguide/rest/data/[RELATIVEURIPART]/.[FORMAT]
  • Single results: http://servername/mapguide/rest/data/[RELATIVEURIPART]/[FEATUREID].[FORMAT]
As mentioned above, the location of restcfg.json will determine the base URL which to access data from this particular data source. The RELATIVEURIPART of the above URLs is based on the relative path of this restcfg.json file.

For example, if restcfg.json was stored like so

 - REST_INSTALL_DIR
    - conf
       - data
          - sheboygan
             - property
                - restcfg.json

Then the URL for accessing the detail page of a specific parcel would be:

http://servername/mapguide/rest/data/sheboygan/property/1.html

The FORMAT of the above URL is the name of the extension keyed under the Representations part of restcfg.json and will let mapguide-rest determine which adapter to instantiate to handle this particular request.

For individual feature access, specifying the value of [FEATUREID] will cause the designated adapter to only return the matching feature whose identity property value is [FEATUREID] in the adapter's given format/representation.

All adapters will be processing URLs in these two forms.

Adapters

Adapters are classes in mapguide-rest which will be instantiated based on the given extension in the incoming URL and will be used to handle the particular HTTP request. Adapters will perform specific actions based on the request URL and the particular HTTP method used.

For example, for the FeatureSetXml adapter:

  • A HTTP GET will return one or more features from the Feature Source in XML format
  • A HTTP POST will insert one or more features into the given Feature Source based on the XML content in the request body
  • A HTTP PUT will update one or more features in the given Feature Source based on the filter and properties specified in the XML request body
  • A HTTP DELETE will delete one or more features in the given Feature Source based on the filter specified in the request parameters
Other adapters may only support certain methods (for the record, only FeatureSetXml supports GET/POST/PUT/DELETE. Other adapters only support GET)

mapguide-rest includes the following adapters:
  • FeatureSetXml - Outputs feature data as XML, also supports create/update/delete of features if configured
  • FeatureSetJson - Outputs feature data as GeoJSON
  • FeatureSetCsv - Outputs feature data as a CSV file. Geometry values are written as WKT
  • MapImage - Outputs feature data as a map image with the feature(s) in question being selected
  • Template - Outputs feature data through a user-defined smarty template.
Adapters are the key to how data publishing works in mapguide-rest. I have a feeling that this could be a somewhat lengthy series of posts. So I'll stop here for now. Stay tuned as I go through each adapter in greater detail.