= Resource Object Model Overhaul = == The problem == The current xml classes were generated via xsd.exe (from .net framework 1.1) from an old MapGuide xsd schema set. Support for newer version xsds (eg. WebLayout v1.1) is either not currently implemented, or support is currently monkey-patched in. Because these generated classes targeted a specific version, it makes moving from older to newer versions of a given resource very hard to accomplish. Unlike MapGuide Studio, support for older versions of MapGuide is something we want to maintain at all costs. Simply put, the current resource object code is un-workable and a cleaner way to meet our requirements is needed. == The solution == === Throw out xsd.exe === xsd.exe generates really ugly code. Although the current version generates partial classes and has INotifyPropertyChanged support, it is still lacking in some areas. The limitations are described [http://themapguyde.blogspot.com/2010/05/xsd2code.html here] We will use [http://xsd2code.codeplex.com Xsd2Code] to generate our xml classes. Xsd2Code has been proven to generate much cleaner code than xsd.exe and allows for greater level of customisation and extension as a result. === Have resource classes implement a base interface === The current generated classes have no common base class or interface, which makes working with them generically a bit difficult as they have nothing in common. Maestro currently uses reflection to do this (ugly). Resource classes will implement the following interface: {{{ public interface IResource : INotifyPropertyChanged { string ResourceId { get; set; } string ResourceType { get; set; } Version ResourceVersion { get; } IServerConnection Connection { get; set; } } }}} === Partition implementations into separate namespaces and assemblies === The problem with running xsd.exe (or any other code generator) against the mapguide xsd schema set is the very high possiblity of naming collisions from the generated code. As such, the classes generated for Maestro 3.0 will be partitioned into separated namespaces. Each xsd will be generated into its own namespace and assmebly. For example: * !LayerDefinition-1.0.0.xsd classes will be in OSGeo.!MapGuide.!ObjectModel.!LayerDefinition-1.0.0.dll under the namespace OSGeo.!MapGuide!.ObjectModel.!LayerDefinition * !WebLayout-1.1.0.xsd classes will be in OSGeo.!MapGuide.!ObjectModel.!WebLayout-1.1.0.dll under the namespace OSGeo.!MapGuide.!ObjectModel.!WebLayout Not every xsd schema requires its own namespace and assembly. Things such as resource headers, data lists, etc. can be grouped together. The root resource object of each assembly will implement the IResource interface. All consuming clients will never reference these assemblies directly. They will use the IResource interface as a means of accessing these classes. [http://www.internetviz-newsletters.com/intertechtraining/e_article000333242.cfm?x=b4tbQ49,b2mW9yHJ Reference aliases] can be employed if we're working with identical types in identical namespaces in different assemblies. === Version-specific resource editors === The current resource editors try to handle as many versions of a given resource as much as possible. This makes maintenace a bit difficult to handle. Instead each version of a given resource will now have its own specific editor. Although this may/will result in lots of redundant code, it facilitates a "divide and conquer" approach to handling this problem and allows us to isolate specific editor functionality to specific editor versions. The current IResourceEditorControl interface will now become: {{{ public interface IResourceEditor { /// /// Gets or sets the resource in its current state /// IResource Resource { get; set; } /// /// Determines if the currently edited resource is a new resource /// bool IsNew { get; } /// /// Refreshes the display to reflect the current object /// void UpdateDisplay(); /// /// Initiates a preview, returns true if the call succeded /// bool Preview(); /// /// Validates the current resource, returns true if the call succeded /// bool ValidateResource(bool recursive); /// /// Initiates profiling, returns true if the call succeded /// bool Profile(); /// /// Returns a value indicating if the editor supports previews /// bool SupportsPreview { get; } /// /// Returns a value indicating if the editor supports validation /// bool SupportsValidate { get; } /// /// Returns a value indicating if the editor supports profiling /// bool SupportsProfiling { get; } /// /// Called before a save, to let the provider do the save, or some preliminary work. /// Return false to let the generic code handle the save. /// bool Save(string savename); } }}} Basically the only change is that the Resource property is now a strongly typed object. Only the editor classes will ever know the underlying implementation. All resource editors will now inherit from the following base class: {{{ public class ResourceEditorBase : UserControl, IResourceEditor { protected ResourceEditorBase(IEditorService ed) { ... } protected ResourceEditorBase(IEditorService ed, string resourceID) { ... } ... } }}} IEditorService is the new name for the currently named EditorInterface interface. Maestro already uses a form pseudo of dependency injection to instantiate the correct editor for a given resources. We will now use a formal API for this approach: {{{ public class ResourceEditorFactory { IResourceEditor GetEditor(IResource resource) { ... } IResourceEditor GetEditor(string resourceType, Version requestedVersion) { ... } } }}} The API allows us to request the right editor for the given version of this resource (the required information is in the IResource interface). In the event that Maestro cannot locate the right editor, the generic XML editor will be used (exactly how it's done right now). === Site Profiles === If the MapGuide Server we're connecting to supports a newer version of a resource type, we want to give the user the choice of whether to stay with the current version, or move up to the latest supported version. We will use a [http://trac.osgeo.org/mapguide/wiki/Maestro3Capabilities Capability concept] to programmatically determine if it is possible to upgrade any resource. {{{ public interface IConnectionCapabilities { bool IsKnownSiteVersion { get; } Version GetLatestSupportedVersion(string resourceType); ... } }}} All resource editors will have an upgrade option built in which will be enabled if the capabilities indicates a known site version returns a version higher than the current version of the edited resources. This is a reasonable balance between doing a silent upgrade (bad) and having to manually upgrade the resource (good, but cumbersome) The Maestro 3.0 API will be bundled with pre-configured capabilities for all known MapGuide versions. For unknown site versions, upgrading is turned off. === Flexible upgrade paths === To make resource upgrades/downgrades easy, we need API support to convert resources to different versions. {{{ public interface IResourceConverter { IResource Convert(IResource resource, Version version); } }}} From a consuming client's perspective, they do not require direct references to the resource model assemblies. Only the implementor of this interface needs to know about this information. The resource upgrade strategies is simply: For upgrading, add new elements with default values. Check if content from the [http://trac.osgeo.org/mapguide/wiki/MapGuideRfc10 ExtendedData property] can provide these values.