/// <summary> /// Write the metadata for an OData association link; makes sure any duplicate of the link's values duplicated in metadata are equal. /// </summary> /// <param name="writer">The Xml writer to write to.</param> /// <param name="baseUri">The base Uri of the document or null if none was specified.</param> /// <param name="entry">The entry for which to write the association link.</param> /// <param name="associationLink">The association link for which to write the metadata.</param> internal static void WriteODataAssociationLinkMetadata(XmlWriter writer, Uri baseUri, ODataEntry entry, ODataAssociationLink associationLink) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); Debug.Assert(entry != null, "entry != null"); Debug.Assert(associationLink != null, "link != null"); Debug.Assert(!string.IsNullOrEmpty(associationLink.Name), "The link name was not verified yet."); Debug.Assert(associationLink.Url != null, "The link Url was not verified yet."); string linkRelation = AtomUtils.ComputeODataAssociationLinkRelation(associationLink); string linkHref = AtomUtils.ToUrlAttributeValue(associationLink.Url, baseUri); string linkHrefLang = null; string linkType = MimeConstants.MimeApplicationXml; string linkTitle = associationLink.Name; int? linkLength = null; AtomLinkMetadata linkMetadata = null; AtomEntryMetadata entryMetadata = entry.Atom(); if (entryMetadata != null) { // TODO: Determine the link metadata from the entry } if (linkMetadata != null) { Uri metadataHref = linkMetadata.Href; if (metadataHref != null) { string metadataHrefString = AtomUtils.ToUrlAttributeValue(metadataHref, baseUri); if (metadataHrefString != linkHref) { throw new ODataException(Strings.ODataAtomWriter_LinkMetadataHrefMustBeEqualWithLinkUrl(metadataHrefString, linkHref)); } } string metadataRelation = linkMetadata.Relation; if (metadataRelation != null && metadataRelation != linkRelation) { throw new ODataException(Strings.ODataAtomWriter_LinkMetadataRelationMustBeEqualWithComputedRelation(metadataRelation, linkRelation)); } string metadataType = linkMetadata.MediaType; if (metadataType != null && metadataType != linkType) { throw new ODataException(Strings.ODataAtomWriter_LinkMetadataMediaTypeMustBeEqualWithComputedType(metadataRelation, linkType)); } string metadataTitle = linkMetadata.Title; if (metadataTitle != null && metadataTitle != linkTitle) { throw new ODataException(Strings.ODataAtomWriter_LinkMetadataTitleMustBeEqualWithLinkName(metadataTitle, linkTitle)); } linkHrefLang = linkMetadata.HrefLang; linkLength = linkMetadata.Length; } WriteAtomLinkMetadataAttributes(writer, linkRelation, linkHref, linkHrefLang, linkTitle, linkType, linkLength); }
/// <summary> /// Adds a new category to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the category to.</param> /// <param name="categoryMetadata">The category metadata to add.</param> internal static void AddCategory(this AtomEntryMetadata entryMetadata, AtomCategoryMetadata categoryMetadata) { Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(categoryMetadata != null, "categoryMetadata != null"); entryMetadata.Categories = entryMetadata.Categories.ConcatToReadOnlyEnumerable("Categories", categoryMetadata); }
/// <summary> /// Adds a new author to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the author to.</param> /// <param name="authorMetadata">The author metadata to add.</param> internal static void AddAuthor(this AtomEntryMetadata entryMetadata, AtomPersonMetadata authorMetadata) { Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(authorMetadata != null, "authorMetadata != null"); entryMetadata.Authors = entryMetadata.Authors.ConcatToReadOnlyEnumerable("Authors", authorMetadata); }
/// <summary> /// Adds a new contributor to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the contributor to.</param> /// <param name="contributorMetadata">The contributor metadata to add.</param> internal static void AddContributor(this AtomEntryMetadata entryMetadata, AtomPersonMetadata contributorMetadata) { Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(contributorMetadata != null, "contributorMetadata != null"); entryMetadata.Contributors = entryMetadata.Contributors.ConcatToReadOnlyEnumerable("Contributors", contributorMetadata); }
/// <summary> /// Adds a new link to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLink(this AtomEntryMetadata entryMetadata, AtomLinkMetadata linkMetadata) { Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); entryMetadata.Links = entryMetadata.Links.ConcatToReadOnlyEnumerable("Ref", linkMetadata); }
private void TryAnnotateV2FeedPackage(ODataEntry entry, EntityInstanceContext entityInstanceContext) { var instance = entityInstanceContext.EntityInstance as ODataPackage; if (instance != null) { // Set Atom entry metadata var atomEntryMetadata = new AtomEntryMetadata(); atomEntryMetadata.Title = instance.Id; if (!string.IsNullOrEmpty(instance.Authors)) { atomEntryMetadata.Authors = new[] { new AtomPersonMetadata { Name = instance.Authors } } } ; if (instance.Published > DateTime.MinValue) { atomEntryMetadata.Published = instance.Published; } if (!string.IsNullOrEmpty(instance.Summary)) { atomEntryMetadata.Summary = instance.Summary; } entry.SetAnnotation(atomEntryMetadata); // Set the ID and links. We have to do this because the self link should have a version containing // SemVer 2.0.0 metadata (e.g. 1.0.0+git). entry.Id = BuildId(instance, entityInstanceContext); entry.ReadLink = new Uri(entry.Id); entry.EditLink = new Uri(entry.Id); // Add package download link entry.MediaResource = new ODataStreamReferenceValue { ContentType = ContentType, ReadLink = BuildLinkForStreamProperty(instance, entityInstanceContext) }; // Make the download action target match the media resource link. entry.Actions = entry .Actions .Select(action => { if (StringComparer.OrdinalIgnoreCase.Equals("Download", action.Title)) { return new ODataAction { Metadata = action.Metadata, Target = entry.MediaResource.ReadLink, Title = action.Title } } ; return(action); }) .ToList(); } }
private void TryAnnotateV2FeedPackage(ODataEntry entry, EntityInstanceContext entityInstanceContext) { var instance = entityInstanceContext.EntityInstance as V2FeedPackage; if (instance != null) { // Set Atom entry metadata var atomEntryMetadata = new AtomEntryMetadata(); atomEntryMetadata.Title = instance.Id; if (!string.IsNullOrEmpty(instance.Authors)) { atomEntryMetadata.Authors = new[] { new AtomPersonMetadata { Name = instance.Authors } }; } if (instance.LastUpdated > DateTime.MinValue) { atomEntryMetadata.Updated = instance.LastUpdated; } if (!string.IsNullOrEmpty(instance.Summary)) { atomEntryMetadata.Summary = instance.Summary; } entry.SetAnnotation(atomEntryMetadata); // Add package download link entry.MediaResource = new ODataStreamReferenceValue { ContentType = ContentType, ReadLink = BuildLinkForStreamProperty("v2", instance.Id, instance.Version, entityInstanceContext.Request) }; } }
/// <summary> /// Adds a new link to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLink(this AtomEntryMetadata entryMetadata, AtomLinkMetadata linkMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); entryMetadata.Links = entryMetadata.Links.ConcatToReadOnlyEnumerable("Links", linkMetadata); }
internal static void AddLinkToEntryMetadata(AtomEntryMetadata entryMetadata, AtomLinkMetadata linkMetadata) { if (object.ReferenceEquals(entryMetadata.Links, EmptyLinksList)) { entryMetadata.Links = new ReadOnlyEnumerable <AtomLinkMetadata>(); } ReaderUtils.GetSourceListOfEnumerable <AtomLinkMetadata>(entryMetadata.Links, "Links").Add(linkMetadata); }
internal static void AddContributorToEntryMetadata(AtomEntryMetadata entryMetadata, AtomPersonMetadata contributorMetadata) { if (object.ReferenceEquals(entryMetadata.Contributors, EmptyPersonsList)) { entryMetadata.Contributors = new ReadOnlyEnumerable <AtomPersonMetadata>(); } ReaderUtils.GetSourceListOfEnumerable <AtomPersonMetadata>(entryMetadata.Contributors, "Contributors").Add(contributorMetadata); }
internal static void AddCategoryToEntryMetadata(AtomEntryMetadata entryMetadata, AtomCategoryMetadata categoryMetadata) { if (object.ReferenceEquals(entryMetadata.Categories, EmptyCategoriesList)) { entryMetadata.Categories = new ReadOnlyEnumerable <AtomCategoryMetadata>(); } ReaderUtils.GetSourceListOfEnumerable <AtomCategoryMetadata>(entryMetadata.Categories, "Categories").Add(categoryMetadata); }
/// <summary> /// Visits an ATOM entry metadata. /// </summary> /// <param name="atomEntryMetadata">The entry metadata to visit.</param> protected override void VisitAtomEntryMetadata(AtomEntryMetadata atomEntryMetadata) { this.ValidateEnumerable <AtomPersonMetadata>(atomEntryMetadata.Authors, "AtomEntryMetadata.Authors"); this.ValidateEnumerable <AtomCategoryMetadata>(atomEntryMetadata.Categories, "AtomEntryMetadata.Categories"); this.ValidateEnumerable <AtomPersonMetadata>(atomEntryMetadata.Contributors, "AtomEntryMetadata.Contributors"); this.ValidateEnumerable <AtomLinkMetadata>(atomEntryMetadata.Links, "AtomEntryMetadata.Links"); base.VisitAtomEntryMetadata(atomEntryMetadata); }
/// <summary> /// Merges custom and EPM ATOM metadata. /// </summary> /// <param name="customEntryMetadata">The custom ATOM metadata, or null if there were no custom ATOM metadata.</param> /// <param name="epmEntryMetadata">The EPM ATOM metadata, or null if there are no EPM mappings to syndication targets.</param> /// <returns>The merged ATOM metadata to write to the output.</returns> /// <remarks>The merge means that if one of the sides has null, the other is used, otherwise if both are non-null /// we verify that the values are the same, otherwise we throw.</remarks> internal static AtomEntryMetadata MergeCustomAndEpmEntryMetadata(AtomEntryMetadata customEntryMetadata, AtomEntryMetadata epmEntryMetadata) { DebugUtils.CheckNoExternalCallers(); AtomEntryMetadata simpleMergeResult; if (TryMergeIfNull(customEntryMetadata, epmEntryMetadata, out simpleMergeResult)) { return(simpleMergeResult); } // We will be modifying the EPM metadata adding the custom into it // The reason is that with EPM we can be sure that the enumerations are of type List (since they were created like that) and thus // we can safely add items into those without reallocating the collections. // Merge Title epmEntryMetadata.Title = MergeAtomTextValue(customEntryMetadata.Title, epmEntryMetadata.Title, "Title"); // Merge Summary epmEntryMetadata.Summary = MergeAtomTextValue(customEntryMetadata.Summary, epmEntryMetadata.Summary, "Summary"); // Merge Rights epmEntryMetadata.Rights = MergeAtomTextValue(customEntryMetadata.Rights, epmEntryMetadata.Rights, "Rights"); // Merge Published epmEntryMetadata.Published = MergeDateTimeValue(customEntryMetadata.Published, epmEntryMetadata.Published, "Published"); // Merge Updated epmEntryMetadata.Updated = MergeDateTimeValue(customEntryMetadata.Updated, epmEntryMetadata.Updated, "Updated"); // Merge authors epmEntryMetadata.Authors = MergePersons(customEntryMetadata.Authors, epmEntryMetadata.Authors); // Merge contributors epmEntryMetadata.Contributors = MergePersons(customEntryMetadata.Contributors, epmEntryMetadata.Contributors); // Copy the rest over from custom metadata since EPM doesn't use these yet. // Categories Debug.Assert(epmEntryMetadata.Categories == null, "Once EPM actually writes to category elements, implement the merge with custom metadata here."); epmEntryMetadata.Categories = customEntryMetadata.Categories; // Icon Debug.Assert(epmEntryMetadata.Icon == null, "Once EPM actually writes to icon element, implement the merge with custom metadata here."); epmEntryMetadata.Icon = customEntryMetadata.Icon; // Links Debug.Assert(epmEntryMetadata.Links == null, "Once EPM actually writes to link element, implement the merge with custom metadata here."); epmEntryMetadata.Links = customEntryMetadata.Links; // Source Debug.Assert(epmEntryMetadata.Source == null, "Once EPM actually writes to source element, implement the merge with custom metadata here."); epmEntryMetadata.Source = customEntryMetadata.Source; return(epmEntryMetadata); }
private void WriteEntry(IExpandedResult expanded, object element, bool resourceInstanceInFeed, ResourceType expectedType) { Uri uri; Func <ProjectionNode, bool> predicate = null; base.IncrementSegmentResultCount(); ODataEntry entry = new ODataEntry(); AtomEntryMetadata annotation = new AtomEntryMetadata(); entry.SetAnnotation <AtomEntryMetadata>(annotation); string name = expectedType.Name; ResourceType actualResourceType = WebUtil.GetNonPrimitiveResourceType(base.Provider, element); if (actualResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { throw new DataServiceException(500, System.Data.Services.Strings.BadProvider_InconsistentEntityOrComplexTypeUsage(actualResourceType.FullName)); } Uri absoluteUri = Serializer.GetIdAndEditLink(element, actualResourceType, base.Provider, base.CurrentContainer, base.AbsoluteServiceUri, out uri); Uri relativeUri = new Uri(absoluteUri.AbsoluteUri.Substring(base.AbsoluteServiceUri.AbsoluteUri.Length), UriKind.Relative); entry.MediaResource = this.GetMediaResource(element, actualResourceType, name, relativeUri); entry.TypeName = actualResourceType.FullName; entry.Id = uri.AbsoluteUri; entry.EditLink = relativeUri; AtomLinkMetadata metadata2 = new AtomLinkMetadata { Title = name }; annotation.EditLink = metadata2; string eTagValue = base.GetETagValue(element, actualResourceType); if (eTagValue != null) { entry.ETag = eTagValue; } IEnumerable <ProjectionNode> projections = base.GetProjections(); if (projections != null) { if (predicate == null) { predicate = projectionNode => projectionNode.TargetResourceType.IsAssignableFrom(actualResourceType); } projections = projections.Where <ProjectionNode>(predicate); entry.SetAnnotation <ProjectedPropertiesAnnotation>(new ProjectedPropertiesAnnotation(from p in projections select p.PropertyName)); } entry.AssociationLinks = this.GetEntityAssociationLinks(actualResourceType, relativeUri, projections); this.PopulateODataOperations(element, resourceInstanceInFeed, entry, actualResourceType); this.odataWriter.WriteStart(entry); this.WriteNavigationProperties(expanded, element, resourceInstanceInFeed, actualResourceType, absoluteUri, relativeUri, projections); entry.Properties = this.GetEntityProperties(element, actualResourceType, relativeUri, projections); this.odataWriter.WriteEnd(); }
/// <summary> /// Adds a new contributor to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the contributor to.</param> /// <param name="contributorMetadata">The contributor metadata to add.</param> internal static void AddContributorToEntryMetadata(AtomEntryMetadata entryMetadata, AtomPersonMetadata contributorMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(contributorMetadata != null, "contributorMetadata != null"); if (object.ReferenceEquals(entryMetadata.Contributors, EmptyPersonsList)) { entryMetadata.Contributors = new ReadOnlyEnumerable <AtomPersonMetadata>(); } ReaderUtils.GetSourceListOfEnumerable(entryMetadata.Contributors, "Contributors").Add(contributorMetadata); }
/// <summary> /// Adds a new link to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the link to.</param> /// <param name="linkMetadata">The link metadata to add.</param> internal static void AddLinkToEntryMetadata(AtomEntryMetadata entryMetadata, AtomLinkMetadata linkMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(linkMetadata != null, "linkMetadata != null"); if (object.ReferenceEquals(entryMetadata.Links, EmptyLinksList)) { entryMetadata.Links = new ReadOnlyEnumerable <AtomLinkMetadata>(); } ReaderUtils.GetSourceListOfEnumerable(entryMetadata.Links, "Links").Add(linkMetadata); }
/// <summary> /// Adds a new category to entry metadata. /// </summary> /// <param name="entryMetadata">The entry metadata to add the category to.</param> /// <param name="categoryMetadata">The category metadata to add.</param> internal static void AddCategoryToEntryMetadata(AtomEntryMetadata entryMetadata, AtomCategoryMetadata categoryMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(entryMetadata != null, "entryMetadata != null"); Debug.Assert(categoryMetadata != null, "categoryMetadata != null"); if (object.ReferenceEquals(entryMetadata.Categories, EmptyCategoriesList)) { entryMetadata.Categories = new ReadOnlyEnumerable <AtomCategoryMetadata>(); } ReaderUtils.GetSourceListOfEnumerable(entryMetadata.Categories, "Categories").Add(categoryMetadata); }
/// <summary> /// Visits an ATOM entry metadata. /// </summary> /// <param name="atomEntryMetadata">The entry metadata to visit.</param> protected virtual void VisitAtomEntryMetadata(AtomEntryMetadata atomEntryMetadata) { IEnumerable <AtomPersonMetadata> authors = atomEntryMetadata.Authors; if (authors != null) { foreach (AtomPersonMetadata author in authors) { this.VisitAtomMetadata(author); } } IEnumerable <AtomCategoryMetadata> categories = atomEntryMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { this.VisitAtomMetadata(category); } } IEnumerable <AtomPersonMetadata> contributors = atomEntryMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { this.VisitAtomMetadata(contributor); } } IEnumerable <AtomLinkMetadata> links = atomEntryMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { this.VisitAtomMetadata(link); } } this.VisitAtomMetadata(atomEntryMetadata.Rights); this.VisitAtomMetadata(atomEntryMetadata.EditLink); this.VisitAtomMetadata(atomEntryMetadata.SelfLink); this.VisitAtomMetadata(atomEntryMetadata.CategoryWithTypeName); this.VisitAtomMetadata(atomEntryMetadata.Source); this.VisitAtomMetadata(atomEntryMetadata.Summary); this.VisitAtomMetadata(atomEntryMetadata.Title); }
public override void Annotate(HttpRequestMessage request, ODataEntry entry, object entityInstance) { var feedPackage = entityInstance as V2FeedPackage; if (feedPackage == null) { return; } // Patch links to use normalized versions var normalizedVersion = NuGetVersionFormatter.Normalize(feedPackage.Version); NormalizeNavigationLinks(entry, request, feedPackage, normalizedVersion); // Set Atom entry metadata var atomEntryMetadata = new AtomEntryMetadata(); atomEntryMetadata.Title = feedPackage.Title; if (!string.IsNullOrEmpty(feedPackage.Authors)) { atomEntryMetadata.Authors = new[] { new AtomPersonMetadata { Name = feedPackage.Authors } }; } if (feedPackage.LastUpdated > DateTime.MinValue) { atomEntryMetadata.Updated = feedPackage.LastUpdated; } if (!string.IsNullOrEmpty(feedPackage.Summary)) { atomEntryMetadata.Summary = feedPackage.Summary; } entry.SetAnnotation(atomEntryMetadata); // Add package download link entry.MediaResource = new ODataStreamReferenceValue { ContentType = ContentType, ReadLink = BuildLinkForStreamProperty("v2", feedPackage.Id, normalizedVersion, request) }; }
/// <summary> /// Fixup AtomEntryMetadata to fix hte baselne issue for Atom Entry payload generator /// </summary> /// <param name="metadata">the AtomEntryMetadata</param> /// <returns>fix-up AtomEntryMetadata</returns> public static AtomEntryMetadata Fixup(this AtomEntryMetadata metadata) { if (metadata == null) { return(new AtomEntryMetadata() { Updated = DateTimeOffset.MaxValue }); } if (metadata.Updated == null) { metadata.Updated = DateTimeOffset.MaxValue; } if (metadata.Source != null && metadata.Source.Updated == null) { metadata.Source.Updated = DateTimeOffset.MaxValue; } return(metadata); }
public void SetsAtomEntryMetadataAnnotation() { // Arrange var v2FeedPackage = new V2FeedPackage() { Id = "SomePackageId", Version = "1.0.0", Title = "Title", Authors = ".NET Foundation", LastUpdated = DateTime.UtcNow, Summary = "Summary" }; var annotationStrategy = new V2FeedPackageAnnotationStrategy(_contentType); var oDataEntry = new ODataEntry(); var request = CreateHttpRequestMessage("https://localhost/api/v2/Packages"); var expectedAtomEntryMetadataAnnotation = new AtomEntryMetadata() { Title = v2FeedPackage.Id, Authors = new[] { new AtomPersonMetadata { Name = v2FeedPackage.Authors } }, Updated = v2FeedPackage.LastUpdated, Summary = v2FeedPackage.Summary }; // Act annotationStrategy.Annotate(request, oDataEntry, v2FeedPackage); var actualAtomEntryMetadataAnnotation = oDataEntry.GetAnnotation <AtomEntryMetadata>(); // Assert Assert.Equal(expectedAtomEntryMetadataAnnotation.Title.Text, actualAtomEntryMetadataAnnotation.Title.Text); Assert.Equal(expectedAtomEntryMetadataAnnotation.Summary.Text, actualAtomEntryMetadataAnnotation.Summary.Text); Assert.Equal(expectedAtomEntryMetadataAnnotation.Authors.Single().Name, actualAtomEntryMetadataAnnotation.Authors.Single().Name); Assert.Equal(expectedAtomEntryMetadataAnnotation.Updated, actualAtomEntryMetadataAnnotation.Updated); }
public void PersonMetadataWriterTest() { string testEmail = "*****@*****.**"; string testName = "Test Author 1"; string testUri = "http://odata.org/authors/1"; var testCases = new[] { new { Person = new AtomPersonMetadata() { Name = testName, Email = testEmail, Uri = new Uri(testUri) }, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testName + @"</name>", @" <uri>" + testUri + @"</uri>", @" <email>" + testEmail + @"</email>", @"</author>"), ExpectedException = (string)null }, new { Person = new AtomPersonMetadata() { Name = null, Email = testEmail, Uri = new Uri(testUri) }, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name />", @" <uri>" + testUri + @"</uri>", @" <email>" + testEmail + @"</email>", @"</author>"), ExpectedException = (string)null }, new { Person = new AtomPersonMetadata() { Name = testName, Email = null, Uri = null }, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testName + @"</name>", @"</author>"), ExpectedException = (string)null }, new { Person = (AtomPersonMetadata)testName, Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testName + @"</name>", @"</author>"), ExpectedException = (string)null }, }; Func <XElement, XElement> fragmentExtractor = (e) => e.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomAuthorElementName); // Convert test cases to test descriptions var testDescriptors = testCases.Select(testCase => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(); AtomEntryMetadata metadata = entry.Atom(); this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry."); metadata.Authors = new AtomPersonMetadata[] { testCase.Person }; return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, ExpectedODataExceptionMessage = testCase.ExpectedException, FragmentExtractor = fragmentExtractor })); }); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
/// <summary> /// Visits an ATOM metadata object. /// </summary> /// <param name="atomMetadata"></param> protected virtual void VisitAtomMetadata(object atomMetadata) { if (atomMetadata == null) { return; } AtomCategoryMetadata atomCategoryMetadata = atomMetadata as AtomCategoryMetadata; if (atomCategoryMetadata != null) { this.VisitAtomCategoryMetadata(atomCategoryMetadata); return; } AtomEntryMetadata atomEntryMetadata = atomMetadata as AtomEntryMetadata; if (atomEntryMetadata != null) { this.VisitAtomEntryMetadata(atomEntryMetadata); return; } AtomFeedMetadata atomFeedMetadata = atomMetadata as AtomFeedMetadata; if (atomFeedMetadata != null) { this.VisitAtomFeedMetadata(atomFeedMetadata); return; } AtomGeneratorMetadata atomGeneratorMetadata = atomMetadata as AtomGeneratorMetadata; if (atomGeneratorMetadata != null) { this.VisitAtomGeneratorMetadata(atomGeneratorMetadata); return; } AtomLinkMetadata atomLinkMetadata = atomMetadata as AtomLinkMetadata; if (atomLinkMetadata != null) { this.VisitAtomLinkMetadata(atomLinkMetadata); return; } AtomPersonMetadata atomPersonMetadata = atomMetadata as AtomPersonMetadata; if (atomPersonMetadata != null) { this.VisitAtomPersonMetadata(atomPersonMetadata); return; } AtomResourceCollectionMetadata atomResourceCollectionMetadata = atomMetadata as AtomResourceCollectionMetadata; if (atomResourceCollectionMetadata != null) { this.VisitAtomResourceCollectionMetadata(atomResourceCollectionMetadata); return; } AtomStreamReferenceMetadata atomStreamReferenceMetadata = atomMetadata as AtomStreamReferenceMetadata; if (atomStreamReferenceMetadata != null) { this.VisitAtomStreamReferenceMetadata(atomStreamReferenceMetadata); return; } AtomTextConstruct atomTextConstruct = atomMetadata as AtomTextConstruct; if (atomTextConstruct != null) { this.VisitAtomTextConstruct(atomTextConstruct); return; } AtomWorkspaceMetadata atomWorkspaceMetadata = atomMetadata as AtomWorkspaceMetadata; if (atomWorkspaceMetadata != null) { this.VisitAtomWorkspaceMetadata(atomWorkspaceMetadata); return; } AtomCategoriesMetadata atomCategoriesMetadata = atomMetadata as AtomCategoriesMetadata; if (atomCategoriesMetadata != null) { this.VisitAtomCategoriesMetadata(atomCategoriesMetadata); return; } ExceptionUtilities.Assert(false, "Unrecognized ATOM metadata object {0} of type {1}.", atomMetadata.ToString(), atomMetadata.GetType().ToString()); }
/// <summary> /// Writes the syndication part of EPM for an entry into ATOM metadata OM. /// </summary> /// <param name="epmTargetTree">The EPM target tree to use.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="resourceType">The resource type of the entry.</param> /// <param name="metadata">The metadata provider to use.</param> /// <param name="version">The version of OData protocol to use.</param> /// <returns>The ATOM metadata OM with the EPM values populated.</returns> internal static AtomEntryMetadata WriteEntryEpm( EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmTargetTree != null, "epmTargetTree != null"); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(resourceType != null, "For any EPM to exist the metadata must be available."); // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = epmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return(null); } AtomEntryMetadata entryMetadata = new AtomEntryMetadata(); foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.IsMultiValueProperty) { Debug.Assert( targetSegment.EpmInfo != null && targetSegment.EpmInfo.Attribute != null, "MultiValue property target segment must have EpmInfo and the Epm Attribute."); ODataVersionChecker.CheckMultiValueProperties(version, targetSegment.EpmInfo.Attribute.SourcePath); // WriteMultiValueEpm(entry, targetSegment, epmValueCache); throw new NotImplementedException(); } else if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the Epm attribute"); bool nullOnParentProperty; object propertyValue = epmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty); string textPropertyValue = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: entryMetadata.Updated = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, version); break; case SyndicationItemProperty.Published: entryMetadata.Published = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, version); break; case SyndicationItemProperty.Rights: entryMetadata.Rights = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Summary: entryMetadata.Summary = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Title: entryMetadata.Title = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } } else if (targetSegment.SegmentName == AtomConstants.AtomAuthorElementName) { AtomPersonMetadata authorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Authors == null, "Found two mappings to author, that is invalid."); if (authorMetadata != null) { entryMetadata.Authors = CreateSinglePersonList(authorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomContributorElementName) { AtomPersonMetadata contributorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Contributors == null, "Found two mappings to contributor, that is invalid."); if (contributorMetadata != null) { entryMetadata.Contributors = CreateSinglePersonList(contributorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomLinkElementName) { AtomLinkMetadata linkMetadata = new AtomLinkMetadata(); //// WriteLinkEpm(entry, targetSegment, epmValueCache); Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to link must be conditional."); linkMetadata.Relation = targetSegment.CriteriaValue; List <AtomLinkMetadata> links; if (entryMetadata.Links == null) { links = new List <AtomLinkMetadata>(); entryMetadata.Links = links; } else { links = entryMetadata.Links as List <AtomLinkMetadata>; Debug.Assert(links != null, "AtomEntryMetadata.Links must be of type List<AtomLinkMetadata> since we create it like that."); } links.Add(linkMetadata); throw new NotImplementedException(); } else if (targetSegment.SegmentName == AtomConstants.AtomCategoryElementName) { AtomCategoryMetadata categoryMetadata = new AtomCategoryMetadata(); //// WriteCategoryEpm(entry, targetSegment, epmValueCache) Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to category must be conditional."); categoryMetadata.Scheme = targetSegment.CriteriaValue; List <AtomCategoryMetadata> categories; if (entryMetadata.Categories == null) { categories = new List <AtomCategoryMetadata>(); entryMetadata.Categories = categories; } else { categories = entryMetadata.Links as List <AtomCategoryMetadata>; Debug.Assert(categories != null, "AtomEntryMetadata.Categories must be of type List<AtomCategoryMetadata> since we create it like that."); } categories.Add(categoryMetadata); throw new NotImplementedException(); } else { throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_TargetSegment)); } } return(entryMetadata); }
public void CategoryMetadataOnEntryWriterTest() { var testCases = this.CreateAtomCategoryTestCases(); Func <XElement, XElement> fragmentExtractor = (e) => { var categoryElement = e.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomCategoryElementName); return(categoryElement ?? new XElement("missingCategory")); }; // Convert test cases to test descriptions IEnumerable <PayloadWriterTestDescriptor <ODataItem> > testDescriptors = testCases.Select(testCase => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(); AtomEntryMetadata metadata = entry.Atom(); this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry."); metadata.Categories = new AtomCategoryMetadata[] { testCase.Category }; return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, ExpectedException2 = testCase.ExpectedException, FragmentExtractor = fragmentExtractor })); }); // Add tests for category with type name string testTypeName = "TestModel.TestTypeName"; string testLabel = "Test category 1 label"; var categoryWithTypeNameTestCases = new[] { // Clean merge, no conflicts new AtomCategoryTestCase { Category = new AtomCategoryMetadata() { Term = null, Scheme = null, Label = testLabel, }, Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", ExpectedException = null }, // Patch, conflicting values match new AtomCategoryTestCase { Category = new AtomCategoryMetadata() { Term = testTypeName, Scheme = TestAtomConstants.ODataSchemeNamespace, Label = testLabel, }, Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", ExpectedException = null }, // Patch conflict on term new AtomCategoryTestCase { Category = new AtomCategoryMetadata() { Term = testTypeName.ToUpper(), Scheme = TestAtomConstants.ODataSchemeNamespace, Label = testLabel, }, Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategoryTermsMustMatch", testTypeName, testTypeName.ToUpper()) }, // Patch conflict on scheme new AtomCategoryTestCase { Category = new AtomCategoryMetadata() { Term = testTypeName, Scheme = TestAtomConstants.ODataSchemeNamespace.ToUpper(), Label = testLabel, }, Xml = @"<category term=""" + testTypeName + @""" scheme=""" + TestAtomConstants.ODataSchemeNamespace + @""" label=""" + testLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_CategorySchemesMustMatch", TestAtomConstants.ODataSchemeNamespace, TestAtomConstants.ODataSchemeNamespace.ToUpper()) }, }; testDescriptors = testDescriptors.Concat(categoryWithTypeNameTestCases.Select(testCase => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(); entry.TypeName = testTypeName; AtomEntryMetadata metadata = entry.Atom(); this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry."); metadata.CategoryWithTypeName = testCase.Category; return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, ExpectedException2 = testCase.ExpectedException, FragmentExtractor = fragmentExtractor })); })); // Add all the categories as the category with type name on entry which has no type name. // This verifies that the writer won't write the category with type name if there's no type name. testDescriptors = testDescriptors.Concat(testCases.Select(testCase => { ODataEntry entry = ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(); AtomEntryMetadata metadata = entry.Atom(); this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry."); metadata.CategoryWithTypeName = testCase.Category; return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = "<missingCategory />", ExpectedException2 = null, FragmentExtractor = fragmentExtractor })); })); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
public void EntryMetadataWriterTest() { const string testPublished = "2010-10-20T20:10:00Z"; AtomTextConstruct testRights = new AtomTextConstruct { Text = "Copyright Data Fx team." }; AtomTextConstruct testSummary = new AtomTextConstruct { Text = "Test summary." }; AtomTextConstruct testTitle = new AtomTextConstruct { Text = "Test title" }; const string testUpdated = "2010-11-01T00:04:00Z"; const string testIcon = "http://odata.org/icon"; const string testSourceId = "http://odata.org/id/random"; const string testLogo = "http://odata.org/logo"; AtomTextConstruct testSubtitle = new AtomTextConstruct { Text = "Test subtitle." }; const string testAuthorName = "Test Author 1"; const string testAuthorEmail = "*****@*****.**"; const string testAuthorUri = "http://odata.org/authors/1"; var testAuthors = new AtomPersonMetadata[] { new AtomPersonMetadata() { Email = testAuthorEmail, Name = testAuthorName, Uri = new Uri(testAuthorUri) } }; var testAuthors2 = new AtomPersonMetadata[0]; const string testCategoryTerm = "Test category 1 term"; const string testCategoryLabel = "Test category 1 label"; const string testCategoryScheme = "http://odata.org/categories/1"; var testCategories = new AtomCategoryMetadata[] { new AtomCategoryMetadata() { Term = testCategoryTerm, Label = testCategoryLabel, Scheme = testCategoryScheme } }; const string testContributorName = "Test Contributor 1"; const string testContributorEmail = "*****@*****.**"; const string testContributorUri = "http://odata.org/contributors/1"; var testContributors = new AtomPersonMetadata[] { new AtomPersonMetadata() { Email = testContributorEmail, Name = testContributorName, Uri = new Uri(testContributorUri) } }; const string testGeneratorName = "Test generator"; const string testGeneratorUri = "http://odata.org/generator"; const string testGeneratorVersion = "3.0"; var testGenerator = new AtomGeneratorMetadata() { Name = testGeneratorName, Uri = new Uri(testGeneratorUri), Version = testGeneratorVersion }; const string testLinkRelation = "http://odata.org/links/1"; const string testLinkTitle = "Test link 1"; const string testLinkHref = "http://odata.org/links/1"; const string testLinkHrefLang = "de-AT"; int? testLinkLength = 999; const string testLinkMediaType = "image/png"; var testLinks = new AtomLinkMetadata[] { new AtomLinkMetadata() { Relation = testLinkRelation, Title = testLinkTitle, Href = new Uri(testLinkHref), HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType } }; AtomFeedMetadata testSource = new AtomFeedMetadata() { Authors = testAuthors, Categories = testCategories, Contributors = testContributors, Generator = testGenerator, Icon = new Uri(testIcon), SourceId = new Uri(testSourceId), Links = testLinks, Logo = new Uri(testLogo), Rights = testRights, Subtitle = testSubtitle, Title = testTitle, Updated = DateTimeOffset.Parse(testUpdated) }; Func <string, Func <XElement, XElement> > fragmentExtractor = (localName) => (e) => e.Element(TestAtomConstants.AtomXNamespace + localName); // TODO, ckerer: specify an Id via metadata if the entry does not specify one; we first have to decide what rules // we want to apply to merging of metadata and ODataLib OM data. var testCases = new[] { new { // specify an author via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors), Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new { // specify an empty author array via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors2), Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name />", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new { // specify no authors via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = null), Xml = string.Join( "$(NL)", @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @"$(Indent)<name />", @"</author>"), Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName) }, new { // specify a category via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Categories = testCategories), Xml = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />", Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName) }, new { // specify a contributor via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Contributors = testContributors), Xml = string.Join( "$(NL)", @"<contributor xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <name>" + testContributorName + @"</name>", @" <uri>" + testContributorUri + @"</uri>", @" <email>" + testContributorEmail + @"</email>", @"</contributor>"), Extractor = fragmentExtractor(TestAtomConstants.AtomContributorElementName) }, new { // specify a link via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Links = testLinks), Xml = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>", Extractor = new Func <XElement, XElement>( (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName) .Where(l => l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName).Value != TestAtomConstants.AtomSelfRelationAttributeValue) .Single()) }, new { // specify a published date via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Published = DateTimeOffset.Parse(testPublished)), Xml = @"<published xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testPublished + @"</published>", Extractor = fragmentExtractor(TestAtomConstants.AtomPublishedElementName) }, new { // specify rights via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Rights = testRights), Xml = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>", Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName) }, new { // specify a source via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = testSource), Xml = string.Join( "$(NL)", @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <id>" + testSourceId + "</id>", @" <title type=""text"">" + testTitle.Text + @"</title>", @" <subtitle type=""text"">" + testSubtitle.Text + @"</subtitle>", @" <updated>" + testUpdated + @"</updated>", @" <link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""/>", @" <category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" />", @" <logo>" + testLogo + @"</logo>", @" <rights type=""text"">" + testRights.Text + @"</rights>", @" <contributor>", @" <name>" + testContributorName + @"</name>", @" <uri>" + testContributorUri + @"</uri>", @" <email>" + testContributorEmail + @"</email>", @" </contributor>", @" <generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""">" + testGeneratorName + @"</generator>", @" <icon>" + testIcon + @"</icon>", @" <author>", @" <name>" + testAuthorName + @"</name>", @" <uri>" + testAuthorUri + @"</uri>", @" <email>" + testAuthorEmail + @"</email>", @" </author>", @"</source>"), Extractor = fragmentExtractor(TestAtomConstants.AtomSourceElementName) }, new { // specify default feed metadata as source CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = new AtomFeedMetadata()), Xml = string.Join( "$(NL)", @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">", @" <id />", @" <title />", @" <updated />", @"</source>"), Extractor = new Func <XElement, XElement>(result => { var source = fragmentExtractor(TestAtomConstants.AtomSourceElementName)(result); // Remove the value of updates as it can't be reliably predicted source.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomUpdatedElementName).Nodes().Remove(); return(source); }) }, new { // specify a summary via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Summary = testSummary), Xml = @"<summary type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSummary.Text + @"</summary>", Extractor = fragmentExtractor(TestAtomConstants.AtomSummaryElementName) }, new { // specify a title via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Title = testTitle), Xml = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>", Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName) }, new { // specify an updated date via metadata CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated)), Xml = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>", Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName) }, }; // Convert test cases to test descriptions IEnumerable <Func <ODataEntry> > entryCreators = new Func <ODataEntry>[] { () => ObjectModelUtils.CreateDefaultEntry(), () => ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(), }; var testDescriptors = testCases.SelectMany(testCase => entryCreators.Select(entryCreator => { ODataEntry entry = entryCreator(); AtomEntryMetadata metadata = entry.Atom(); this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry."); testCase.CustomizeMetadata(metadata); return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration => new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings) { Xml = testCase.Xml, FragmentExtractor = testCase.Extractor })); })); this.CombinatorialEngineProvider.RunCombinations( testDescriptors.PayloadCases(WriterPayloads.EntryPayloads), this.WriterTestConfigurationProvider.AtomFormatConfigurations, (testDescriptor, testConfiguration) => { testConfiguration = testConfiguration.Clone(); testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri); TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger); }); }
/// <summary>Write the entry element.</summary> /// <param name="expanded">Expanded result provider for the specified <paramref name="element"/>.</param> /// <param name="element">Element representing the entry element.</param> /// <param name="resourceInstanceInFeed">true if the resource instance being serialized is inside a feed; false otherwise.</param> /// <param name="expectedType">Expected type of the entry element.</param> private void WriteEntry(IExpandedResult expanded, object element, bool resourceInstanceInFeed, ResourceType expectedType) { Debug.Assert(element != null, "element != null"); Debug.Assert(expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType, "expectedType != null && expectedType.ResourceTypeKind == ResourceTypeKind.EntityType"); this.IncrementSegmentResultCount(); ODataEntry entry = new ODataEntry(); if (!resourceInstanceInFeed) { entry.SetSerializationInfo(new ODataFeedAndEntrySerializationInfo { NavigationSourceName = this.CurrentContainer.Name, NavigationSourceEntityTypeName = this.CurrentContainer.ResourceType.FullName, ExpectedTypeName = expectedType.FullName }); } string title = expectedType.Name; #pragma warning disable 618 if (this.contentFormat == ODataFormat.Atom) #pragma warning restore 618 { AtomEntryMetadata entryAtom = new AtomEntryMetadata(); entryAtom.EditLink = new AtomLinkMetadata { Title = title }; entry.SetAnnotation(entryAtom); } ResourceType actualResourceType = WebUtil.GetNonPrimitiveResourceType(this.Provider, element); if (actualResourceType.ResourceTypeKind != ResourceTypeKind.EntityType) { // making sure that the actual resource type is an entity type throw new DataServiceException(500, Microsoft.OData.Service.Strings.BadProvider_InconsistentEntityOrComplexTypeUsage(actualResourceType.FullName)); } EntityToSerialize entityToSerialize = this.WrapEntity(element, actualResourceType); // populate the media resource, if the entity is a MLE. entry.MediaResource = this.GetMediaResource(entityToSerialize, title); // Write the type name this.PayloadMetadataPropertyManager.SetTypeName(entry, this.CurrentContainer.ResourceType.FullName, actualResourceType.FullName); // Write Id element this.PayloadMetadataPropertyManager.SetId(entry, () => entityToSerialize.SerializedKey.Identity); // Write "edit" link this.PayloadMetadataPropertyManager.SetEditLink(entry, () => entityToSerialize.SerializedKey.RelativeEditLink); // Write the etag property, if the type has etag properties this.PayloadMetadataPropertyManager.SetETag(entry, () => this.GetETagValue(element, actualResourceType)); IEnumerable <ProjectionNode> projectionNodes = this.GetProjections(); if (projectionNodes != null) { // Filter the projection nodes for the actual type of the entity // The projection node might refer to the property in a derived type. If the TargetResourceType of // the projection node is not a super type, then we do not want to serialize this property. projectionNodes = projectionNodes.Where(projectionNode => projectionNode.TargetResourceType.IsAssignableFrom(actualResourceType)); // Because we are going to enumerate through these multiple times, create a list. projectionNodes = projectionNodes.ToList(); // And add the annotation to tell ODataLib which properties to write into content (the projections) entry.SetAnnotation(new ProjectedPropertiesAnnotation(projectionNodes.Select(p => p.PropertyName))); } // Populate the advertised actions IEnumerable <ODataAction> actions; if (this.TryGetAdvertisedActions(entityToSerialize, resourceInstanceInFeed, out actions)) { foreach (ODataAction action in actions) { entry.AddAction(action); } } // Populate all the normal properties entry.Properties = this.GetEntityProperties(entityToSerialize, projectionNodes); // And start the entry var args = new DataServiceODataWriterEntryArgs(entry, element, this.Service.OperationContext); this.dataServicesODataWriter.WriteStart(args); // Now write all the navigation properties this.WriteNavigationProperties(expanded, entityToSerialize, resourceInstanceInFeed, projectionNodes); // And write the end of the entry this.dataServicesODataWriter.WriteEnd(args); #if ASTORIA_FF_CALLBACKS this.Service.InternalOnWriteItem(target, element); #endif }
/// <summary> /// Converts the Object Model representation of Atom metadata for entries into appropriate PayloadElement annotations /// </summary> /// <param name="entryMetadata">the Atom entry metadata, in Object Model representation, to convert</param> /// <param name="entry">the EntityInstance to annotate</param> private static void ConvertAtomEntryMetadata(AtomEntryMetadata entryMetadata, EntityInstance entry) { ExceptionUtilities.CheckArgumentNotNull(entryMetadata, "entryMetadata"); ExceptionUtilities.CheckArgumentNotNull(entry, "entry"); foreach (var author in entryMetadata.Authors) { entry.AtomAuthor(author.Name, author.Uri == null ? null : author.Uri.OriginalString, author.Email); } foreach (var category in entryMetadata.Categories) { entry.AtomCategory(category.Term, category.Scheme, category.Label); } foreach (var contributor in entryMetadata.Contributors) { entry.AtomContributor(contributor.Name, contributor.Uri == null? null : contributor.Uri.OriginalString, contributor.Email); } if (entryMetadata.EditLink != null) { AtomLinkMetadata editLink = entryMetadata.EditLink; entry.AtomEditLink(editLink.Href == null ? null : editLink.Href.OriginalString, editLink.MediaType, editLink.HrefLang, editLink.Title, ToString(editLink.Length)); } foreach (var link in entryMetadata.Links) { entry.AtomLink(link.Href == null ? null : link.Href.OriginalString, link.Relation, link.MediaType, link.HrefLang, link.Title, ToString(link.Length)); } if (entryMetadata.Published.HasValue) { entry.AtomPublished(ToString(entryMetadata.Published)); } if (entryMetadata.Rights != null) { entry.AtomRights(entryMetadata.Rights.Text, ToString(entryMetadata.Rights.Kind)); } if (entryMetadata.SelfLink != null) { AtomLinkMetadata selfLink = entryMetadata.SelfLink; entry.AtomSelfLink(selfLink.Href == null ? null : selfLink.Href.OriginalString, selfLink.MediaType, selfLink.HrefLang, selfLink.Title, ToString(selfLink.Length)); } if (entryMetadata.CategoryWithTypeName != null) { AtomCategoryMetadata categoryWithTypeName = entryMetadata.CategoryWithTypeName; entry.AtomCategoryWithTypeName(categoryWithTypeName.Term, categoryWithTypeName.Label); } if (entryMetadata.Source != null) { EntitySetInstance tempSourceFeed = new EntitySetInstance(); ConvertAtomFeedMetadata(entryMetadata.Source, tempSourceFeed); entry.AtomSource(tempSourceFeed); } if (entryMetadata.Summary != null) { entry.AtomSummary(entryMetadata.Summary.Text, ToString(entryMetadata.Summary.Kind)); } if (entryMetadata.Title != null) { entry.AtomTitle(entryMetadata.Title.Text, ToString(entryMetadata.Title.Kind)); } if (entryMetadata.Updated.HasValue) { entry.AtomUpdated(ToString(entryMetadata.Updated)); } }
/// <summary> /// Write the ATOM metadata for an entry /// </summary> /// <param name="writer">The Xml writer to write to.</param> /// <param name="baseUri">The base Uri of the document or null if none was specified.</param> /// <param name="entry">The entry for which to write the metadata.</param> /// <param name="epmEntryMetadata">The ATOM metadata for the entry which came from EPM.</param> internal static void WriteEntryMetadata(XmlWriter writer, Uri baseUri, ODataEntry entry, AtomEntryMetadata epmEntryMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); // TODO, ckerer: implement the rule around authors (an entry has to have an author directly or in the <entry:source> unless the feed has an author). // currently we make all entries have an author. AtomEntryMetadata customEntryMetadata = entry.GetAnnotation<AtomEntryMetadata>(); AtomEntryMetadata entryMetadata = ODataAtomWriterMetadataEpmMergeUtils.MergeCustomAndEpmEntryMetadata(customEntryMetadata, epmEntryMetadata); if (entryMetadata == null) { // write all required metadata elements with default content // <atom:title></atom:title> ODataAtomWriterUtils.WriteEmptyElement(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace); // <atom:updated>dateTimeOffset</atom:updated> // NOTE: the <updated> element is required and if not specified the best we can do is to create a default // one with the current date/time. ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(DateTimeOffset.UtcNow)); WriteEmptyAuthor(writer); } else { // <atom:title>text</atom:title> // NOTE: writes an empty element even if no title was specified since the title is required ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, entryMetadata.Title); AtomTextConstruct summary = entryMetadata.Summary; if (summary != null) { // <atom:summary>text</atom:summary> ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSummaryElementName, AtomConstants.AtomNamespace, summary); } DateTimeOffset? published = entryMetadata.Published; if (published.HasValue) { // <atom:published>dateTimeOffset</atom:published> ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPublishedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(published.Value)); } // <atom:updated>date</atom:updated> // NOTE: the <updated> element is required and if not specified the best we can do is to create a default // one with the current date/time. DateTimeOffset updated = entryMetadata.Updated.HasValue ? entryMetadata.Updated.Value : DateTimeOffset.UtcNow; ODataAtomWriterUtils.WriteElementWithTextContent( writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(updated)); bool wroteAuthor = false; IEnumerable<AtomPersonMetadata> authors = entryMetadata.Authors; if (authors != null) { foreach (AtomPersonMetadata author in authors) { if (author == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_AuthorMetadataMustNotContainNull); } // <atom:author>author data</atom:author> writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace); WritePersonMetadata(writer, baseUri, author); writer.WriteEndElement(); wroteAuthor = true; } } if (!wroteAuthor) { // write empty authors since they are required WriteEmptyAuthor(writer); } IEnumerable<AtomPersonMetadata> contributors = entryMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { if (contributor == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_ContributorMetadataMustNotContainNull); } // <atom:contributor>contributor data</atom:contributor> writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace); WritePersonMetadata(writer, baseUri, contributor); writer.WriteEndElement(); } } IEnumerable<AtomLinkMetadata> links = entryMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { if (link == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_LinkMetadataMustNotContainNull); } // <atom:link>...</atom:link> WriteAtomLinkMetadata(writer, baseUri, link); } } IEnumerable<AtomCategoryMetadata> categories = entryMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { if (category == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_CategoryMetadataMustNotContainNull); } // <atom:category term="..." scheme="..." label="..."></atom:category> WriteCategory(writer, category); } } if (entryMetadata.Rights != null) { // <atom:rights>rights</atom:rights> ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, entryMetadata.Rights); } Uri icon = entryMetadata.Icon; if (icon != null) { // <atom:icon>Uri</atom:icon> ODataAtomWriterUtils.WriteElementWithTextContent( writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIconElementName, AtomConstants.AtomNamespace, AtomUtils.ToUrlAttributeValue(icon, baseUri)); } AtomFeedMetadata source = entryMetadata.Source; if (source != null) { // <atom:source> writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSourceElementName, AtomConstants.AtomNamespace); WriteFeedMetadata(writer, baseUri, source, null); // </atom:source> writer.WriteEndElement(); } } }
/// <summary> /// Writes the syndication part of EPM for an entry into ATOM metadata OM. /// </summary> /// <param name="epmTargetTree">The EPM target tree to use.</param> /// <param name="epmValueCache">The entry properties value cache to use to access the properties.</param> /// <param name="resourceType">The resource type of the entry.</param> /// <param name="metadata">The metadata provider to use.</param> /// <param name="version">The version of OData protocol to use.</param> /// <returns>The ATOM metadata OM with the EPM values populated.</returns> internal static AtomEntryMetadata WriteEntryEpm( EpmTargetTree epmTargetTree, EntryPropertiesValueCache epmValueCache, ResourceType resourceType, DataServiceMetadataProviderWrapper metadata, ODataVersion version) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(epmTargetTree != null, "epmTargetTree != null"); Debug.Assert(epmValueCache != null, "epmValueCache != null"); Debug.Assert(resourceType != null, "For any EPM to exist the metadata must be available."); // If there are no syndication mappings, just return null. EpmTargetPathSegment syndicationRootSegment = epmTargetTree.SyndicationRoot; Debug.Assert(syndicationRootSegment != null, "EPM Target tree must always have syndication root."); if (syndicationRootSegment.SubSegments.Count == 0) { return null; } AtomEntryMetadata entryMetadata = new AtomEntryMetadata(); foreach (EpmTargetPathSegment targetSegment in syndicationRootSegment.SubSegments) { if (targetSegment.IsMultiValueProperty) { Debug.Assert( targetSegment.EpmInfo != null && targetSegment.EpmInfo.Attribute != null, "MultiValue property target segment must have EpmInfo and the Epm Attribute."); ODataVersionChecker.CheckMultiValueProperties(version, targetSegment.EpmInfo.Attribute.SourcePath); // WriteMultiValueEpm(entry, targetSegment, epmValueCache); throw new NotImplementedException(); } else if (targetSegment.HasContent) { EntityPropertyMappingInfo epmInfo = targetSegment.EpmInfo; Debug.Assert( epmInfo != null && epmInfo.Attribute != null, "If the segment has content it must have EpmInfo which in turn must have the Epm attribute"); bool nullOnParentProperty; object propertyValue = epmInfo.ReadEntryPropertyValue(epmValueCache, resourceType, metadata, out nullOnParentProperty); string textPropertyValue = EpmWriterUtils.GetPropertyValueAsText(propertyValue); switch (epmInfo.Attribute.TargetSyndicationItem) { case SyndicationItemProperty.Updated: entryMetadata.Updated = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Updated, version); break; case SyndicationItemProperty.Published: entryMetadata.Published = CreateDateTimeValue(propertyValue, SyndicationItemProperty.Published, version); break; case SyndicationItemProperty.Rights: entryMetadata.Rights = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Summary: entryMetadata.Summary = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; case SyndicationItemProperty.Title: entryMetadata.Title = CreateAtomTextConstruct(textPropertyValue, epmInfo.Attribute.TargetTextContentKind, version); break; default: throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_ContentTarget)); } } else if (targetSegment.SegmentName == AtomConstants.AtomAuthorElementName) { AtomPersonMetadata authorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Authors == null, "Found two mappings to author, that is invalid."); if (authorMetadata != null) { entryMetadata.Authors = CreateSinglePersonList(authorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomContributorElementName) { AtomPersonMetadata contributorMetadata = WritePersonEpm(targetSegment, epmValueCache, resourceType, metadata); Debug.Assert(entryMetadata.Contributors == null, "Found two mappings to contributor, that is invalid."); if (contributorMetadata != null) { entryMetadata.Contributors = CreateSinglePersonList(contributorMetadata); } } else if (targetSegment.SegmentName == AtomConstants.AtomLinkElementName) { AtomLinkMetadata linkMetadata = new AtomLinkMetadata(); //// WriteLinkEpm(entry, targetSegment, epmValueCache); Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to link must be conditional."); linkMetadata.Relation = targetSegment.CriteriaValue; List<AtomLinkMetadata> links; if (entryMetadata.Links == null) { links = new List<AtomLinkMetadata>(); entryMetadata.Links = links; } else { links = entryMetadata.Links as List<AtomLinkMetadata>; Debug.Assert(links != null, "AtomEntryMetadata.Links must be of type List<AtomLinkMetadata> since we create it like that."); } links.Add(linkMetadata); throw new NotImplementedException(); } else if (targetSegment.SegmentName == AtomConstants.AtomCategoryElementName) { AtomCategoryMetadata categoryMetadata = new AtomCategoryMetadata(); //// WriteCategoryEpm(entry, targetSegment, epmValueCache) Debug.Assert(targetSegment.CriteriaValue != null, "Mapping to category must be conditional."); categoryMetadata.Scheme = targetSegment.CriteriaValue; List<AtomCategoryMetadata> categories; if (entryMetadata.Categories == null) { categories = new List<AtomCategoryMetadata>(); entryMetadata.Categories = categories; } else { categories = entryMetadata.Links as List<AtomCategoryMetadata>; Debug.Assert(categories != null, "AtomEntryMetadata.Categories must be of type List<AtomCategoryMetadata> since we create it like that."); } categories.Add(categoryMetadata); throw new NotImplementedException(); } else { throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WriteEntryEpm_TargetSegment)); } } return entryMetadata; }
/// <summary> /// Write the ATOM metadata for an entry /// </summary> /// <param name="writer">The Xml writer to write to.</param> /// <param name="baseUri">The base Uri of the document or null if none was specified.</param> /// <param name="entry">The entry for which to write the metadata.</param> /// <param name="epmEntryMetadata">The ATOM metadata for the entry which came from EPM.</param> internal static void WriteEntryMetadata(XmlWriter writer, Uri baseUri, ODataEntry entry, AtomEntryMetadata epmEntryMetadata) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(writer != null, "writer != null"); // TODO, ckerer: implement the rule around authors (an entry has to have an author directly or in the <entry:source> unless the feed has an author). // currently we make all entries have an author. AtomEntryMetadata customEntryMetadata = entry.GetAnnotation <AtomEntryMetadata>(); AtomEntryMetadata entryMetadata = ODataAtomWriterMetadataEpmMergeUtils.MergeCustomAndEpmEntryMetadata(customEntryMetadata, epmEntryMetadata); if (entryMetadata == null) { // write all required metadata elements with default content // <atom:title></atom:title> ODataAtomWriterUtils.WriteEmptyElement(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace); // <atom:updated>dateTimeOffset</atom:updated> // NOTE: the <updated> element is required and if not specified the best we can do is to create a default // one with the current date/time. ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(DateTimeOffset.UtcNow)); WriteEmptyAuthor(writer); } else { // <atom:title>text</atom:title> // NOTE: writes an empty element even if no title was specified since the title is required ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, entryMetadata.Title); AtomTextConstruct summary = entryMetadata.Summary; if (summary != null) { // <atom:summary>text</atom:summary> ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSummaryElementName, AtomConstants.AtomNamespace, summary); } DateTimeOffset?published = entryMetadata.Published; if (published.HasValue) { // <atom:published>dateTimeOffset</atom:published> ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPublishedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(published.Value)); } // <atom:updated>date</atom:updated> // NOTE: the <updated> element is required and if not specified the best we can do is to create a default // one with the current date/time. DateTimeOffset updated = entryMetadata.Updated.HasValue ? entryMetadata.Updated.Value : DateTimeOffset.UtcNow; ODataAtomWriterUtils.WriteElementWithTextContent( writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(updated)); bool wroteAuthor = false; IEnumerable <AtomPersonMetadata> authors = entryMetadata.Authors; if (authors != null) { foreach (AtomPersonMetadata author in authors) { if (author == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_AuthorMetadataMustNotContainNull); } // <atom:author>author data</atom:author> writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace); WritePersonMetadata(writer, baseUri, author); writer.WriteEndElement(); wroteAuthor = true; } } if (!wroteAuthor) { // write empty authors since they are required WriteEmptyAuthor(writer); } IEnumerable <AtomPersonMetadata> contributors = entryMetadata.Contributors; if (contributors != null) { foreach (AtomPersonMetadata contributor in contributors) { if (contributor == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_ContributorMetadataMustNotContainNull); } // <atom:contributor>contributor data</atom:contributor> writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace); WritePersonMetadata(writer, baseUri, contributor); writer.WriteEndElement(); } } IEnumerable <AtomLinkMetadata> links = entryMetadata.Links; if (links != null) { foreach (AtomLinkMetadata link in links) { if (link == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_LinkMetadataMustNotContainNull); } // <atom:link>...</atom:link> WriteAtomLinkMetadata(writer, baseUri, link); } } IEnumerable <AtomCategoryMetadata> categories = entryMetadata.Categories; if (categories != null) { foreach (AtomCategoryMetadata category in categories) { if (category == null) { throw new ODataException(Strings.ODataAtomWriterMetadataUtils_CategoryMetadataMustNotContainNull); } // <atom:category term="..." scheme="..." label="..."></atom:category> WriteCategory(writer, category); } } if (entryMetadata.Rights != null) { // <atom:rights>rights</atom:rights> ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomRightsElementName, AtomConstants.AtomNamespace, entryMetadata.Rights); } Uri icon = entryMetadata.Icon; if (icon != null) { // <atom:icon>Uri</atom:icon> ODataAtomWriterUtils.WriteElementWithTextContent( writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomIconElementName, AtomConstants.AtomNamespace, AtomUtils.ToUrlAttributeValue(icon, baseUri)); } AtomFeedMetadata source = entryMetadata.Source; if (source != null) { // <atom:source> writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSourceElementName, AtomConstants.AtomNamespace); WriteFeedMetadata(writer, baseUri, source, null); // </atom:source> writer.WriteEndElement(); } } }
private static void AddEntryMetadata(EntityInstance payloadElement, ODataEntry entry) { AtomEntryMetadata metadata = null; foreach (XmlTreeAnnotation epmTree in payloadElement.Annotations.OfType <XmlTreeAnnotation>()) { if (epmTree.NamespaceName == TestAtomConstants.AtomNamespace) { if (metadata == null) { metadata = new AtomEntryMetadata(); } string localName = epmTree.LocalName; if (localName == TestAtomConstants.AtomAuthorElementName) { Debug.Assert(!epmTree.IsAttribute); AtomPersonMetadata author = CreateAuthorMetadata(epmTree.Children); List <AtomPersonMetadata> authors; if (metadata.Authors == null) { authors = new List <AtomPersonMetadata>(); metadata.Authors = authors; } else { authors = (List <AtomPersonMetadata>)metadata.Authors; } authors.Add(author); } else if (localName == TestAtomConstants.AtomCategoryElementName) { Debug.Assert(!epmTree.IsAttribute); AtomCategoryMetadata category = CreateCategoryMetadata(epmTree.Children); List <AtomCategoryMetadata> categories; if (metadata.Categories == null) { categories = new List <AtomCategoryMetadata>(); metadata.Categories = categories; } else { categories = (List <AtomCategoryMetadata>)metadata.Categories; } categories.Add(category); } else if (localName == TestAtomConstants.AtomContributorElementName) { Debug.Assert(!epmTree.IsAttribute); AtomPersonMetadata contributor = CreateAuthorMetadata(epmTree.Children); List <AtomPersonMetadata> contributors; if (metadata.Contributors == null) { contributors = new List <AtomPersonMetadata>(); metadata.Contributors = contributors; } else { contributors = (List <AtomPersonMetadata>)metadata.Contributors; } contributors.Add(contributor); } else if (localName == TestAtomConstants.AtomIdElementName) { Debug.Assert(!epmTree.IsAttribute); entry.Id = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomLinkElementName) { Debug.Assert(!epmTree.IsAttribute); AtomLinkMetadata link = CreateLinkMetadata(epmTree.Children); List <AtomLinkMetadata> links; if (metadata.Links == null) { links = new List <AtomLinkMetadata>(); metadata.Links = links; } else { links = (List <AtomLinkMetadata>)metadata.Links; } links.Add(link); } else if (localName == TestAtomConstants.AtomPublishedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Published = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else if (localName == TestAtomConstants.AtomRightsElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Rights = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomSourceElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Source = CreateFeedMetadata(epmTree.Children, null); } else if (localName == TestAtomConstants.AtomSummaryElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Summary = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomTitleElementName) { Debug.Assert(!epmTree.IsAttribute); AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children); metadata.Title = new AtomTextConstruct { Kind = atomConstructKind, Text = epmTree.PropertyValue }; } else if (localName == TestAtomConstants.AtomUpdatedElementName) { Debug.Assert(!epmTree.IsAttribute); metadata.Updated = string.IsNullOrEmpty(epmTree.PropertyValue) ? (DateTimeOffset?)null : DateTimeOffset.Parse(epmTree.PropertyValue); } else { throw new NotSupportedException("Unsupported atom metadata '" + localName + "' found for entry!"); } } } // Fix up metadata for baselining metadata = metadata.Fixup(); if (metadata != null) { entry.SetAnnotation <AtomEntryMetadata>(metadata); } }