/// <summary>
        /// Writes the ATOM metadata for a single (resource) collection element.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param>
        /// <param name="collection">The collection element to get the metadata for and write it.</param>
        internal static void WriteCollectionMetadata(XmlWriter writer, ODataResourceCollectionInfo collection)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(collection != null, "collection != null");
            Debug.Assert(collection.Name != null, "collection.Name should have been validated at this point");

            // TODO: implement writing the rest of the NYI collection metadata [see AtomPub spec].
            AtomResourceCollectionMetadata metadata = collection.Atom();

            string title = null;

            if (metadata != null)
            {
                title = metadata.Title;
            }

            if (title == null)
            {
                title = collection.Name;
            }

            // <atom:title>title</atom:title>
            ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title);
        }
        /// <summary>
        /// Write the ATOM metadata for a feed
        /// </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="feed">The feed for which to write the metadata.</param>
        internal static void WriteFeedMetadata(XmlWriter writer, Uri baseUri, ODataFeed feed)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(feed != null, "feed != null");

            AtomFeedMetadata feedMetadata = feed.GetAnnotation <AtomFeedMetadata>();

            if (feedMetadata == null)
            {
                // create the required metadata elements with default values.

                // <atom:id>idValue</atom:id>
                Debug.Assert(!string.IsNullOrEmpty(feed.Id), "The feed Id should have been validated by now.");
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomIdElementName,
                    AtomConstants.AtomNamespace,
                    feed.Id);

                // <atom:title></atom:title>
                ODataAtomWriterUtils.WriteEmptyElement(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace);

                // <atom:updated>dateTimeOffset</atom:updated>
                ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomUpdatedElementName, AtomConstants.AtomNamespace, ODataAtomConvert.ToString(DateTimeOffset.UtcNow));
            }
            else
            {
                WriteFeedMetadata(writer, baseUri, feedMetadata, feed);
            }
        }
        /// <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);
            }
        }
        /// <summary>
        /// Writes the ATOM metadata for a single workspace element.
        /// </summary>
        /// <param name="writer">The <see cref="XmlWriter"/> to write to.</param>
        /// <param name="workspace">The workspace element to get the metadata for and write it.</param>
        internal static void WriteWorkspaceMetadata(XmlWriter writer, ODataWorkspace workspace)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(workspace != null, "workspace != null");

            AtomWorkspaceMetadata metadata = workspace.Atom();
            string title = null;

            if (metadata != null)
            {
                title = metadata.Title;
            }

            if (title == null)
            {
                title = AtomConstants.AtomWorkspaceDefaultTitle;
            }

            // <atom:title>title</atom:title>
            ODataAtomWriterUtils.WriteElementWithTextContent(writer, AtomConstants.NonEmptyAtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, title);
        }
        /// <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>
        /// Write the given feed metadata in atom format
        /// </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="feedMetadata">The metadata to write.</param>
        /// <param name="feed">The feed for which to write the meadata or null if it is the metadata of an atom:source element.</param>
        private static void WriteFeedMetadata(XmlWriter writer, Uri baseUri, AtomFeedMetadata feedMetadata, ODataFeed feed)
        {
            Debug.Assert(writer != null, "writer != null");
            Debug.Assert(feedMetadata != null, "Feed metadata must not be null!");

            // <atom:id>text</atom:id>
            // NOTE: this is the Id of the feed. For a regular feed this is stored on the feed itself;
            // if used in the context of an <atom:source> element it is stored in metadata
            Debug.Assert(feed == null || !string.IsNullOrEmpty(feed.Id), "The feed Id should have been validated by now.");
            string id = feed == null ? feedMetadata.SourceId : feed.Id;

            ODataAtomWriterUtils.WriteElementWithTextContent(
                writer,
                AtomConstants.AtomNamespacePrefix,
                AtomConstants.AtomIdElementName,
                AtomConstants.AtomNamespace,
                id);

            // <atom:title>text</atom:title>
            // NOTE: write an empty element if no title is specified since the element is required
            ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomTitleElementName, AtomConstants.AtomNamespace, feedMetadata.Title);

            if (feedMetadata.Subtitle != null)
            {
                // <atom:subtitle>text</atom:subtitle>
                ODataAtomWriterMetadataUtils.WriteTextConstruct(writer, AtomConstants.AtomNamespacePrefix, AtomConstants.AtomSubtitleElementName, AtomConstants.AtomNamespace, feedMetadata.Subtitle);
            }

            // <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 = feedMetadata.Updated.HasValue ? feedMetadata.Updated.Value : DateTimeOffset.UtcNow;

            ODataAtomWriterUtils.WriteElementWithTextContent(
                writer,
                AtomConstants.AtomNamespacePrefix,
                AtomConstants.AtomUpdatedElementName,
                AtomConstants.AtomNamespace,
                ODataAtomConvert.ToString(updated));

            IEnumerable <AtomPersonMetadata> authors = feedMetadata.Authors;

            if (authors != null)
            {
                foreach (AtomPersonMetadata author in authors)
                {
                    // <atom:author>author data</atom:author>
                    writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomAuthorElementName, AtomConstants.AtomNamespace);
                    WritePersonMetadata(writer, baseUri, author);
                    writer.WriteEndElement();
                }
            }

            IEnumerable <AtomLinkMetadata> links = feedMetadata.Links;

            if (links != null)
            {
                foreach (AtomLinkMetadata link in links)
                {
                    // <atom:link>...</atom:link>
                    WriteAtomLinkMetadata(writer, baseUri, link);
                }
            }

            IEnumerable <AtomCategoryMetadata> categories = feedMetadata.Categories;

            if (categories != null)
            {
                foreach (AtomCategoryMetadata category in categories)
                {
                    // <atom:category term="..." scheme="..." label="..."></atom:category>
                    WriteCategory(writer, category);
                }
            }

            Uri logo = feedMetadata.Logo;

            if (logo != null)
            {
                // <atom:logo>Uri</atom:logo>
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomLogoElementName,
                    AtomConstants.AtomNamespace,
                    AtomUtils.ToUrlAttributeValue(logo, baseUri));
            }

            if (feedMetadata.Rights != null)
            {
                // <atom:rights>rights</atom:rights>
                ODataAtomWriterMetadataUtils.WriteTextConstruct(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomRightsElementName,
                    AtomConstants.AtomNamespace,
                    feedMetadata.Rights);
            }

            IEnumerable <AtomPersonMetadata> contributors = feedMetadata.Contributors;

            if (contributors != null)
            {
                foreach (AtomPersonMetadata contributor in contributors)
                {
                    // <atom:contributor>contributor data</atom:contributor>
                    writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomContributorElementName, AtomConstants.AtomNamespace);
                    WritePersonMetadata(writer, baseUri, contributor);
                    writer.WriteEndElement();
                }
            }

            AtomGeneratorMetadata generator = feedMetadata.Generator;

            if (generator != null)
            {
                // <atom:generator uri="..." version="...">name</atom:generator>
                writer.WriteStartElement(AtomConstants.AtomNamespacePrefix, AtomConstants.AtomGeneratorElementName, AtomConstants.AtomNamespace);
                if (generator.Uri != null)
                {
                    writer.WriteAttributeString(AtomConstants.AtomGeneratorUriAttributeName, AtomUtils.ToUrlAttributeValue(generator.Uri, baseUri));
                }

                if (!string.IsNullOrEmpty(generator.Version))
                {
                    writer.WriteAttributeString(AtomConstants.AtomGeneratorVersionAttributeName, generator.Version);
                }

                writer.WriteString(generator.Name);
                writer.WriteEndElement();
            }

            Uri icon = feedMetadata.Icon;

            if (icon != null)
            {
                // <atom:icon>Uri</atom:icon>
                ODataAtomWriterUtils.WriteElementWithTextContent(
                    writer,
                    AtomConstants.AtomNamespacePrefix,
                    AtomConstants.AtomIconElementName,
                    AtomConstants.AtomNamespace,
                    AtomUtils.ToUrlAttributeValue(icon, baseUri));
            }
        }
示例#7
0
        /// <summary>
        /// Finish writing an entry.
        /// </summary>
        /// <param name="entry">The entry to write.</param>
        protected override void EndEntry(ODataEntry entry)
        {
            Debug.Assert(entry != null, "entry != null");

            string       typeName  = entry.TypeName;
            ResourceType entryType = ValidationUtils.ValidateTypeName(this.MetadataProvider, typeName, ResourceTypeKind.EntityType, false);

            // Initialize the property value cache and cache the entry properties.
            EntryPropertiesValueCache propertyValueCache        = new EntryPropertiesValueCache(entry);
            EpmResourceTypeAnnotation epmResourceTypeAnnotation = null;

            if (entryType != null)
            {
                Debug.Assert(entryType.IsReadOnly, "The resource must be read-only to be applied to an entry.");
                entryType.EnsureEpmAvailability();
                epmResourceTypeAnnotation = entryType.Epm();
            }

            // <atom:id>idValue</atom:id>
            // NOTE: do not generate a relative Uri for the ID; it is independent of xml:base
            ODataAtomWriterUtils.WriteElementWithTextContent(
                this.writer,
                AtomConstants.AtomNamespacePrefix,
                AtomConstants.AtomIdElementName,
                AtomConstants.AtomNamespace,
                entry.Id);

            // <category term="type" scheme="odatascheme"/>
            // If no type information is provided, don't include the category element for type at all
            // NOTE: the validation of the type name happened at the beginning of this method.
            if (typeName != null)
            {
                ODataAtomWriterMetadataUtils.WriteCategory(this.writer, typeName, AtomConstants.ODataSchemeNamespace, null);
            }

            Uri editLink = entry.EditLink;

            if (editLink != null)
            {
                // <link rel="edit" title="Title" href="LinkHRef"/>
                ODataAtomWriterUtils.WriteReadOrEditLink(this.writer, this.BaseUri, editLink, AtomConstants.AtomEditRelationAttributeValue, typeName);
            }

            Uri readLink = entry.ReadLink;

            if (readLink != null)
            {
                // <link rel="self" title="Title" href="LinkHRef"/>
                ODataAtomWriterUtils.WriteReadOrEditLink(this.writer, this.BaseUri, readLink, AtomConstants.AtomSelfRelationAttributeValue, typeName);
            }

            // named streams
            IEnumerable <ODataMediaResource> namedStreams = entry.NamedStreams;

            if (namedStreams != null)
            {
                foreach (ODataMediaResource namedStream in namedStreams)
                {
                    ValidationUtils.ValidateNamedStream(namedStream, this.Version);

                    ODataAtomWriterUtils.WriteNamedStream(this.writer, this.BaseUri, namedStream);
                }
            }

            // association links
            IEnumerable <ODataAssociationLink> associationLinks = entry.AssociationLinks;

            if (associationLinks != null)
            {
                foreach (ODataAssociationLink associationLink in associationLinks)
                {
                    ValidationUtils.ValidateAssociationLink(associationLink, this.Version);

                    ODataAtomWriterUtils.WriteAssociationLink(this.writer, this.BaseUri, entry, associationLink);
                }
            }

            // write entry metadata including syndication EPM
            AtomEntryMetadata epmEntryMetadata = null;

            if (epmResourceTypeAnnotation != null)
            {
                ODataVersionChecker.CheckEntityPropertyMapping(this.Version, entryType);

                epmEntryMetadata = EpmSyndicationWriter.WriteEntryEpm(
                    epmResourceTypeAnnotation.EpmTargetTree,
                    propertyValueCache,
                    entryType,
                    this.MetadataProvider,
                    this.Version);
            }

            ODataAtomWriterMetadataUtils.WriteEntryMetadata(this.writer, this.BaseUri, entry, epmEntryMetadata);

            // write the content
            this.WriteEntryContent(entry, entryType, propertyValueCache, epmResourceTypeAnnotation == null ? null : epmResourceTypeAnnotation.EpmSourceTree.Root);

            // write custom EPM
            if (epmResourceTypeAnnotation != null)
            {
                EpmCustomWriter.WriteEntryEpm(
                    this.writer,
                    epmResourceTypeAnnotation.EpmTargetTree,
                    propertyValueCache,
                    entryType,
                    this.MetadataProvider);
            }

            // </entry>
            this.writer.WriteEndElement();
        }