private string[] ExecuteShpLoadProcedure(LengthyOperationProgressCallBack cb, IShpLoadProcedure shpl, ref bool firstExecution) { List<string> resCreatedOrUpdated = new List<string>(); var shpFiles = shpl.SourceFile; int pcPerFile = (int)(100 / shpFiles.Count); int current = 0; string root = shpl.RootPath; if (!root.EndsWith("/")) //NOXLATE root += "/"; //NOXLATE string sdp = shpl.SpatialDataSourcesPath; string lp = shpl.LayersPath; if (!string.IsNullOrEmpty(sdp)) { if (!sdp.EndsWith("/")) //NOXLATE sdp += "/"; //NOXLATE } if (!string.IsNullOrEmpty(lp)) { if (!lp.EndsWith("/")) //NOXLATE lp += "/"; //NOXLATE } string fsRoot = (string.IsNullOrEmpty(sdp) ? root : sdp) + shpl.SpatialDataSourcesFolder; string layerRoot = (string.IsNullOrEmpty(lp) ? root : lp) + shpl.LayersFolder; if (!fsRoot.EndsWith("/")) //NOXLATE fsRoot += "/"; //NOXLATE if (!layerRoot.EndsWith("/")) //NOXLATE layerRoot += "/"; //NOXLATE List<string> resToUpdate = new List<string>(); if (shpl.ResourceId != null) { resToUpdate.AddRange(shpl.ResourceId); firstExecution = false; } else { firstExecution = true; } 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); //NOXLATE extraFiles[shp].Add(prefix + "shx"); //NOXLATE extraFiles[shp].Add(prefix + "dbf"); //NOXLATE extraFiles[shp].Add(prefix + "idx"); //NOXLATE extraFiles[shp].Add(prefix + "prj"); //NOXLATE extraFiles[shp].Add(prefix + "cpg"); //NOXLATE //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"; //NOXLATE string lyrId = layerRoot + resName + ".LayerDefinition"; //NOXLATE if (shpl.GenerateSpatialDataSources) { //Skip only if we have an update list and this resource id is not in it bool skip = (resToUpdate.Count > 0 && !resToUpdate.Contains(fsId)); if (!skip) { //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 var conp = new NameValueCollection(); conp["DefaultFileLocation"] = StringConstants.MgDataFilePath + dataName; //NOXLATE var fs = ObjectFactory.CreateFeatureSource(this.Parent, "OSGeo.SHP", conp); //NOXLATE fs.ResourceID = fsId; this.Parent.ResourceService.SaveResource(fs); resCreatedOrUpdated.Add(fsId); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateCreated, 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.Parent.ResourceService.SetResourceData(fsId, dataName, ResourceDataType.File, System.IO.File.OpenRead(file)); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateLoaded, 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.Parent.ResourceService.SetResourceData(fsId, dn, ResourceDataType.File, System.IO.File.OpenRead(extraFile)); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateLoaded, extraFile), current)); } } //Step 3: Test to make sure we're all good so far string result = this.Parent.FeatureService.TestConnection(fsId); if (Utility.IsSuccessfulConnectionTestResult(result)) { //Step 4: Test to see if default cs needs to be specified FdoSpatialContextList spatialContexts = this.Parent.FeatureService.GetSpatialContextInfo(fsId, false); if (!string.IsNullOrEmpty(shpl.CoordinateSystem)) { bool hasPrj = false; //If there is no prj file, we can just upload one with the specified WKT foreach (var resd in fs.EnumerateResourceData()) { if (resd.Name == resName + ".prj") //NOXLATE { hasPrj = true; break; } } //Case 1: No .prj file. Most probable if (!hasPrj) { string tmp = System.IO.Path.GetTempFileName(); System.IO.File.WriteAllText(tmp, shpl.CoordinateSystem); using (var fsr = System.IO.File.OpenRead(tmp)) { fs.SetResourceData(resName + ".prj", ResourceDataType.File, fsr); //NOXLATE cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateUploadedPrj, resName), current)); } try { System.IO.File.Delete(tmp); } catch { } } else if (spatialContexts.SpatialContext.Count == 0) //Case 2: No Spatial contexts. Declare one using SupplementalContextInfo { //Register the default CS from the load procedure fs.AddSpatialContextOverride(new OSGeo.MapGuide.ObjectModels.FeatureSource_1_0_0.SpatialContextType() { Name = "Default", //NOXLATE CoordinateSystem = shpl.CoordinateSystem }); //Update this feature source this.Parent.ResourceService.SaveResource(fs); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateSetSpatialContext, fsId), current)); } else if (spatialContexts.SpatialContext.Count == 1) //Case 3: One spatial context with blank WKT. Override it using the SupplementalContextInfo { var sc = spatialContexts.SpatialContext[0]; if (string.IsNullOrEmpty(sc.CoordinateSystemWkt)) { //Register the default CS from the load procedure fs.AddSpatialContextOverride(new OSGeo.MapGuide.ObjectModels.FeatureSource_1_0_0.SpatialContextType() { Name = sc.Name, CoordinateSystem = shpl.CoordinateSystem }); //Update this feature source this.Parent.ResourceService.SaveResource(fs); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateSetSpatialContext, fsId), current)); } } } } } } if (shpl.GenerateLayers) { //Skip only if we have an update list and this resource id is not in it bool skip = (resToUpdate.Count > 0 && !resToUpdate.Contains(lyrId)); if (!skip) { //NOTE: Because we are working against 1.0.0 object types this will always create 1.0.0 Layer Definition //resources //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 // //NOTE: I think we can get away with the full schema walk here. It's very unlikely we will be uploading a flat //file with hundreds of classes. Even then, flat-file schema walk performance blows RDBMS walking performance //out of the water anyway. FeatureSourceDescription desc = this.Parent.FeatureService.DescribeFeatureSource(fsId); //Step 2: Find the first feature class with a geometry property ClassDefinition clsDef = null; GeometricPropertyDefinition geom = null; bool done = false; foreach (ClassDefinition cls in desc.AllClasses) { if (done) break; foreach (PropertyDefinition prop in cls.Properties) { if (done) break; if (prop.Type == OSGeo.MapGuide.MaestroAPI.Schema.PropertyDefinitionType.Geometry) { clsDef = cls; geom = (GeometricPropertyDefinition)prop; done = true; } } } if (clsDef != null && geom != null) { var ld = ObjectFactory.CreateDefaultLayer(this.Parent, LayerType.Vector, new Version(1, 0, 0)); //Step 3: Assign default properties ld.ResourceID = lyrId; var vld = ld.SubLayer as IVectorLayerDefinition; vld.ResourceId = fsId; vld.FeatureName = clsDef.QualifiedName; vld.Geometry = geom.Name; //Step 4: Infer geometry storage support and remove unsupported styles var scale = vld.GetScaleRangeAt(0); var geomTypes = geom.GetIndividualGeometricTypes(); var remove = new List<string>(); if (Array.IndexOf(geomTypes, FeatureGeometricType.Point) < 0) { remove.Add(FeatureGeometricType.Point.ToString().ToLower()); } if (Array.IndexOf(geomTypes, FeatureGeometricType.Curve) < 0) { remove.Add(FeatureGeometricType.Curve.ToString().ToLower()); } if (Array.IndexOf(geomTypes, FeatureGeometricType.Surface) < 0) { remove.Add(FeatureGeometricType.Surface.ToString().ToLower()); } scale.RemoveStyles(remove); this.Parent.ResourceService.SaveResource(ld); resCreatedOrUpdated.Add(lyrId); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateCreated, lyrId), current)); } } } success = true; } else { cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateFileNotFound, file), current)); } //This file is now fully processed, so increment progress current += pcPerFile; if (success) { cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateSuccess, file), current)); } } return resCreatedOrUpdated.ToArray(); }
private string[] ExecuteShpLoadProcedure(LengthyOperationProgressCallBack cb, IShpLoadProcedure shpl, ref bool firstExecution) { List <string> resCreatedOrUpdated = new List <string>(); var shpFiles = shpl.SourceFile; int pcPerFile = (int)(100 / shpFiles.Count); int current = 0; string root = shpl.RootPath; if (!root.EndsWith("/")) //NOXLATE { root += "/"; //NOXLATE } string sdp = shpl.SpatialDataSourcesPath; string lp = shpl.LayersPath; if (!string.IsNullOrEmpty(sdp)) { if (!sdp.EndsWith("/")) //NOXLATE { sdp += "/"; //NOXLATE } } if (!string.IsNullOrEmpty(lp)) { if (!lp.EndsWith("/")) //NOXLATE { lp += "/"; //NOXLATE } } string fsRoot = (string.IsNullOrEmpty(sdp) ? root : sdp) + shpl.SpatialDataSourcesFolder; string layerRoot = (string.IsNullOrEmpty(lp) ? root : lp) + shpl.LayersFolder; if (!fsRoot.EndsWith("/")) //NOXLATE { fsRoot += "/"; //NOXLATE } if (!layerRoot.EndsWith("/")) //NOXLATE { layerRoot += "/"; //NOXLATE } List <string> resToUpdate = new List <string>(); if (shpl.ResourceId != null) { resToUpdate.AddRange(shpl.ResourceId); firstExecution = false; } else { firstExecution = true; } 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); //NOXLATE extraFiles[shp].Add(prefix + "shx"); //NOXLATE extraFiles[shp].Add(prefix + "dbf"); //NOXLATE extraFiles[shp].Add(prefix + "idx"); //NOXLATE extraFiles[shp].Add(prefix + "prj"); //NOXLATE extraFiles[shp].Add(prefix + "cpg"); //NOXLATE //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"; //NOXLATE string lyrId = layerRoot + resName + ".LayerDefinition"; //NOXLATE if (shpl.GenerateSpatialDataSources) { //Skip only if we have an update list and this resource id is not in it bool skip = (resToUpdate.Count > 0 && !resToUpdate.Contains(fsId)); if (!skip) { //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 var conp = new NameValueCollection(); conp["DefaultFileLocation"] = StringConstants.MgDataFilePath + dataName; //NOXLATE var fs = ObjectFactory.CreateFeatureSource("OSGeo.SHP", conp); //NOXLATE fs.ResourceID = fsId; this.Parent.ResourceService.SaveResource(fs); resCreatedOrUpdated.Add(fsId); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateCreated, 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.Parent.ResourceService.SetResourceData(fsId, dataName, ResourceDataType.File, System.IO.File.OpenRead(file)); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateLoaded, 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.Parent.ResourceService.SetResourceData(fsId, dn, ResourceDataType.File, System.IO.File.OpenRead(extraFile)); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateLoaded, extraFile), current)); } } //Step 3: Test to make sure we're all good so far string result = this.Parent.FeatureService.TestConnection(fsId); if (Utility.IsSuccessfulConnectionTestResult(result)) { //Step 4: Test to see if default cs needs to be specified FdoSpatialContextList spatialContexts = this.Parent.FeatureService.GetSpatialContextInfo(fsId, false); if (!string.IsNullOrEmpty(shpl.CoordinateSystem)) { bool hasPrj = false; //If there is no prj file, we can just upload one with the specified WKT var resData = this.Parent.ResourceService.EnumerateResourceData(fs.ResourceID); foreach (var resd in resData.ResourceData) { if (resd.Name == resName + ".prj") //NOXLATE { hasPrj = true; break; } } //Case 1: No .prj file. Most probable if (!hasPrj) { string tmp = System.IO.Path.GetTempFileName(); System.IO.File.WriteAllText(tmp, shpl.CoordinateSystem); using (var fsr = System.IO.File.OpenRead(tmp)) { this.Parent.ResourceService.SetResourceData(fs.ResourceID, resName + ".prj", ResourceDataType.File, fsr); //NOXLATE cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateUploadedPrj, resName), current)); } try { System.IO.File.Delete(tmp); } catch { } } else if (spatialContexts.SpatialContext.Count == 0) //Case 2: No Spatial contexts. Declare one using SupplementalContextInfo { //Register the default CS from the load procedure fs.AddSpatialContextOverride(new OSGeo.MapGuide.ObjectModels.FeatureSource.v1_0_0.SpatialContextType() { Name = "Default", //NOXLATE CoordinateSystem = shpl.CoordinateSystem }); //Update this feature source this.Parent.ResourceService.SaveResource(fs); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateSetSpatialContext, fsId), current)); } else if (spatialContexts.SpatialContext.Count == 1) //Case 3: One spatial context with blank WKT. Override it using the SupplementalContextInfo { var sc = spatialContexts.SpatialContext[0]; if (string.IsNullOrEmpty(sc.CoordinateSystemWkt)) { //Register the default CS from the load procedure fs.AddSpatialContextOverride(new OSGeo.MapGuide.ObjectModels.FeatureSource.v1_0_0.SpatialContextType() { Name = sc.Name, CoordinateSystem = shpl.CoordinateSystem }); //Update this feature source this.Parent.ResourceService.SaveResource(fs); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateSetSpatialContext, fsId), current)); } } } } } } if (shpl.GenerateLayers) { //Skip only if we have an update list and this resource id is not in it bool skip = (resToUpdate.Count > 0 && !resToUpdate.Contains(lyrId)); if (!skip) { //NOTE: Because we are working against 1.0.0 object types this will always create 1.0.0 Layer Definition //resources //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 // //NOTE: I think we can get away with the full schema walk here. It's very unlikely we will be uploading a flat //file with hundreds of classes. Even then, flat-file schema walk performance blows RDBMS walking performance //out of the water anyway. FeatureSourceDescription desc = this.Parent.FeatureService.DescribeFeatureSource(fsId); //Step 2: Find the first feature class with a geometry property ClassDefinition clsDef = null; GeometricPropertyDefinition geom = null; bool done = false; foreach (ClassDefinition cls in desc.AllClasses) { if (done) { break; } foreach (PropertyDefinition prop in cls.Properties) { if (done) { break; } if (prop.Type == OSGeo.MapGuide.MaestroAPI.Schema.PropertyDefinitionType.Geometry) { clsDef = cls; geom = (GeometricPropertyDefinition)prop; done = true; } } } if (clsDef != null && geom != null) { var ld = ObjectFactory.CreateDefaultLayer(LayerType.Vector, new Version(1, 0, 0)); //Step 3: Assign default properties ld.ResourceID = lyrId; var vld = ld.SubLayer as IVectorLayerDefinition; vld.ResourceId = fsId; vld.FeatureName = clsDef.QualifiedName; vld.Geometry = geom.Name; //Step 4: Infer geometry storage support and remove unsupported styles var scale = vld.GetScaleRangeAt(0); var geomTypes = geom.GetIndividualGeometricTypes(); var remove = new List <string>(); if (Array.IndexOf(geomTypes, FeatureGeometricType.Point) < 0) { remove.Add(FeatureGeometricType.Point.ToString().ToLower()); } if (Array.IndexOf(geomTypes, FeatureGeometricType.Curve) < 0) { remove.Add(FeatureGeometricType.Curve.ToString().ToLower()); } if (Array.IndexOf(geomTypes, FeatureGeometricType.Surface) < 0) { remove.Add(FeatureGeometricType.Surface.ToString().ToLower()); } scale.RemoveStyles(remove); this.Parent.ResourceService.SaveResource(ld); resCreatedOrUpdated.Add(lyrId); cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateCreated, lyrId), current)); } } } success = true; } else { cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateFileNotFound, file), current)); } //This file is now fully processed, so increment progress current += pcPerFile; if (success) { cb(this, new LengthyOperationProgressArgs(string.Format(Strings.TemplateSuccess, file), current)); } } return(resCreatedOrUpdated.ToArray()); }