/// <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);
        }
Example #6
0
        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)
                };
            }
        }
Example #8
0
        /// <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);
 }
Example #12
0
 /// <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);
        }
Example #14
0
        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);
 }
Example #21
0
        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);
        }
Example #22
0
        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());
        }
Example #24
0
        /// <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);
            });
        }
Example #27
0
        /// <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();
                }
            }
        }
Example #32
0
        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);
            }
        }