/// <summary>
        /// Adds a new contributor to feed metadata.
        /// </summary>
        /// <param name="feedMetadata">The feed metadata to add the contributor to.</param>
        /// <param name="contributorMetadata">The author metadata to add.</param>
        internal static void AddContributor(this AtomFeedMetadata feedMetadata, AtomPersonMetadata contributorMetadata)
        {
            Debug.Assert(feedMetadata != null, "feedMetadata != null");
            Debug.Assert(contributorMetadata != null, "contributorMetadata != null");

            feedMetadata.Contributors = feedMetadata.Contributors.ConcatToReadOnlyEnumerable("Contributors", contributorMetadata);
        }
        /// <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);
        }
Пример #3
0
        private static AtomPersonMetadata CreateAuthorMetadata(IEnumerable <XmlTreeAnnotation> children)
        {
            AtomPersonMetadata metadata = null;

            foreach (XmlTreeAnnotation epmTree in children)
            {
                if (epmTree.NamespaceName == TestAtomConstants.AtomNamespace)
                {
                    if (metadata == null)
                    {
                        metadata = new AtomPersonMetadata();
                    }

                    string localName = epmTree.LocalName;
                    if (localName == TestAtomConstants.AtomPersonNameElementName)
                    {
                        Debug.Assert(!epmTree.IsAttribute);
                        metadata.Name = epmTree.PropertyValue;
                    }
                    else if (localName == TestAtomConstants.AtomPersonUriElementName)
                    {
                        Debug.Assert(!epmTree.IsAttribute);
                        metadata.Uri = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue);
                    }
                    else if (localName == TestAtomConstants.AtomPersonEmailElementName)
                    {
                        Debug.Assert(!epmTree.IsAttribute);
                        metadata.Email = epmTree.PropertyValue;
                    }
                }
            }

            return(metadata);
        }
Пример #4
0
        /// <summary>
        /// Creates a list of ATOM person metadata with a single item.
        /// </summary>
        /// <param name="person">The person metadata to include.</param>
        /// <returns>The list of ATOM person metadata.</returns>
        private static List <AtomPersonMetadata> CreateSinglePersonList(AtomPersonMetadata person)
        {
            List <AtomPersonMetadata> personList = new List <AtomPersonMetadata>();

            personList.Add(person);
            return(personList);
        }
        /// <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 author to feed metadata.
        /// </summary>
        /// <param name="feedMetadata">The feed metadata to add the author to.</param>
        /// <param name="authorMetadata">The author metadata to add.</param>
        internal static void AddAuthor(this AtomFeedMetadata feedMetadata, AtomPersonMetadata authorMetadata)
        {
            Debug.Assert(feedMetadata != null, "feedMetadata != null");
            Debug.Assert(authorMetadata != null, "authorMetadata != null");

            feedMetadata.Authors = feedMetadata.Authors.ConcatToReadOnlyEnumerable("Authors", authorMetadata);
        }
Пример #7
0
 internal static void AddAuthorToFeedMetadata(AtomFeedMetadata feedMetadata, AtomPersonMetadata authorMetadata)
 {
     if (object.ReferenceEquals(feedMetadata.Authors, EmptyPersonsList))
     {
         feedMetadata.Authors = new ReadOnlyEnumerable <AtomPersonMetadata>();
     }
     ReaderUtils.GetSourceListOfEnumerable <AtomPersonMetadata>(feedMetadata.Authors, "Authors").Add(authorMetadata);
 }
        /// <summary>
        /// Adds a new author to feed metadata.
        /// </summary>
        /// <param name="feedMetadata">The feed metadata to add the author to.</param>
        /// <param name="authorMetadata">The author metadata to add.</param>
        internal static void AddAuthorToFeedMetadata(AtomFeedMetadata feedMetadata, AtomPersonMetadata authorMetadata)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(feedMetadata != null, "feedMetadata != null");
            Debug.Assert(authorMetadata != null, "authorMetadata != null");

            if (object.ReferenceEquals(feedMetadata.Authors, EmptyPersonsList))
            {
                feedMetadata.Authors = new ReadOnlyEnumerable <AtomPersonMetadata>();
            }

            ReaderUtils.GetSourceListOfEnumerable(feedMetadata.Authors, "Authors").Add(authorMetadata);
        }
        /// <summary>
        /// Writes the specified start/end tags and the specified person metadata as content
        /// </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="personMetadata">The person metadata to write.</param>
        internal static void WritePersonMetadata(XmlWriter writer, Uri baseUri, AtomPersonMetadata personMetadata)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(personMetadata != null, "Person metadata must not be null.");

            // <atom:name>name of person</atom:name>
            // NOTE: write an empty element if no name is specified because the element is required.
            ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPersonNameElementName, AtomConstants.AtomNamespace, personMetadata.Name);

            string uriString = personMetadata.UriFromEpm;

            if (uriString != null)
            {
                Debug.Assert(
                    personMetadata.Uri == null,
                    "If the internal UriFromEpm was used, then the Uri property must be left null. The merge between custom and EPM is probably wrong.");
            }
            else
            {
                Uri uri = personMetadata.Uri;
                if (uri != null)
                {
                    uriString = AtomUtils.ToUrlAttributeValue(uri, baseUri);
                }
            }

            if (uriString != null)
            {
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomPersonUriElementName,
                    AtomConstants.AtomNamespace,
                    uriString);
            }

            string email = personMetadata.Email;

            if (email != null)
            {
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomPersonEmailElementName,
                    AtomConstants.AtomNamespace,
                    email);
            }
        }
Пример #10
0
 /// <summary>
 /// Creates a list of ATOM person metadata with a single item.
 /// </summary>
 /// <param name="person">The person metadata to include.</param>
 /// <returns>The list of ATOM person metadata.</returns>
 private static List<AtomPersonMetadata> CreateSinglePersonList(AtomPersonMetadata person)
 {
     List<AtomPersonMetadata> personList = new List<AtomPersonMetadata>();
     personList.Add(person);
     return personList;
 }
Пример #11
0
        /// <summary>
        /// Writes EPM value to a person construct (author or contributor).
        /// </summary>
        /// <param name="targetSegment">The target segment which points to either author or contributor element.</param>
        /// <param name="epmValueCache">The EPM value cache to use to get property values.</param>
        /// <param name="resourceType">The resource type of the entry being processed.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <returns>The person metadata or null if no person metadata should be written for this mapping.</returns>
        private static AtomPersonMetadata WritePersonEpm(
            EpmTargetPathSegment targetSegment,
            EntryPropertiesValueCache epmValueCache,
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata)
        {
            Debug.Assert(targetSegment != null, "targetSegment != null");
            Debug.Assert(
                targetSegment.SegmentName == AtomConstants.AtomAuthorElementName || targetSegment.SegmentName == AtomConstants.AtomContributorElementName,
                "targetSegment must be author or contributor.");

            AtomPersonMetadata personMetadata = null;

            foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments)
            {
                Debug.Assert(subSegment.HasContent, "sub segment of author segment must have content, there are no subsegments which don't have content under author.");
                string textPropertyValue = GetEntryPropertyValueAsText(subSegment, epmValueCache, resourceType, metadata);

                if (textPropertyValue == null)
                {
                    // TODO: In Multi-Values or in V3 mapping nulls to author/contributor subelements is not legal since there's no way to express it.
                    // author/contributor subelements don't allow extension attributes, so we can't add the m:null attribute.
                    continue;
                }

                // Initialize the person element only if we actually need to write something to it.
                if (personMetadata == null)
                {
                    personMetadata = new AtomPersonMetadata();
                }

                Debug.Assert(subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null, "The author subsegment must have EPM info and EPM attribute.");
                switch (subSegment.EpmInfo.Attribute.TargetSyndicationItem)
                {
                case SyndicationItemProperty.AuthorName:
                case SyndicationItemProperty.ContributorName:
                    personMetadata.Name = textPropertyValue;
                    break;

                case SyndicationItemProperty.AuthorEmail:
                case SyndicationItemProperty.ContributorEmail:
                    // TODO: Validate the email value. In V3 or in multi-values the email value must not be null and it must not be empty
                    // since the syndication API doesn't allow empty email values (see below) and it's questionable if ATOM allows it itself.

                    // In case the value is empty the syndication API will actually omit the email element from the payload
                    // we have to simulate that behavior here by not setting the property in that case.
                    if (textPropertyValue.Length > 0)
                    {
                        personMetadata.Email = textPropertyValue;
                    }

                    break;

                case SyndicationItemProperty.AuthorUri:
                case SyndicationItemProperty.ContributorUri:
                    // TODO: Validate the uri value. In V3 or in multi-values the uri value must not be null and it must not be empty
                    // since the syndication API doesn't allow empty uri values (see below) and it's questionable if ATOM allows it itself.

                    // In case the value is empty the syndication API will actually omit the uri element from the payload
                    // we have to simulate that behavior here by not setting the property in that case.
                    if (textPropertyValue.Length > 0)
                    {
                        personMetadata.UriFromEpm = textPropertyValue;
                    }

                    break;

                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WritePersonEpm));
                }
            }

            return(personMetadata);
        }
Пример #12
0
        private static AtomFeedMetadata CreateFeedMetadata(IEnumerable <XmlTreeAnnotation> children, ODataFeed feed)
        {
            AtomFeedMetadata metadata = null;

            foreach (XmlTreeAnnotation epmTree in children)
            {
                if (epmTree.NamespaceName == TestAtomConstants.AtomNamespace)
                {
                    if (metadata == null)
                    {
                        metadata = new AtomFeedMetadata();
                    }

                    string localName = epmTree.LocalName;
                    if (localName == TestAtomConstants.AtomAuthorElementName)
                    {
                        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)
                    {
                        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)
                    {
                        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.AtomGeneratorElementName)
                    {
                        metadata.Generator = CreateGeneratorMetadata(epmTree);
                    }
                    else if (localName == TestAtomConstants.AtomIconElementName)
                    {
                        metadata.Icon = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue);
                    }
                    else if (localName == TestAtomConstants.AtomIdElementName)
                    {
                        Debug.Assert(!epmTree.IsAttribute);
                        Uri id = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue, UriKind.Absolute);
                        if (feed == null)
                        {
                            // we are creating the metadata for an entry's 'source' metadata;
                            // we don't have a feed to store the Id on so it has to go into metadata
                            metadata.SourceId = id;
                        }
                        else
                        {
                            feed.Id = id;
                        }
                    }
                    else if (localName == TestAtomConstants.AtomLinkElementName)
                    {
                        AtomLinkMetadata link = CreateLinkMetadata(epmTree.Children);

                        List <AtomLinkMetadata> links;
                        if (metadata.Links == null)
                        {
                            links          = new List <AtomLinkMetadata>();
                            metadata.Links = links;
                        }
                        else
                        {
                            links = (List <AtomLinkMetadata>)metadata.Contributors;
                        }
                        links.Add(link);
                    }
                    else if (localName == TestAtomConstants.AtomLogoElementName)
                    {
                        metadata.Logo = string.IsNullOrEmpty(epmTree.PropertyValue) ? null : new Uri(epmTree.PropertyValue);
                    }
                    else if (localName == TestAtomConstants.AtomRightsElementName)
                    {
                        AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children);
                        metadata.Rights = new AtomTextConstruct {
                            Kind = atomConstructKind, Text = epmTree.PropertyValue
                        };
                    }
                    else if (localName == TestAtomConstants.AtomSubtitleElementName)
                    {
                        AtomTextConstructKind atomConstructKind = GetAtomConstructKind(epmTree.Children);
                        metadata.Subtitle = new AtomTextConstruct {
                            Kind = atomConstructKind, Text = epmTree.PropertyValue
                        };
                    }
                    else if (localName == TestAtomConstants.AtomTitleElementName)
                    {
                        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 found!");
                    }
                }
            }

            return(metadata);
        }
Пример #13
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);
        }
Пример #14
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);
            }
        }
 /// <summary>
 /// Visits an ATOM person metadata.
 /// </summary>
 /// <param name="atomPersonMetadata">The person metadata to visit.</param>
 protected virtual void VisitAtomPersonMetadata(AtomPersonMetadata atomPersonMetadata)
 {
 }
Пример #16
0
        /// <summary>
        /// Writes EPM value to a person construct (author or contributor).
        /// </summary>
        /// <param name="targetSegment">The target segment which points to either author or contributor element.</param>
        /// <param name="epmValueCache">The EPM value cache to use to get property values.</param>
        /// <param name="resourceType">The resource type of the entry being processed.</param>
        /// <param name="metadata">The metadata provider to use.</param>
        /// <returns>The person metadata or null if no person metadata should be written for this mapping.</returns>
        private static AtomPersonMetadata WritePersonEpm(
            EpmTargetPathSegment targetSegment, 
            EntryPropertiesValueCache epmValueCache, 
            ResourceType resourceType,
            DataServiceMetadataProviderWrapper metadata)
        {
            Debug.Assert(targetSegment != null, "targetSegment != null");
            Debug.Assert(
                targetSegment.SegmentName == AtomConstants.AtomAuthorElementName || targetSegment.SegmentName == AtomConstants.AtomContributorElementName, 
                "targetSegment must be author or contributor.");

            AtomPersonMetadata personMetadata = null;
            foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments)
            {
                Debug.Assert(subSegment.HasContent, "sub segment of author segment must have content, there are no subsegments which don't have content under author.");
                string textPropertyValue = GetEntryPropertyValueAsText(subSegment, epmValueCache, resourceType, metadata);

                if (textPropertyValue == null)
                {
                    // TODO: In Multi-Values or in V3 mapping nulls to author/contributor subelements is not legal since there's no way to express it.
                    // author/contributor subelements don't allow extension attributes, so we can't add the m:null attribute.
                    continue;
                }

                // Initialize the person element only if we actually need to write something to it.
                if (personMetadata == null)
                {
                    personMetadata = new AtomPersonMetadata();
                }

                Debug.Assert(subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null, "The author subsegment must have EPM info and EPM attribute.");
                switch (subSegment.EpmInfo.Attribute.TargetSyndicationItem)
                {
                    case SyndicationItemProperty.AuthorName:
                    case SyndicationItemProperty.ContributorName:
                        personMetadata.Name = textPropertyValue;
                        break;
                    case SyndicationItemProperty.AuthorEmail:
                    case SyndicationItemProperty.ContributorEmail:
                        // TODO: Validate the email value. In V3 or in multi-values the email value must not be null and it must not be empty
                        // since the syndication API doesn't allow empty email values (see below) and it's questionable if ATOM allows it itself.

                        // In case the value is empty the syndication API will actually omit the email element from the payload
                        // we have to simulate that behavior here by not setting the property in that case.
                        if (textPropertyValue.Length > 0)
                        {
                            personMetadata.Email = textPropertyValue;
                        }

                        break;
                    case SyndicationItemProperty.AuthorUri:
                    case SyndicationItemProperty.ContributorUri:
                        // TODO: Validate the uri value. In V3 or in multi-values the uri value must not be null and it must not be empty
                        // since the syndication API doesn't allow empty uri values (see below) and it's questionable if ATOM allows it itself.

                        // In case the value is empty the syndication API will actually omit the uri element from the payload
                        // we have to simulate that behavior here by not setting the property in that case.
                        if (textPropertyValue.Length > 0)
                        {
                            personMetadata.UriFromEpm = textPropertyValue;
                        }

                        break;
                    default:
                        throw new ODataException(Strings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_WritePersonEpm));
                }
            }

            return personMetadata;
        }
Пример #17
0
        public void FeedMetadataWriterTest()
        {
            AtomTextConstruct testRights = new AtomTextConstruct {
                Text = "Copyright Data Fx team."
            };
            AtomTextConstruct testTitle = new AtomTextConstruct {
                Text = "Test title"
            };
            AtomTextConstruct testSubtitle = new AtomTextConstruct {
                Text = "Test subtitle"
            };
            const string testUpdated = "2010-11-01T00:04:00Z";
            const string testIcon    = "http://odata.org/icon";
            const string testLogo    = "http://odata.org/logo";

            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)
                }
            };

            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
                }
            };

            var selfLink = new AtomLinkMetadata()
            {
                Relation  = TestAtomConstants.AtomSelfRelationAttributeValue,
                Title     = testLinkTitle,
                Href      = new Uri(testLinkHref),
                HrefLang  = testLinkHrefLang,
                Length    = testLinkLength,
                MediaType = testLinkMediaType
            };

            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 FeedMetadataTestCase[] {
                new FeedMetadataTestCase { // specify an icon via metadata
                    CustomizeMetadata = metadata => metadata.Icon = new Uri(testIcon),
                    Xml       = @"<icon xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testIcon + @"</icon>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomIconElementName)
                },
                new FeedMetadataTestCase { // specify a logo via metadata
                    CustomizeMetadata = metadata => metadata.Logo = new Uri(testLogo),
                    Xml       = @"<logo xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testLogo + @"</logo>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomLogoElementName)
                },
                new FeedMetadataTestCase { // specify rights via metadata
                    CustomizeMetadata = metadata => metadata.Rights = testRights,
                    Xml       = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName)
                },
                new FeedMetadataTestCase { // specify a subtitle via metadata
                    CustomizeMetadata = metadata => metadata.Subtitle = testSubtitle,
                    Xml       = @"<subtitle type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSubtitle.Text + @"</subtitle>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomSubtitleElementName)
                },
                new FeedMetadataTestCase { // specify a title via metadata
                    CustomizeMetadata = metadata => metadata.Title = testTitle,
                    Xml       = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName)
                },
                new FeedMetadataTestCase { // specify an updated date via metadata
                    CustomizeMetadata = metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated),
                    Xml       = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName)
                },
                new FeedMetadataTestCase { // no author specified, the default author with empty name is written
                    CustomizeMetadata = metadata => metadata.Authors = null,
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name />",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new FeedMetadataTestCase { // specify an author via metadata
                    CustomizeMetadata = 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 FeedMetadataTestCase { // no author specified but some entries written, no author should be written
                    CustomizeMetadata = metadata => metadata.Authors = null,
                    CustomizePayload  = feed => new ODataItem[] { feed, ObjectModelUtils.CreateDefaultEntry() },
                    Xml       = "<authors />",
                    Extractor = result => new XElement("authors", fragmentExtractor(TestAtomConstants.AtomAuthorElementName)(result))
                },
                new FeedMetadataTestCase { // specify an author via metadata and some entries (the author should be written anyway)
                    CustomizeMetadata = metadata => metadata.Authors = testAuthors,
                    CustomizePayload  = feed => new ODataItem[] { feed, ObjectModelUtils.CreateDefaultEntry() },
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testAuthorName + @"</name>",
                        @"  <uri>" + testAuthorUri + @"</uri>",
                        @"  <email>" + testAuthorEmail + @"</email>",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new FeedMetadataTestCase { // specify a category via metadata
                    CustomizeMetadata = metadata => metadata.Categories = testCategories,
                    Xml       = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName)
                },
                new FeedMetadataTestCase { // specify a contributor via metadata
                    CustomizeMetadata = 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 FeedMetadataTestCase { // specify a generator via metadata
                    CustomizeMetadata = metadata => metadata.Generator = testGenerator,
                    Xml       = @"<generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testGeneratorName + @"</generator>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomGeneratorElementName)
                },
                new FeedMetadataTestCase { // specify a link via metadata
                    CustomizeMetadata = metadata => metadata.Links = testLinks,
                    Xml       = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""  xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                .Single()
                },
                new FeedMetadataTestCase { // no self link specified
                    CustomizeMetadata = metadata => metadata.SelfLink = null,
                    Xml       = @"<selflink/>",
                    Extractor = (e) => new XElement("selflink",
                                                    e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                                    .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomSelfRelationAttributeValue))
                },
                new FeedMetadataTestCase { // Some self link specified
                    CustomizeMetadata = metadata => metadata.SelfLink = selfLink,
                    Xml       = @"<link rel=""" + TestAtomConstants.AtomSelfRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""  xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomSelfRelationAttributeValue)
                },
                new FeedMetadataTestCase { // Non-self relation
                    CustomizeMetadata = metadata => metadata.SelfLink = new AtomLinkMetadata {
                        Relation = "SelF", Href = new Uri(testLinkHref)
                    },
                    ExpectedException = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "self", "SelF"),
                },
                new FeedMetadataTestCase { // no next link on either OM or metadata specified
                    CustomizeMetadata = metadata => metadata.NextPageLink = null,
                    Xml       = @"<nextlink/>",
                    Extractor = (e) => new XElement("nextlink",
                                                    e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                                    .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue)),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
                new FeedMetadataTestCase { // the next link is only specified on metadata - nothing is written
                    CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata {
                        Relation = "next", Href = new Uri(testLinkHref)
                    },
                    Xml       = @"<nextlink/>",
                    Extractor = (e) => new XElement("nextlink",
                                                    e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                                    .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue)),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
                new FeedMetadataTestCase { // Next link specified only on the OM
                    CustomizeMetadata = metadata => metadata.NextPageLink = null,
                    CustomizePayload  = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); },
                    Xml       = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" href=""" + testLinkHref + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
                new FeedMetadataTestCase { // Next link specified both on OM and on metadata - no conflicts
                    CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata {
                        Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType
                    },
                    CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); },
                    Xml       = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""  xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
                new FeedMetadataTestCase { // Next link specified both on OM and on metadata - no conflicts cause values are identical
                    CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata {
                        Relation = TestAtomConstants.AtomNextRelationAttributeValue, Href = new Uri(testLinkHref), Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType
                    },
                    CustomizePayload = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); },
                    Xml       = @"<link rel=""" + TestAtomConstants.AtomNextRelationAttributeValue + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""  xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                                .SingleOrDefault(l => (string)l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName) == TestAtomConstants.AtomNextRelationAttributeValue),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
                new FeedMetadataTestCase { // Next link specified both on OM and on metadata - conflict on relation
                    CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata {
                        Relation = "Next", Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType
                    },
                    CustomizePayload      = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); },
                    ExpectedException     = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkRelationsMustMatch", "next", "Next"),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
                new FeedMetadataTestCase { // Next link specified both on OM and on metadata - conflict on href
                    CustomizeMetadata = metadata => metadata.NextPageLink = new AtomLinkMetadata {
                        Href = new Uri("http://odata.org/different"), Title = testLinkTitle, HrefLang = testLinkHrefLang, Length = testLinkLength, MediaType = testLinkMediaType
                    },
                    CustomizePayload      = feed => { feed.NextPageLink = new Uri(testLinkHref); return(new ODataItem[] { feed }); },
                    ExpectedException     = ODataExpectedExceptions.ODataException("ODataAtomWriterMetadataUtils_LinkHrefsMustMatch", testLinkHref, "http://odata.org/different"),
                    SkipTestConfiguration = tc => tc.IsRequest
                },
            };

            this.CreateTestDescriptorsAndRunTests(testCases, WriterPayloads.FeedPayloads);
        }
Пример #18
0
        public void EntryMetadataWriterTest()
        {
            const string      testPublished = "2010-10-20T20:10:00Z";
            AtomTextConstruct testRights    = new AtomTextConstruct {
                Text = "Copyright Data Fx team."
            };
            AtomTextConstruct testSummary = new AtomTextConstruct {
                Text = "Test summary."
            };
            AtomTextConstruct testTitle = new AtomTextConstruct {
                Text = "Test title"
            };
            const string      testUpdated  = "2010-11-01T00:04:00Z";
            const string      testIcon     = "http://odata.org/icon";
            const string      testSourceId = "http://odata.org/id/random";
            const string      testLogo     = "http://odata.org/logo";
            AtomTextConstruct testSubtitle = new AtomTextConstruct {
                Text = "Test subtitle."
            };

            const string testAuthorName  = "Test Author 1";
            const string testAuthorEmail = "*****@*****.**";
            const string testAuthorUri   = "http://odata.org/authors/1";

            var testAuthors = new AtomPersonMetadata[]
            {
                new AtomPersonMetadata()
                {
                    Email = testAuthorEmail,
                    Name  = testAuthorName,
                    Uri   = new Uri(testAuthorUri)
                }
            };

            var testAuthors2 = new AtomPersonMetadata[0];

            const string testCategoryTerm   = "Test category 1 term";
            const string testCategoryLabel  = "Test category 1 label";
            const string testCategoryScheme = "http://odata.org/categories/1";

            var testCategories = new AtomCategoryMetadata[]
            {
                new AtomCategoryMetadata()
                {
                    Term   = testCategoryTerm,
                    Label  = testCategoryLabel,
                    Scheme = testCategoryScheme
                }
            };

            const string testContributorName  = "Test Contributor 1";
            const string testContributorEmail = "*****@*****.**";
            const string testContributorUri   = "http://odata.org/contributors/1";

            var testContributors = new AtomPersonMetadata[]
            {
                new AtomPersonMetadata()
                {
                    Email = testContributorEmail,
                    Name  = testContributorName,
                    Uri   = new Uri(testContributorUri)
                }
            };

            const string testGeneratorName    = "Test generator";
            const string testGeneratorUri     = "http://odata.org/generator";
            const string testGeneratorVersion = "3.0";

            var testGenerator = new AtomGeneratorMetadata()
            {
                Name    = testGeneratorName,
                Uri     = new Uri(testGeneratorUri),
                Version = testGeneratorVersion
            };

            const string testLinkRelation  = "http://odata.org/links/1";
            const string testLinkTitle     = "Test link 1";
            const string testLinkHref      = "http://odata.org/links/1";
            const string testLinkHrefLang  = "de-AT";
            int?         testLinkLength    = 999;
            const string testLinkMediaType = "image/png";

            var testLinks = new AtomLinkMetadata[]
            {
                new AtomLinkMetadata()
                {
                    Relation  = testLinkRelation,
                    Title     = testLinkTitle,
                    Href      = new Uri(testLinkHref),
                    HrefLang  = testLinkHrefLang,
                    Length    = testLinkLength,
                    MediaType = testLinkMediaType
                }
            };

            AtomFeedMetadata testSource = new AtomFeedMetadata()
            {
                Authors      = testAuthors,
                Categories   = testCategories,
                Contributors = testContributors,
                Generator    = testGenerator,
                Icon         = new Uri(testIcon),
                SourceId     = new Uri(testSourceId),
                Links        = testLinks,
                Logo         = new Uri(testLogo),
                Rights       = testRights,
                Subtitle     = testSubtitle,
                Title        = testTitle,
                Updated      = DateTimeOffset.Parse(testUpdated)
            };

            Func <string, Func <XElement, XElement> > fragmentExtractor = (localName) => (e) => e.Element(TestAtomConstants.AtomXNamespace + localName);

            // TODO, ckerer: specify an Id via metadata if the entry does not specify one; we first have to decide what rules
            //               we want to apply to merging of metadata and ODataLib OM data.
            var testCases = new[] {
                new { // specify an author via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors),
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testAuthorName + @"</name>",
                        @"  <uri>" + testAuthorUri + @"</uri>",
                        @"  <email>" + testAuthorEmail + @"</email>",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new { // specify an empty author array via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = testAuthors2),
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name />",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new { // specify no authors via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Authors = null),
                    Xml = string.Join(
                        "$(NL)",
                        @"<author xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"$(Indent)<name />",
                        @"</author>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomAuthorElementName)
                },
                new { // specify a category via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Categories = testCategories),
                    Xml       = @"<category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" xmlns=""" + TestAtomConstants.AtomNamespace + @""" />",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomCategoryElementName)
                },
                new { // specify a contributor via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Contributors = testContributors),
                    Xml = string.Join(
                        "$(NL)",
                        @"<contributor xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <name>" + testContributorName + @"</name>",
                        @"  <uri>" + testContributorUri + @"</uri>",
                        @"  <email>" + testContributorEmail + @"</email>",
                        @"</contributor>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomContributorElementName)
                },
                new { // specify a link via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Links = testLinks),
                    Xml       = @"<link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""  xmlns=""" + TestAtomConstants.AtomNamespace + @"""/>",
                    Extractor = new Func <XElement, XElement>(
                        (e) => e.Elements(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomLinkElementName)
                        .Where(l => l.Attribute(TestAtomConstants.AtomLinkRelationAttributeName).Value != TestAtomConstants.AtomSelfRelationAttributeValue)
                        .Single())
                },
                new { // specify a published date via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Published = DateTimeOffset.Parse(testPublished)),
                    Xml       = @"<published xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testPublished + @"</published>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomPublishedElementName)
                },
                new { // specify rights via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Rights = testRights),
                    Xml       = @"<rights type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testRights.Text + @"</rights>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomRightsElementName)
                },
                new { // specify a source via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = testSource),
                    Xml = string.Join(
                        "$(NL)",
                        @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <id>" + testSourceId + "</id>",
                        @"  <title type=""text"">" + testTitle.Text + @"</title>",
                        @"  <subtitle type=""text"">" + testSubtitle.Text + @"</subtitle>",
                        @"  <updated>" + testUpdated + @"</updated>",
                        @"  <link rel=""" + testLinkRelation + @""" type = """ + testLinkMediaType + @""" title=""" + testLinkTitle + @""" href=""" + testLinkHref + @""" hreflang=""" + testLinkHrefLang + @""" length=""" + testLinkLength + @"""/>",
                        @"  <category term=""" + testCategoryTerm + @""" scheme=""" + testCategoryScheme + @""" label=""" + testCategoryLabel + @""" />",
                        @"  <logo>" + testLogo + @"</logo>",
                        @"  <rights type=""text"">" + testRights.Text + @"</rights>",
                        @"  <contributor>",
                        @"    <name>" + testContributorName + @"</name>",
                        @"    <uri>" + testContributorUri + @"</uri>",
                        @"    <email>" + testContributorEmail + @"</email>",
                        @"  </contributor>",
                        @"  <generator uri=""" + testGeneratorUri + @""" version=""" + testGeneratorVersion + @""">" + testGeneratorName + @"</generator>",
                        @"  <icon>" + testIcon + @"</icon>",
                        @"  <author>",
                        @"    <name>" + testAuthorName + @"</name>",
                        @"    <uri>" + testAuthorUri + @"</uri>",
                        @"    <email>" + testAuthorEmail + @"</email>",
                        @"  </author>",
                        @"</source>"),
                    Extractor = fragmentExtractor(TestAtomConstants.AtomSourceElementName)
                },
                new { // specify default feed metadata as source
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Source = new AtomFeedMetadata()),
                    Xml = string.Join(
                        "$(NL)",
                        @"<source xmlns=""" + TestAtomConstants.AtomNamespace + @""">",
                        @"  <id />",
                        @"  <title />",
                        @"  <updated />",
                        @"</source>"),
                    Extractor = new Func <XElement, XElement>(result => {
                        var source = fragmentExtractor(TestAtomConstants.AtomSourceElementName)(result);
                        // Remove the value of updates as it can't be reliably predicted
                        source.Element(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomUpdatedElementName).Nodes().Remove();
                        return(source);
                    })
                },
                new { // specify a summary via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Summary = testSummary),
                    Xml       = @"<summary type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testSummary.Text + @"</summary>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomSummaryElementName)
                },
                new { // specify a title via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Title = testTitle),
                    Xml       = @"<title type=""text"" xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testTitle.Text + @"</title>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomTitleElementName)
                },
                new { // specify an updated date via metadata
                    CustomizeMetadata = new Action <AtomEntryMetadata>(metadata => metadata.Updated = DateTimeOffset.Parse(testUpdated)),
                    Xml       = @"<updated xmlns=""" + TestAtomConstants.AtomNamespace + @""">" + testUpdated + @"</updated>",
                    Extractor = fragmentExtractor(TestAtomConstants.AtomUpdatedElementName)
                },
            };

            // Convert test cases to test descriptions
            IEnumerable <Func <ODataEntry> > entryCreators = new Func <ODataEntry>[]
            {
                () => ObjectModelUtils.CreateDefaultEntry(),
                () => ObjectModelUtils.CreateDefaultEntryWithAtomMetadata(),
            };
            var testDescriptors = testCases.SelectMany(testCase =>
                                                       entryCreators.Select(entryCreator =>
            {
                ODataEntry entry           = entryCreator();
                AtomEntryMetadata metadata = entry.Atom();
                this.Assert.IsNotNull(metadata, "Expected default entry metadata on a default entry.");
                testCase.CustomizeMetadata(metadata);
                return(new PayloadWriterTestDescriptor <ODataItem>(this.Settings, entry, testConfiguration =>
                                                                   new AtomWriterTestExpectedResults(this.Settings.ExpectedResultSettings)
                {
                    Xml = testCase.Xml, FragmentExtractor = testCase.Extractor
                }));
            }));

            this.CombinatorialEngineProvider.RunCombinations(
                testDescriptors.PayloadCases(WriterPayloads.EntryPayloads),
                this.WriterTestConfigurationProvider.AtomFormatConfigurations,
                (testDescriptor, testConfiguration) =>
            {
                testConfiguration = testConfiguration.Clone();
                testConfiguration.MessageWriterSettings.SetServiceDocumentUri(ServiceDocumentUri);

                TestWriterUtils.WriteAndVerifyODataPayload(testDescriptor, testConfiguration, this.Assert, this.Logger);
            });
        }
        /// <summary>
        /// Writes the specified start/end tags and the specified person metadata as content
        /// </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="personMetadata">The person metadata to write.</param>
        internal static void WritePersonMetadata(XmlWriter writer, Uri baseUri, AtomPersonMetadata personMetadata)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(personMetadata != null, "Person metadata must not be null.");

            // <atom:name>name of person</atom:name>
            // NOTE: write an empty element if no name is specified because the element is required.
            ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomPersonNameElementName, AtomConstants.AtomNamespace, personMetadata.Name);

            string uriString = personMetadata.UriFromEpm;
            if (uriString != null)
            {
                Debug.Assert(
                    personMetadata.Uri == null,
                    "If the internal UriFromEpm was used, then the Uri property must be left null. The merge between custom and EPM is probably wrong.");
            }
            else
            {
                Uri uri = personMetadata.Uri;
                if (uri != null)
                {
                    uriString = AtomUtils.ToUrlAttributeValue(uri, baseUri);
                }
            }

            if (uriString != null)
            {
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomPersonUriElementName,
                    AtomConstants.AtomNamespace,
                    uriString);
            }

            string email = personMetadata.Email;
            if (email != null)
            {
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer, 
                    AtomConstants.AtomNamespacePrefix, 
                    AtomConstants.AtomPersonEmailElementName, 
                    AtomConstants.AtomNamespace, 
                    email);
            }
        }
Пример #20
0
 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);
 }
        /// <summary>
        /// Visits an ATOM metadata object.
        /// </summary>
        /// <param name="atomMetadata"></param>
        protected virtual void VisitAtomMetadata(object atomMetadata)
        {
            if (atomMetadata == null)
            {
                return;
            }

            AtomCategoryMetadata atomCategoryMetadata = atomMetadata as AtomCategoryMetadata;

            if (atomCategoryMetadata != null)
            {
                this.VisitAtomCategoryMetadata(atomCategoryMetadata);
                return;
            }

            AtomEntryMetadata atomEntryMetadata = atomMetadata as AtomEntryMetadata;

            if (atomEntryMetadata != null)
            {
                this.VisitAtomEntryMetadata(atomEntryMetadata);
                return;
            }

            AtomFeedMetadata atomFeedMetadata = atomMetadata as AtomFeedMetadata;

            if (atomFeedMetadata != null)
            {
                this.VisitAtomFeedMetadata(atomFeedMetadata);
                return;
            }

            AtomGeneratorMetadata atomGeneratorMetadata = atomMetadata as AtomGeneratorMetadata;

            if (atomGeneratorMetadata != null)
            {
                this.VisitAtomGeneratorMetadata(atomGeneratorMetadata);
                return;
            }

            AtomLinkMetadata atomLinkMetadata = atomMetadata as AtomLinkMetadata;

            if (atomLinkMetadata != null)
            {
                this.VisitAtomLinkMetadata(atomLinkMetadata);
                return;
            }

            AtomPersonMetadata atomPersonMetadata = atomMetadata as AtomPersonMetadata;

            if (atomPersonMetadata != null)
            {
                this.VisitAtomPersonMetadata(atomPersonMetadata);
                return;
            }

            AtomResourceCollectionMetadata atomResourceCollectionMetadata = atomMetadata as AtomResourceCollectionMetadata;

            if (atomResourceCollectionMetadata != null)
            {
                this.VisitAtomResourceCollectionMetadata(atomResourceCollectionMetadata);
                return;
            }

            AtomStreamReferenceMetadata atomStreamReferenceMetadata = atomMetadata as AtomStreamReferenceMetadata;

            if (atomStreamReferenceMetadata != null)
            {
                this.VisitAtomStreamReferenceMetadata(atomStreamReferenceMetadata);
                return;
            }

            AtomTextConstruct atomTextConstruct = atomMetadata as AtomTextConstruct;

            if (atomTextConstruct != null)
            {
                this.VisitAtomTextConstruct(atomTextConstruct);
                return;
            }

            AtomWorkspaceMetadata atomWorkspaceMetadata = atomMetadata as AtomWorkspaceMetadata;

            if (atomWorkspaceMetadata != null)
            {
                this.VisitAtomWorkspaceMetadata(atomWorkspaceMetadata);
                return;
            }

            AtomCategoriesMetadata atomCategoriesMetadata = atomMetadata as AtomCategoriesMetadata;

            if (atomCategoriesMetadata != null)
            {
                this.VisitAtomCategoriesMetadata(atomCategoriesMetadata);
                return;
            }

            ExceptionUtilities.Assert(false, "Unrecognized ATOM metadata object {0} of type {1}.", atomMetadata.ToString(), atomMetadata.GetType().ToString());
        }
        /// <summary>
        /// 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);
        }
Пример #23
0
 /// <summary>
 /// Visits an ATOM person metadata.
 /// </summary>
 /// <param name="atomPersonMetadata">The person metadata to visit.</param>
 protected override void VisitAtomPersonMetadata(AtomPersonMetadata atomPersonMetadata)
 {
     this.ValidateUri(atomPersonMetadata.Uri);
     base.VisitAtomPersonMetadata(atomPersonMetadata);
 }