You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by fm...@apache.org on 2013/07/26 13:22:21 UTC

[16/51] [partial] initial commit

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
new file mode 100644
index 0000000..f65938b
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.consumer;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
+import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties.EntityProviderReadPropertiesBuilder;
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+
+/**
+ * Xml entity (content type dependent) consumer for reading input (from <code>content</code>).
+ * 
+ * @author SAP AG
+ */
+public class XmlEntityConsumer {
+
+  /** Default used charset for reader */
+  private static final String DEFAULT_CHARSET = "UTF-8";
+
+  public XmlEntityConsumer() throws EntityProviderException {
+    super();
+  }
+
+  public ODataFeed readFeed(final EdmEntitySet entitySet, final InputStream content, final EntityProviderReadProperties properties) throws EntityProviderException {
+    XMLStreamReader reader = null;
+    EntityProviderException cachedException = null;
+
+    try {
+      reader = createStaxReader(content);
+
+      EntityInfoAggregator eia = EntityInfoAggregator.create(entitySet);
+      XmlFeedConsumer xfc = new XmlFeedConsumer();
+      return xfc.readFeed(reader, eia, properties);
+    } catch (EntityProviderException e) {
+      cachedException = e;
+      throw cachedException;
+    } catch (XMLStreamException e) {
+      cachedException = new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+      throw cachedException;
+    } finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
+      if (reader != null) {
+        try {
+          reader.close();
+        } catch (XMLStreamException e) {
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+          }
+        }
+      }
+    }
+  }
+
+  public ODataEntry readEntry(final EdmEntitySet entitySet, final InputStream content, final EntityProviderReadProperties properties) throws EntityProviderException {
+    XMLStreamReader reader = null;
+    EntityProviderException cachedException = null;
+
+    try {
+      XmlEntryConsumer xec = new XmlEntryConsumer();
+      reader = createStaxReader(content);
+
+      EntityInfoAggregator eia = EntityInfoAggregator.create(entitySet);
+      ODataEntry result = xec.readEntry(reader, eia, properties);
+      return result;
+    } catch (EntityProviderException e) {
+      cachedException = e;
+      throw cachedException;
+    } catch (XMLStreamException e) {
+      cachedException = new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+      throw cachedException;
+    } finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
+      if (reader != null) {
+        try {
+          reader.close();
+        } catch (XMLStreamException e) {
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+          }
+        }
+      }
+    }
+  }
+
+  public Map<String, Object> readProperty(final EdmProperty edmProperty, final InputStream content, final EntityProviderReadProperties properties) throws EntityProviderException {
+    XMLStreamReader reader = null;
+    EntityProviderException cachedException = null;
+    XmlPropertyConsumer xec = new XmlPropertyConsumer();
+
+    try {
+      reader = createStaxReader(content);
+      Map<String, Object> result = xec.readProperty(reader, edmProperty, properties.getMergeSemantic(), properties.getTypeMappings());
+      return result;
+    } catch (XMLStreamException e) {
+      cachedException = new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+      throw cachedException;
+    } finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
+      if (reader != null) {
+        try {
+          reader.close();
+        } catch (XMLStreamException e) {
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+          }
+        }
+      }
+    }
+  }
+
+  public Object readPropertyValue(final EdmProperty edmProperty, final InputStream content) throws EntityProviderException {
+    return readPropertyValue(edmProperty, content, null);
+  }
+
+  public Object readPropertyValue(final EdmProperty edmProperty, final InputStream content, final Class<?> typeMapping) throws EntityProviderException {
+    try {
+      final Map<String, Object> result;
+      EntityProviderReadPropertiesBuilder propertiesBuilder = EntityProviderReadProperties.init().mergeSemantic(false);
+      if (typeMapping == null) {
+        result = readProperty(edmProperty, content, propertiesBuilder.build());
+      } else {
+        Map<String, Object> typeMappings = new HashMap<String, Object>();
+        typeMappings.put(edmProperty.getName(), typeMapping);
+        result = readProperty(edmProperty, content, propertiesBuilder.addTypeMappings(typeMappings).build());
+      }
+      return result.get(edmProperty.getName());
+    } catch (EdmException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  public String readLink(final EdmEntitySet entitySet, final Object content) throws EntityProviderException {
+    XMLStreamReader reader = null;
+    EntityProviderException cachedException = null;
+    XmlLinkConsumer xlc = new XmlLinkConsumer();
+
+    try {
+      reader = createStaxReader(content);
+      return xlc.readLink(reader, entitySet);
+    } catch (XMLStreamException e) {
+      cachedException = new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+      throw cachedException;
+    } finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
+      if (reader != null) {
+        try {
+          reader.close();
+        } catch (XMLStreamException e) {
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+          }
+        }
+      }
+    }
+  }
+
+  public List<String> readLinks(final EdmEntitySet entitySet, final Object content) throws EntityProviderException {
+    XMLStreamReader reader = null;
+    EntityProviderException cachedException = null;
+    XmlLinkConsumer xlc = new XmlLinkConsumer();
+
+    try {
+      reader = createStaxReader(content);
+      return xlc.readLinks(reader, entitySet);
+    } catch (XMLStreamException e) {
+      cachedException = new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+      throw cachedException;
+    } finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
+      if (reader != null) {
+        try {
+          reader.close();
+        } catch (XMLStreamException e) {
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+          }
+        }
+      }
+    }
+  }
+
+  private XMLStreamReader createStaxReader(final Object content) throws XMLStreamException, EntityProviderException {
+    XMLInputFactory factory = XMLInputFactory.newInstance();
+    factory.setProperty(XMLInputFactory.IS_VALIDATING, false);
+    factory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
+
+    if (content == null) {
+      throw new EntityProviderException(EntityProviderException.ILLEGAL_ARGUMENT
+          .addContent("Got not supported NULL object as content to de-serialize."));
+    }
+
+    if (content instanceof InputStream) {
+      XMLStreamReader streamReader = factory.createXMLStreamReader((InputStream) content, DEFAULT_CHARSET);
+      // verify charset encoding set in content is supported (if not set UTF-8 is used as defined in 'http://www.w3.org/TR/2008/REC-xml-20081126/')
+      String characterEncodingInContent = streamReader.getCharacterEncodingScheme();
+      if (characterEncodingInContent != null && !DEFAULT_CHARSET.equalsIgnoreCase(characterEncodingInContent)) {
+        throw new EntityProviderException(EntityProviderException.UNSUPPORTED_CHARACTER_ENCODING.addContent(characterEncodingInContent));
+      }
+      return streamReader;
+    }
+    throw new EntityProviderException(EntityProviderException.ILLEGAL_ARGUMENT
+        .addContent("Found not supported content of class '" + content.getClass() + "' to de-serialize."));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
new file mode 100644
index 0000000..881d8c7
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
@@ -0,0 +1,684 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.consumer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
+import org.apache.olingo.odata2.api.edm.EdmNavigationProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
+import org.apache.olingo.odata2.api.ep.callback.OnReadInlineContent;
+import org.apache.olingo.odata2.api.ep.callback.ReadEntryResult;
+import org.apache.olingo.odata2.api.ep.callback.ReadFeedResult;
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+import org.apache.olingo.odata2.api.exception.ODataApplicationException;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
+import org.apache.olingo.odata2.core.commons.ContentType;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityTypeMapping;
+import org.apache.olingo.odata2.core.ep.entry.EntryMetadataImpl;
+import org.apache.olingo.odata2.core.ep.entry.MediaMetadataImpl;
+import org.apache.olingo.odata2.core.ep.entry.ODataEntryImpl;
+import org.apache.olingo.odata2.core.ep.feed.FeedMetadataImpl;
+import org.apache.olingo.odata2.core.ep.feed.ODataFeedImpl;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+import org.apache.olingo.odata2.core.uri.ExpandSelectTreeNodeImpl;
+
+/**
+ * Atom/XML format reader/consumer for entries.
+ * 
+ * {@link XmlEntryConsumer} instance can be reused for several {@link #readEntry(XMLStreamReader, EntityInfoAggregator, EntityProviderReadProperties)} calls
+ * but be aware that the instance and their <code>readEntry*</code> methods are <b>NOT THREAD SAFE</b>.
+ * @author SAP AG
+ */
+public class XmlEntryConsumer {
+
+  private Map<String, String> foundPrefix2NamespaceUri;
+  private ODataEntryImpl readEntryResult;
+  private Map<String, Object> properties;
+  private MediaMetadataImpl mediaMetadata;
+  private EntryMetadataImpl entryMetadata;
+  private ExpandSelectTreeNodeImpl expandSelectTree;
+  private EntityTypeMapping typeMappings;
+  private String currentHandledStartTagName;
+
+  public ODataEntry readEntry(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties readProperties) throws EntityProviderException {
+    try {
+      initialize(readProperties);
+
+      while (reader.hasNext() && !isEntryEndTag(reader)) {
+        reader.nextTag();
+        if (reader.isStartElement()) {
+          handleStartedTag(reader, eia, readProperties);
+        }
+      }
+
+      if (!readProperties.getMergeSemantic()) {
+        validateMandatoryPropertiesAvailable(eia, readEntryResult);
+      }
+
+      return readEntryResult;
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    } catch (EdmException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  private boolean isEntryEndTag(final XMLStreamReader reader) {
+    return reader.isEndElement()
+        && Edm.NAMESPACE_ATOM_2005.equals(reader.getNamespaceURI())
+        && FormatXml.ATOM_ENTRY.equals(reader.getLocalName());
+  }
+
+  /**
+   * Initialize the {@link XmlEntryConsumer} to be ready for read of an entry.
+   * 
+   * @param readProperties
+   * @throws EntityProviderException
+   */
+  private void initialize(final EntityProviderReadProperties readProperties) throws EntityProviderException {
+    properties = new HashMap<String, Object>();
+    mediaMetadata = new MediaMetadataImpl();
+    entryMetadata = new EntryMetadataImpl();
+    expandSelectTree = new ExpandSelectTreeNodeImpl();
+    foundPrefix2NamespaceUri = new HashMap<String, String>();
+
+    readEntryResult = new ODataEntryImpl(properties, mediaMetadata, entryMetadata, expandSelectTree);
+    typeMappings = EntityTypeMapping.create(readProperties.getTypeMappings());
+    foundPrefix2NamespaceUri.putAll(readProperties.getValidatedPrefixNamespaceUris());
+  }
+
+  /**
+   * Validates that all mandatory properties are found and set at the {@link #readEntryResult} entity.
+   * If a mandatory property is missing an {@link EntityProviderException} is thrown.
+   * 
+   * @param eia entity info which contains the information which properties are mandatory
+   * @param entry entry for which the mandatory properties are validated
+   * @throws EntityProviderException if a mandatory property is missing
+   */
+  private void validateMandatoryPropertiesAvailable(final EntityInfoAggregator eia, final ODataEntryImpl entry) throws EntityProviderException {
+    Collection<EntityPropertyInfo> propertyInfos = new ArrayList<EntityPropertyInfo>(eia.getPropertyInfos());
+    propertyInfos.removeAll(eia.getKeyPropertyInfos());
+    Map<String, Object> data = entry.getProperties();
+
+    for (EntityPropertyInfo entityPropertyInfo : propertyInfos) {
+      boolean mandatory = entityPropertyInfo.isMandatory();
+      if (mandatory && !data.containsKey(entityPropertyInfo.getName())) {
+        throw new EntityProviderException(EntityProviderException.MISSING_PROPERTY.addContent(entityPropertyInfo.getName()));
+      }
+    }
+  }
+
+  private void handleStartedTag(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties readProperties)
+      throws EntityProviderException, XMLStreamException, EdmException {
+
+    currentHandledStartTagName = reader.getLocalName();
+
+    if (FormatXml.ATOM_ID.equals(currentHandledStartTagName)) {
+      readId(reader);
+    } else if (FormatXml.ATOM_ENTRY.equals(currentHandledStartTagName)) {
+      readEntry(reader);
+    } else if (FormatXml.ATOM_LINK.equals(currentHandledStartTagName)) {
+      readLink(reader, eia, readProperties);
+    } else if (FormatXml.ATOM_CONTENT.equals(currentHandledStartTagName)) {
+      readContent(reader, eia);
+    } else if (FormatXml.M_PROPERTIES.equals(currentHandledStartTagName)) {
+      readProperties(reader, eia);
+    } else if (!readProperties.getMergeSemantic()) {
+      readCustomElement(reader, currentHandledStartTagName, eia);
+    } else {
+      skipStartedTag(reader);
+    }
+  }
+
+  private void readCustomElement(final XMLStreamReader reader, final String tagName, final EntityInfoAggregator eia) throws EdmException, EntityProviderException, XMLStreamException {
+    EntityPropertyInfo targetPathInfo = eia.getTargetPathInfo(tagName);
+    NamespaceContext nsctx = reader.getNamespaceContext();
+
+    boolean skipTag = true;
+    if (!Edm.NAMESPACE_ATOM_2005.equals(reader.getName().getNamespaceURI())) {
+
+      if (targetPathInfo != null) {
+        final String customPrefix = targetPathInfo.getCustomMapping().getFcNsPrefix();
+        final String customNamespaceURI = targetPathInfo.getCustomMapping().getFcNsUri();
+
+        if (customPrefix != null && customNamespaceURI != null) {
+          String xmlPrefix = nsctx.getPrefix(customNamespaceURI);
+          String xmlNamespaceUri = reader.getNamespaceURI(customPrefix);
+
+          if (customNamespaceURI.equals(xmlNamespaceUri) && customPrefix.equals(xmlPrefix)) {
+            skipTag = false;
+            reader.require(XMLStreamConstants.START_ELEMENT, customNamespaceURI, tagName);
+            reader.next();
+            reader.require(XMLStreamConstants.CHARACTERS, null, null);
+            final String text = reader.getText();
+            reader.nextTag();
+            reader.require(XMLStreamConstants.END_ELEMENT, customNamespaceURI, tagName);
+
+            final EntityPropertyInfo propertyInfo = getValidatedPropertyInfo(eia, tagName);
+            final Class<?> typeMapping = typeMappings.getMappingClass(propertyInfo.getName());
+            final EdmSimpleType type = (EdmSimpleType) propertyInfo.getType();
+            final Object value = type.valueOfString(text, EdmLiteralKind.DEFAULT, propertyInfo.getFacets(),
+                typeMapping == null ? type.getDefaultType() : typeMapping);
+            properties.put(tagName, value);
+          }
+        }
+      } else {
+        throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(tagName));
+      }
+    }
+
+    if (skipTag) {
+      skipStartedTag(reader);
+    }
+  }
+
+  /**
+   * Skip the tag to which the {@link XMLStreamReader} currently points.
+   * Therefore it is read until an end element tag with current local name is found.
+   * 
+   * @param reader
+   * @throws XMLStreamException
+   */
+  private void skipStartedTag(final XMLStreamReader reader) throws XMLStreamException {
+    final String name = reader.getLocalName();
+    int read = 1;
+    while (read > 0 && reader.hasNext()) {
+      reader.next();
+      if (reader.hasName() && name.equals(reader.getLocalName())) {
+        if (reader.isEndElement()) {
+          read--;
+        } else if (reader.isStartElement()) {
+          read++;
+        }
+      }
+    }
+  }
+
+  private void readEntry(final XMLStreamReader reader) throws EntityProviderException, XMLStreamException {
+    reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_ENTRY);
+
+    extractNamespacesFromTag(reader);
+    final String etag = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_ETAG);
+    entryMetadata.setEtag(etag);
+  }
+
+  private void extractNamespacesFromTag(final XMLStreamReader reader) throws EntityProviderException {
+    // collect namespaces
+    int namespaceCount = reader.getNamespaceCount();
+    for (int i = 0; i < namespaceCount; i++) {
+      String namespacePrefix = reader.getNamespacePrefix(i);
+      String namespaceUri = reader.getNamespaceURI(i);
+
+      foundPrefix2NamespaceUri.put(namespacePrefix, namespaceUri);
+    }
+  }
+
+  private void checkAllMandatoryNamespacesAvailable() throws EntityProviderException {
+    if (!foundPrefix2NamespaceUri.containsValue(Edm.NAMESPACE_D_2007_08)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_D_2007_08));
+    } else if (!foundPrefix2NamespaceUri.containsValue(Edm.NAMESPACE_M_2007_08)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_M_2007_08));
+    } else if (!foundPrefix2NamespaceUri.containsValue(Edm.NAMESPACE_ATOM_2005)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_ATOM_2005));
+    }
+  }
+
+  /**
+   * 
+   * @param reader
+   * @param eia
+   * @param readProperties
+   * @throws EntityProviderException
+   * @throws XMLStreamException
+   * @throws EdmException
+   */
+  private void readLink(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties readProperties) throws EntityProviderException, XMLStreamException, EdmException {
+    reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_LINK);
+
+    final String rel = reader.getAttributeValue(null, FormatXml.ATOM_REL);
+    final String uri = reader.getAttributeValue(null, FormatXml.ATOM_HREF);
+    final String type = reader.getAttributeValue(null, FormatXml.ATOM_TYPE);
+    final String etag = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_ETAG);
+
+    // read to next tag to check if <link> contains any further tags
+    reader.nextTag();
+
+    if (reader.isEndElement()) {
+      reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_LINK);
+
+      if (rel == null || uri == null) {
+        throw new EntityProviderException(EntityProviderException.MISSING_ATTRIBUTE.addContent(
+            FormatXml.ATOM_HREF + "' and/or '" + FormatXml.ATOM_REL).addContent(FormatXml.ATOM_LINK));
+      } else if (rel.startsWith(Edm.NAMESPACE_REL_2007_08)) {
+        final String navigationPropertyName = rel.substring(Edm.NAMESPACE_REL_2007_08.length());
+        entryMetadata.putAssociationUri(navigationPropertyName, uri);
+      } else if (rel.equals(Edm.LINK_REL_EDIT_MEDIA)) {
+        mediaMetadata.setEditLink(uri);
+        mediaMetadata.setEtag(etag);
+      }
+    } else {
+      if (rel != null && rel.startsWith(Edm.NAMESPACE_REL_2007_08)) {
+        readInlineContent(reader, eia, readProperties, type, rel);
+      }
+    }
+  }
+
+  /**
+   * Inline content was found and {@link XMLStreamReader} already points to <m:inline> tag.
+   * 
+   * @param reader
+   * @param eia
+   * @param readProperties
+   * @param atomLinkType the atom <code>type</code> attribute value of the <code>link</code> tag
+   * @param atomLinkRel the atom <code>rel</code> attribute value of the <code>link</code> tag
+   * @throws XMLStreamException
+   * @throws EntityProviderException
+   * @throws EdmException
+   */
+  private void readInlineContent(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties readProperties,
+      final String atomLinkType, final String atomLinkRel)
+      throws XMLStreamException, EntityProviderException, EdmException {
+
+    //
+    String navigationPropertyName = atomLinkRel.substring(Edm.NAMESPACE_REL_2007_08.length());
+
+    EdmNavigationProperty navigationProperty = (EdmNavigationProperty) eia.getEntityType().getProperty(navigationPropertyName);
+    EdmEntitySet entitySet = eia.getEntitySet().getRelatedEntitySet(navigationProperty);
+    EntityInfoAggregator inlineEia = EntityInfoAggregator.create(entitySet);
+
+    final EntityProviderReadProperties inlineProperties = createInlineProperties(readProperties, navigationProperty);
+
+    // validations
+    boolean isFeed = isInlineFeedValidated(reader, eia, atomLinkType, navigationPropertyName);
+
+    List<ODataEntry> inlineEntries = new ArrayList<ODataEntry>();
+
+    while (!(reader.isEndElement() && Edm.NAMESPACE_M_2007_08.equals(reader.getNamespaceURI()) && FormatXml.M_INLINE.equals(reader.getLocalName()))) {
+
+      if (reader.isStartElement() && Edm.NAMESPACE_ATOM_2005.equals(reader.getNamespaceURI()) && FormatXml.ATOM_ENTRY.equals(reader.getLocalName())) {
+        XmlEntryConsumer xec = new XmlEntryConsumer();
+        ODataEntry inlineEntry = xec.readEntry(reader, inlineEia, inlineProperties);
+        inlineEntries.add(inlineEntry);
+      }
+      // next tag
+      reader.next();
+    }
+
+    updateExpandSelectTree(navigationPropertyName, inlineEntries);
+    updateReadProperties(readProperties, navigationPropertyName, navigationProperty, isFeed, inlineEntries);
+
+    reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+  }
+
+  /**
+   * Updates the read properties ({@link #properties}) for this {@link ReadEntryResult} ({@link #readEntryResult}).
+   * 
+   * @param readProperties
+   * @param navigationPropertyName
+   * @param navigationProperty
+   * @param isFeed
+   * @param inlineEntries
+   * @throws EntityProviderException 
+   */
+  private void updateReadProperties(final EntityProviderReadProperties readProperties, final String navigationPropertyName,
+      final EdmNavigationProperty navigationProperty, final boolean isFeed, final List<ODataEntry> inlineEntries) throws EntityProviderException {
+    Object entry = extractODataEntity(isFeed, inlineEntries);
+    OnReadInlineContent callback = readProperties.getCallback();
+    if (callback == null) {
+      readEntryResult.setContainsInlineEntry(true);
+      properties.put(navigationPropertyName, entry);
+    } else {
+      doCallback(readProperties, navigationProperty, callback, isFeed, entry);
+    }
+  }
+
+  /**
+   * Updates the expand select tree ({@link #expandSelectTree}) for this {@link ReadEntryResult} ({@link #readEntryResult}).
+   * 
+   * @param navigationPropertyName
+   * @param inlineEntries
+   * @throws EntityProviderException 
+   */
+  private void updateExpandSelectTree(final String navigationPropertyName, final List<ODataEntry> inlineEntries) throws EntityProviderException {
+    expandSelectTree.setExpanded();
+    ExpandSelectTreeNodeImpl subNode = getExpandSelectTreeNode(inlineEntries);
+    expandSelectTree.putLink(navigationPropertyName, subNode);
+  }
+
+  /**
+   * Get the {@link ExpandSelectTreeNodeImpl} from the <code>inlineEntries</code> or if none exists create a new
+   * {@link ExpandSelectTreeNodeImpl}.
+   * 
+   * @param inlineEntries entries which are checked for existing {@link ExpandSelectTreeNodeImpl}
+   * @return {@link ExpandSelectTreeNodeImpl} from the <code>inlineEntries</code> or if none exists create a new {@link ExpandSelectTreeNodeImpl}.
+   * @throws EntityProviderException if an unsupported {@link ExpandSelectTreeNode} implementation was found.
+   */
+  private ExpandSelectTreeNodeImpl getExpandSelectTreeNode(final List<ODataEntry> inlineEntries) throws EntityProviderException {
+    if (inlineEntries.isEmpty()) {
+      return new ExpandSelectTreeNodeImpl();
+    } else {
+      ExpandSelectTreeNode inlinedEntryEstNode = inlineEntries.get(0).getExpandSelectTree();
+      if (inlinedEntryEstNode instanceof ExpandSelectTreeNodeImpl) {
+        return (ExpandSelectTreeNodeImpl) inlinedEntryEstNode;
+      } else {
+        throw new EntityProviderException(EntityProviderException.ILLEGAL_ARGUMENT
+            .addContent("Unsupported implementation for " + ExpandSelectTreeNode.class + " found."));
+      }
+    }
+  }
+
+  /**
+   * Get a list of {@link ODataEntry}, an empty list, a single {@link ODataEntry} or <code>NULL</code> based on 
+   * <code>isFeed</code> value and <code>inlineEntries</code> content.
+   * 
+   * @param isFeed
+   * @param inlineEntries
+   * @return
+   */
+  private Object extractODataEntity(final boolean isFeed, final List<ODataEntry> inlineEntries) {
+    if (isFeed) {
+      //TODO: fill metadata correctly with inline count and inline next link. Both are currently ignored.
+      return new ODataFeedImpl(inlineEntries, new FeedMetadataImpl());
+    } else if (!inlineEntries.isEmpty()) {
+      return inlineEntries.get(0);
+    }
+    return null;
+  }
+
+  /**
+   * Do the callback based on given parameters.
+   * 
+   * @param readProperties
+   * @param navigationProperty
+   * @param callback
+   * @param isFeed
+   * @param entry
+   * @throws EntityProviderException
+   */
+  private void doCallback(final EntityProviderReadProperties readProperties, final EdmNavigationProperty navigationProperty,
+      final OnReadInlineContent callback, final boolean isFeed, final Object content) throws EntityProviderException {
+
+    try {
+      if (isFeed) {
+        ReadFeedResult callbackInfo = new ReadFeedResult(readProperties, navigationProperty, (ODataFeed) content);
+        callback.handleReadFeed(callbackInfo);
+      } else {
+        ReadEntryResult callbackInfo = new ReadEntryResult(readProperties, navigationProperty, (ODataEntry) content);
+        callback.handleReadEntry(callbackInfo);
+      }
+    } catch (ODataApplicationException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  /**
+   * Create {@link EntityProviderReadProperties} which can be used for reading of inline properties/entrys of navigation links within
+   * this current read entry.
+   * 
+   * @param readProperties
+   * @param navigationProperty
+   * @return
+   * @throws EntityProviderException 
+   */
+  private EntityProviderReadProperties createInlineProperties(final EntityProviderReadProperties readProperties, final EdmNavigationProperty navigationProperty) throws EntityProviderException {
+    final OnReadInlineContent callback = readProperties.getCallback();
+
+    EntityProviderReadProperties currentReadProperties = EntityProviderReadProperties.initFrom(readProperties).addValidatedPrefixes(foundPrefix2NamespaceUri).build();
+    if (callback == null) {
+      return currentReadProperties;
+    } else {
+      try {
+        return callback.receiveReadProperties(currentReadProperties, navigationProperty);
+      } catch (ODataApplicationException e) {
+        throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+      }
+    }
+  }
+
+  /**
+   * <p>
+   * Inline content was found and {@link XMLStreamReader} already points to <code><m:inline> tag</code>.
+   * <br/>
+   * <b>ATTENTION</b>: If {@link XMLStreamReader} does not point to the <code><m:inline> tag</code> an exception is thrown.
+   * </p>
+   * <p>
+   * Check whether it is an inline <code>Feed</code> or <code>Entry</code> and validate that...
+   * <ul>
+   * <li>...{@link FormatXml#M_INLINE} tag is correctly set.</li>
+   * <li>...based on {@link EdmMultiplicity} of {@link EdmNavigationProperty} all tags are correctly set.</li>
+   * <li>...{@link FormatXml#ATOM_TYPE} tag is correctly set and according to {@link FormatXml#ATOM_ENTRY} or {@link FormatXml#ATOM_FEED} to following tags are available.</li>
+   * </ul>
+   * 
+   * For the case that one of above validations fail an {@link EntityProviderException} is thrown.
+   * If validation was successful <code>true</code> is returned for <code>Feed</code> and <code>false</code> for <code>Entry</code>
+   * multiplicity.
+   * </p>
+   * 
+   * @param reader xml content reader which already points to <code><m:inline> tag</code>
+   * @param eia all necessary information about the entity 
+   * @param type the atom type attribute value of the <code>link</code> tag
+   * @param navigationPropertyName the navigation property name of the entity
+   * @return <code>true</code> for <code>Feed</code> and <code>false</code> for <code>Entry</code>
+   * @throws EntityProviderException is thrown if at least one validation fails.
+   * @throws EdmException if edm access fails
+   */
+  private boolean isInlineFeedValidated(final XMLStreamReader reader, final EntityInfoAggregator eia, final String type, final String navigationPropertyName) throws EntityProviderException, EdmException {
+    boolean isFeed = false;
+    try {
+      reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+      //
+      ContentType cType = ContentType.parse(type);
+      if (cType == null) {
+        throw new EntityProviderException(EntityProviderException.INVALID_INLINE_CONTENT.addContent("xml data"));
+      }
+
+      EdmNavigationProperty navigationProperty = (EdmNavigationProperty) eia.getEntityType().getProperty(navigationPropertyName);
+      EdmMultiplicity navigationMultiplicity = navigationProperty.getMultiplicity();
+
+      switch (navigationMultiplicity) {
+      case MANY:
+        validateFeedTags(reader, cType);
+        isFeed = true;
+        break;
+      case ONE:
+      case ZERO_TO_ONE:
+        validateEntryTags(reader, cType);
+        break;
+      }
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.INVALID_INLINE_CONTENT.addContent("xml data"), e);
+    }
+    return isFeed;
+  }
+
+  private void validateEntryTags(final XMLStreamReader reader, final ContentType cType) throws XMLStreamException, EntityProviderException {
+    if (FormatXml.ATOM_ENTRY.equals(cType.getParameters().get(FormatXml.ATOM_TYPE))) {
+      int next = reader.nextTag();
+      if (XMLStreamConstants.START_ELEMENT == next) {
+        reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_ENTRY);
+      } else {
+        reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+      }
+    } else {
+      throw new EntityProviderException(EntityProviderException.INVALID_INLINE_CONTENT.addContent("entry"));
+    }
+  }
+
+  private void validateFeedTags(final XMLStreamReader reader, final ContentType cType) throws XMLStreamException, EntityProviderException {
+    if (FormatXml.ATOM_FEED.equals(cType.getParameters().get(FormatXml.ATOM_TYPE))) {
+      int next = reader.nextTag();
+      if (XMLStreamConstants.START_ELEMENT == next) {
+        reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_FEED);
+      } else {
+        reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_M_2007_08, FormatXml.M_INLINE);
+      }
+    } else {
+      throw new EntityProviderException(EntityProviderException.INVALID_INLINE_CONTENT.addContent("feed"));
+    }
+  }
+
+  private void readContent(final XMLStreamReader reader, final EntityInfoAggregator eia) throws EntityProviderException, XMLStreamException, EdmException {
+    reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_CONTENT);
+
+    extractNamespacesFromTag(reader);
+
+    checkAllMandatoryNamespacesAvailable();
+
+    final String contentType = reader.getAttributeValue(null, FormatXml.ATOM_TYPE);
+    final String sourceLink = reader.getAttributeValue(null, FormatXml.ATOM_SRC);
+
+    reader.nextTag();
+
+    if (reader.isStartElement() && reader.getLocalName().equals(FormatXml.M_PROPERTIES)) {
+      readProperties(reader, eia);
+    } else if (reader.isEndElement()) {
+      reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_CONTENT);
+    } else {
+      throw new EntityProviderException(EntityProviderException.INVALID_STATE
+          .addContent("Expected closing 'content' or starting 'properties' but found '" + reader.getLocalName() + "'."));
+    }
+
+    mediaMetadata.setContentType(contentType);
+    mediaMetadata.setSourceLink(sourceLink);
+  }
+
+  private void readId(final XMLStreamReader reader) throws EntityProviderException, XMLStreamException {
+    reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_ID);
+    reader.next();
+    if (reader.isCharacters()) {
+      entryMetadata.setId(reader.getText());
+    }
+    reader.nextTag();
+    reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_ID);
+  }
+
+  private void readProperties(final XMLStreamReader reader, final EntityInfoAggregator entitySet) throws XMLStreamException, EdmException, EntityProviderException {
+    // validate namespace
+    checkAllMandatoryNamespacesAvailable();
+    reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_M_2007_08, FormatXml.M_PROPERTIES);
+    if (entitySet.getEntityType().hasStream()) {
+      // external properties
+      checkCurrentHandledStartTag(FormatXml.M_PROPERTIES);
+    } else {
+      // inline properties
+      checkCurrentHandledStartTag(FormatXml.ATOM_CONTENT);
+    }
+
+    EntityPropertyInfo property;
+    XmlPropertyConsumer xpc = new XmlPropertyConsumer();
+
+    String closeTag = null;
+    boolean run = true;
+    reader.next();
+
+    while (run) {
+      if (reader.isStartElement() && closeTag == null) {
+        closeTag = reader.getLocalName();
+        if (isEdmNamespaceProperty(reader)) {
+          if (properties.containsKey(closeTag)) {
+            throw new EntityProviderException(EntityProviderException.DOUBLE_PROPERTY.addContent(closeTag));
+          }
+          property = getValidatedPropertyInfo(entitySet, closeTag);
+          final Object value = xpc.readStartedElement(reader, property, typeMappings);
+          properties.put(closeTag, value);
+          closeTag = null;
+        }
+      } else if (reader.isEndElement()) {
+        if (reader.getLocalName().equals(closeTag)) {
+          closeTag = null;
+        } else if (Edm.NAMESPACE_M_2007_08.equals(reader.getNamespaceURI()) && FormatXml.M_PROPERTIES.equals(reader.getLocalName())) {
+          run = false;
+        }
+      }
+      reader.next();
+    }
+  }
+
+  /**
+   * Check if the {@link #currentHandledStartTagName} is the same as the <code>expectedTagName</code>.
+   * If tag name is not as expected or if {@link #currentHandledStartTagName} is not set an {@link EntityProviderException} is thrown.
+   * 
+   * @param expectedTagName expected name for {@link #currentHandledStartTagName}
+   * @throws EntityProviderException if tag name is not as expected or if {@link #currentHandledStartTagName} is <code>NULL</code>.
+   */
+  private void checkCurrentHandledStartTag(final String expectedTagName) throws EntityProviderException {
+    if (currentHandledStartTagName == null) {
+      throw new EntityProviderException(EntityProviderException.INVALID_STATE.addContent("No current handled start tag name set."));
+    } else if (!currentHandledStartTagName.equals(expectedTagName)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_PARENT_TAG.addContent(expectedTagName).addContent(currentHandledStartTagName));
+    }
+  }
+
+  /**
+   * Checks if property of currently read tag in {@link XMLStreamReader} is defined in 
+   * <code>edm properties namespace</code> {@value Edm#NAMESPACE_D_2007_08}.
+   * 
+   * If no namespace uri definition is found for namespace prefix of property (<code>tag</code>) an exception is thrown.
+   * 
+   * @param reader {@link XMLStreamReader} with position at to checked tag
+   * @return <code>true</code> if property is in <code>edm properties namespace</code>, otherwise <code>false</code>.
+   * @throws EntityProviderException If no namespace uri definition is found for namespace prefix of property (<code>tag</code>).
+   */
+  private boolean isEdmNamespaceProperty(final XMLStreamReader reader) throws EntityProviderException {
+    final String nsUri = reader.getNamespaceURI();
+    if (nsUri == null) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(reader.getLocalName()));
+    } else {
+      return Edm.NAMESPACE_D_2007_08.equals(nsUri);
+    }
+  }
+
+  /**
+   * Get validated {@link EntityPropertyInfo} for property with given <code>name</code>.
+   * If validation fails an {@link EntityProviderException} is thrown.
+   * 
+   * Currently this is the case if no {@link EntityPropertyInfo} if found for given <code>name</code>.
+   * 
+   * @param entitySet
+   * @param name
+   * @return valid {@link EntityPropertyInfo} (which is never <code>NULL</code>).
+   * @throws EntityProviderException
+   */
+  private EntityPropertyInfo getValidatedPropertyInfo(final EntityInfoAggregator entitySet, final String name) throws EntityProviderException {
+    EntityPropertyInfo info = entitySet.getPropertyInfo(name);
+    if (info == null) {
+      throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(name));
+    }
+    return info;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlFeedConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlFeedConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlFeedConsumer.java
new file mode 100644
index 0000000..b15c1f0
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlFeedConsumer.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.consumer;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.feed.FeedMetadataImpl;
+import org.apache.olingo.odata2.core.ep.feed.ODataFeedImpl;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * Atom/XML format reader/consumer for feeds.
+ * 
+ * {@link XmlFeedConsumer} instance use {@link XmlEntryConsumer#readEntry(XMLStreamReader, EntityInfoAggregator, EntityProviderReadProperties)} 
+ * for read/consume of several entries.
+ * 
+ * @author SAP AG
+ */
+public class XmlFeedConsumer {
+
+  /**
+   * 
+   * @param reader
+   * @param eia
+   * @param readProperties
+   * @return {@link ODataFeed} object
+   * @throws EntityProviderException
+   */
+  public ODataFeed readFeed(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties readProperties) throws EntityProviderException {
+    try {
+      // read xml tag
+      reader.require(XMLStreamConstants.START_DOCUMENT, null, null);
+      reader.nextTag();
+
+      // read feed tag
+      reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_FEED);
+      Map<String, String> foundPrefix2NamespaceUri = extractNamespacesFromTag(reader);
+      foundPrefix2NamespaceUri.putAll(readProperties.getValidatedPrefixNamespaceUris());
+      checkAllMandatoryNamespacesAvailable(foundPrefix2NamespaceUri);
+      EntityProviderReadProperties entryReadProperties =
+          EntityProviderReadProperties.initFrom(readProperties).addValidatedPrefixes(foundPrefix2NamespaceUri).build();
+
+      // read feed data (metadata and entries)
+      return readFeedData(reader, eia, entryReadProperties);
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  /**
+   * Read all feed specific data (like <code>inline count</code> and <code>next link</code>) as well as all feed entries (<code>entry</code>).
+   * 
+   * @param reader
+   * @param eia
+   * @param entryReadProperties
+   * @return
+   * @throws XMLStreamException
+   * @throws EntityProviderException
+   */
+  private ODataFeed readFeedData(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties entryReadProperties) throws XMLStreamException, EntityProviderException {
+    FeedMetadataImpl metadata = new FeedMetadataImpl();
+    XmlEntryConsumer xec = new XmlEntryConsumer();
+    List<ODataEntry> results = new ArrayList<ODataEntry>();
+
+    while (reader.hasNext() && !isFeedEndTag(reader)) {
+      if (FormatXml.ATOM_ENTRY.equals(reader.getLocalName())) {
+        ODataEntry entry = xec.readEntry(reader, eia, entryReadProperties);
+        results.add(entry);
+      } else if (FormatXml.M_COUNT.equals(reader.getLocalName())) {
+        reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_M_2007_08, FormatXml.M_COUNT);
+
+        reader.next();
+        if (reader.hasText()) {
+          String inlineCountString = reader.getText();
+          try {
+            int inlineCountNumber = Integer.valueOf(inlineCountString);
+            if (inlineCountNumber >= 0) {
+              metadata.setInlineCount(inlineCountNumber);
+            } else {
+              throw new EntityProviderException(EntityProviderException.INLINECOUNT_INVALID.addContent(inlineCountNumber));
+            }
+          } catch (NumberFormatException e) {
+            throw new EntityProviderException(EntityProviderException.INLINECOUNT_INVALID.addContent(""), e);
+          }
+        }
+      } else if (FormatXml.ATOM_LINK.equals(reader.getLocalName())) {
+        reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_ATOM_2005, FormatXml.ATOM_LINK);
+
+        final String rel = reader.getAttributeValue(null, FormatXml.ATOM_REL);
+        if (FormatXml.ATOM_NEXT_LINK.equals(rel)) {
+          final String uri = reader.getAttributeValue(null, FormatXml.ATOM_HREF);
+          metadata.setNextLink(uri);
+        } else if (FormatXml.ATOM_DELTA_LINK.equals(rel)) {
+          final String uri = reader.getAttributeValue(null, FormatXml.ATOM_HREF);
+          metadata.setDeltaLink(uri);
+        }
+
+        reader.next();
+      } else {
+        reader.next();
+      }
+      readTillNextStartTag(reader);
+    }
+    return new ODataFeedImpl(results, metadata);
+  }
+
+  private void readTillNextStartTag(final XMLStreamReader reader) throws XMLStreamException {
+    while (reader.hasNext() && !reader.isStartElement()) {
+      reader.next();
+    }
+  }
+
+  private boolean isFeedEndTag(final XMLStreamReader reader) {
+    return reader.isEndElement()
+        && Edm.NAMESPACE_ATOM_2005.equals(reader.getNamespaceURI())
+        && FormatXml.ATOM_FEED.equals(reader.getLocalName());
+  }
+
+  /**
+   * 
+   * @param reader
+   * @return 
+   * @throws EntityProviderException
+   */
+  private Map<String, String> extractNamespacesFromTag(final XMLStreamReader reader) throws EntityProviderException {
+    // collect namespaces
+    Map<String, String> foundPrefix2NamespaceUri = new HashMap<String, String>();
+    int namespaceCount = reader.getNamespaceCount();
+    for (int i = 0; i < namespaceCount; i++) {
+      String namespacePrefix = reader.getNamespacePrefix(i);
+      String namespaceUri = reader.getNamespaceURI(i);
+
+      foundPrefix2NamespaceUri.put(namespacePrefix, namespaceUri);
+    }
+    return foundPrefix2NamespaceUri;
+  }
+
+  /**
+   * 
+   * @param foundPrefix2NamespaceUri 
+   * @throws EntityProviderException
+   */
+  private void checkAllMandatoryNamespacesAvailable(final Map<String, String> foundPrefix2NamespaceUri) throws EntityProviderException {
+    if (!foundPrefix2NamespaceUri.containsValue(Edm.NAMESPACE_D_2007_08)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_D_2007_08));
+    } else if (!foundPrefix2NamespaceUri.containsValue(Edm.NAMESPACE_M_2007_08)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_M_2007_08));
+    } else if (!foundPrefix2NamespaceUri.containsValue(Edm.NAMESPACE_ATOM_2005)) {
+      throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_ATOM_2005));
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumer.java
new file mode 100644
index 0000000..d419c5b
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumer.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.consumer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmEntitySet;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * @author SAP AG
+ */
+public class XmlLinkConsumer {
+
+  /**
+   * Reads single link with format {@code <uri>http://somelink</uri>}.
+   * @param reader
+   * @param entitySet
+   * @return link as string object
+   * @throws EntityProviderException
+   */
+  public String readLink(final XMLStreamReader reader, final EdmEntitySet entitySet) throws EntityProviderException {
+    try {
+      reader.next();
+      return readLink(reader);
+    } catch (final XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  private String readLink(final XMLStreamReader reader) throws XMLStreamException {
+    return readTag(reader, Edm.NAMESPACE_D_2007_08, FormatXml.D_URI);
+  }
+
+  private String readTag(final XMLStreamReader reader, final String namespaceURI, final String localName) throws XMLStreamException {
+    reader.require(XMLStreamConstants.START_ELEMENT, namespaceURI, localName);
+
+    reader.next();
+    reader.require(XMLStreamConstants.CHARACTERS, null, null);
+    final String result = reader.getText();
+
+    reader.nextTag();
+    reader.require(XMLStreamConstants.END_ELEMENT, namespaceURI, localName);
+
+    return result;
+  }
+
+  /**
+   * Reads multiple links with format 
+   * <pre>
+   * {@code
+   * <links>
+   *  <uri>http://somelink</uri>
+   *  <uri>http://anotherLink</uri>
+   *  <uri>http://somelink/yetAnotherLink</uri>
+   * </links>
+   * }
+   * </pre>
+   * @param reader
+   * @param entitySet
+   * @return list of string based links
+   * @throws EntityProviderException
+   */
+  public List<String> readLinks(final XMLStreamReader reader, final EdmEntitySet entitySet) throws EntityProviderException {
+    try {
+      List<String> links = new ArrayList<String>();
+
+      reader.next();
+      reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, FormatXml.D_LINKS);
+
+      reader.nextTag();
+      while (!reader.isEndElement()) {
+        if (reader.getLocalName().equals(FormatXml.M_COUNT)) {
+          readTag(reader, Edm.NAMESPACE_M_2007_08, FormatXml.M_COUNT);
+        } else {
+          final String link = readLink(reader);
+          links.add(link);
+        }
+        reader.nextTag();
+      }
+
+      reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, FormatXml.D_LINKS);
+
+      return links;
+    } catch (final XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
new file mode 100644
index 0000000..d44c6c5
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.consumer;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
+import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
+import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
+import org.apache.olingo.odata2.core.ep.aggregator.EntityTypeMapping;
+import org.apache.olingo.odata2.core.ep.util.FormatXml;
+
+/**
+ * @author SAP AG
+ */
+public class XmlPropertyConsumer {
+
+  public static final String TRUE = "true";
+
+  public Map<String, Object> readProperty(final XMLStreamReader reader, final EdmProperty property, final boolean merge) throws EntityProviderException {
+    return readProperty(reader, property, merge, null);
+  }
+
+  public Map<String, Object> readProperty(final XMLStreamReader reader, final EdmProperty property, final boolean merge, final Map<String, Object> typeMappings) throws EntityProviderException {
+    EntityPropertyInfo eia = EntityInfoAggregator.create(property);
+
+    try {
+      reader.next();
+
+      Object value = readStartedElement(reader, eia, EntityTypeMapping.create(typeMappings));
+
+      if (eia.isComplex() && merge) {
+        mergeWithDefaultValues(value, eia);
+      }
+
+      Map<String, Object> result = new HashMap<String, Object>();
+      result.put(eia.getName(), value);
+      return result;
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    } catch (EdmException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private void mergeWithDefaultValues(final Object value, final EntityPropertyInfo epi) throws EntityProviderException {
+    if (!(value instanceof Map)) {
+      throw new EntityProviderException(EntityProviderException.COMMON);
+    }
+    if (!epi.isComplex()) {
+      throw new EntityProviderException(EntityProviderException.COMMON);
+    }
+
+    mergeComplexWithDefaultValues((Map<String, Object>) value, (EntityComplexPropertyInfo) epi);
+  }
+
+  private void mergeComplexWithDefaultValues(final Map<String, Object> complexValue, final EntityComplexPropertyInfo ecpi) {
+    for (EntityPropertyInfo info : ecpi.getPropertyInfos()) {
+      Object obj = complexValue.get(info.getName());
+      if (obj == null) {
+        if (info.isComplex()) {
+          Map<String, Object> defaultValue = new HashMap<String, Object>();
+          mergeComplexWithDefaultValues(defaultValue, ecpi);
+          complexValue.put(info.getName(), defaultValue);
+        } else {
+          EdmFacets facets = info.getFacets();
+          if (facets != null) {
+            complexValue.put(info.getName(), facets.getDefaultValue());
+          }
+        }
+      }
+    }
+  }
+
+  protected Object readStartedElement(final XMLStreamReader reader, final EntityPropertyInfo propertyInfo, final EntityTypeMapping typeMappings) throws EntityProviderException, EdmException {
+    Map<String, Object> name2Value = new HashMap<String, Object>();
+    Object result = null;
+
+    try {
+      reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, propertyInfo.getName());
+      final String nullAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_NULL);
+
+      if (TRUE.equals(nullAttribute)) {
+        reader.nextTag();
+      } else if (propertyInfo.isComplex()) {
+        final String typeAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_TYPE);
+        String expectedTypeAttributeValue = propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+        if (typeAttribute != null && !expectedTypeAttributeValue.equals(typeAttribute)) {
+          throw new EntityProviderException(EntityProviderException.INVALID_COMPLEX_TYPE.addContent(expectedTypeAttributeValue).addContent(typeAttribute));
+        }
+
+        reader.nextTag();
+        while (reader.hasNext() && !reader.isEndElement()) {
+          String childName = reader.getLocalName();
+          EntityPropertyInfo childProperty = getChildProperty(childName, propertyInfo);
+          if (childProperty == null) {
+            throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(childName));
+          }
+          Object value = readStartedElement(reader, childProperty, typeMappings.getEntityTypeMapping(propertyInfo.getName()));
+          name2Value.put(childName, value);
+          reader.nextTag();
+        }
+      } else {
+        Class<?> mapping = typeMappings.getMappingClass(propertyInfo.getName());
+        result = convert(propertyInfo, reader.getElementText(), mapping);
+      }
+      reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, propertyInfo.getName());
+
+      // if reading finished check which result must be returned
+      if (result != null) {
+        return result;
+      } else if (!name2Value.isEmpty()) {
+        return name2Value;
+      }
+    } catch (XMLStreamException e) {
+      throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
+    }
+    return null;
+  }
+
+  private EntityPropertyInfo getChildProperty(final String childPropertyName, final EntityPropertyInfo property) throws EdmException, EntityProviderException {
+    if (property.isComplex()) {
+      EntityComplexPropertyInfo complex = (EntityComplexPropertyInfo) property;
+      return complex.getPropertyInfo(childPropertyName);
+    }
+    throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(
+        "Expected complex property but found simple for property with name '" + property.getName() + "'"));
+  }
+
+  private Object convert(final EntityPropertyInfo property, final String value, final Class<?> typeMapping) throws EdmException, EntityProviderException {
+    if (!property.isComplex()) {
+      EdmSimpleType type = (EdmSimpleType) property.getType();
+      return type.valueOfString(value, EdmLiteralKind.DEFAULT, property.getFacets(),
+          typeMapping == null ? type.getDefaultType() : typeMapping);
+    }
+    throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(
+        "Expected simple property but found complex for property with name '" + property.getName() + "'"));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/EntryMetadataImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/EntryMetadataImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/EntryMetadataImpl.java
new file mode 100644
index 0000000..a4b1fbd
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/EntryMetadataImpl.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.entry;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.ep.entry.EntryMetadata;
+
+/**
+ * @author SAP AG
+ */
+public class EntryMetadataImpl implements EntryMetadata {
+  private String id;
+  private String etag;
+  private String uri;
+  private Map<String, List<String>> associationUris = new HashMap<String, List<String>>();
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  public void setId(final String id) {
+    this.id = id;
+  }
+
+  @Override
+  public String getEtag() {
+    return etag;
+  }
+
+  public void setEtag(final String etag) {
+    this.etag = etag;
+  }
+
+  @Override
+  public String getUri() {
+    return uri;
+  }
+
+  public void setUri(final String uri) {
+    this.uri = uri;
+  }
+
+  @Override
+  public List<String> getAssociationUris(final String navigationPropertyName) {
+    final List<String> uris = associationUris.get(navigationPropertyName);
+    if (uris == null) {
+      return Collections.emptyList();
+    } else {
+      return Collections.unmodifiableList(uris);
+    }
+  }
+
+  public void putAssociationUri(final String navigationPropertyName, final String uri) {
+    List<String> uris = associationUris.get(navigationPropertyName);
+    if (uris == null) {
+      uris = new ArrayList<String>();
+    }
+    uris.add(uri);
+    associationUris.put(navigationPropertyName, uris);
+  }
+
+  @Override
+  public String toString() {
+    return "EntryMetadataImpl [id=" + id + ", etag=" + etag + ", uri=" + uri + ", associationUris=" + associationUris + "]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/MediaMetadataImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/MediaMetadataImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/MediaMetadataImpl.java
new file mode 100644
index 0000000..2d8d436
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/MediaMetadataImpl.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.entry;
+
+import org.apache.olingo.odata2.api.ep.entry.MediaMetadata;
+
+/**
+ * @author SAP AG
+ */
+public class MediaMetadataImpl implements MediaMetadata {
+
+  private String sourceLink;
+  private String etag;
+  private String contentType;
+  private String editLink;
+
+  @Override
+  public String getSourceLink() {
+    return sourceLink;
+  }
+
+  @Override
+  public String getEtag() {
+    return etag;
+  }
+
+  @Override
+  public String getContentType() {
+    return contentType;
+  }
+
+  @Override
+  public String getEditLink() {
+    return editLink;
+  }
+
+  public void setSourceLink(final String sourceLink) {
+    this.sourceLink = sourceLink;
+  }
+
+  public void setEtag(final String etag) {
+    this.etag = etag;
+  }
+
+  public void setContentType(final String contentType) {
+    this.contentType = contentType;
+  }
+
+  public void setEditLink(final String editLink) {
+    this.editLink = editLink;
+  }
+
+  @Override
+  public String toString() {
+    return "MediaMetadataImpl [sourceLink=" + sourceLink + ", etag=" + etag + ", contentType=" + contentType + ", editLink=" + editLink + "]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/ODataEntryImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/ODataEntryImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/ODataEntryImpl.java
new file mode 100644
index 0000000..2a94a68
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/entry/ODataEntryImpl.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.entry;
+
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.ep.entry.EntryMetadata;
+import org.apache.olingo.odata2.api.ep.entry.MediaMetadata;
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
+import org.apache.olingo.odata2.core.uri.ExpandSelectTreeNodeImpl;
+
+/**
+ * @author SAP AG
+ */
+public class ODataEntryImpl implements ODataEntry {
+
+  private final Map<String, Object> data;
+  private final EntryMetadata entryMetadata;
+  private final MediaMetadata mediaMetadata;
+  private final ExpandSelectTreeNode expandSelectTree;
+  private boolean containsInlineEntry;
+
+  public ODataEntryImpl(final Map<String, Object> data, final MediaMetadata mediaMetadata, final EntryMetadata entryMetadata, final ExpandSelectTreeNodeImpl expandSelectTree) {
+    this(data, mediaMetadata, entryMetadata, expandSelectTree, false);
+  }
+
+  public ODataEntryImpl(final Map<String, Object> data, final MediaMetadata mediaMetadata, final EntryMetadata entryMetadata, final ExpandSelectTreeNode expandSelectTree, final boolean containsInlineEntry) {
+    this.data = data;
+    this.entryMetadata = entryMetadata;
+    this.mediaMetadata = mediaMetadata;
+    this.expandSelectTree = expandSelectTree;
+    this.containsInlineEntry = containsInlineEntry;
+  }
+
+  @Override
+  public Map<String, Object> getProperties() {
+    return data;
+  }
+
+  @Override
+  public MediaMetadata getMediaMetadata() {
+    return mediaMetadata;
+  }
+
+  @Override
+  public EntryMetadata getMetadata() {
+    return entryMetadata;
+  }
+
+  @Override
+  public boolean containsInlineEntry() {
+    return containsInlineEntry;
+  }
+
+  @Override
+  public ExpandSelectTreeNode getExpandSelectTree() {
+    return expandSelectTree;
+  }
+
+  public void setContainsInlineEntry(final boolean containsInlineEntry) {
+    this.containsInlineEntry = containsInlineEntry;
+  }
+
+  @Override
+  public String toString() {
+    return "ODataEntryImpl [data=" + data + ", "
+        + "entryMetadata=" + entryMetadata + ", "
+        + "mediaMetadata=" + mediaMetadata + ", "
+        + "expandSelectTree=" + expandSelectTree + ", "
+        + "containsInlineEntry=" + containsInlineEntry + "]";
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/FeedMetadataImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/FeedMetadataImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/FeedMetadataImpl.java
new file mode 100644
index 0000000..3f18298
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/FeedMetadataImpl.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.feed;
+
+import org.apache.olingo.odata2.api.ep.feed.FeedMetadata;
+
+public class FeedMetadataImpl implements FeedMetadata {
+
+  private Integer inlineCount = null;
+  private String nextLink = null;
+  private String deltaLink;
+
+  public void setInlineCount(final int inlineCount) {
+    this.inlineCount = inlineCount;
+  }
+
+  @Override
+  public Integer getInlineCount() {
+    return inlineCount;
+  }
+
+  public void setNextLink(final String nextLink) {
+    this.nextLink = nextLink;
+  }
+
+  @Override
+  public String getNextLink() {
+    return nextLink;
+  }
+
+  public void setDeltaLink(final String deltaLink) {
+    this.deltaLink = deltaLink;
+  }
+
+  @Override
+  public String getDeltaLink() {
+    return deltaLink;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/ff2b0a0e/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/ODataFeedImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/ODataFeedImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/ODataFeedImpl.java
new file mode 100644
index 0000000..9dd0328
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/feed/ODataFeedImpl.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ *        or more contributor license agreements.  See the NOTICE file
+ *        distributed with this work for additional information
+ *        regarding copyright ownership.  The ASF licenses this file
+ *        to you under the Apache License, Version 2.0 (the
+ *        "License"); you may not use this file except in compliance
+ *        with the License.  You may obtain a copy of the License at
+ * 
+ *          http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *        Unless required by applicable law or agreed to in writing,
+ *        software distributed under the License is distributed on an
+ *        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *        KIND, either express or implied.  See the License for the
+ *        specific language governing permissions and limitations
+ *        under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.ep.feed;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
+import org.apache.olingo.odata2.api.ep.feed.FeedMetadata;
+import org.apache.olingo.odata2.api.ep.feed.ODataFeed;
+
+public class ODataFeedImpl implements ODataFeed {
+
+  private final List<ODataEntry> entries;
+  private final FeedMetadata feedMetadata;
+
+  public ODataFeedImpl(final List<ODataEntry> entries, final FeedMetadata feedMetadata) {
+    this.entries = entries;
+    this.feedMetadata = feedMetadata;
+
+  }
+
+  @Override
+  public List<ODataEntry> getEntries() {
+    return entries;
+  }
+
+  @Override
+  public FeedMetadata getFeedMetadata() {
+    return feedMetadata;
+  }
+
+}