[mapguide-commits] r9121 - in trunk/Tools/Maestro: OSGeo.MapGuide.MaestroAPI OSGeo.MapGuide.MaestroAPI/Resource/Validation OSGeo.MapGuide.MaestroAPI/Schema OSGeo.MapGuide.MaestroAPI.Tests
svn_mapguide at osgeo.org
svn_mapguide at osgeo.org
Tue Jan 24 04:41:11 PST 2017
Author: jng
Date: 2017-01-24 04:41:11 -0800 (Tue, 24 Jan 2017)
New Revision: 9121
Modified:
trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/ValidationTests.cs
trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/FeatureSourceValidator.cs
trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/ValidationStatusCode.cs
trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Schema/GeometricPropertyDefinition.cs
trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs
trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx
Log:
Add some validation rules for ODBC configuration documents, which includes checking for incomplete X/Y column mappings
Fixes #2476
Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/FeatureSourceValidator.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/FeatureSourceValidator.cs 2017-01-20 11:23:01 UTC (rev 9120)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/FeatureSourceValidator.cs 2017-01-24 12:41:11 UTC (rev 9121)
@@ -21,12 +21,15 @@
#endregion Disclaimer / License
using OSGeo.MapGuide.MaestroAPI.Exceptions;
+using OSGeo.MapGuide.MaestroAPI.Schema;
+using OSGeo.MapGuide.MaestroAPI.SchemaOverrides;
using OSGeo.MapGuide.MaestroAPI.Services;
using OSGeo.MapGuide.ObjectModels;
using OSGeo.MapGuide.ObjectModels.Common;
using OSGeo.MapGuide.ObjectModels.FeatureSource;
using System;
using System.Collections.Generic;
+using System.Linq;
namespace OSGeo.MapGuide.MaestroAPI.Resource.Validation
{
@@ -219,11 +222,58 @@
}
}
+ string configDocXml = feature.GetConfigurationContent(Connection);
+ if (!string.IsNullOrEmpty(configDocXml))
+ {
+ var doc = ConfigurationDocument.LoadXml(configDocXml);
+ var odbcDoc = doc as OdbcConfigurationDocument;
+ if (odbcDoc != null)
+ {
+ issues.AddRange(ValidateOdbcDoc(feature, odbcDoc));
+ }
+ }
+
context.MarkValidated(resource.ResourceID);
return issues.ToArray();
}
+ private IEnumerable<ValidationIssue> ValidateOdbcDoc(IFeatureSource fs, OdbcConfigurationDocument odbcDoc)
+ {
+ foreach (var schema in odbcDoc.Schemas)
+ {
+ var featureClasses = schema
+ .Classes
+ .Where(c => !string.IsNullOrEmpty(c.DefaultGeometryPropertyName) && c.Properties.Any(p => p.Type == Schema.PropertyDefinitionType.Geometry && p.Name == c.DefaultGeometryPropertyName));
+
+ foreach (var fc in featureClasses)
+ {
+ var geomProp = fc.Properties.OfType<GeometricPropertyDefinition>().FirstOrDefault(p => p.Name == fc.DefaultGeometryPropertyName);
+ if (geomProp != null)
+ {
+ //Must be point
+ if (geomProp.GeometricTypes != FeatureGeometricType.Point)
+ {
+ yield return new ValidationIssue(fs, ValidationStatus.Error, ValidationStatusCode.Error_OdbcConfig_InvalidLogicalGeometryProperty, string.Format(Strings.ODBC_InvalidGeometryProperty, fc.Name, geomProp.Name));
+ }
+
+ var ovTable = odbcDoc.GetOverride(schema.Name, fc.Name);
+ if (ovTable == null) //If it has geometry, it must have a table override
+ {
+ yield return new ValidationIssue(fs, ValidationStatus.Error, ValidationStatusCode.Error_OdbcConfig_NoTableOverrideForFeatureClass, string.Format(Strings.ODBC_NoSuchTableOverrideForFeatureClass, fc.Name));
+ }
+ else if (geomProp.GeometricTypes == FeatureGeometricType.Point)
+ {
+ if (string.IsNullOrEmpty(ovTable.XColumn) || string.IsNullOrEmpty(ovTable.YColumn))
+ {
+ yield return new ValidationIssue(fs, ValidationStatus.Error, ValidationStatusCode.Error_OdbcConfig_IncompleteXYZColumnMapping, string.Format(Strings.ODBC_IncompleteXYZColumnMapping, fc.Name));
+ }
+ }
+ }
+ }
+ }
+ }
+
/// <summary>
/// Gets the resource type and version this validator supports
/// </summary>
Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/ValidationStatusCode.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/ValidationStatusCode.cs 2017-01-20 11:23:01 UTC (rev 9120)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Resource/Validation/ValidationStatusCode.cs 2017-01-24 12:41:11 UTC (rev 9121)
@@ -474,6 +474,25 @@
/// </summary>
Error_SymbolDefinition_ImageGraphicReferenceResourceDataNotFound,
+ /// <summary>
+ /// The ODBC configuration document has a Feature Class that has no corresponding ODBC
+ /// table override definition (that would specify how its geometry property maps to X/Y/Z
+ /// columns)
+ /// </summary>
+ Error_OdbcConfig_NoTableOverrideForFeatureClass = 5801,
+
+ /// <summary>
+ /// The ODBC configuration document contains a logical feature class with a geometry
+ /// property that is not of type Point (other geometry types are not mappable in ODBC)
+ /// </summary>
+ Error_OdbcConfig_InvalidLogicalGeometryProperty,
+
+ /// <summary>
+ /// The ODBC configuration document contains a table override item with an incomplete X or Y column
+ /// mapping
+ /// </summary>
+ Error_OdbcConfig_IncompleteXYZColumnMapping
+
#endregion errors
}
}
\ No newline at end of file
Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Schema/GeometricPropertyDefinition.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Schema/GeometricPropertyDefinition.cs 2017-01-20 11:23:01 UTC (rev 9120)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Schema/GeometricPropertyDefinition.cs 2017-01-24 12:41:11 UTC (rev 9121)
@@ -324,7 +324,7 @@
var hev = Utility.GetFdoAttribute(node, "hasElevation"); //NOXLATE
var srs = Utility.GetFdoAttribute(node, "srsName"); //NOXLATE
- this.GeometricTypes = ProcessGeometricTypes(gt.Value);
+ this.GeometricTypes = ProcessGeometricTypes(gt2.Value);
if (gt2 != null)
this.SpecificGeometryTypes = ProcessSpecificGeometryTypes(gt2.Value);
Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs 2017-01-20 11:23:01 UTC (rev 9120)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.Designer.cs 2017-01-24 12:41:11 UTC (rev 9121)
@@ -1,17 +1,17 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
-// Runtime Version:4.0.30319.34209
+// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
-namespace OSGeo.MapGuide.MaestroAPI
-{
-
-
+namespace OSGeo.MapGuide.MaestroAPI {
+ using System;
+
+
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
@@ -1987,6 +1987,33 @@
}
/// <summary>
+ /// Looks up a localized string similar to Table mapping for Feature class ({0}) has an incomplete column mapping. Either the X or Y or both columns are not specified.
+ /// </summary>
+ public static string ODBC_IncompleteXYZColumnMapping {
+ get {
+ return ResourceManager.GetString("ODBC_IncompleteXYZColumnMapping", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Feature class ({0}) has a logical geometry property ({1}) that is not of the Point geometry type.
+ /// </summary>
+ public static string ODBC_InvalidGeometryProperty {
+ get {
+ return ResourceManager.GetString("ODBC_InvalidGeometryProperty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Feature class ({0}) has no corresponding ODBC table override item.
+ /// </summary>
+ public static string ODBC_NoSuchTableOverrideForFeatureClass {
+ get {
+ return ResourceManager.GetString("ODBC_NoSuchTableOverrideForFeatureClass", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to All Files.
/// </summary>
public static string PickAll {
Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx 2017-01-20 11:23:01 UTC (rev 9120)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI/Strings.resx 2017-01-24 12:41:11 UTC (rev 9121)
@@ -894,4 +894,13 @@
<data name="UnseedableTileSet" xml:space="preserve">
<value>The given Map Definition or Tile Set Definition cannot be seeded</value>
</data>
+ <data name="ODBC_InvalidGeometryProperty" xml:space="preserve">
+ <value>Feature class ({0}) has a logical geometry property ({1}) that is not of the Point geometry type</value>
+ </data>
+ <data name="ODBC_NoSuchTableOverrideForFeatureClass" xml:space="preserve">
+ <value>Feature class ({0}) has no corresponding ODBC table override item</value>
+ </data>
+ <data name="ODBC_IncompleteXYZColumnMapping" xml:space="preserve">
+ <value>Table mapping for Feature class ({0}) has an incomplete column mapping. Either the X or Y or both columns are not specified</value>
+ </data>
</root>
\ No newline at end of file
Modified: trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/ValidationTests.cs
===================================================================
--- trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/ValidationTests.cs 2017-01-20 11:23:01 UTC (rev 9120)
+++ trunk/Tools/Maestro/OSGeo.MapGuide.MaestroAPI.Tests/ValidationTests.cs 2017-01-24 12:41:11 UTC (rev 9121)
@@ -24,12 +24,16 @@
using OSGeo.MapGuide.MaestroAPI.Resource;
using OSGeo.MapGuide.MaestroAPI.Resource.Validation;
using OSGeo.MapGuide.MaestroAPI.Schema;
+using OSGeo.MapGuide.MaestroAPI.SchemaOverrides;
using OSGeo.MapGuide.MaestroAPI.Services;
using OSGeo.MapGuide.ObjectModels;
+using OSGeo.MapGuide.ObjectModels.Common;
+using OSGeo.MapGuide.ObjectModels.FeatureSource;
using OSGeo.MapGuide.ObjectModels.LayerDefinition;
using OSGeo.MapGuide.ObjectModels.LoadProcedure;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
@@ -243,6 +247,8 @@
[Test]
public void TestCase1896()
{
+ //This test case is for ticket 1896: Maestro layer validation incorrectly report missing primary key
+
var fs = new FeatureSchema();
var doc = new XmlDocument();
@@ -263,5 +269,170 @@
Assert.True(cls.IdentityProperties.Count > 0, "Expected identity properties in: " + cls.QualifiedName);
}
}
+
+ [Test]
+ public void TestCase_FsValidator_ValidatesOdbcConfigurationIssues()
+ {
+ var conf = new OdbcConfigurationDocument();
+
+ var sc = new FdoSpatialContextListSpatialContext();
+ sc.CoordinateSystemName = "LL84";
+ sc.CoordinateSystemWkt = "";
+ sc.Description = "Default Spatial Context";
+ sc.Extent = new FdoSpatialContextListSpatialContextExtent()
+ {
+ LowerLeftCoordinate = new FdoSpatialContextListSpatialContextExtentLowerLeftCoordinate()
+ {
+ X = "-180.0",
+ Y = "-180.0"
+ },
+ UpperRightCoordinate = new FdoSpatialContextListSpatialContextExtentUpperRightCoordinate()
+ {
+ X = "180.0",
+ Y = "180.0"
+ }
+ };
+ sc.ExtentType = FdoSpatialContextListSpatialContextExtentType.Static;
+ sc.Name = "Default";
+ sc.XYTolerance = 0.0001;
+ sc.ZTolerance = 0.0001;
+
+ var schema = new FeatureSchema("Default", "Default Schema");
+ var klass = new ClassDefinition("Test", "Test Class");
+ var id = new DataPropertyDefinition("ID", "Identity");
+ var geom = new GeometricPropertyDefinition("Geometry", "geometry")
+ {
+ GeometricTypes = FeatureGeometricType.Point
+ };
+ geom.SpatialContextAssociation = sc.Name;
+ klass.AddProperty(id, true);
+ klass.AddProperty(geom);
+ klass.DefaultGeometryPropertyName = geom.Name;
+ schema.AddClass(klass);
+
+ conf.AddSchema(schema);
+ conf.AddSpatialContext(sc);
+
+ var odbcTable = new OdbcTableItem()
+ {
+ ClassName = klass.Name,
+ SchemaName = schema.Name,
+ SpatialContextName = sc.Name,
+ XColumn = "X",
+ YColumn = null
+ };
+ conf.AddOverride(odbcTable);
+
+ Func<Stream> xmlStreamFunc = () => new MemoryStream(Encoding.UTF8.GetBytes(conf.ToXml()));
+
+ var mockConn = new Mock<IServerConnection>();
+ var mockFeatSvc = new Mock<IFeatureService>();
+ var mockResSvc = new Mock<IResourceService>();
+
+ var resId = "Library://Test.FeatureSource";
+ var dataName = "config.xml";
+
+ mockFeatSvc.Setup(fs => fs.TestConnection(It.Is<string>(arg => arg == resId))).Returns("true");
+ mockFeatSvc.Setup(fs => fs.GetSpatialContextInfo(It.Is<string>(arg => arg == resId), It.IsAny<bool>())).Returns(new FdoSpatialContextList
+ {
+ SpatialContext = new System.ComponentModel.BindingList<FdoSpatialContextListSpatialContext>()
+ {
+ sc
+ }
+ });
+ mockFeatSvc.Setup(fs => fs.GetSchemas(It.Is<string>(arg => arg == resId))).Returns(new[] { schema.Name });
+
+ mockResSvc.Setup(rs => rs.GetResourceData(It.Is<string>(arg => arg == resId), It.Is<string>(arg => arg == dataName))).Returns(xmlStreamFunc);
+
+ mockConn.Setup(c => c.FeatureService).Returns(mockFeatSvc.Object);
+ mockConn.Setup(c => c.ResourceService).Returns(mockResSvc.Object);
+
+ var mockFs = new Mock<IFeatureSource>();
+ mockFs.Setup(fs => fs.ConfigurationDocument).Returns(dataName);
+ mockFs.Setup(fs => fs.ResourceID).Returns(resId);
+ mockFs.Setup(fs => fs.Extension).Returns(Enumerable.Empty<IFeatureSourceExtension>());
+ mockFs.Setup(fs => fs.ResourceType).Returns(ResourceTypes.FeatureSource.ToString());
+ mockFs.Setup(fs => fs.Provider).Returns("OSGeo.ODBC");
+ mockFs.Setup(fs => fs.Serialize()).Returns(string.Empty);
+
+ //XYZ column misconfigurations
+
+ var context = new ResourceValidationContext(mockConn.Object);
+ var validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ var issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(1, issues.Count());
+ Assert.AreEqual(ValidationStatusCode.Error_OdbcConfig_IncompleteXYZColumnMapping, issues.First().StatusCode);
+
+ odbcTable.XColumn = null;
+ odbcTable.YColumn = "Y";
+
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(1, issues.Count());
+ Assert.AreEqual(ValidationStatusCode.Error_OdbcConfig_IncompleteXYZColumnMapping, issues.First().StatusCode);
+
+ odbcTable.XColumn = null;
+ odbcTable.YColumn = "Y";
+ odbcTable.ZColumn = "Z";
+
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(1, issues.Count());
+ Assert.AreEqual(ValidationStatusCode.Error_OdbcConfig_IncompleteXYZColumnMapping, issues.First().StatusCode);
+
+ odbcTable.XColumn = "X";
+ odbcTable.YColumn = null;
+ odbcTable.ZColumn = "Z";
+
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(1, issues.Count());
+ Assert.AreEqual(ValidationStatusCode.Error_OdbcConfig_IncompleteXYZColumnMapping, issues.First().StatusCode);
+
+ odbcTable.XColumn = "X";
+ odbcTable.YColumn = "Y";
+
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(0, issues.Count());
+
+ //Bogus mapping class target
+ odbcTable.ClassName = "IDontExist";
+
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(1, issues.Count());
+ Assert.AreEqual(ValidationStatusCode.Error_OdbcConfig_NoTableOverrideForFeatureClass, issues.First().StatusCode);
+
+ //Bogus logical geometry property
+ odbcTable.ClassName = klass.Name;
+ geom.GeometricTypes = FeatureGeometricType.Surface;
+
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(1, issues.Count());
+ Assert.AreEqual(ValidationStatusCode.Error_OdbcConfig_InvalidLogicalGeometryProperty, issues.First().StatusCode);
+
+ //All good
+ geom.GeometricTypes = FeatureGeometricType.Point;
+ context = new ResourceValidationContext(mockConn.Object);
+ validator = new FeatureSourceValidator();
+ validator.Connection = mockConn.Object;
+ issues = validator.Validate(context, mockFs.Object, false);
+ Assert.AreEqual(0, issues.Count());
+ }
}
}
More information about the mapguide-commits
mailing list