Tuesday 2 October 2018

A short MapGuide poll: What you said

A month-and-a-half ago, I put up a short poll regarding DWF support in MapGuide.

I got 97 responses in the time window that I left that poll open, and this is what you said.

Regarding whether you use this DWF support in MapGuide:



I also posed a hypothetical situation where we removed DWF support from MapGuide and asked how badly you'd be affected as a result:

My motivation for this poll was simple. I believe that DWF support in MapGuide is now a technical burden that is not worth carrying on.

This feature is terminal. You won't see any DWF-related enhancements (not from me anyways). Any DWF-related issues still open will most likely never be fixed. Because I doubt that anyone would be familiar enough with the underlying DWF toolkit library to keep maintaining this support as it stands.

Also, presumably this DWF support was originally put in as value proposition from Autodesk to integrate with AutoCAD and friends. Well, since they've officially bailed out at the beginning of this year, that is yet another reason I'm cold on DWF support in MapGuide. Given my dwindling free time on anything MapGuide related, I'd rather spend it (wherever I can) on making MapGuide a better GIS/WebMap server than trying to maintain support for technologies that Autodesk themselves have given up on.

And judging by these poll results, I would gather that you (the poll respondent) would mostly agree with my sentiments.

Wednesday 15 August 2018

A short MapGuide poll

If you are a MapGuide user/developer reading this post, I have a short survey I'd like you to take part in.

I'll leave submissions open until the end of this month which should be enough time to gather a good representative opinion on this matter.

Friday 3 August 2018

Announcing: MapGuide Maestro 6.0m10 and a new build of Fusion

This announcement is a double-whammy because they are both somewhat intertwined.

Firstly, we'll start with a new build of Fusion that cleans up several aspects of the viewer framework. These changes in Fusion are slated for inclusion in a future release of MapGuide

New PHP entry point for fusion templates

This new build of Fusion introduces a new PHP entry point for the 5 fusion templates.

Instead of loading say ... the slate template like so:

http://servername/mapguide/fusion/templates/mapguide/slate/index.html

You can now load it like so:

http://servername/mapguide/fusion/templates/mapguide/index.php?template=slate

This entry point supports all the same query string parameters as the original templates but with support for the following additional parameters:
  • template (required) - The name of the template to load 
  • debug (optional) - If set to 1, the entry point will use fusion.js instead of fusionSF-compressed.js, making the whole debug/development process way more simpler.
The entry point also fetches the application definition and writes it out to the underlying template as JSON, avoiding the need for the initial round trip to fetch this document among other things.


Fixing external base layer support 

The way external base layers are currently supported in Fusion is a bit crufty which this build also addresses:
  • Fusion no longer attempts to append script tags to support Google Maps / Bing / OSM / Stamen. The way we do it is unsafe according to modern browsers. That is now the responsibility of the new entry point.
  • For Bing / OSM / Stamen, we no longer load external helper scripts at all. This is because such support is already present in OpenLayers itself and the external scripts are merely convenience wrappers that we can easily implement ourselves in Fusion.
  • Finally, XYZ layers are now properly supported in Fusion. This means you can do things like consuming OSM tiles from your own OSM tile server, or maybe use non-watermarked CycleMap/TransportMap layers, or you can finally be able to consume your own MapGuide XYZ Tile Set Definitions.
Now the reason this announcement is a double-header is because these changes in Fusion really needs tooling assistance to best take advantage of these changes, so here's also a new release of MapGuide Maestro as well. Here's the notable changes.

Fusion XYZ layer editor support

Now that we have proper XYZ tile layer support in Fusion we now have support for consuming external XYZ tile sets.

 
Because MapGuide XYZ Tile Sets Definitions can now be consumable with Fusion, you can specify a tile set URL for such a Tile Set Definition by clicking the new Add from XYZ Tile Set Definition toolbar button.

If you want to consume OSM tiles from your own OSM tile server you can use this editor and point it to your OSM tile server with the requisite ${x}, ${y} and ${z} placeholders.

RtMapInspector tool improvements 

The other major feature of this new release is improvements to the RtMapInspector.

For a refresher, the RtMapInspector tool was introduced way back in a beta release of Maestro 5.0 and the purpose of this tool was to easily inspect the state of any runtime map if you know its session id and map name so you can easily debug map manipulation and state updates. Did your MapGuide application code correctly added your new layer? You can use this tool to inspect the map state and find out.

Having looked at this tool more recently, I've come to realise that I'm only skimming the surface of what this tool is capable of and with this release, the capabilities have been significantly expanded.

For example, the tool now lets you see the map image for the current map state



But it also occurred to me if we're inspecting a map, we can (and should be able to) also inspect its layers (and their feature sources) too! So when you select any layer in this tool, a new Inspect Layer button is enabled.


Clicking it will bring up an inspection dialog that shows the layer's XML and be able to interact with its feature source using the same components as the local feature source preview.



Other Changes
  • Now requires .net Framework 4.7.1. The windows installer will check for this (and install if required)
  • Maestro API now uses the latest stable releases of NetTopologySuite and GeoAPI
  • The MgTileSeeder tool now targets .net Core 2.1

Download MapGuide Maestro
Download test build of Fusion

Wednesday 11 July 2018

Introducing: New experimental bindings for the MapGuide API

I haven't been quiet on the MapGuide front. I've just been deeply entrenched in my lab conducting an important experiment whose results are finally coming into fruition that I am back here to make this exciting announcement.

That experiment was: Can we generate bindings for the MapGuide API using a vanilla version of SWIG? Yes we can!

Background

This is an important question that we needed an answer for and we wanted that answer to be "Yes". 

We currently provide bindings for the MapGuide API in:
  • Java
  • PHP 5.x
  • .net (full framework)
However, we currently use an ancient and heavily modified version of SWIG, whose unclear audit trail of modifications and changes means that being able to support newer versions of PHP (ie. PHP 7.x) or variants of .net like .net Core is nigh-impossible, which puts us in a bit of a pickle because:
  • PHP 5.6 (our current bundled version of PHP) will be end-of-life on December 2018. Bundling and targeting an EOL version of PHP is not a good look. To bundle the current version of PHP (7.x) we need to be able to generate a compatible PHP extension for it. We can't do that with current internal copy of SWIG as the zend extension APIs have massively breaking changes from PHP5 to PHP7.
  • .net Core is where the action is at in the .net space, and not having a presence in this space diminishes our story of being able to build MapGuide applications in .net because as time goes on, that definition of ".net" will assume to mean both the (windows-only) full framework and (cross-platform) .net core.
  • We may want to add support for additional programming languages in the future. Can't do it with our super-modified copy of SWIG again because of the unclear history of changes made to this tool.
Given these factors, and the untenable situation we currently find ourselves in technology-wise, we needed to explore the possibility of generating the bindings using a vanilla (un-modified) version of SWIG. If we're going to go vanilla, we want the latest and greatest, which supports generating bindings for PHP7, and can support .net core with the right amount of SWIG typemap elbow-grease, so all the more motivation to get this working!

What we now have

2 months since the decision to embark on this journey, the mission to get functional MapGuide bindings using vanilla SWIG has been a success! We now have the following bindings for the MapGuide API:
  • A Java binding modeled on the non-crufty official Java binding. Requires Java 7 or higher.
  • A (currently windows-only) PHP extension for PHP 7.1
  • A netstandard2.0-compatible binding for .net that works on both .net Core and full framework and is also cross-platform for platforms where both .net Core and official MapGuide binary packages are available for. For Linux, that means this .net binding works in Ubuntu 14.04 64-bit (where .net Core also has packages available). The nuget package for this binding is fully self-contained and includes the necessary native dependencies (both 32 and 64-bit) needed for the .net library to work. For .net full framework, it includes an MSBuild .targets file to ensure all the required native dependencies are copied out to your application's output directory.
Where to get it

You can grab the bits from the releases page of the mapguide-api-bindings GitHub repo.

For .net, you will have to setup a local package source and drop the nuget package there in order to consume in your library/application.

You will need MapGuide Open Source 3.1.1 installed as this is the only version of MapGuide I am generating these bindings for and testing against. Please observe the current supported platform matrix to see what combinations of technology stacks work with this new set of bindings. Please also observe the respective notes on the .net, PHP and Java bindings to observe what changes and adjustments you need to make in your MapGuide application should you want to try out these bindings.

Sample applications (to make sure this stuff works)

As proof that these bindings work, here's a sample asp.net core application using the new MapGuide .net binding. As a testament to what targeting .net Core gives us, you could bypass building the sample application from source and perhaps give the self-contained package a go. Thanks to the powerful publishing capabilities provided by the dotnet CLI, we can publish a self-contained .net core application with zero external dependencies. In the case of this sample application, you can download the zip, extract it to a windows or Ubuntu 14.04 64-bit machine with a standard MapGuide Open Source 3.1.1 install, run the MvcCoreSample executable within, go to http://localhost:5000 and your MapGuide application is up and running!




For Java and PHP, I'm still cooking up some sample applications in the same vein as the asp.net core one (ie. Porting across the MapGuide Developer's Guide samples), but for now the only verification that these bindings work is that our current binding test suite run to completion (with some failures, but these failures are known failures that are also present in our current bindings).

Where to from here?

I intend for the mapguide-api-bindings project to serve as an incubation area where we can iron out any show-stopping problems before planning for the eventual inclusion into MapGuide proper and supplementing (and in the case of PHP, replacing) our current bindings because eventually, we have to. We cannot keep bundling and targeting PHP 5.x forever. We need to be able to target newer versions of these programming languages, and maybe in some cases new programming languages.

mapguide-api-bindings project repo
asp.net core sample application repo

Thursday 10 May 2018

Announcing: MapGuide Maestro 6.0m9

Here's a new milestone release of MapGuide Maestro. Here's what's new in this release.

mapguide-react-layout support

One of the design goals of mapguide-react-layout viewer was to be highly compatible with existing Web and Flexible layout documents ensuring for the same authoring experience as the existing AJAX and Fusion viewer offerings.

However, the authoring experience in Maestro knows nothing about mapguide-react-layout, so any authoring experience still assumes the use of AJAX or Fusion viewers.

With this release, we have a new preference for specifying the base URL of a mapguide-react-layout installation.


Once this is set, the Web and Flexible Layout editors light up with additional viewer URLs allowing you to load the Web/Flexible Layout with a mapguide-react-layout template of your choice. 



Since the UI for this has changed from a read-only text box to a combo box, once cannot easily select the URL to copy/paste. To workaround this, a convenience "Copy to Clipboard" button is included to easily copy the current viewer URL for pasting elsewhere.

The other authoring experience change is that a new Flexible Layout will no longer include Fusion widgets that are not supported by mapguide-react-layout. These widgets are really esoteric ones, so most authors won't probably notice any differences.

MgTileSeeder improvements

The new MgTileSeeder tool has been improved with the following changes:
  • A new --failed-requests parameter for specifying a log file to log failed requests to
  • A new --max-parallelism parameter for controlling the max degreee of parallelism when sending tile requests
  • New xyz_replay and mapguide_replay commands for re-requesting failed requests from a log file previously logged via the new --failed-requests parameter
Improved OGR Feature Source support

The OGR provider has been the primary recipient of my continued developer attention since the release of MapGuide Open Source 3.1.1 as there are many things in the provider with room for improvement. Given this, it was time to also give the OGR provider equivalent treatment in Maestro, so with this release, feature sources using the OGR provider now has its own specialized editor.



Most of the UI here should be self-explanatory, but the Other Properties section deserves some explanation. This is a future-proof data grid for editing connection properties that may be introduced in future builds/releases of the OGR provider.

Another case where the OGR provider gets better treatment is the support in the SHP feature source editor to convert it across to use the OGR provider. 



This feature was added to improve the SHP story for MapGuide on 64-bit Linux where the current dedicated SHP provider has unresolved 64-bit portability problems making it unusable. However, the OGR provider has no such issues making it a viable alternative FDO provider for SHP files on 64-bit Linux. This conversion feature helps facilitate this transition in an easy manner. However, there's still some glaring problems with the converted OGR feature source, such as the FDO provider using a hard-coded schema name of "OGRSchema". Nothing some python scripting elbow grease can't fix afterwards. Or you can watch this space :)

Other fixes/changes
  • Fix: Rename resource with "update references" checked will disregard overwrite flag
  • Fix: NullReferenceException when ticking a new geometry type and adding a rule to the grid for the first time in Layer Definition editor
  • Fix: MgInvalidRepositoryTypeException when validating layers. Previous workaround was to disable validation on save. With this release you can safely re-enable this if you so choose.
  • Fix: Editing default path in line usage context in Symbol Definition editor does nothing
  • Fix: Cannot browse symbol definiton parameters in any field of the Path editor dialog 
Download 
Project Web Site

Tuesday 10 April 2018

Some patches and fixes of MapGuide Open Source 3.1.1

Barely a week after releasing MapGuide Open Source 3.1.1, I've added some patches that may be of use for some of you out there.

Firstly, I've uploaded a newer release of Fusion that includes a fix for an issue with Google Maps support discovered after the 3.1.1 release. If you downloaded Fusion with the updated Bing Maps support in the past, this release is packaged in the same fashion: Download, extract and overwrite the existing Fusion installation.

Secondly, for those that use Oracle and have been clamoring for 12c support. I've uploaded experimental King Oracle FDO provider dlls that have been built against the Oracle 12c instant client SDK. These providers have not yet been fully tested against Oracle 12c and has been made available for you to provide any feedback or report any issues regarding 12c support.

If either one of these patches is of interest to you, grab them from the updated 3.1.1 release notes page.

Wednesday 4 April 2018

Announcing: mg-desktop and MapGuide nuget packages for 3.1.1

It's been so long since putting out the last release of MapGuide that you sometimes forget that there are also supplemental build artifacts that tail off of the main MapGuide build process that need to be released as well!

In our case, that would be new nuget packages for the MapGuide .net API and mg-desktop.

The new mg-desktop binaries are also available as plain zip packages, should the NuGet way of acquiring not work out for you.

Tuesday 3 April 2018

Announcing: MapGuide Open Source 3.1.1

I am pleased to announce the final release of MapGuide Open Source 3.1.1

The only changes from the Release Candidate are:
  • A fix in the AJAX viewer to prevent clicks in interactive tooltip content from falling through (possibly accidentally triggering map selections as a result).
  • Permission fixes for the windows installer and linux install scripts so that the Fusion QuickPlot widget can work out of the box.
Download/Release Notes

Thursday 29 March 2018

Wednesday 28 March 2018

Making Immutable.JS objects easier to work with in TypeScript: TypeScript 2.8 edition

TypeScript 2.8 was released today and one of the new touted features is conditional types.

With the introduction of condition types, it was worth revisiting an older post of mine about making immutable.js easier to use in TypeScript and see how one would solve this problem with TypeScript 2.8.

For reference, consider these interfaces:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
interface IGeographicCoordinate {
    lat: number;
    lng: number;
}

interface IPlacemark {
    id: number;
    coordinate: IGeographicCoordinate;
    name: string;
}

At the time of that post (this was before the revolutionary TypeScript 2.0 release), this was the best I could do to work with the immutable.js versions objects that adhered to the shape of the above interfaces.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
type GeographicCoordinateProperties = "lat" | "lng";
type PlacemarkProperties = "id" | "coordinate" | "name";

interface IGeographicCoordinateImmutable {
    get(key: GeographicCoordinateProperties): any;
    get(key: "lat"): number;
    get(key: "lng"): number;
}

interface IPlacemarkImmutable {
    get(key: PlacemarkProperties): any;
    get(key: "id"): number;
    get(key: "coordinate"): IGeographicCoordinateImmutable;
    get(key: "name"): string;
}

Notice we had to manually write "immutable" equivalents of every interface and we didn't have constructs like keyof to auto-deduce all the allowed property names. We also had to manually spell out all the specific return types for each property name due to mapped types not existing yet at that point in time.

With TypeScript 2.8, we can leverage conditional types and features from earlier versions of TypeScript to create this majestic piece of generic and type-safe beauty:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
interface ImmutableObject<T> {
    get<P extends keyof T>(key: P): T[P] extends Array<infer U> ? ImmutableList<U> : T[P] extends object ? ImmutableObject<T[P]> : T[P]; 
}

interface ImmutableList<T> {
    count(): number;
    get(index: number): T extends object ? ImmutableObject<T> : T;
}

// The immutable.js fromJS() API
declare function fromJS<T>(obj: T): ImmutableObject<T>;

So how does this work? To illustrate, lets update our example interfaces to include a 3rd interface


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
interface IGeographicCoordinate {
    lat: number;
    lng: number;
}

interface IPlacemark {
    id: number;
    coordinate: IGeographicCoordinate;
    name: string;
}

interface ISearchResult {
    query: string;
    results: IPlacemark[];
}

Then let's start with the get method of ImmutableObject<T>

The fragment P extends keyof T describes the type placeholder P on this method that is any variable that is a valid member name of type T. Using our above interfaces as an example, keyof IPlacemark is the type equivalent of:

 "id" | "coordinate" | "name"

The type of key parameter of the get method is constrained to any of the member names in T (auto-deduced via the keyof operator), thus you cannot plug in names of members that are not part of T.

The return type T[P] is a mapped type that gives the corresponding type based on the value you put in for the key parameter. If we use IPlacemark as an example:
  • Calling get with "id" will deduce T[P] to the type: number
  • Calling get with "coordinate" will deduce T[P] to the type: IGeographicCoordinate
  • Calling get with "name" will deduce T[P] to the type: string
We then leverage the new conditional types feature to conditionally deduce the appropriate return type based on properties of T[P] that we can ask of through the conditional types feature:
  • If the mapped type is an array (T[P] extends Array) resolve the return type to ImmutableList of the inferred type U. The infer U fragment defines an ad-hoc type placeholder U that will resolve to the item type of the array.
  • Otherwise, if it is an object (T[P] extends object) resolve the return type to ImmutableObject of the mapped type
  • Otherwise, it will resolve the return type to the mapped type.
To illustrate with ISearchResult as an example:
  • Calling get with "query" will deduce a return type of: string
  • Calling get with "results" will deduce a return type of: ImmutableList<IPlacemark>
Now on to the get method of ImmutableList<T>

ImmutableList<T> is a immutable collection wrapper. The get method here simply returns the item of type T at the specified index. Once again we leverage conditional types to ask some questions of the type T to deduce the correct return type.
  • If T is an object (T extends object), resolve the return type to: ImmutableObject<T>, making this mapped type fully recursive all the way down however many levels it needs to go
  • Otherwise T must only be a primitive type, so resolve the return type as-is.
Now how do we know this actually works and is not some abstract piece of theory?

See for yourself on the TypeScript playground (NOTE: If the code fragment doesn't load in the playground, you can copy/paste the code from this gist I've prepared earlier)

No red squiggles! Also, put your mouse over every variable, you will see the type matches the type specified in the respective end-of-line comment.

Hopefully this post has shed some light on how powerful this new conditional types feature of TypeScript 2.8 really is

Tuesday 27 March 2018

Announcing: MapGuide Open Source 3.1.1 Release Candidate

I am pleased to announce the release candidate of MapGuide Open Source 3.1.1 is now available.

Of the ton of bug fixes and minor enhancements since the 3.1 release, the key changes of note in 3.1.1 are:

Have a gander at the full list of changes for more information.

This is a release candidate, and not the final release as it's been so long since the 3.1 release that I want to make sure our release process is still sound after such a long break between releases. Barring anything of a show-stopping nature, the final release of 3.1.1 will drop one week from now.

Friday 16 March 2018

A TypeScript-powered moment of clarity

Today was a case where I forgot about one of the major strengths of TypeScript: The type-safety that it provides you and the features available to allow for writing code with maximum type-safety.

Consider this simple utility function in TypeScript

1
2
3
export const strIsNullOrEmpty(str: string | null | undefined): boolean {
    return str == null || str == "";
}

The function does what it says on the tin: Checks if the given string is null (or undefined) or an empty string and returns true if that's the case or false otherwise.

There's no problems with using this function, until you turn on null checks or use this function in a TS code-base with null checks enabled.


And if I hover over the red squiggly, I see this:


But how is that possible? I know that by calling this function, there's no way that the variable str could be null or undefined.

This is indeed the case ... at runtime.

At compile-time TypeScript does not know that. So short of spamming exclamation points all over your code, how can we tell TypeScript that the string we passed in cannot be null or undefined if we just checked for it?

The key is to change the function from the above example into this:

1
2
3
export function strIsNullOrEmpty(str: string | null | undefined): str is null | undefined {
    return str == null || str == "";
}

And the red squiggle goes away.

This is feature of TypeScript known as type guards. It's a way to write functions that evaluate to true/false at runtime, but at compile time allows you to make some assertions about the type of the variable you passed in to the TypeScript compiler. In our case, passing in a variable that could be a string or null or undefined has to be either null or undefined if this function returns true. If it returns false, then it has to be a non-null string, which TypeScript knows then to strip of the null | undefined on any subsequent if block following that function call. This is what's known in TypeScript as type narrowing.

Type guards have been in TypeScript for a long time, but it took today for me to realise that some of my utility functions (like this example) should've been written as type guards, especially with the advent of TypeScript 2.0 and its powerful null checking capabilities.

Now to double check places in my code where I've been sprinkling ! operators all over the place.

Wednesday 21 February 2018

Announcing: mapguide-react-layout 0.11

Here's a long overdue release of mapguide-react-layout with a ton of new features.

GIFs and screenshots galore below. Brace yourselves!

Adding external WMS layers

A new component is available to easily add external WMS layers to your map.



As previously mentioned, you can access this component through a InvokeURL command that uses a component://AddManageLayers URI instead of a normal URL.

Partial Application State now encoded in URL

Through the use of react-url-query, we now have the ability to transfer part of our internal application state into the URL, allowing us to reload the browser window and be able to resume from where we left off.


The following bits of application state are now encoded into the URL:
  • Current view (x/y/scale)
  • Current active map (for multiple map configurations)
  • Shown/Hidden layer and group names
  • Current session id
Share Link to View

A new component is available to easily share this newly stateful URLs to other users.


Once again, you can access this new feature through an InvokeURL that has a component://ShareLinkToView URI instead of a normal URL. The session id is omitted by default, but you can tick Include Session ID to include your session id

Measure Segment Display

This was a feature missing from the equivalent Fusion widget that has finally been ported over. The measure tool properly displays individual measured segments.


Segments are only displayed for geodesic measurements. 

Drawing/Digitization improvements

Digitization now supports easily undoing the most recently drawn point by pressing the 'U' key.


This key and the key for cancelling the digitization (ESC) can be bound to different keys through new viewer mount options.

Template Improvements

The ajax-viewer template has been tweaked to look more like the original

This is possible because of the use of react-splitter-layout that gives us resizable panels.

The slate, maroon, limegold and turquoiseyellow templates also use this new component to finally give us resizable sidebars.


HTML property values in Selection Panel

Through new mount options, you can specify property values that are HTML to be presented as actual HTML, meaning property values that used to look like this:


Now looks like this:


This feature is disabled by default and you must opt into it (through new mount options). If the HTML content you're presenting is potentially un-trusted you can provide a sanitization function to clean the provided content (for example, with DOMPurify) to guard against possible cross-site scripting attacks.

Other Changes
  • Updated React to 16.2
  • Updated Blueprint to 1.35.5
  • Updated OpenLayers to 4.6.4
  • Updated TypeScript to 2.7.2
  • Debug viewer bundle (viewer-debug.js) now included
  • Added support for CenterSelection fusion widget. This marks the end of the Fusion widget porting work. No further Fusion widgets will be ported across. The list of Fusion widgets that will not be ported across can be found here.
  • Added support for extra extension properties in Redline and SelectPolygon widgets
  • Flyouts are now mutually exclusive, behaving more like their Fusion counterparts
  • Broke/404 toolbar/menu icons now gracefully show error icon as a placeholder.
  • Added support for manual feature tooltip toggling. This replaces click-based map selection if active and can be controlled through the Viewer Options UI.
  • Fix: Initial view of the map not using full viewport.
  • Fix: Commands now fall back to running in modal dialog if Task Pane is not present.
  • AJAX map frame viewer API is now fully emulated.

Project Home Page
Download
mapguide-react-layout on npm

React-ing to the need for a modern MapGuide viewer (Part 20): It doesn't have to *specifically* be a URL

Wow! It's been 5 months since the last post related to mapguide-react-layout.

No I haven't stopped development. There's still plenty of things I want to achieve with this project before I consider it "done". It just had to take a back seat to other things that needed some attention:
Now that things have calmed down a bit, before I talk about the new release of mapguide-react-layout that will drop real soon, I want to talk about a capability of mapguide-react-layout that has been present for some time now, but I want to dedicate this entire post to because understanding this capability is the key in knowing how we can add new features to mapguide-react-layout yet retain the ability to use our existing Web Layout and Application Definitions to reference such new features.

I'm sure most of you should already be familiar with InvokeURL commands. You can define these commands in both a Web Layout and an Application Definition. They get represented in the AJAX/Fusion viewer as toolbar or menu items. When you click them, they invoke the specified URL into a given target (the Task Pane, a new window or a specific frame). InvokeURL commands is the basic gateway to custom MapGuide viewer functionality.

InvokeURL commands are also supported in mapguide-react-layout, except we can do extra things with such commands in mapguide-react-layout by leveraging the fact that a URL is merely a type of URI (Uniform Resource Identifier) and a URI ... does not necessarily have to start with http://. MapGuide resource identifiers (eg. Library://Foo/Bar.MapDefinition) are basically like URIs so this shouldn't be too much of a foreign concept.

So what does mapguide-react-layout do with this fact?

To demonstrate, here's a new feature that will be in the next release of mapguide-react-layout: A component to easily add external WMS layers


How can you access this new feature? Through an InvokeURL command.

Except, you don't invoke a URL you invoke a URI ... of our own custom creation.


As you can see from the above screenshot, we've invented our own component:// URI scheme to easily tap into new features in mapguide-react-layout without any structural changes required in the Web Layout or Application Definition schemas. We just leverage the existing InvokeURL command support and leverage the fact that whatever we're invoking in mapguide-react-layout ... doesn't necessarily have to be a URL. component URIs are structured as follows:

component://[component name][?query]

A component name refers to any component that's registered in the component registry. If a component can take parameters, you can pass them through the query string. Several components are available in the standard viewer bundle. The list of accessible components is available here.

If you use the npm module to roll your own custom viewer bundle, we provide APIs to allow you to easily create your own custom components. This is demonstrated in this example project.

The list of components available is small so far, that will grow over time as we add new features in future releases of mapguide-react-layout and the best thing about this is that to take advantage of such features, no changes to any authoring tools is required. You just have to enter a different kind of URI instead of a URL.

Saturday 10 February 2018

One MapGuide/FDO build system to rule them all?

Before the bombshell of the death of Autodesk Infrastructure Map Server was dropped, I was putting the final finishing touches of making (pun intended) the MapGuide/FDO build experience on Linux a more pleasant experience.

Namely, I had it with autotools (some may describe it as autohell) as the way to build MapGuide/FDO on Linux. For FDO, this was the original motivation for introducing CMake as an alternative. CMake is a more pleasant way to build software on Linux over autotools because:
  1. CMake builds your sources outside of the source tree. If you're doing development on a SVN working copy this is an absolute boon as it means when it comes time to commit any changes, you don't have to deal with sifting through tons of autotools-generated junk that is left in your actual SVN wc.
  2. CMake builds are faster than their autotools counterpart.
  3. It is much easier to find and consume external libraries with CMake than it is through autotools, which makes build times faster because we can just source system-installed copies of thirdparty libraries we use, instead of waste time having to build these copies (in our internal thirdparty source tree) ourselves. If we are able to use system-installed copies of libraries when building FDO, then we can take advantage of SVN sparse checkouts and be able to skip downloading whole chunks of thirdparty library sources that we never have to build!
Sadly, while this sounds nice in theory, the CMake way to build FDO had fallen into a state of disrepair. My distaste for autotools was sufficient motivation to get the CMake build back into working condition. Several weeks of bashing at various CMakeLists.txt files later, the FDO CMake build was operational again and had some several major advantages over the autotools build (in addition to what was already mentioned):
  • We can setup the CMake to generate build configurations for Ninja instead of standard make. A ninja-powered CMake build is faster than standard make ^.
  • On Ubuntu 14.04 LTS (the current Ubuntu version we're targeting), all the thirdparty libraries we use were available for us to apt-get install in the right version ranges, and the CMake build can take advantage of all of them. Not a single internal thirdparty library copy needs to be built!
  • We can easily light up compiler features like AddressSanitizer and linking with the faster gold instead of ld. AddressSanitizer in particular easily helped us catch some issues that have flew under the radar.
  • All of the unit tests are build-able and more importantly ... executable outside the source tree, making it easier to fix up whatever was failing.
Although we now had a functional FDO CMake build. MapGuide still was built on Linux using autotools. So for the same reasons and motivations, I started the process of introducing CMake to the MapGuide build system for Linux.

Unlike FDO, MapGuide still needed some of the internal thirdparty libraries built.
  • DBXML - No ubuntu package available, though we can get it to build against a system-provided version of xerces, so we can at least skip building that part of DBXML.
  • Apache HTTPD - Ubuntu package available, but having MapGuide be able to integrate with an Ubuntu-provided httpd installation was not in the scope of this work, even though this is a nice thing to have.
  • PHP - Same reasons as Apache HTTPD
  • Antigrain Geometry - No ubuntu package available. Also the AGG sources are basically wedded to our Renderers project anyways.
  • DWF Toolkit - No ubuntu package available
  • CS-Map - No ubuntu package available
For everything else, Ubuntu provided the package in the right version ranges for CMake to take advantage of. Another few weeks of bashing various CMakeLists.txt files into shape and we had FDO and MapGuide both build-able on Linux via CMake. To solve the problem of still needing to build some internal thirdparty libs, but still be able to retain the CMake quality of everything is built outside the source tree, some wrapper shell scripts are provided that will copy applicable thirdparty library sources out of the current directory, build them in their copied directories and then invoke CMake and pass in all the required parameters so that it will know where to look for the internal libraries to link against when it comes to build MapGuide proper.

This was also backported to FDO, so that on distros where we do not have all our required thirdparty libraries available, we can selectively build internal copies and be able to find/link the rest, and have CMake take care of all of that for us.

So what's with the title of this post?

Remember when I wrote about how interesting vcpkg was?

What is best used with vcpkg to easily consume thirdparty libraries on Windows? Why CMake of course! Now building MapGuide on Windows via CMake is not on the immediate horizon. We'll still be maintaining Visual Studio project files by hand (instead of auto-generating them with CMake) for the immediate future, but can you imagine being able to build FDO and MapGuide on both Windows and Linux with CMake and not have to waste time on huge SVN checkouts and building thirdparty libraries? That future is starting to look real possible now!

For the next major release of MapGuide Open Source, it is my plan to use CMake over autotools as the way to build both MapGuide and FDO on Linux.

^ Well, the ninja-powered CMake build used to be blazing fast until Meltdown and Spectre happened. My dev environment got the OS security patches and whatever build performance gains that were made through ninja and CMake were instantly wiped out and we were back to square one in terms of build time. Still, the autotools build performed worse after the meltdown patches, so while CMake still beats the autotools build in terms of build time, we ultimately gained nothing on this front.

Thanks Intel!!!