/// <summary> /// Initializes a new instance of the <see cref="ResourceEditorServiceBase"/> class. /// </summary> /// <param name="resourceID">The resource ID.</param> /// <param name="conn">The conn.</param> /// <remarks> /// The editor service does not do live edits of the resource you pass in to this constructor /// /// When an editor is modifying a resource, it is not modifying the resource you specify here. It is instead modifying a /// session-based copy of the resource that is created internally by the editor service. On a save action (a call to /// <see cref="M:Maestro.Editors.ResourceEditorServiceBase.Save"/>), the session-based copy is copied back into the resource /// id you specified, overwriting its contents and data files. /// /// This provides an extra level of safety against unintentional edits, as such edits will only apply to the session-copy, only /// being committed back to the resource id you specified on an explicit save action. /// </remarks> protected ResourceEditorServiceBase(string resourceID, IServerConnection conn) { this.IsNew = ResourceIdentifier.IsSessionBased(resourceID); this.ResourceID = resourceID; _conn = conn; this.PreviewLocale = "en"; //NOXLATE }
/// <summary> /// Saves the edited resource under a different resource ID. The session copy, which holds the current changes is copied back /// to the specified resource ID /// </summary> /// <param name="resourceID"></param> public void SaveAs(string resourceID) { if (ResourceIdentifier.IsSessionBased(resourceID)) { throw new ArgumentException(Strings.NotSessionBasedId); //LOCALIZE } if (!OnBeforeSave()) { //_conn.ResourceService.SaveResourceAs(_editCopy, resourceID); _conn.ResourceService.CopyResource(_editCopy.ResourceID, resourceID, true); this.ResourceID = resourceID; this.IsNew = false; this.IsDirty = false; OnDirtyStateChanged(); OnSaved(); } }
/// <summary> /// Perform base validation logic /// </summary> /// <param name="context"></param> /// <param name="resource"></param> /// <param name="recurse"></param> /// <returns></returns> protected ValidationIssue[] ValidateBase(ResourceValidationContext context, IResource resource, bool recurse) { Check.ArgumentNotNull(context, nameof(context)); if (context.IsAlreadyValidated(resource.ResourceID)) { return(null); } var ldef = resource as ILayerDefinition; var vldef = ldef.SubLayer as IVectorLayerDefinition; var gldef = ldef.SubLayer as IRasterLayerDefinition; var dldef = ldef.SubLayer as IDrawingLayerDefinition; List <ValidationIssue> issues = new List <ValidationIssue>(); var header = ResourceIdentifier.IsSessionBased(resource.ResourceID) ? null : context.Connection.ResourceService.GetResourceHeader(resource.ResourceID); var meta = header?.Metadata?.Simple; if (meta != null) { //Is WMS published? if (meta.Property.Any(p => p.Name == "_IsPublished" && p.Value == "1")) { //Check that it has bounds var b = meta.Property.FirstOrDefault(p => p.Name == "_Bounds"); bool hasBounds = true; if (b != null) { if (string.IsNullOrEmpty(b.Value?.Trim())) { hasBounds = false; } } else { hasBounds = false; } if (!hasBounds) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_WmsPublishedLayerMissingBounds, Strings.LDF_WmsPublishedLayerMissingBounds)); } } } if (ldef.SubLayer == null) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_LayerNull, Strings.LDF_LayerNullError)); } ClassDefinition cls = null; if (vldef != null || gldef != null) { //Load referenced feature source IFeatureSource fs = null; try { fs = (IFeatureSource)context.GetResource(ldef.SubLayer.ResourceId); } catch (Exception) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_FeatureSourceLoadError, string.Format(Strings.LDF_FeatureSourceLoadError))); } if (fs != null) { //Verify specified feature class and geometry check out try { string qualClassName = vldef == null ? gldef.FeatureName : vldef.FeatureName; string geometry = vldef == null ? gldef.Geometry : vldef.Geometry; bool foundSchema = false; bool foundGeometry = false; cls = this.Connection.FeatureService.GetClassDefinition(fs.ResourceID, qualClassName); if (cls != null) { foundSchema = true; foreach (PropertyDefinition col in cls.Properties) { if (col.Name == geometry) { foundGeometry = true; break; } } if (vldef != null && vldef.PropertyMapping != null) { foreach (INameStringPair s in vldef.PropertyMapping) { bool found = false; foreach (PropertyDefinition col in cls.Properties) { if (col.Name == s.Name) { found = true; break; } } if (!found) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_InvalidPropertyMapping, string.Format(Strings.LDF_InvalidPropertyMapping, s.Name, qualClassName))); } } } } if (!foundSchema) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_ClassNotFound, string.Format(Strings.LDF_SchemaMissingError, qualClassName, fs.ResourceID))); } else if (!foundGeometry) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_GeometryNotFound, string.Format(Strings.LDF_GeometryMissingError, geometry, qualClassName, fs.ResourceID))); } } catch (Exception ex) { issues.Add(new ValidationIssue(fs, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_Generic, string.Format(Strings.LDF_SchemaAndColumnReadFailedError, ex.ToString()))); } if (recurse) { issues.AddRange(ResourceValidatorSet.Validate(context, fs, recurse)); } } } if (vldef != null) { if (string.IsNullOrEmpty(vldef.FeatureName)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_MissingFeatureName, Strings.LDF_MissingFeatureSourceError)); } if (string.IsNullOrEmpty(vldef.Geometry)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_MissingGeometry, Strings.LDF_MissingGeometryError)); } if (vldef.VectorScaleRange == null || !vldef.HasVectorScaleRanges()) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_MissingScaleRanges, Strings.LDF_MissingScaleRangesError)); } else { //Test for overlapping scale ranges List <KeyValuePair <double, double> > ranges = new List <KeyValuePair <double, double> >(); foreach (IVectorScaleRange vsr in vldef.VectorScaleRange) { IVectorScaleRange2 vsr2 = vsr as IVectorScaleRange2; if (vsr2 != null) { var area = vsr2.AreaStyle; var line = vsr2.LineStyle; var point = vsr2.PointStyle; if (vsr2.CompositeStyleCount > 0 && (area != null || line != null || point != null)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Warning, ValidationStatusCode.Warning_LayerDefinition_CompositeStyleDefinedAlongsideBasicStyle, string.Format( Strings.LDF_CompositeStyleDefinedAlongsideBasicStyle, vsr2.MinScale.HasValue ? vsr2.MinScale.Value : 0, vsr2.MaxScale.HasValue ? vsr2.MaxScale.Value.ToString() : Strings.Infinity))); } if (vsr2.CompositeStyleCount > 0) { foreach (var cs in vsr2.CompositeStyle) { foreach (var cr in cs.CompositeRule) { if (cr.CompositeSymbolization != null) { foreach (var si in cr.CompositeSymbolization.SymbolInstance) { //verify that symbol references point to valid symbol definitions if (si.Reference.Type == SymbolInstanceType.Reference) { var symRef = (ISymbolInstanceReferenceLibrary)si.Reference; if (!context.ResourceExists(symRef.ResourceId)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_SymbolDefintionReferenceNotFound, string.Format( Strings.LDF_SymbolDefintionReferenceNotFound, symRef.ResourceId))); } if (cls != null) { //warn if the symbol definition has usage contexts that are irrelevant against the layer's feature source var prop = cls.FindProperty(vldef.Geometry) as GeometricPropertyDefinition; if (prop != null) { var gtypes = new List <FeatureGeometricType>(prop.GetIndividualGeometricTypes()); var sym = context.GetResource(symRef.ResourceId) as ISimpleSymbolDefinition; if (sym != null) { if (sym.LineUsage != null && !gtypes.Contains(FeatureGeometricType.Curve)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Information, ValidationStatusCode.Info_LayerDefinition_IrrelevantUsageContext, string.Format( Strings.LDF_IrrelevantUsageContext, symRef.ResourceId, FeatureGeometricType.Curve.ToString()))); } if (sym.AreaUsage != null && !gtypes.Contains(FeatureGeometricType.Surface)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Information, ValidationStatusCode.Info_LayerDefinition_IrrelevantUsageContext, string.Format( Strings.LDF_IrrelevantUsageContext, symRef.ResourceId, FeatureGeometricType.Surface.ToString()))); } if (sym.PointUsage != null && !gtypes.Contains(FeatureGeometricType.Point)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Information, ValidationStatusCode.Info_LayerDefinition_IrrelevantUsageContext, string.Format( Strings.LDF_IrrelevantUsageContext, symRef.ResourceId, FeatureGeometricType.Point.ToString()))); } } } } } //verify that the overrides specified are for symbol parameters that actually exist if (si.ParameterOverrides.Count > 0) { if (si.Reference.Type == SymbolInstanceType.Reference) { var symRef = (ISymbolInstanceReferenceLibrary)si.Reference; var sym = (ISymbolDefinitionBase)context.GetResource(symRef.ResourceId); var paramList = new Dictionary <string, IParameter>(); foreach (var p in sym.GetParameters()) { paramList[p.Identifier] = p; } foreach (var ov in si.ParameterOverrides.Override) { if (!paramList.ContainsKey(ov.ParameterIdentifier)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Warning, ValidationStatusCode.Warning_LayerDefinition_SymbolParameterOverrideToNonExistentParameter, string.Format( Strings.LDF_SymbolParameterOverrideToNonExistentParameter, symRef.ResourceId, ov.ParameterIdentifier))); } } } } } } } } } } ranges.Add(new KeyValuePair <double, double>( vsr.MaxScale.HasValue ? vsr.MaxScale.Value : double.PositiveInfinity, vsr.MinScale.HasValue ? vsr.MinScale.Value : double.NegativeInfinity)); } double min = double.PositiveInfinity; double max = double.NegativeInfinity; foreach (KeyValuePair <double, double> sr in ranges) { min = Math.Min(min, sr.Value); max = Math.Max(max, sr.Key); if (sr.Key < sr.Value) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_MinMaxScaleSwapped, string.Format(Strings.LDF_MinAndMaxScaleSwappedError, sr.Value, sr.Key))); } } ranges.Sort(CompareScales); //TODO: Detect gaps in scale ranges for (int i = 0; i < ranges.Count; i++) { for (int j = i + 1; j < ranges.Count; j++) { if (ranges[i].Key > ranges[j].Value || ranges[i].Value > ranges[j].Value) { issues.Add(new ValidationIssue(resource, ValidationStatus.Information, ValidationStatusCode.Info_LayerDefinition_ScaleRangeOverlap, string.Format(Strings.LDF_ScaleRangesOverlapInformation, ranges[i].Value, ranges[i].Key, ranges[j].Value, ranges[j].Key))); } } } } if (meta != null) { //Is this WMS queryable? if (meta.Property.Any(p => p.Name == "_Queryable" && p.Value == "1")) { //We should have some property mappings, otherwise WMS GetFeatureInfo will return nothing if (!(vldef.PropertyMapping?.Any() == true)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Warning, ValidationStatusCode.Warning_LayerDefinition_NoPropertyMappingsForWmsQueryableLayer, Strings.LDF_WmsQueryableLayerNoPropertyMappings)); } } } } else if (gldef != null) { if (string.IsNullOrEmpty(gldef.FeatureName)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_MissingFeatureName, Strings.LDF_MissingFeatureSourceError)); } if (string.IsNullOrEmpty(gldef.Geometry)) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_MissingGeometry, Strings.LDF_MissingGeometryError)); } if (gldef.GridScaleRange == null || gldef.GridScaleRangeCount == 0) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_NoGridScaleRanges, Strings.LDF_MissingScaleRangesError)); } else if (gldef.GridScaleRangeCount != 1) { issues.Add(new ValidationIssue(resource, ValidationStatus.Warning, ValidationStatusCode.Warning_LayerDefinition_MultipleGridScaleRanges, Strings.LDF_MultipleScaleRangesWarning)); } } else if (dldef != null) { IDrawingSource dws = null; try { dws = (IDrawingSource)context.GetResource(dldef.ResourceId); } catch (Exception) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_DrawingSourceError, Strings.LDF_DrawingSourceError)); } if (dws != null) { if (Array.IndexOf(this.Connection.Capabilities.SupportedServices, (int)ServiceType.Drawing) >= 0) { var dwSvc = (IDrawingService)this.Connection.GetService((int)ServiceType.Drawing); //Check if specified section exists var shtList = dwSvc.EnumerateDrawingSections(dws.ResourceID); DrawingSectionListSection sheet = null; foreach (var sht in shtList.Section) { if (sht.Name.Equals(dldef.Sheet)) { sheet = sht; break; } } if (sheet == null) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_DrawingSourceSheetNotFound, string.Format(Strings.LDF_SheetNotFound, dldef.Sheet))); } else { //null or empty filter means all layers, in that case do nothing if (!string.IsNullOrEmpty(dldef.LayerFilter)) { //Check if specified layers all exist in specified section var specifiedLayers = dldef.LayerFilter.Split(','); //NOXLATE var dwLayers = new Dictionary <string, string>(); var shtLayers = dwSvc.EnumerateDrawingLayers(dws.ResourceID, sheet.Name); foreach (var sl in shtLayers) { dwLayers.Add(sl, sl); } foreach (var sl in specifiedLayers) { if (!dwLayers.ContainsKey(sl.Trim())) { issues.Add(new ValidationIssue(resource, ValidationStatus.Error, ValidationStatusCode.Error_LayerDefinition_DrawingSourceSheetLayerNotFound, string.Format(Strings.LDF_SheetLayerNotFound, sl.Trim(), sheet.Name))); } } } } } if (recurse) { issues.AddRange(ResourceValidatorSet.Validate(context, dws, recurse)); } } } else { issues.Add(new ValidationIssue(resource, ValidationStatus.Warning, ValidationStatusCode.Warning_LayerDefinition_UnsupportedLayerType, Strings.LDF_UnsupportedLayerTypeWarning)); } context.MarkValidated(resource.ResourceID); return(issues.ToArray()); }