= !MapGuide RFC 117 - Desktop Platform API = This page contains a change request (RFC) for the !MapGuide Open Source project. More !MapGuide RFCs can be found on the [wiki:MapGuideRfcs RFCs] page. == Status == ||RFC Template Version||(1.0)|| ||Submission Date||20 June 2011|| ||Last Modified||18 Jan 2012|| ||Author||Jackie Ng|| ||RFC Status||adopted|| ||Implementation Status||Implemented|| ||Proposed Milestone||2.4|| ||Assigned PSC guide(s)||(when determined)|| ||'''Voting History'''||(vote date)|| ||+1|||| ||+0|||| ||-0|||| ||-1|||| ||no vote|| || == Overview == This RFC proposes a desktop-based implementation of the MapGuide Platform API. == Motivation == Snipped from the [http://trac.osgeo.org/mapguide/wiki/Future/DesktopSdk Futures] article ... > MapGuide contains all of the features of a great desktop mapping component: Data access, rudimentary GIS, stylization and more. > > Although the current build is tightly bound to a server service, it would be useful to create a build profile (free of any server dependencies) that provided a desktop developer to quickly add spatial visualisation and interactivity to their application. The web and server-centric nature of MapGuide means that it is currently not possible to have a '''truly disconnected''' desktop client mapping application. Under MapGuide 6.5, this was somewhat possible by using the technique of embedding the ActiveX viewer control and loading a MWF filled with static layer data. If you wind the clock even further back, Autodesk had a specialized product for this purpose (Envision/OnSite Desktop) which has long since been discontinued. Under the current MapGuide, there is nothing that approaches this kind of setup in terms of installation and resource footprint. Currently, if you want to build a MapGuide "desktop" application, you '''have''' to have a MapGuide Server and Web Tier present on the desktop and incur the overhead of having both of these running at the same time. Clayton Hotson's [http://au.autodesk.com/?nd=class&session_id=5241 AU 2009 Presentation] showed that it was indeed possible to utilize components of the MapGuide stack '''outside''' of the MapGuide Server to create applications that have no server or web tier dependencies (in the case of the AU presentation: A map renderer). The MapGuide Platform API itself is already modular and abstract enough to have an implementation in MapGuide/AIMS and another implementation in AutoCAD Map3D. What would be really nice is to take the concepts from that presentation to its logical conclusion, into a separate '''desktop-based''' implementation of the MapGuide Platform API Having a desktop-based MapGuide API opens up a whole new class of mapping applications that can use the same data access, rendering and stylization available in MapGuide, but without needing connectivity to a local or remove MapGuide Server as all the functionality is now self contained. This makes for a suitable foundation for mobile and remote field mapping applications. == Proposed Solution == A desktop-implementation of the MapGuide API currently exists on [http://mg-desktop.googlecode.com Google Code]. A binary package is [http://code.google.com/p/mg-desktop/downloads/list available to download], which contains some test programs that use this API. This desktop API implements the abstract classes and interfaces defined in the Platform API: * MgMapBase * MgLayerBase * MgSelectionBase * MgFeatureService * MgResourceService * MgFeatureReader * MgDataReader * MgSqlDataReader * ... others In addition, several MapGuide Server-specific APIs have also been ported across: * MgDrawingService * MgRenderingService * MgTileService Also included in mg-desktop, is a WinForms-based map viewer component library which has 80% of the functionality of the AJAX/Fusion viewer, which can be embedded in your own .net applications. The missing 20% is mainly support for tiled map layers and maps with dynamic/tiled layer combinations. In terms of implementation details: MgFeatureService for the desktop is a thin wrapper around FDO. Each service API maps to its corresponding FDO command. MgResourceService for the desktop wraps a pre-defined directory on the native filesystem. Package loading is also implemented allowing for spatial data portability between a MapGuide Server and an application using the Desktop Platform API. Because it wraps the underlying filesystem and resource ids are mapped to file paths, resource ids are '''no longer case-sensitive''' for windows where file paths are not case-sensitive. MgMapBase, MgLayerBase and MgSelectionBase are near 1:1 copies of their MapGuide Server counterparts. Because the desktop implementation does not have to address http statelessness like the MapGuide Web API, the Open() and Save() and Create() methods of MgMapBase are not required and have been removed from the desktop implementation. MgFeatureReader, MgDataReader and MgSqlDataReader wraps their respective FDO reader interfaces. Feature Joins and Extended Feature Classes are also supported, re-using the same component (GwsQueryEngine) as the MapGuide Server. This desktop implementation fulfills the data access (MgFeatureService) and rendering/stylization (MgRenderingService) requirements needed to build a functional desktop mapping application. This desktop implementation also includes a functional .net wrapper API, created via the existing SWIG infrastructure already present in the MapGuide source tree. Due to the tight dependency on server code, certain object caching and pooling mechanisms have been omitted from the desktop implementation. As already mentioned, the desktop implementation does not have to address http statelessness like the MapGuide Web API, as such certain concepts no longer apply when moving to the desktop: * Session Expiry - Session repositories still exist as a storage mechanism for transient resources, but session cleanup is now a manual action and not one that is automatically performed at certain intervals, thus there is no longer a need to keep a session "alive" as you would in a normal MapGuide Web Application * Using the session repository to maintain runtime map state and selection * Authentication * Resource Security As a result, the code you would write has been greatly simplified. Here's some examples (in .net) Creating a runtime map: {{{ using OSGeo.MapGuide; ... public void CreateMap() { MgResourceIdentifier mapId = new MgResourceIdentifier("Library://Samples/Sheboygan/Maps/Sheboygan.MapDefinition"); MgdMap map = new MgdMap(mapId); //That's it! You can now pass it to MgRenderingService to render images //No need to Open() or Save() like you would normally do with the //MapGuide Web API } }}} Accessing Services: {{{ using OSGeo.MapGuide; ... public void CreateServices() { //Use the MgServiceFactory class to create your required services MgServiceFactory factory = new MgServiceFactory(); MgdFeatureService featSvc = (MgdFeatureService)factory.CreateService(MgServiceType.FeatureService); MgdResourceService resSvc = (MgdResourceService)factory.CreateService(MgServiceType.ResourceService); MgRenderingService renSvc = (MgRenderingService)factory.CreateService(MgServiceType.RenderingService); } }}} Staying close to the naming conventions established in MapGuide, the desktop implementations of abstract classes in PlatformBase are prefixed "Mgd". Thus MgdMap is the desktop implementation of MgMapBase, MgdFeatureService is the desktop implementation of MgFeatureService, etc, etc. All these implementations can be upcasted, allowing them to be used with any existing code that targets these parent classes, allowing for the same level of code reuse that currently exists between AutoCAD Map3D and MapGuide. This RFC proposes that the desktop implementation that currently resides in Google Code be integrated into the offical MapGuide Source Tree. Doing so allows us to have a desktop API that will automatically gain all the enhancements/bugfixes that are made to the shared components. In addition, we can reuse the existing SWIG recipe files because both desktop and server will be using the same header files, allowing for reusable .net wrapper assemblies. The SWIG recipe files hosted on Google Code currently generate a monolithic .net assembly. == Desktop API additions to base platform APIs == In addition to implementing the core abstract classes provided by the MgPlatformBase library, the implementations are extended with additional APIs exclusive to this particular implementation: === MgdFeatureService === Adds support for additional FDO features currently not exposed in the MgFeatureService, such as: * Querying features with scrollable feature readers * A fine-grained CRUD API instead of the monolithic UpdateFeatures() in MgFeatureService * Provider registration/unregistration * CreateFeatureSource() supports the ability to create RDBMS feature sources (MySQL, SQL Server and PostgreSQL) via the desktop-only MgRdbmsFeatureSourceParams class. {{{ class MG_DESKTOP_API MgdFeatureService : public MgFeatureService { ... PUBLISHED_API: // Selects features from a feature source according to the criteria set in the // MgFeatureQueryOptions argument. Returns a feature reader that has counting and // scrolling capabilities MgdScrollableFeatureReader* SelectFeaturesExtended(MgResourceIdentifier* resource, CREFSTRING className, MgFeatureQueryOptions* options); // Registers a new FDO provider given its library path void RegisterProvider(CREFSTRING providerLibraryPath); // Un-registers a given FDO provider from the provider registry void UnregisterProvider(CREFSTRING providerName); // Inserts a new feature into the specified feature class of the specified feature source MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues); // Updates features of the specified feature class of the specified feature source with the specified filter int UpdateFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter); // Deletes features from the specified feature class of the specified feature source with the specified filter int DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter); // Inserts a new feature into the specified feature class of the specified feature source using the specified transaction MgFeatureReader* InsertFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, MgTransaction* trans); // Updates features of the specified feature class of the specified feature source with the specified filter using the specified transaction int UpdateFeatures(MgResourceIdentifier* resource, CREFSTRING className, MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans); // Deletes features from the specified feature class of the specified feature source with the specified filter using the specified transaction int DeleteFeatures(MgResourceIdentifier* resource, CREFSTRING className, CREFSTRING filter, MgTransaction* trans); }; }}} === MgdLayer === Adds extra convenience methods for new APIs in MgdFeatureService {{{ class MG_DESKTOP_API MgdLayer : public MgLayerBase { ... PUBLISHED_API: //Convenience form of MgFeatureService::BeginTransaction() virtual MgTransaction* BeginTransaction(); //Convenience form of MgdFeatureService::SelectFeaturesExtended() virtual MgdScrollableFeatureReader* SelectFeaturesExtended(MgFeatureQueryOptions* options); //Convenience form of MgdFeatureService::InsertFeatures() virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* propertyValues); //Convenience form of MgdFeatureService::UpdateFeatures() virtual int UpdateFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter); //Convenience form of MgdFeatureService::DeleteFeatures() virtual int DeleteFeatures(CREFSTRING filter); //Convenience form of MgdFeatureService::InsertFeatures() virtual MgFeatureReader* InsertFeatures(MgPropertyCollection* propertyValues, MgTransaction* trans); //Convenience form of MgdFeatureService::UpdateFeatures() virtual int UpdateFeatures(MgPropertyCollection* propertyValues, CREFSTRING filter, MgTransaction* trans); //Convenience form of MgdFeatureService::DeleteFeatures() virtual int DeleteFeatures(CREFSTRING filter, MgTransaction* trans); }; }}} == Implications == Like AutoCAD Map3D, certain aspects of the Platform API does not translate cleanly from the MapGuide Server context or are no longer applicable. As such the following functionality is currently not implemented (and throws MgNotImplementedException when invoked). * MgResourceService * EnumerateRepositories * CreateRepository * DeleteRepository * UpdateRepository * GetResourceHeader * ChangeResourceOwner * InheritPermissionsFrom * GetRepositoryContent * GetRepositoryHeader * EnumerateReferences * MgFeatureService * DescribeWfsFeatureType * GetWfsFeature The following resource types are not utilised under the Desktop API: * Web Layout * Application Definition Other features that are not yet fully implemented, tested or incomplete: * MgTransaction support In terms of compatibility, existing MapGuide application code is compatible at the source code level provided the code is targeting the subset of the MapGuide API that is supported and implemented by this desktop API. Once integrated into the MapGuide Source tree, it is possible for binary compatibility provided the client application is targeting the same shared wrapper components (Foundation, Geometry, PlatformBase, MdfModel, MdfParser) and that the desktop and server were built from the same source code revision as the desktop API can utilise the existing SWIG recipe files. Or to put it in simpler words: A .net application that references: * OSGeo.MapGuide.Foundation.dll * OSGeo.MapGuide.Geometry.dll * OSGeo.MapGuide.PlatformBase.dll Should be able to work on the desktop API, which would have identically generated assemblies. It is planned, should this RFC be approved, to put the migrated source into a "Desktop" top-level directory under MgDev. This will have minimal impact on the rest of the source tree. There are no plans to make this desktop API production ready for the 2.3 milestone. The scope of this RFC is to simply have the source of the desktop implementation integrated into the MapGuide source tree in a functional state by that stage. Unless there is interest from Autodesk, maintenance and enhancement of this codebase to keep up to date with future upstream platform and component changes will be a community responsibility Although care has been taken to avoid using windows-specific APIs, this current implementation currently only builds on Windows. Support for Linux is beyond the scope of this RFC and will be handled separately in a future date. == Test Plan == The desktop implementation already uses a near-identical test suite as the MapGuide Server and thus already has the same level of code coverage. == Funding / Resources == Community