예제 #1
0
 internal ODataAtomReader(ODataAtomInputContext atomInputContext, IEdmEntityType expectedEntityType, bool readingFeed) : base(atomInputContext, expectedEntityType, readingFeed, null)
 {
     this.atomInputContext = atomInputContext;
     this.atomEntryAndFeedDeserializer = new ODataAtomEntryAndFeedDeserializer(atomInputContext);
     if (this.atomInputContext.MessageReaderSettings.ReaderBehavior.EntryXmlCustomizationCallback != null)
     {
         this.atomInputContext.InitializeReaderCustomization();
         this.atomEntryAndFeedDeserializersStack = new Stack<ODataAtomEntryAndFeedDeserializer>();
         this.atomEntryAndFeedDeserializersStack.Push(this.atomEntryAndFeedDeserializer);
     }
 }
예제 #2
0
        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="atomInputContext">The input to read the payload from.</param>
        /// <param name="expectedEntityType">The expected entity type for the entry to be read (in case of entry reader) or entries in the feed to be read (in case of feed reader).</param>
        /// <param name="readingFeed">true if the reader is created for reading a feed; false when it is created for reading an entry.</param>
        internal ODataAtomReader(ODataAtomInputContext atomInputContext, IEdmEntityType expectedEntityType, bool readingFeed)
            : base(atomInputContext, expectedEntityType, readingFeed, null /*listener*/)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(atomInputContext != null, "atomInputContext != null");

            this.atomInputContext = atomInputContext;
            this.atomEntryAndFeedDeserializer = new ODataAtomEntryAndFeedDeserializer(atomInputContext);

            if (this.atomInputContext.MessageReaderSettings.AtomEntryXmlCustomizationCallback != null)
            {
                this.atomInputContext.InitializeReaderCustomization();
                this.atomEntryAndFeedDeserializersStack = new Stack<ODataAtomEntryAndFeedDeserializer>();
                this.atomEntryAndFeedDeserializersStack.Push(this.atomEntryAndFeedDeserializer);
            }
        }
예제 #3
0
 protected override bool ReadAtEntryEndImplementation()
 {
     bool isTopLevel = base.IsTopLevel;
     bool isExpandedLinkContent = base.IsExpandedLinkContent;
     bool emptyInline = base.CurrentEntry == null;
     base.PopScope(ODataReaderState.EntryEnd);
     if (!emptyInline)
     {
         bool flag4 = false;
         if (this.atomInputContext.MessageReaderSettings.ReaderBehavior.EntryXmlCustomizationCallback != null)
         {
             XmlReader objB = this.atomInputContext.PopCustomReader();
             if (!object.ReferenceEquals(this.atomInputContext.XmlReader, objB))
             {
                 flag4 = true;
                 this.atomEntryAndFeedDeserializersStack.Pop();
                 this.atomEntryAndFeedDeserializer = this.atomEntryAndFeedDeserializersStack.Peek();
             }
         }
         if (!flag4)
         {
             this.atomEntryAndFeedDeserializer.ReadEntryEnd();
         }
     }
     bool flag5 = true;
     if (isTopLevel)
     {
         this.atomEntryAndFeedDeserializer.ReadPayloadEnd();
         this.ReplaceScope(ODataReaderState.Completed);
         return false;
     }
     if (isExpandedLinkContent)
     {
         this.atomEntryAndFeedDeserializer.ReadNavigationLinkContentAfterExpansion(emptyInline);
         this.ReplaceScope(ODataReaderState.NavigationLinkEnd);
         return flag5;
     }
     if (this.atomEntryAndFeedDeserializer.ReadFeedContent(this.CurrentFeedState, base.IsExpandedLinkContent))
     {
         this.ReadEntryStart();
         return flag5;
     }
     this.ReplaceScope(ODataReaderState.FeedEnd);
     return flag5;
 }
예제 #4
0
 private void ReadEntryStart()
 {
     ODataEntry entry = ReaderUtils.CreateNewEntry();
     if (this.atomInputContext.MessageReaderSettings.ReaderBehavior.EntryXmlCustomizationCallback != null)
     {
         this.atomEntryAndFeedDeserializer.VerifyEntryStart();
         Uri xmlBaseUri = this.atomInputContext.XmlReader.XmlBaseUri;
         XmlReader objB = this.atomInputContext.MessageReaderSettings.ReaderBehavior.EntryXmlCustomizationCallback(entry, this.atomInputContext.XmlReader, this.atomInputContext.XmlReader.ParentXmlBaseUri);
         if (objB != null)
         {
             if (object.ReferenceEquals(this.atomInputContext.XmlReader, objB))
             {
                 throw new ODataException(Microsoft.Data.OData.Strings.ODataAtomReader_EntryXmlCustomizationCallbackReturnedSameInstance);
             }
             this.atomInputContext.PushCustomReader(objB, xmlBaseUri);
             this.atomEntryAndFeedDeserializer = new ODataAtomEntryAndFeedDeserializer(this.atomInputContext);
             this.atomEntryAndFeedDeserializersStack.Push(this.atomEntryAndFeedDeserializer);
         }
         else
         {
             this.atomInputContext.PushCustomReader(this.atomInputContext.XmlReader, null);
         }
     }
     this.atomEntryAndFeedDeserializer.ReadEntryStart(entry);
     this.EnterScope(ODataReaderState.EntryStart, entry, base.CurrentEntityType);
     AtomScope currentScope = (AtomScope) base.CurrentScope;
     currentScope.DuplicatePropertyNamesChecker = this.atomInputContext.CreateDuplicatePropertyNamesChecker();
     string entityTypeNameFromPayload = this.atomEntryAndFeedDeserializer.FindTypeName();
     base.ApplyEntityTypeNameFromPayload(entityTypeNameFromPayload);
     if (base.CurrentFeedValidator != null)
     {
         base.CurrentFeedValidator.ValidateEntry(base.CurrentEntityType);
     }
     ODataEntityPropertyMappingCache cache = this.atomInputContext.Model.EnsureEpmCache(this.CurrentEntryState.EntityType, 0x7fffffff);
     if (cache != null)
     {
         currentScope.CachedEpm = cache;
     }
     if (this.atomEntryAndFeedDeserializer.XmlReader.IsEmptyElement)
     {
         this.CurrentEntryState.EntryElementEmpty = true;
     }
     else
     {
         this.atomEntryAndFeedDeserializer.XmlReader.Read();
         if (this.atomInputContext.UseServerApiBehavior)
         {
             this.CurrentEntryState.FirstNavigationLinkDescriptor = null;
         }
         else
         {
             this.CurrentEntryState.FirstNavigationLinkDescriptor = this.atomEntryAndFeedDeserializer.ReadEntryContent(this.CurrentEntryState);
         }
     }
 }
예제 #5
0
        /// <summary>
        /// Reads the start of an entry and sets up the reader state correctly.
        /// </summary>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element                    - The method will fail if it's not atom:entry.
        /// Post-Condition: XmlNodeType.Element (empty) atom:entry - The entry element when reading entry and the entry element is empty.
        ///                 XmlNodeType.EndElement atom:entry      - The end element of the entry (if there were no nav. links. in it)
        ///                 XmlNodeType.Element atom:link          - The start tag of the atom:link which represents the first navigation link in the entry.
        /// </remarks>
        private void ReadEntryStart()
        {
            this.atomEntryAndFeedDeserializer.AssertXmlCondition(XmlNodeType.Element);

            ODataEntry entry = ReaderUtils.CreateNewEntry();

            if (this.atomInputContext.MessageReaderSettings.AtomEntryXmlCustomizationCallback != null)
            {
                this.atomEntryAndFeedDeserializer.VerifyEntryStart();

                // Note that we're passing in the buffering reader positioned on the atom:entry element, but that element might have been already buffered
                // although the reader is currently not in buffering mode.
                // We must remember the base URI, since we use it as the starting xml:base for the wrapped buffering reader over the reader returned
                // from the customization callback;
                Uri entryXmlBaseUri = this.atomInputContext.XmlReader.XmlBaseUri;
                this.atomInputContext.XmlReader.AssertNotBuffering();
                XmlReader entryReader = this.atomInputContext.MessageReaderSettings.AtomEntryXmlCustomizationCallback(
                    entry,
                    this.atomInputContext.XmlReader,
                    this.atomInputContext.XmlReader.ParentXmlBaseUri);
                if (entryReader != null)
                {
                    if (object.ReferenceEquals(this.atomInputContext.XmlReader, entryReader))
                    {
                        throw new ODataException(o.Strings.ODataAtomReader_EntryXmlCustomizationCallbackReturnedSameInstance);
                    }

                    // Push the new reader.
                    // We need to use the xml:base from the entry element itself, since the inner reader starts on that element
                    // and thus our wrapping reader will not see that element again and will not read it's xml:base value for the stack.
                    this.atomInputContext.PushCustomReader(entryReader, entryXmlBaseUri);

                    // And push a new deserializer.
                    this.atomEntryAndFeedDeserializer = new ODataAtomEntryAndFeedDeserializer(this.atomInputContext);
                    this.atomEntryAndFeedDeserializersStack.Push(this.atomEntryAndFeedDeserializer);
                }
                else
                {
                    // Push the same reader so that we know that customization didn't happen at this level.
                    this.atomInputContext.PushCustomReader(this.atomInputContext.XmlReader, /*xmlBaseUri*/ null);
                }
            }

            // Read the start of the entry (etag and type name)
            this.atomEntryAndFeedDeserializer.ReadEntryStart(entry);

            // Setup the new entry state
            this.EnterScope(ODataReaderState.EntryStart, entry, this.CurrentEntityType);
            AtomScope entryScope = (AtomScope)this.CurrentScope;
            entryScope.DuplicatePropertyNamesChecker = this.atomInputContext.CreateDuplicatePropertyNamesChecker();

            // Read ahead to detect the type name and use it.
            string typeNameFromPayload = this.atomEntryAndFeedDeserializer.FindTypeName();

            this.ApplyEntityTypeNameFromPayload(typeNameFromPayload);

            // Validate type with feed validator if available
            if (this.CurrentFeedValidator != null)
            {
                this.CurrentFeedValidator.ValidateEntry(this.CurrentEntityType);
            }

            // NOTE: when reading, we assume the model has been validated already and thus pass int.MaxValue for the maxMappingCount.
            ODataEntityPropertyMappingCache cachedEpm = this.atomInputContext.Model.EnsureEpmCache(this.CurrentEntryState.EntityType, /*maxMappingCount*/ int.MaxValue);
            if (cachedEpm != null)
            {
                entryScope.CachedEpm = cachedEpm;
            }

            Debug.Assert(
                this.atomEntryAndFeedDeserializer.XmlReader.NodeType == XmlNodeType.Element &&
                this.atomEntryAndFeedDeserializer.XmlReader.LocalName == AtomConstants.AtomEntryElementName &&
                this.atomEntryAndFeedDeserializer.XmlReader.NamespaceURI == AtomConstants.AtomNamespace,
                "The XML reader must be on the atom:entry element by now.");
            if (this.atomEntryAndFeedDeserializer.XmlReader.IsEmptyElement)
            {
                // If the entry element is empty, remember that so that we can easily decide what to do next time the reader is called.
                this.CurrentEntryState.EntryElementEmpty = true;
            }
            else
            {
                // Move to the first child node of the entry
                this.atomEntryAndFeedDeserializer.XmlReader.Read();

                if (this.atomInputContext.UseServerApiBehavior)
                {
                    this.CurrentEntryState.FirstNavigationLinkDescriptor = null;
                }
                else
                {
                    // Read the entry content.
                    // If we find a nav. link, store it on the scope for reporting once we report the entry itself.
                    this.CurrentEntryState.FirstNavigationLinkDescriptor = this.atomEntryAndFeedDeserializer.ReadEntryContent(this.CurrentEntryState);
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Implementation of the reader logic when in state 'EntryEnd'.
        /// </summary>
        /// <returns>true if more items can be read from the reader; otherwise false.</returns>
        /// <remarks>
        /// Pre-Condition:   XmlNodeType.Element (empty) atom:entry - The empty start tag of atom:entry.
        ///                  XmlNodeType.EndElement atom:entry      - The end element of the atom:entry.
        ///                  XmlNodeType.Element (empty) m:inline   - the empty m:inline element of an expanded null entry.
        ///                  XmlNodeType.EndElement m:inline        - the end element m:inline of an expanded null entry.
        /// Post-Condition:  Any                                    - The node right after the top-level atom:entry element.
        ///                  XmlNodeType.EndElement atom:feed       - The end element of the parent feed for the entry.
        ///                  XmlNodeType.Element (empty) atom:entry - The empty start tag of the next entry in the parent feed.
        ///                  XmlNodeType.EndElement atom:entry      - The end element of the next entry in the parent feed (if it had no nav. links).
        ///                  XmlNodeType.Element atom:link          - The start tag of the atom:link which represents the first navigation link in the next entry in the parent feed.
        ///                  XmlNodeType.EndElement atom:link       - The end of parent expanded link.
        /// </remarks>
        protected override bool ReadAtEntryEndImplementation()
        {
            bool isTopLevel = this.IsTopLevel;
            bool isExpandedLinkContent = this.IsExpandedLinkContent;
            bool isNullEntry = this.CurrentEntry == null;
            this.PopScope(ODataReaderState.EntryEnd);

            Debug.Assert(!isNullEntry || isExpandedLinkContent, "Null entry can only occure inside an expanded link.");

            if (!isNullEntry)
            {
                bool entryXmlCustomizationUsed = false;
                if (this.atomInputContext.MessageReaderSettings.AtomEntryXmlCustomizationCallback != null)
                {
                    XmlReader entryReader = this.atomInputContext.PopCustomReader();
                    if (!object.ReferenceEquals(this.atomInputContext.XmlReader, entryReader))
                    {
                        entryXmlCustomizationUsed = true;

                        // Pop the deserializer so that we use the one for the parent reader from now on.
                        this.atomEntryAndFeedDeserializersStack.Pop();
                        this.atomEntryAndFeedDeserializer = this.atomEntryAndFeedDeserializersStack.Peek();
                    }
                }

                // We assume that if the customization was used, then the parent reader was moved to after the end-element (empty start-element)
                // only if no customization was used we need to read over it here (note that we leave it on the end-element when we report the EndEntry
                // so that streaming scenarios work as expected, that is reading one entry reads just that from the stream and not a byte more).
                if (!entryXmlCustomizationUsed)
                {
                    // Read over the end element (or the empty start element)
                    this.atomEntryAndFeedDeserializer.ReadEntryEnd();
                }
            }

            bool result = true;
            if (isTopLevel)
            {
                Debug.Assert(this.State == ODataReaderState.Start, "this.State == ODataReaderState.Start");

                // Read the end of the payload
                this.atomEntryAndFeedDeserializer.ReadPayloadEnd();

                // replace the 'Start' scope with the 'Completed' scope
                this.ReplaceScope(ODataReaderState.Completed);
                result = false;
            }
            else if (isExpandedLinkContent)
            {
#if DEBUG
                if (isNullEntry)
                {
                    this.atomEntryAndFeedDeserializer.AssertXmlCondition(true, XmlNodeType.EndElement);
                    Debug.Assert(
                        this.atomEntryAndFeedDeserializer.XmlReader.LocalName == AtomConstants.ODataInlineElementName &&
                        this.atomEntryAndFeedDeserializer.XmlReader.NamespaceURI == AtomConstants.ODataMetadataNamespace,
                        "The reader must be positied on the m:inline empty start tag, or end element");
                }
#endif

                this.atomEntryAndFeedDeserializer.ReadNavigationLinkContentAfterExpansion(isNullEntry);

                // replace the 'NavigationLinkStart' scope with the 'NavigationLinkEnd' scope
                Debug.Assert(this.CurrentScope.State == ODataReaderState.NavigationLinkStart, "Should be in NavigationLinkStart state.");
                this.ReplaceScope(ODataReaderState.NavigationLinkEnd);
            }
            else
            {
                // End of entry in a feed
                Debug.Assert(this.State == ODataReaderState.FeedStart, "Expected reader to be in state feed start before reading the next entry.");

                // Continue reading the content of the parent feed
                if (this.atomEntryAndFeedDeserializer.ReadFeedContent(this.CurrentFeedState, this.IsExpandedLinkContent))
                {
                    this.atomEntryAndFeedDeserializer.AssertXmlCondition(XmlNodeType.Element);
                    Debug.Assert(
                        this.atomEntryAndFeedDeserializer.XmlReader.LocalName == AtomConstants.AtomEntryElementName &&
                        this.atomEntryAndFeedDeserializer.XmlReader.NamespaceURI == AtomConstants.AtomNamespace,
                        "The reader must be on the start element of atom:entry.");

                    // Found another entry in the feed
                    this.ReadEntryStart();
                }
                else
                {
                    this.atomEntryAndFeedDeserializer.AssertXmlCondition(XmlNodeType.EndElement);
                    Debug.Assert(
                        this.atomEntryAndFeedDeserializer.XmlReader.LocalName == AtomConstants.AtomFeedElementName &&
                        this.atomEntryAndFeedDeserializer.XmlReader.NamespaceURI == AtomConstants.AtomNamespace,
                        "The reader must be on the end element of atom:feed.");

                    // End of the parent feed
                    this.ReplaceScope(ODataReaderState.FeedEnd);
                }
            }

            return result;
        }