[mapguide-commits] r4780 - in trunk/Tools/Maestro/MaestroAPI: . Generated

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Mon Apr 12 09:44:34 EDT 2010


Author: jng
Date: 2010-04-12 09:44:33 -0400 (Mon, 12 Apr 2010)
New Revision: 4780

Modified:
   trunk/Tools/Maestro/MaestroAPI/Generated/LoadProcedure-1.0.0.cs
   trunk/Tools/Maestro/MaestroAPI/ServerConnectionBase.cs
   trunk/Tools/Maestro/MaestroAPI/ServerConnectionI.cs
Log:
#579: This submission adds API support for the basic execution of Load Procedures.

Modified: trunk/Tools/Maestro/MaestroAPI/Generated/LoadProcedure-1.0.0.cs
===================================================================
--- trunk/Tools/Maestro/MaestroAPI/Generated/LoadProcedure-1.0.0.cs	2010-04-12 00:41:31 UTC (rev 4779)
+++ trunk/Tools/Maestro/MaestroAPI/Generated/LoadProcedure-1.0.0.cs	2010-04-12 13:44:33 UTC (rev 4780)
@@ -94,9 +94,9 @@
     [System.Xml.Serialization.XmlIncludeAttribute(typeof(DwgLoadProcedureType))]
     [System.Xml.Serialization.XmlIncludeAttribute(typeof(ShpLoadProcedureType))]
     public class LoadProcedureType {
+
+        private string[] m_sourceFile;
         
-        private StringCollection m_sourceFile;
-        
         private string m_rootPath;
         
         private string m_coordinateSystem;
@@ -129,11 +129,11 @@
         
         private string m_symbolLibrariesFolder;
         
-        private StringCollection m_resourceId;
+        private string[] m_resourceId;
         
         /// <remarks/>
         [System.Xml.Serialization.XmlElementAttribute("SourceFile")]
-        public StringCollection SourceFile {
+        public string[] SourceFile {
             get {
                 return this.m_sourceFile;
             }
@@ -306,7 +306,7 @@
         
         /// <remarks/>
         [System.Xml.Serialization.XmlElementAttribute("ResourceId")]
-        public StringCollection ResourceId {
+        public string[] ResourceId {
             get {
                 return this.m_resourceId;
             }

Modified: trunk/Tools/Maestro/MaestroAPI/ServerConnectionBase.cs
===================================================================
--- trunk/Tools/Maestro/MaestroAPI/ServerConnectionBase.cs	2010-04-12 00:41:31 UTC (rev 4779)
+++ trunk/Tools/Maestro/MaestroAPI/ServerConnectionBase.cs	2010-04-12 13:44:33 UTC (rev 4780)
@@ -100,8 +100,8 @@
 			m_resourceTypeLookup.Add("ApplicationDefinition", typeof(ApplicationDefinition.ApplicationDefinitionType));
             m_resourceTypeLookup.Add("SymbolLibrary", typeof(SymbolLibraryType));
             m_resourceTypeLookup.Add("PrintLayout", typeof(PrintLayout));
+            m_resourceTypeLookup.Add("LoadProcedure", typeof(LoadProcedure));
 
-
 			m_schemasPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Schemas");
 			m_username = null;
 			m_password = null;
@@ -2117,6 +2117,445 @@
             }
         }
 
+        /// <summary>
+        /// Executes the specified load procedure. Only SDF and SHP load procedures are supported.
+        /// Also note that the following load procedure features are ignored during execution:
+        ///  - Generalization of data
+        ///  - Conversion from SHP to SDF
+        ///  - SDF2 to SDF3 conversion
+        ///  - SDF3 duplicate key handling
+        /// </summary>
+        /// <param name="resourceID"></param>
+        /// <param name="ignoreUnsupportedFeatures">If false, will throw exceptions when executing a load procedure containing unsupported features.</param>
+        /// <param name="callback"></param>
+        /// <returns>A list of resource IDs that were created from the execution of this load procedure</returns>
+        public string[] ExecuteLoadProcedure(string resourceID, bool ignoreUnsupportedFeatures, LengthyOperationProgressCallBack callback)
+        {
+            //TODO: Localize callback messages
+            //TODO: Localize exception messages
+            //TODO: This would currently overwrite everything. In reality, the load procedure has
+            //a list of resource ids which are overwritable, anything not on the list is untouchable.
+            //I presume if this list is empty, then everything is overwritten and the resource list
+            //list is then assigned to the load procedure, which is then updated so that on subsequent runs,
+            //only resources in the list are overwritten instead of everything.
 
+            string[] resourcesCreatedOrUpdated = null;
+
+            if (!ResourceIdentifier.Validate(resourceID))
+                throw new ArgumentException("Invalid resource id: " + resourceID);
+
+            if (ResourceIdentifier.GetExtension(resourceID) != "LoadProcedure")
+                throw new ArgumentException("Not a load procedure resource id: " + resourceID);
+
+            LengthyOperationProgressCallBack cb = callback;
+
+            //Assign dummy callback if none specified
+            if (cb == null)
+                cb = delegate { };
+
+            LoadProcedure proc = (LoadProcedure)GetResource(resourceID);
+
+            //bool loadProcedureUpdated = false;
+            //bool updateGeneratedResourceIds = false;
+            
+            //TODO: SDF and SHP load procedures share lots of common logic. Merge the two 
+            //once everything's all good.
+
+            SdfLoadProcedureType sdfl = proc.Item as SdfLoadProcedureType;
+            ShpLoadProcedureType shpl = proc.Item as ShpLoadProcedureType;
+
+            if (sdfl != null)
+            {
+                if (!ignoreUnsupportedFeatures)
+                {
+                    //Anything less than 100% implies use of generalization
+                    if (sdfl.Generalization < 100.0)
+                    {
+                        throw new NotSupportedException("Generalization of data is not supported");
+                    }
+                }
+
+                resourcesCreatedOrUpdated = ExecuteSdfLoadProcedure(cb, sdfl);
+            }
+            else if (shpl != null)
+            {
+                if (!ignoreUnsupportedFeatures)
+                {
+                    //Anything less than 100% implies use of generalization
+                    if (shpl.Generalization < 100.0)
+                    {
+                        throw new NotSupportedException("Generalization of data is not supported");
+                    }
+                    //Can't do this because we don't have a portable .net FDO/MG Feature Service
+                    if (shpl.ConvertToSdf)
+                    {
+                        throw new NotSupportedException("Conversion of SHP files to SDF files is not supported");
+                    }
+                }
+                resourcesCreatedOrUpdated = ExecuteShpLoadProcedure(cb, shpl);
+            }
+            else //We don't support anything else (and probably never will)
+            {
+                throw new NotSupportedException("Unsupported load procedure type");
+            }
+
+            proc.Item.ResourceId = resourcesCreatedOrUpdated;
+            this.SaveResourceAs(proc, resourceID);
+
+            return resourcesCreatedOrUpdated;
+        }
+
+        private string[] ExecuteShpLoadProcedure(LengthyOperationProgressCallBack cb, ShpLoadProcedureType shpl)
+        {
+            List<string> resCreatedOrUpdated = new List<string>();
+
+            string[] shpFiles = shpl.SourceFile;
+            int pcPerFile = (int)(100 / shpFiles.Length);
+            int current = 0;
+
+            string fsRoot = shpl.SpatialDataSourcesPath + shpl.SpatialDataSourcesFolder;
+            string layerRoot = shpl.LayersPath + shpl.LayersFolder;
+
+            if (!fsRoot.EndsWith("/"))
+                fsRoot += "/";
+            if (!layerRoot.EndsWith("/"))
+                layerRoot += "/";
+
+            Dictionary<string, List<string>> extraFiles = new Dictionary<string, List<string>>();
+            //Unlike SDF, a SHP file actually consists of multiple files
+            foreach (string shp in shpFiles)
+            {
+                if (!extraFiles.ContainsKey(shp))
+                    extraFiles[shp] = new List<string>();
+                //we want to preserve casing for everything before the extension
+                string prefix = shp.Substring(0, shp.LastIndexOf(".") + 1);
+                extraFiles[shp].Add(prefix + "shx");
+                extraFiles[shp].Add(prefix + "dbf");
+                extraFiles[shp].Add(prefix + "idx");
+                extraFiles[shp].Add(prefix + "prj");
+                extraFiles[shp].Add(prefix + "cpg");
+
+                //TODO: Are we missing anything else?
+            }
+
+            foreach (string file in shpFiles)
+            {
+                bool success = false;
+                if (System.IO.File.Exists(file))
+                {
+                    string resName = System.IO.Path.GetFileNameWithoutExtension(file);
+                    string dataName = System.IO.Path.GetFileName(file);
+
+                    string fsId = fsRoot + resName + ".FeatureSource";
+                    string lyrId = layerRoot + resName + ".LayerDefinition";
+
+                    if (shpl.GenerateSpatialDataSources)
+                    {
+                        //Process is as follows:
+                        //
+                        // 1. Create and save feature source document.
+                        // 2. Upload sdf file as resource data for this document.
+                        // 3. Test the connection, it should check out.
+                        // 4. If no spatial contexts are detected, assign a default one from the load procedure and save the modified feature source.
+
+                        //Step 1: Create feature source document
+                        FeatureSource fs = new FeatureSource();
+                        fs.ResourceId = fsId;
+                        fs.Provider = "OSGeo.SHP";
+                        fs.Parameter = new NameValuePairTypeCollection();
+                        fs.Parameter.Add(new NameValuePairType() { Name = "DefaultFileLocation", Value = "%MG_DATA_FILE_PATH%" + dataName });
+
+                        this.SaveResource(fs);
+                        resCreatedOrUpdated.Add(fsId);
+                        cb(this, new LengthyOperationProgressArgs("Created: " + fsId, current));
+
+                        //TODO: When the infrastructure is available to us (ie. A portable .net FDO/MG Feature Service API wrapper)
+                        //Maybe then we can actually implement the generalization and conversion properties. Until then, we skip
+                        //these options
+
+                        //Step 2: Load resource data for document
+                        this.SetResourceData(fsId, dataName, ResourceDataType.File, System.IO.File.OpenRead(file));
+
+                        cb(this, new LengthyOperationProgressArgs("Loaded: " + file, current));
+
+                        //Load supplementary files
+                        foreach (string extraFile in extraFiles[file])
+                        {
+                            string dn = System.IO.Path.GetFileName(extraFile);
+                            if (System.IO.File.Exists(extraFile))
+                            {
+                                this.SetResourceData(fsId, dn, ResourceDataType.File, System.IO.File.OpenRead(extraFile));
+                                cb(this, new LengthyOperationProgressArgs("Loaded: " + extraFile, current));
+                            }
+                        }
+
+                        //Step 3: Test to make sure we're all good so far
+                        string result = this.TestConnection(fsId);
+
+                        //LocalNativeConnection returns this string, so I'm assuming this is the "success" result
+                        if (result == "No errors")
+                        {
+                            //Step 4: Test to see if default cs needs to be specified
+                            FdoSpatialContextList spatialContexts = this.GetSpatialContextInfo(fsId, false);
+                            if (spatialContexts.SpatialContext.Count == 0 && !string.IsNullOrEmpty(shpl.CoordinateSystem))
+                            {
+                                //Register the default CS from the load procedure
+                                fs.SupplementalSpatialContextInfo = new SpatialContextTypeCollection();
+                                fs.SupplementalSpatialContextInfo.Add(new SpatialContextType()
+                                {
+                                    Name = "Default",
+                                    CoordinateSystem = shpl.CoordinateSystem
+                                });
+
+                                //Update this feature source
+                                this.SaveResource(fs);
+
+                                cb(this, new LengthyOperationProgressArgs("Set default spatial context for: " + fsId, current));
+                            }
+                        }
+                    }
+
+                    if (shpl.GenerateLayers)
+                    {
+                        //Process is as follows
+                        //
+                        // 1. Describe the schema of the feature source
+                        // 2. If it contains at least one feature class, create a layer definition
+                        // 3. Set the following layer definition properties:
+                        //    - Feature Source: the feature source id
+                        //    - Feature Class: the first feature class in the schema
+                        //    - Geometry: the first geometry property in the first feature class
+                        // 4. Infer the supported geometry types for this feature class. Toggle supported styles accordingly.
+
+                        //Step 1: Describe the schema
+                        FeatureSourceDescription desc = DescribeFeatureSource(fsId);
+
+                        if (desc.Schemas.Length > 0)
+                        {
+                            //Step 2: Find the first feature class with a geometry property
+                            FeatureSourceDescription.FeatureSourceSchema clsDef = null;
+                            FeatureSetColumn geom = null;
+
+                            bool done = false;
+
+                            foreach (FeatureSourceDescription.FeatureSourceSchema cls in desc.Schemas)
+                            {
+                                if (done) break;
+
+                                foreach (FeatureSetColumn prop in cls.Columns)
+                                {
+                                    if (done) break;
+
+                                    if (typeof(Topology.Geometries.IGeometry).IsAssignableFrom(prop.Type))
+                                    {
+                                        clsDef = cls;
+                                        geom = prop;
+                                        done = true;
+                                    }
+                                }
+                            }
+
+                            if (clsDef != null && geom != null)
+                            {
+                                LayerDefinition ld = CreateResourceObject<LayerDefinition>();
+
+                                //Step 3: Assign default properties
+                                ld.ResourceId = lyrId;
+                                VectorLayerDefinitionType vld = ld.Item as VectorLayerDefinitionType;
+                                vld.ResourceId = fsId;
+                                vld.FeatureName = clsDef.Fullname;
+                                vld.Geometry = geom.Name;
+
+                                this.SaveResource(ld);
+                                resCreatedOrUpdated.Add(lyrId);
+                                cb(this, new LengthyOperationProgressArgs("Created: " + lyrId, current));
+
+                                //Step 4: Infer geometry storage support and remove unsupported styles
+                                //TODO: There doesn't seem to be a MaestroAPI way to figure out geometry storage types atm
+                            }
+                        }
+                    }
+
+                    success = true;
+                }
+                else
+                {
+                    cb(this, new LengthyOperationProgressArgs("File not found: " + file, current));
+                }
+
+                //This file is now fully processed, so increment progress
+                current += pcPerFile;
+
+                if (success)
+                {
+                    cb(this, new LengthyOperationProgressArgs("Success: " + file, current));
+                }
+            }
+
+            return resCreatedOrUpdated.ToArray();
+        }
+
+        private string[] ExecuteSdfLoadProcedure(LengthyOperationProgressCallBack cb, SdfLoadProcedureType sdfl)
+        {
+            List<string> resCreatedOrUpdated = new List<string>();
+
+            string[] files = sdfl.SourceFile;
+            int pcPerFile = (int)(100 / files.Length);
+            int current = 0;
+
+            string fsRoot = sdfl.SpatialDataSourcesPath + sdfl.SpatialDataSourcesFolder;
+            string layerRoot = sdfl.LayersPath + sdfl.LayersFolder;
+
+            if (!fsRoot.EndsWith("/"))
+                fsRoot += "/";
+            if (!layerRoot.EndsWith("/"))
+                layerRoot += "/";
+
+            foreach (string file in files)
+            {
+                bool success = false;
+                if (System.IO.File.Exists(file))
+                {
+                    //GOTCHA: We are assuming these SDF files are not SDF2 files. This is
+                    //because there is no multi-platform solution to convert SDF2 files to SDF3
+
+                    string resName = System.IO.Path.GetFileNameWithoutExtension(file);
+                    string dataName = System.IO.Path.GetFileName(file);
+                    string fsId = fsRoot + resName + ".FeatureSource";
+                    string lyrId = layerRoot + resName + ".LayerDefinition";
+
+                    if (sdfl.GenerateSpatialDataSources)
+                    {
+                        //Process is as follows:
+                        //
+                        // 1. Create and save feature source document.
+                        // 2. Upload sdf file as resource data for this document.
+                        // 3. Test the connection, it should check out.
+                        // 4. If no spatial contexts are detected, assign a default one from the load procedure and save the modified feature source.
+
+                        //Step 1: Create feature source document
+                        FeatureSource fs = new FeatureSource();
+                        fs.ResourceId = fsId;
+                        fs.Provider = "OSGeo.SDF";
+                        fs.Parameter = new NameValuePairTypeCollection();
+                        fs.Parameter.Add(new NameValuePairType() { Name = "File", Value = "%MG_DATA_FILE_PATH%" + dataName });
+
+                        this.SaveResource(fs);
+                        resCreatedOrUpdated.Add(fsId);
+                        cb(this, new LengthyOperationProgressArgs("Created: " + fsId, current));
+
+                        //TODO: When the infrastructure is available to us (ie. A portable .net FDO/MG Feature Service API wrapper)
+                        //Maybe then we can actually implement the generalization and duplicate record handling properties. Until then, we skip
+                        //these options
+
+                        //Step 2: Load resource data for document
+                        this.SetResourceData(fsId, dataName, ResourceDataType.File, System.IO.File.OpenRead(file));
+
+                        cb(this, new LengthyOperationProgressArgs("Loaded: " + file, current));
+
+                        //Step 3: Test to make sure we're all good so far
+                        string result = this.TestConnection(fsId);
+
+                        //LocalNativeConnection returns this string, so I'm assuming this is the "success" result
+                        if (result == "No errors")
+                        {
+                            //Step 4: Test to see if default cs needs to be specified
+                            FdoSpatialContextList spatialContexts = this.GetSpatialContextInfo(fsId, false);
+                            if (spatialContexts.SpatialContext.Count == 0 && !string.IsNullOrEmpty(sdfl.CoordinateSystem))
+                            {
+                                //Register the default CS from the load procedure
+                                fs.SupplementalSpatialContextInfo = new SpatialContextTypeCollection();
+                                fs.SupplementalSpatialContextInfo.Add(new SpatialContextType()
+                                {
+                                    Name = "Default",
+                                    CoordinateSystem = sdfl.CoordinateSystem
+                                });
+
+                                //Update this feature source
+                                this.SaveResource(fs);
+
+                                cb(this, new LengthyOperationProgressArgs("Set default spatial context for: " + fsId, current));
+                            }
+                        }
+                    }
+
+                    if (sdfl.GenerateLayers)
+                    {
+                        //Process is as follows
+                        //
+                        // 1. Describe the schema of the feature source
+                        // 2. If it contains at least one feature class, create a layer definition
+                        // 3. Set the following layer definition properties:
+                        //    - Feature Source: the feature source id
+                        //    - Feature Class: the first feature class in the schema
+                        //    - Geometry: the first geometry property in the first feature class
+                        // 4. Infer the supported geometry types for this feature class. Toggle supported styles accordingly.
+
+                        //Step 1: Describe the schema
+                        FeatureSourceDescription desc = DescribeFeatureSource(fsId);
+
+                        if (desc.Schemas.Length > 0)
+                        {
+                            //Step 2: Find the first feature class with a geometry property
+                            FeatureSourceDescription.FeatureSourceSchema clsDef = null;
+                            FeatureSetColumn geom = null;
+
+                            bool done = false;
+
+                            foreach (FeatureSourceDescription.FeatureSourceSchema cls in desc.Schemas)
+                            {
+                                if (done) break;
+
+                                foreach (FeatureSetColumn prop in cls.Columns)
+                                {
+                                    if (done) break;
+
+                                    if (typeof(Topology.Geometries.IGeometry).IsAssignableFrom(prop.Type))
+                                    {
+                                        clsDef = cls;
+                                        geom = prop;
+                                        done = true;
+                                    }
+                                }
+                            }
+
+                            if (clsDef != null && geom != null)
+                            {
+                                LayerDefinition ld = CreateResourceObject<LayerDefinition>();
+
+                                //Step 3: Assign default properties
+                                ld.ResourceId = lyrId;
+                                VectorLayerDefinitionType vld = ld.Item as VectorLayerDefinitionType;
+                                vld.ResourceId = fsId;
+                                vld.FeatureName = clsDef.Fullname;
+                                vld.Geometry = geom.Name;
+
+                                this.SaveResource(ld);
+                                resCreatedOrUpdated.Add(lyrId);
+                                cb(this, new LengthyOperationProgressArgs("Created: " + lyrId, current));
+
+                                //Step 4: Infer geometry storage support and remove unsupported styles
+                                //TODO: There doesn't seem to be a MaestroAPI way to figure out geometry storage types atm
+                            }
+                        }
+                    }
+
+                    success = true;
+                }
+                else
+                {
+                    cb(this, new LengthyOperationProgressArgs("File not found: " + file, current));
+                }
+
+                //This file is now fully processed, so increment progress
+                current += pcPerFile;
+
+                if (success)
+                {
+                    cb(this, new LengthyOperationProgressArgs("File processed: " + file, current));
+                }
+            }
+            return resCreatedOrUpdated.ToArray();
+        }
     }
 }

Modified: trunk/Tools/Maestro/MaestroAPI/ServerConnectionI.cs
===================================================================
--- trunk/Tools/Maestro/MaestroAPI/ServerConnectionI.cs	2010-04-12 00:41:31 UTC (rev 4779)
+++ trunk/Tools/Maestro/MaestroAPI/ServerConnectionI.cs	2010-04-12 13:44:33 UTC (rev 4780)
@@ -398,5 +398,14 @@
         /// <typeparam name="T">The type of the object to create</typeparam>
         /// <returns>A new instance of the object</returns>
         T CreateResourceObject<T>();
+
+        /// <summary>
+        /// Executes the specified load procedure
+        /// </summary>
+        /// <param name="resourceID"></param>
+        /// <param name="ignoreUnsupportedFeatures"></param>
+        /// <param name="callback"></param>
+        /// <returns>A list of resource IDs that were created from the execution of this load procedure</returns>
+        string[] ExecuteLoadProcedure(string resourceID, bool ignoreUnsupportedFeatures, LengthyOperationProgressCallBack callback);
 	}
 }



More information about the mapguide-commits mailing list