/// <summary> /// Constructor which creates an empty root. /// </summary> /// <param name="epmTargetTree">Target xml tree</param> internal EpmSourceTree(EpmTargetTree epmTargetTree) { DebugUtils.CheckNoExternalCallers(); this.root = new EpmSourcePathSegment(); this.epmTargetTree = epmTargetTree; }
private static void Validate(EpmSourcePathSegment pathSegment, IEdmType type) { foreach (EpmSourcePathSegment segment in pathSegment.SubProperties) { IEdmTypeReference propertyType = GetPropertyType(type, segment.PropertyName); IEdmType type2 = (propertyType == null) ? null : propertyType.Definition; Validate(segment, type2); } }
/// <summary> /// Validates the specified segment and all its subsegments. /// </summary> /// <param name="pathSegment">The path segment to validate.</param> /// <param name="type">The type of the property represented by this segment (null for open properties).</param> private static void Validate(EpmSourcePathSegment pathSegment, IEdmType type) { Debug.Assert(pathSegment != null, "pathSegment != null"); foreach (EpmSourcePathSegment subSegment in pathSegment.SubProperties) { IEdmTypeReference subSegmentTypeReference = GetPropertyType(type, subSegment.PropertyName); IEdmType subSegmentType = subSegmentTypeReference == null ? null : subSegmentTypeReference.Definition; Validate(subSegment, subSegmentType); } }
internal void Add(EntityPropertyMappingInfo epmInfo) { List <EpmSourcePathSegment> list = new List <EpmSourcePathSegment>(); EpmSourcePathSegment root = this.Root; EpmSourcePathSegment segment2 = null; IEdmType actualPropertyType = epmInfo.ActualPropertyType; string[] strArray = epmInfo.Attribute.SourcePath.Split(new char[] { '/' }); int length = strArray.Length; for (int i = 0; i < length; i++) { string propertyName = strArray[i]; if (propertyName.Length == 0) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath)); } IEdmTypeReference propertyType = GetPropertyType(actualPropertyType, propertyName); IEdmType type2 = (propertyType == null) ? null : propertyType.Definition; if ((type2 == null) && (i < (length - 1))) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, actualPropertyType.ODataFullName())); } actualPropertyType = type2; segment2 = root.SubProperties.SingleOrDefault <EpmSourcePathSegment>(e => e.PropertyName == propertyName); if (segment2 != null) { root = segment2; } else { EpmSourcePathSegment item = new EpmSourcePathSegment(propertyName); root.SubProperties.Add(item); root = item; } list.Add(root); } if ((actualPropertyType != null) && !actualPropertyType.IsODataPrimitiveTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(root.PropertyName)); } if (segment2 != null) { if (segment2.EpmInfo.DefiningTypesAreEqual(epmInfo)) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath)); } this.epmTargetTree.Remove(segment2.EpmInfo); } epmInfo.SetPropertyValuePath(list.ToArray()); root.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
internal void Add(EntityPropertyMappingInfo epmInfo) { List<EpmSourcePathSegment> list = new List<EpmSourcePathSegment>(); EpmSourcePathSegment root = this.Root; EpmSourcePathSegment segment2 = null; IEdmType actualPropertyType = epmInfo.ActualPropertyType; string[] strArray = epmInfo.Attribute.SourcePath.Split(new char[] { '/' }); int length = strArray.Length; for (int i = 0; i < length; i++) { string propertyName = strArray[i]; if (propertyName.Length == 0) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath)); } IEdmTypeReference propertyType = GetPropertyType(actualPropertyType, propertyName); IEdmType type2 = (propertyType == null) ? null : propertyType.Definition; if ((type2 == null) && (i < (length - 1))) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, actualPropertyType.ODataFullName())); } actualPropertyType = type2; segment2 = root.SubProperties.SingleOrDefault<EpmSourcePathSegment>(e => e.PropertyName == propertyName); if (segment2 != null) { root = segment2; } else { EpmSourcePathSegment item = new EpmSourcePathSegment(propertyName); root.SubProperties.Add(item); root = item; } list.Add(root); } if ((actualPropertyType != null) && !actualPropertyType.IsODataPrimitiveTypeKind()) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_EndsWithNonPrimitiveType(root.PropertyName)); } if (segment2 != null) { if (segment2.EpmInfo.DefiningTypesAreEqual(epmInfo)) { throw new ODataException(Microsoft.Data.OData.Strings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath)); } this.epmTargetTree.Remove(segment2.EpmInfo); } epmInfo.SetPropertyValuePath(list.ToArray()); root.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
/// <summary> /// Adds a path to the source and target tree which is obtained by looking at the EntityPropertyMappingAttribute in the <paramref name="epmInfo"/> /// </summary> /// <param name="epmInfo">EnitityPropertyMappingInfo holding the source path</param> internal void Add(EntityPropertyMappingInfo epmInfo) { DebugUtils.CheckNoExternalCallers(); List <EpmSourcePathSegment> pathToCurrentSegment = new List <EpmSourcePathSegment>(); EpmSourcePathSegment currentSourceSegment = this.Root; EpmSourcePathSegment foundSourceSegment = null; IEdmType currentType = epmInfo.ActualPropertyType; Debug.Assert(!string.IsNullOrEmpty(epmInfo.Attribute.SourcePath), "Invalid source path"); string[] propertyPath = epmInfo.Attribute.SourcePath.Split('/'); int propertyPathLength = propertyPath.Length; Debug.Assert(propertyPathLength > 0, "Must have been validated during EntityPropertyMappingAttribute construction"); for (int sourcePropertyIndex = 0; sourcePropertyIndex < propertyPathLength; sourcePropertyIndex++) { string propertyName = propertyPath[sourcePropertyIndex]; if (propertyName.Length == 0) { throw new ODataException(ODataErrorStrings.EpmSourceTree_InvalidSourcePath(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath)); } IEdmTypeReference nextPropertyTypeReference = GetPropertyType(currentType, propertyName); IEdmType nextPropertyType = nextPropertyTypeReference == null ? null : nextPropertyTypeReference.Definition; // If we don't find a property type this is an open property; check whether this is the last segment in the path // since otherwise this would not be an open primitive property and only open primitive properties are allowed. if (nextPropertyType == null && sourcePropertyIndex < propertyPathLength - 1) { throw new ODataException(ODataErrorStrings.EpmSourceTree_OpenComplexPropertyCannotBeMapped(propertyName, currentType.ODataFullName())); } currentType = nextPropertyType; foundSourceSegment = currentSourceSegment.SubProperties.SingleOrDefault(e => e.PropertyName == propertyName); if (foundSourceSegment != null) { currentSourceSegment = foundSourceSegment; } else { EpmSourcePathSegment newSourceSegment = new EpmSourcePathSegment(propertyName); currentSourceSegment.SubProperties.Add(newSourceSegment); currentSourceSegment = newSourceSegment; } pathToCurrentSegment.Add(currentSourceSegment); } // The last segment is the one being mapped from by the user specified attribute. // It must be a primitive type - we don't allow mappings of anything else than primitive properties directly. // Note that we can only verify this for non-open properties, for open properties we must assume it's a primitive type // and we will make this check later during serialization again when we actually have the value of the property. if (currentType != null) { if (!currentType.IsODataPrimitiveTypeKind()) { throw new ODataException(ODataErrorStrings.EpmSourceTree_EndsWithNonPrimitiveType(currentSourceSegment.PropertyName)); } } Debug.Assert(foundSourceSegment == null || foundSourceSegment.EpmInfo != null, "Can't have a leaf node in the tree without EpmInfo."); // Two EpmAttributes with same PropertyName in the same type, this could be a result of inheritance if (foundSourceSegment != null) { Debug.Assert(object.ReferenceEquals(foundSourceSegment, currentSourceSegment), "currentSourceSegment variable should have been updated already to foundSourceSegment"); // Check for duplicates on the same entity type Debug.Assert(foundSourceSegment.SubProperties.Count == 0, "If non-leaf, it means we allowed complex type to be a leaf node"); if (foundSourceSegment.EpmInfo.DefiningTypesAreEqual(epmInfo)) { throw new ODataException(ODataErrorStrings.EpmSourceTree_DuplicateEpmAttributesWithSameSourceName(epmInfo.DefiningType.ODataFullName(), epmInfo.Attribute.SourcePath)); } // In case of inheritance, we need to remove the node from target tree which was mapped to base type property this.epmTargetTree.Remove(foundSourceSegment.EpmInfo); } epmInfo.SetPropertyValuePath(pathToCurrentSegment.ToArray()); currentSourceSegment.EpmInfo = epmInfo; this.epmTargetTree.Add(epmInfo); }
/// <summary> /// Write the content of the given entry. /// </summary> /// <param name="entry">The entry for which to write properties.</param> /// <param name="entryType">The <see cref="IEdmEntityType"/> of the entry (or null if not metadata is available).</param> /// <param name="propertiesValueCache">The cache of properties.</param> /// <param name="rootSourcePathSegment">The root of the EPM source tree, if there's an EPM applied.</param> /// <param name="projectedProperties">Set of projected properties, or null if all properties should be written.</param> private void WriteEntryContent( ODataEntry entry, IEdmEntityType entryType, EntryPropertiesValueCache propertiesValueCache, EpmSourcePathSegment rootSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { Debug.Assert(entry != null, "entry != null"); Debug.Assert(propertiesValueCache != null, "propertiesValueCache != null"); ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource == null) { // <content type="application/xml"> this.atomOutputContext.XmlWriter.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.AtomTypeAttributeName, MimeConstants.MimeApplicationXml); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); this.atomEntryAndFeedSerializer.WriteProperties( entryType, propertiesValueCache.EntryProperties, false /* isWritingCollection */, this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart, this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd, this.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); // </content> this.atomOutputContext.XmlWriter.WriteEndElement(); } else { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.atomEntryAndFeedSerializer.WriteEntryMediaEditLink(mediaResource); if (mediaResource.ReadLink != null) { // <content type="type" src="src"> this.atomOutputContext.XmlWriter.WriteStartElement( AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContentElementName, AtomConstants.AtomNamespace); Debug.Assert(!string.IsNullOrEmpty(mediaResource.ContentType), "The default stream content type should have been validated by now. If we have a read link we must have a non-empty content type as well."); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.AtomTypeAttributeName, mediaResource.ContentType); this.atomOutputContext.XmlWriter.WriteAttributeString( AtomConstants.MediaLinkEntryContentSourceAttributeName, this.atomEntryAndFeedSerializer.UriToUrlAttributeValue(mediaResource.ReadLink)); // </content> this.atomOutputContext.XmlWriter.WriteEndElement(); } this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); this.atomEntryAndFeedSerializer.WriteProperties( entryType, propertiesValueCache.EntryProperties, false /* isWritingCollection */, this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart, this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd, this.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomEntryAndFeedSerializer.AssertRecursionDepthIsZero(); } }
private void WriteEntryContent(ODataEntry entry, IEdmEntityType entryType, EntryPropertiesValueCache propertiesValueCache, EpmSourcePathSegment rootSourcePathSegment, ProjectedPropertiesAnnotation projectedProperties) { ODataStreamReferenceValue mediaResource = entry.MediaResource; if (mediaResource == null) { this.atomOutputContext.XmlWriter.WriteStartElement("", "content", "http://www.w3.org/2005/Atom"); this.atomOutputContext.XmlWriter.WriteAttributeString("type", "application/xml"); this.atomEntryAndFeedSerializer.WriteProperties(entryType, propertiesValueCache.EntryProperties, false, new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart), new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd), base.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); this.atomOutputContext.XmlWriter.WriteEndElement(); } else { WriterValidationUtils.ValidateStreamReferenceValue(mediaResource, true); this.atomEntryAndFeedSerializer.WriteEntryMediaEditLink(mediaResource); if (mediaResource.ReadLink != null) { this.atomOutputContext.XmlWriter.WriteStartElement("", "content", "http://www.w3.org/2005/Atom"); this.atomOutputContext.XmlWriter.WriteAttributeString("type", mediaResource.ContentType); this.atomOutputContext.XmlWriter.WriteAttributeString("src", this.atomEntryAndFeedSerializer.UriToUrlAttributeValue(mediaResource.ReadLink)); this.atomOutputContext.XmlWriter.WriteEndElement(); } this.atomEntryAndFeedSerializer.WriteProperties(entryType, propertiesValueCache.EntryProperties, false, new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesStart), new Action(this.atomEntryAndFeedSerializer.WriteEntryPropertiesEnd), base.DuplicatePropertyNamesChecker, propertiesValueCache, rootSourcePathSegment, projectedProperties); } }