Wednesday, 20 March 2013

250 not out

Hmmm, didn't I just celebrate my 200 post milestone not too long ago?

Time either flies or MapGuide/FDO/Fusion/Maestro is still a deep pool with plenty of material to still salvage from.



Given my current draft queue, I think it's the latter :)

MapGuide tidbits: Fusion with .net/Java

Let me clear up a possible misconception with Fusion.

Just because Fusion is built with HTML, JavaScript and PHP does not mean PHP is your only choice of language for building extending application functionality through the MapGuide API.

Fusion, like the AJAX viewer both provide the same common extension points for your viewer:

  • Invoke Script commands
  • Invoke URL commands
Invoke Script commands are javascript-based, so for the AJAX viewer, you're coding commands against it's viewer API, for Fusion you're coding commands against the Fusion API

Invoke URL commands simply launch the specified URL into the Task Pane or a specified target. The AJAX/Fusion viewer does not care about whether the page serving that URL is written in PHP, .net or Java. All your viewer cares about is that your page exists and accepts a SESSION, LOCALE and a MAPNAME parameter, that contain the MapGuide session id, the desired locale code, and the map name (to be able to Open() a MgMap) respectively. You can write this page in any of the languages supported by the MapGuide Web API. The viewer doesn't care.

Besides, even if you did not install the PHP viewer as part of the MapGuide installation, PHP the runtime is still installed regardless as that's required by the MapGuide Site Administrator and the feature source previewer applications and Fusion. So PHP will never be missing in a MapGuide installation.

Sunday, 17 March 2013

Announcing: MapGuide Open Source 2.5 RC1

Here's the first (and probably only) Release Candidiate for MapGuide Open Source 2.5

The release comes in the following flavours:
  • 32/64-bit Windows Installer
  • 32/64-bit Windows InstantSetup bundles
  • 32-bit Ubuntu 12.04 deb installer
  • 32-bit CentOS 6.x tarball
This release was built with the FDO 3.8.0 RC1 binary SDKs for windows and linux and still includes the ArcSDE provider.

The key changes/fixes from beta 1 include:
All currently open tickets targeted for 2.5 will either be moved to 2.6 or closed due to ticket inactivity and/or lack of information (what did I say about this?). Only report issues targeting 2.5 if it is:
  • Related to Fusion
  • A true show-stopping defect in the server or web tier that prevents us from shipping the final release.
Otherwise, it's not considered high-priority enough for us to address for 2.5

Saturday, 16 March 2013

MapGuide tidbits: scale range gotcha

Here's a little gotcha to be aware of.

Consider this Layer Definition



Do you think this layer covers all scales from 0 to 15000?

For those who thought not, you can stop reading this post now :)

Otherwise read on.

The layer above does not actually cover all scales from 0 to 15000 because the stylizer only considers a view to be in a given scale range if the scale is greater than or equal to the minimum scale and less than the maximum scale of that scale range

ie. Your view scale is applicable for this range if: min scale <= view scale < max scale

This means for a view scale of 5000 or 10000, you actually have no matches according to the stylizer and nothing from that layer will be rendered out.

This isn't much of a big deal for a Map Definition full of dynamic layers, but for Map Definitions with tiled layers, this can be a problem. One or more of your finite scales may be off by 1 and nothing is actually rendered in your map tiles as a result.

So remembering the range check as stated above helps.

Wednesday, 13 March 2013

MapGuide tidbits: The golden rule of selection

I probably have mentioned about this in passing in a previous post, but it's probably worth repeating in a separate dedicated post because it's very important. The golden rule of selection:

For a layer to be selectable, it's feature class must have identity properties

If you can't select objects on from a layer on a map, always refer to the above rule. It will be true 99% of the time.

Now where this would commonly be the case (no identity properties) is if you are creating a layer off of a database view, where FDO is generally not clever enough to infer the identity properties from that view. In such cases, schema overrides come to the rescue allowing to you override how the FDO provider is supposed to interpret your physical data store.

Now surprisingly, this rule does not just apply to you users and developers building MapGuide applications. It equally applies to us developers hacking on the MapGuide core.

Case in point, a show-stopping bug relating to the RFC123 optimizations. After scratching my head for days wondering why a SQL Server RFC123-optimized layer was not selectable, I remembered about this rule and it lit a light bulb, giving me greater clues about the source of the problems. Turns out the MgFeatureReader wrapping our FDO join query result used for rendering/stylization presented a class definition that (you guessed it) did not have any identity properties. So when MapGuide needed to extract the class definition from the MgFeatureReader to build a selection set, there was nothing there to build a selection out of!

After some hacking around of the class definition that's returned by the reader in such cases, we now have selections working again!

So it helps to memorize this rule. It won't let you down because it sure didn't let me down.

Saturday, 9 March 2013

MapGuide tidbits: UpdateFeatures

Here's a long overdue post about a part of the MapGuide API that will no doubt confuse beginners (and some experienced ones too). The UpdateFeatures method of MgFeatureService

What does this method do?

UpdateFeatures is your one stop shop for all you spatial data CRUD needs. Don't let the name fool you, this method does the full (C)reate, (U)pdate and (D)elete portions of the CRUD quartet, the (R)ead portion handled by the SelectFeatures method. If you are going to be manipulating data in your MapGuide Feature Sources, you will need to know how to use this method.

The method signature looks like this:

MgPropertyCollection UpdateFeatures(MgResourceIdentifier resource, MgFeatureCommandCollection commands, bool useTransaction); 

and a new variant that takes MgTransaction objects was introduced in MapGuide Open Source 2.2

MgPropertyCollection UpdateFeatures(MgResourceIdentifier resource, MgFeatureCommandCollection commands, MgTransaction transaction); 

The general process of using this method is:

  1. Identify the Feature Source you are going to be manipulating
  2. Load up one or more manipulation commands 
  3. Execute the UpdateFeatures method
  4. Inspect and/or process the return value
Manipulation commands

You can load up to 3 different types of commands into the MgFeatureCommandCollection
  • MgInsertFeatures: A command that inserts one or more features/records into a specific feature class. Analogous to a SQL INSERT or BULK INSERT.
  • MgUpdateFeatures: A command that updates features in a specific feature class with the given set of property values based on a filter criteria. Analogous to a SQL UPDATE.
  • MgDeleteFeatures: A command that deletes features in a specific feature class based on a filter criteria. Analogous to a SQL DELETE.
The commands are executed sequentially in the order that they were added into the collection

Transactions

If you call UpdateFeatures with useTransaction = true or call the other variant passing in a valid MgTransaction object. The method will execute atomically inside a transaction (created internally or the one you passed in). If any failures occur, the method as a whole will fail and a MgFdoException is thrown on the first failure. 

If you passed in a MgTransaction object, you will have to remember to rollback this transaction after catching the exception. If you call UpdateFeatures with useTransaction = true, a transaction is created internally, and is rollbacked internally in the event of a failure. An MgFdoException is still thrown in this case.

If you call UpdateFeatures with useTransaction = false or call the other variant with a null MgTransaction, the method will not throw any MgFdoException, which will undoubtedly be a great source of confusion.

Exceptions that occur with a non-transactional UpdateFeatures are actually serialized out as part of the return value. Read on to the next section for the nitty gritty.

The key thing to note here is that transactions are not universally supported across the different FDO providers, so it is illegal to call UpdateFeatures with useTransaction = true if the underlying FDO provider does not support transactions. To determine whether transactions can be used, you would have to inspect the FDO provider's capabilities XML (with the GetCapabilities method).

However, if you know what Feature Sources you'll be working with up-front, then you'll most likely know what its capabilities are and you can bypass this programmatic checking of capabilities and just call UpdateFeatures transactionally or non-transactionally.

The return value

The UpdateFeatures method returns a MgPropertyCollection that contains a command result corresponding with each command in the input MgFeatureCommandCollection. The first item in the MgPropertyCollection carries the result of the first command in the MgFeatureCommandCollection, and so on.

This is the mechanism by which individual command results can be inspected in a non-transactional call to UpdateFeatures, as some commands in a MgFeatureCommandCollection may succeed and some may fail.

As a general rule, never call UpdateFeatures and disregard the return value. It is important to inspect the values in this collection to determine whether your call as a whole is a success or failure.

The type of results in this collection depends on the type of command executed:
  • A MgInsertFeatures returns a MgFeatureProperty containing a MgFeatureReader of the inserted features. You should remember to always close these readers as dangling feature readers are a notorious cause of busy resource errors.
  • A MgUpdateFeatures returns a MgInt32Property containing the number of features updated.
  • A MgDeleteFeatures returns a MgInt32Property containing the number of features deleted.
  • An MgStringProperty indicates a failure with the corresponding command and contains the serialized FDO exception message.
Now until MapGuide Open Source 2.4, we actually forgot to include that final point in the API documentation which just happens to be the most important point of them all as it is the way you check if an UpdateFeatures has partially failed in a non-transactional call. Transaction calls throw exceptions, non-transactional calls serialize internally caught exceptions into MgStringProperty objects.

Does it have to be *this* complicated?

That was my initial thought when I looked at this method the first time round. Having to create all these commands, all these collections, all these objects just to insert one feature! The API just feels so clunky with all this complex setup of the UpdateFeatures method parameters.

It is this thought that drove me to provide a simplified set of APIs in mg-desktop to simplify the insert/update/delete of spatial data, by actually providing indiviudal InsertFeatures/UpdateFeatures/DeleteFeatures methods so you don't have to go through this complex monolithic method call. Bringing such convenience APIs over to MapGuide proper is under my consideration   for something after MGOS 2.5.

My thoughts on this API changed however when I looked at the WFS-T specification. I couldn't help but notice that the WFS-T inputs and outputs described in the specification conceptually map quite easily into the inputs and outputs of this "clunky" UpdateFeatures API. So I guess this API was designed this way for a reason: To lay the groundwork for adding WFS-T support in MapGuide for anyone who accepts the challenge ;-)

In closing

So what's the minimum you should get out of this?
  • Call UpdateFeatures transactionally if you can. It simplifies error handling. All you have to do is be on the lookout for MgFdoExceptions
  • Not all FDO providers support transactions. You can programmatically check its capabilities to determine if transactions are supported. But if you know what feature sources you're working with, you would generally know up front whether transactions are available to you or not.
  • Always inspect the return value. If you don't really care, then at the minimum always close any feature readers and log/aggregate any MgStringProperty values in the MgPropertyCollections as these represent the command failures in a non-transactional UpdateFeatures call
  • Yeah the API is somewhat clunky, but IMO it's clunky for a reason. We can definitely make things simpler, but it will have to be a post-2.5 release exercise

Fusion redlining revisited.

For the next MapGuide Open Source 2.5 release (not sure if it will be another beta or straight to RC atm), we're giving the Fusion (in particular the Redline widget) a bit more spit and polish.

History

As explained previously, in this author's opinion, the original Redline widget for Fusion was completely useless functionality wise:

  • Can't plot a view of your map with your redlines
  • Can't control the styling of your redlines
  • GML is your only import/export format. Who on earth consumes GML? Certainly not Autodesk's geospatial products!
So we threw it out and rebuilt it based on the original Generic Tasks sample for the AJAX viewer.

Now admittedly, the v1 re-implementation (which was in AIMS 2013) was nothing more than a carbon copy of the Generic Tasks sample, meaning not much real thought was put into usability and user efficiency. The redlining process was a cumbersome multi-step process that didn't really scream productivity.

So for the MGOS 2.4 iteration of this widget, we patched up the usability problems, shortcutting most of the previously mandatory setup steps (with options to revisit these steps if required). We also took advantage of some previously-unknown fusion components (to me anyway) to improve the digitizing process with informative prompts.

This iteration while usable and powerful, had one remaining limitation. SDF was the only import/export format. While round-tripping between Autodesk's geospatial products is not a problem, round-tripping to other geospatial software is a problem because SDF is not exactly a well supported format outside of Autodesk's range of geospatial products.

The widget improvements

So for the MGOS 2.5 iteration of this widget, the Redline widget now supports the following formats:
  • Import: SDF, SQLite and SHP (as a zip file)
  • Export: SDF, SQLite, SHP (as a zip file), KML and KMZ
That's 2 extra import formats and 4 extra export formats!

Here's how the revised management UI looks


Most of the UI functions as it did before, so we'll just cover the bits that have changed.

What was previously the "New" button has now been separated into its own section 


This may look a bit complex, but it's not really. You pick the types of geometries you want to be able to digitize and hit the button to create the redline data store of the desired format. 

Why did we have to do this? Simple. If we want to support the ever-ubiquitous ESRI SHP file as a redline import/export format, we have to cater to its extremely cumbersome file storage limitations. While SDF/SQLite files can happily store all 3 geometry types for redline data, SHP can only support one geometry type per SHP file

So if we want the user to be able to record redlines in SHP files, we have to know what type of SHP file the user wants to create. As you can see from the screenshot, as all 3 geometry types are selected so SHP is not available as an option. But if you only checked one of those types, the ability to create a SHP file for redlines is then made available.

The second difference, is in the actual redline digitizing UI. Geometry types that cannot be digitized will be disabled. So the digitizing UI for a point-only SHP file looks like this (notice how only "Point" is enabled):



The final difference, is the expanded list of download options.


"Download Data" will serve out the redline data store as before. KML and KMZ download options take advantage of MapGuide's built-in KML service APIs to export the selected redline layer out as KML/KMZ files. Unlike the normal usage scenario, this a full KML/KMZ dump of the layer (ie. a GetFeaturesKml call) and not the map (ie. GetMapKml), which is actually a KML skeleton of NetworkLinks back into the mapagent to get the actual layer KML data.

So how does this KML look? Here's some redlines I've prepared earlier


Clicking "Download KML" or "Download KMZ" gives you the download prompt.


Which looks like this when we look at it from Google Earth


As you can see, we lose a bit of visual fidelity because MapGuide styles don't cleanly translate 1:1 to KML styles, but the core geometric shapes and text information are there.

A general note about Importing/Exporting

I guess we failed to document this when re-implementing this widget so it's better now than never.

There are some caveats to take note of when importing/exporting redlines.
  • Your export format is the format that you specified when you created/imported the redline data store. If you created a SQLite redline data store, that is what you will get prompted to download (a SQLite file) when exporting. Previously the only supported data store format was SDF, so this wasn't much of an issue.
  • If exporting redlines as SHP, you will be prompted to download a zip file. Once again, the shapefile format is not one file, but a set of inter-related files. Since we can't prompt you to download multiple files at once, the widget zips up the files in question and serves that file out for download.
  • Similarly for importing redline files. If you want to import a SHP redline, it has to be a zip file of the SHP file and its related DBF, IDX, SHX, etc files.
  • On the general subject of importing, the file you choose to upload must meet certain structural requirements in order to be accepted as a redline feature source. Generally speaking, we assume you are uploading redline files created orignally by this widget.
  • Exporting only exports the data and not its visual representation (ie. the Layer Definition)
  • Similarly, importing will set up a default Layer Definition for your uploaded data.