You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2016/08/17 12:36:20 UTC

[1/2] olingo-odata2 git commit: [OLINGO-1005] Support edmx references in metadata

Repository: olingo-odata2
Updated Branches:
  refs/heads/master eee416532 -> 8d90a1606


[OLINGO-1005] Support edmx references in metadata


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/546466ce
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/546466ce
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/546466ce

Branch: refs/heads/master
Commit: 546466ceb9db7956c7eb344aa78a1afde3041744
Parents: eee4165
Author: Christian Amend <ch...@sap.com>
Authored: Tue Jun 14 17:30:41 2016 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Wed Aug 17 14:31:39 2016 +0200

----------------------------------------------------------------------
 .../odata2/api/edm/provider/DataServices.java   | 36 ++++++++++
 .../olingo/odata2/api/ep/EntityProvider.java    | 32 +++++++++
 .../odata2/core/ep/BasicEntityProvider.java     | 23 +++++-
 .../odata2/core/ep/ProviderFacadeImpl.java      |  7 ++
 .../core/ep/producer/XmlMetadataProducer.java   | 50 ++++++++++----
 .../odata2/core/ep/BasicProviderTest.java       | 73 +++++++++++++++++++-
 .../ep/consumer/XmlMetadataConsumerTest.java    | 70 ++++++++++++++-----
 .../apache/olingo/odata2/fit/ref/BatchTest.java | 27 ++++----
 8 files changed, 270 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/provider/DataServices.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/provider/DataServices.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/provider/DataServices.java
index 552eb01..535a4e8 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/provider/DataServices.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/edm/provider/DataServices.java
@@ -29,6 +29,8 @@ public class DataServices {
 
   private List<Schema> schemas;
   private String dataServiceVersion;
+  private String customEdmxVersion;
+  private List<AnnotationElement> annotationElements;
 
   /**
    * Sets the schemas for this {@link DataServices}
@@ -51,6 +53,33 @@ public class DataServices {
   }
 
   /**
+   * Sets the collection of {@link AnnotationElement} for this {@link DataServices}
+   * @param annotationElements
+   * @return {@link ComplexType} for method chaining
+   */
+  public DataServices setAnnotationElements(final List<AnnotationElement> annotationElements) {
+    this.annotationElements = annotationElements;
+    return this;
+  }
+
+  /**
+   * Sets a custom edmx version which is used in the metadata document
+   * @param customEdmxVersion
+   * @return {@link ComplexType} for method chaining
+   */
+  public DataServices setCustomEdmxVersion(String customEdmxVersion) {
+    this.customEdmxVersion = customEdmxVersion;
+    return this;
+  }
+
+  /**
+   * @return collection of {@link AnnotationElement} annotation elements
+   */
+  public List<AnnotationElement> getAnnotationElements() {
+    return annotationElements;
+  }
+
+  /**
    * @return List<{@link Schema}>
    */
   public List<Schema> getSchemas() {
@@ -63,4 +92,11 @@ public class DataServices {
   public String getDataServiceVersion() {
     return dataServiceVersion;
   }
+
+  /**
+   * @return <b>String</b> custom edmx version
+   */
+  public String getCustomEdmxVersion() {
+    return customEdmxVersion;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
index 361a94e..438dd0b 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
@@ -31,6 +31,7 @@ import org.apache.olingo.odata2.api.edm.Edm;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.provider.DataServices;
 import org.apache.olingo.odata2.api.edm.provider.Schema;
 import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
 import org.apache.olingo.odata2.api.ep.feed.ODataDeltaFeed;
@@ -78,6 +79,22 @@ public final class EntityProvider {
         throws EntityProviderException;
 
     /**
+     * Write metadata document in XML format for the given schemas and the provided predefined
+     * namespaces at the EDMX element. PredefinedNamespaces is of type
+     * Map{@literal <}prefix,namespace{@literal >} and may be null or an empty Map.
+     * <b>Important<b>
+     * This method takes edmx references into account
+     * This method will not calculate the DataServiceVersion but will instead take the version provided via the
+     * signature if no version is set the default version 2.0 is used.
+     * @param serviceMetadata
+     * @param predefinedNamespaces type of Map{@literal <}prefix,namespace{@literal >} and may be null or an empty Map
+     * @return resulting {@link ODataResponse} with written metadata content.
+     * @throws EntityProviderException if writing of data (serialization) fails
+     */
+    ODataResponse writeMetadata(final DataServices serviceMetadata,
+        final Map<String, String> predefinedNamespaces) throws EntityProviderException;
+
+    /**
      * Write service document based on given {@link Edm} and <code>service root</code> as
      * given content type.
      * 
@@ -484,6 +501,21 @@ public final class EntityProvider {
   }
 
   /**
+   * Write metadata document in XML format for the given schemas and the provided predefined
+   * namespaces at the EDMX element. PredefinedNamespaces is of type
+   * Map{@literal <}prefix,namespace{@literal >} and may be null or an empty Map.
+   * 
+   * @param serviceMetadata
+   * @param predefinedNamespaces type of Map{@literal <}prefix,namespace{@literal >} and may be null or an empty Map
+   * @return resulting {@link ODataResponse} with written metadata content.
+   * @throws EntityProviderException if writing of data (serialization) fails
+   */
+  public static ODataResponse writeMetadata(final DataServices serviceMetadata,
+      final Map<String, String> predefinedNamespaces) throws EntityProviderException {
+    return createEntityProvider().writeMetadata(serviceMetadata, predefinedNamespaces);
+  }
+
+  /**
    * Write service document based on given {@link Edm} and <code>service root</code> as
    * given content type.
    * 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/BasicEntityProvider.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/BasicEntityProvider.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/BasicEntityProvider.java
index 56d34fc..7766431 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/BasicEntityProvider.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/BasicEntityProvider.java
@@ -232,12 +232,18 @@ public class BasicEntityProvider {
    */
   public ODataResponse writeMetadata(final List<Schema> schemas, final Map<String, String> predefinedNamespaces)
       throws EntityProviderException {
-    ODataResponseBuilder builder = ODataResponse.newBuilder();
     String dataServiceVersion = ODataServiceVersion.V10;
     if (schemas != null) {
       dataServiceVersion = calculateDataServiceVersion(schemas);
     }
     DataServices metadata = new DataServices().setSchemas(schemas).setDataServiceVersion(dataServiceVersion);
+    return writeMetadataInternal(predefinedNamespaces, dataServiceVersion, metadata);
+  }
+
+  private ODataResponse writeMetadataInternal(final Map<String, String> predefinedNamespaces, String dataServiceVersion,
+      DataServices metadata) throws EntityProviderException,
+      EntityProviderProducerException {
+    ODataResponseBuilder builder = ODataResponse.newBuilder();
     OutputStreamWriter writer = null;
     CircleStreamBuffer csb = new CircleStreamBuffer();
     try {
@@ -260,6 +266,21 @@ public class BasicEntityProvider {
   }
 
   /**
+   * Writes the metadata in XML format. Predefined namespaces is of type Map{@literal <}prefix,namespace{@literal >} and
+   * may be null or an empty Map.
+   * @param serviceMetadata
+   * @param predefinedNamespaces
+   * @return resulting {@link ODataResponse} with written metadata content
+   * @throws EntityProviderException
+   */
+  public ODataResponse writeMetadata(final DataServices serviceMetadata,
+      final Map<String, String> predefinedNamespaces) throws EntityProviderException {
+    String dataServiceVersion = serviceMetadata.getDataServiceVersion() == null ? ODataServiceVersion.V20
+        : serviceMetadata.getDataServiceVersion();
+    return writeMetadataInternal(predefinedNamespaces, dataServiceVersion, serviceMetadata);
+  }
+
+  /**
    * Calculates the necessary data service version for the metadata serialization
    * @param schemas
    * @return DataServiceversion as String

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
index 4937e30..739513c 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
@@ -31,6 +31,7 @@ import org.apache.olingo.odata2.api.edm.Edm;
 import org.apache.olingo.odata2.api.edm.EdmEntitySet;
 import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
+import org.apache.olingo.odata2.api.edm.provider.DataServices;
 import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
 import org.apache.olingo.odata2.api.edm.provider.Schema;
 import org.apache.olingo.odata2.api.ep.EntityProvider.EntityProviderInterface;
@@ -220,6 +221,12 @@ public class ProviderFacadeImpl implements EntityProviderInterface {
   }
 
   @Override
+  public ODataResponse writeMetadata(final DataServices seriviceMetadata,
+      final Map<String, String> predefinedNamespaces) throws EntityProviderException {
+    return create().writeMetadata(seriviceMetadata, predefinedNamespaces);
+  }
+
+  @Override
   public Edm readMetadata(final InputStream inputStream, final boolean validate) throws EntityProviderException {
     EdmProvider provider = new EdmxProvider().parse(inputStream, validate);
     return new EdmImplProv(provider);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
index f301482..6bba219 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlMetadataProducer.java
@@ -67,28 +67,48 @@ public class XmlMetadataProducer {
       Map<String, String> predefinedNamespaces) throws EntityProviderException {
 
     try {
+      String edmxNamespace = Edm.NAMESPACE_EDMX_2007_06;
+      String defaultNamespace = Edm.NAMESPACE_EDM_2008_09;
+
+      if (predefinedNamespaces == null) {
+        predefinedNamespaces = new HashMap<String, String>();
+      } else {
+        String predefinedEdmxNamespace = predefinedNamespaces.get(Edm.PREFIX_EDMX);
+        if (predefinedEdmxNamespace != null) {
+          edmxNamespace = predefinedEdmxNamespace;
+          predefinedNamespaces.remove(Edm.PREFIX_EDMX);
+        }
+        String predefinedDefaultNamespace = predefinedNamespaces.get(null);
+        if (predefinedDefaultNamespace != null) {
+          defaultNamespace = predefinedDefaultNamespace;
+          predefinedNamespaces.remove(null);
+        }
+      }
+
       xmlStreamWriter.writeStartDocument();
-      xmlStreamWriter.setPrefix(Edm.PREFIX_EDMX, Edm.NAMESPACE_EDMX_2007_06);
+      xmlStreamWriter.setPrefix(Edm.PREFIX_EDMX, edmxNamespace);
       xmlStreamWriter.setPrefix(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
-      xmlStreamWriter.setDefaultNamespace(Edm.NAMESPACE_EDM_2008_09);
 
-      xmlStreamWriter.writeStartElement(Edm.NAMESPACE_EDMX_2007_06, "Edmx");
-      xmlStreamWriter.writeAttribute("Version", "1.0");
-      xmlStreamWriter.writeNamespace(Edm.PREFIX_EDMX, Edm.NAMESPACE_EDMX_2007_06);
+      xmlStreamWriter.writeStartElement(edmxNamespace, "Edmx");
+      xmlStreamWriter.writeNamespace(Edm.PREFIX_EDMX, edmxNamespace);
+      if(metadata.getCustomEdmxVersion() == null){
+        xmlStreamWriter.writeAttribute("Version", "1.0");
+      }else {
+        xmlStreamWriter.writeAttribute("Version", metadata.getCustomEdmxVersion());
+      }
+
+      for (Map.Entry<String, String> entry : predefinedNamespaces.entrySet()) {
+        xmlStreamWriter.writeNamespace(entry.getKey(), entry.getValue());
+      }
+
+      writeAnnotationElements(metadata.getAnnotationElements(), predefinedNamespaces, xmlStreamWriter);
 
-      xmlStreamWriter.writeStartElement(Edm.NAMESPACE_EDMX_2007_06, XmlMetadataConstants.EDM_DATA_SERVICES);
+      xmlStreamWriter.writeStartElement(edmxNamespace, XmlMetadataConstants.EDM_DATA_SERVICES);
+      xmlStreamWriter.setDefaultNamespace(defaultNamespace);
       xmlStreamWriter.writeAttribute(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08,
           XmlMetadataConstants.EDM_DATA_SERVICE_VERSION, metadata.getDataServiceVersion());
       xmlStreamWriter.writeNamespace(Edm.PREFIX_M, Edm.NAMESPACE_M_2007_08);
 
-      if (predefinedNamespaces != null) {
-        for (Map.Entry<String, String> entry : predefinedNamespaces.entrySet()) {
-          xmlStreamWriter.writeNamespace(entry.getKey(), entry.getValue());
-        }
-      } else {
-        predefinedNamespaces = new HashMap<String, String>();
-      }
-
       Collection<Schema> schemas = metadata.getSchemas();
       if (schemas != null) {
         for (Schema schema : schemas) {
@@ -97,7 +117,7 @@ public class XmlMetadataProducer {
             xmlStreamWriter.writeAttribute(XmlMetadataConstants.EDM_SCHEMA_ALIAS, schema.getAlias());
           }
           xmlStreamWriter.writeAttribute(XmlMetadataConstants.EDM_SCHEMA_NAMESPACE, schema.getNamespace());
-          xmlStreamWriter.writeDefaultNamespace(Edm.NAMESPACE_EDM_2008_09);
+          xmlStreamWriter.writeDefaultNamespace(defaultNamespace);
 
           writeAnnotationAttributes(schema.getAnnotationAttributes(), predefinedNamespaces, null, xmlStreamWriter);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/BasicProviderTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/BasicProviderTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/BasicProviderTest.java
index ecefecd..031f692 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/BasicProviderTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/BasicProviderTest.java
@@ -26,14 +26,21 @@ import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
+import org.apache.olingo.odata2.api.ODataServiceVersion;
 import org.apache.olingo.odata2.api.edm.Edm;
 import org.apache.olingo.odata2.api.edm.EdmProperty;
 import org.apache.olingo.odata2.api.edm.EdmTyped;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationAttribute;
+import org.apache.olingo.odata2.api.edm.provider.AnnotationElement;
+import org.apache.olingo.odata2.api.edm.provider.DataServices;
 import org.apache.olingo.odata2.api.edm.provider.EdmProvider;
+import org.apache.olingo.odata2.api.edm.provider.Schema;
 import org.apache.olingo.odata2.api.ep.EntityProviderException;
 import org.apache.olingo.odata2.api.processor.ODataResponse;
 import org.apache.olingo.odata2.core.commons.ContentType;
@@ -63,7 +70,8 @@ public class BasicProviderTest extends AbstractProviderTest {
     predefinedNamespaces.put("annoPrefix2", "http://annoNamespace");
     predefinedNamespaces.put("annoPrefix", "http://annoNamespace");
 
-    ODataResponse response = provider.writeMetadata(null, predefinedNamespaces);
+    List<Schema> schemas = null;
+    ODataResponse response = provider.writeMetadata(schemas, predefinedNamespaces);
     assertNotNull(response);
     assertNotNull(response.getEntity());
     assertNull("BasicProvider should not set content header", response.getContentHeader());
@@ -131,6 +139,69 @@ public class BasicProviderTest extends AbstractProviderTest {
   }
 
   @Test
+  public void metadataWithReferences() throws Exception {
+    DataServices serviceMetadata = new DataServices();
+    List<AnnotationElement> annoElements = new ArrayList<AnnotationElement>();
+    annoElements.add(createElementWithoutInclude());
+    annoElements.add(createElementWithInclude());
+    serviceMetadata.setAnnotationElements(annoElements);
+    serviceMetadata.setDataServiceVersion(ODataServiceVersion.V20);
+    ODataResponse response = provider.writeMetadata(serviceMetadata, null);
+    assertNotNull(response);
+    assertNotNull(response.getEntity());
+    assertNull("BasicProvider should not set content header", response.getContentHeader());
+    String metadata = StringHelper.inputStreamToString((InputStream) response.getEntity());
+    assertTrue(metadata.contains(
+        "edmx:Reference xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\" Uri=\"http://someurl.com\""));
+    assertTrue(metadata.contains("edmx:Include xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\""));
+  }
+  
+  @Test
+  public void metadataWithReferencesAndPredefinedNamespaces() throws Exception {
+    DataServices serviceMetadata = new DataServices();
+    serviceMetadata.setCustomEdmxVersion("4.0");
+    List<AnnotationElement> annoElements = new ArrayList<AnnotationElement>();
+    annoElements.add(createElementWithoutInclude());
+    annoElements.add(createElementWithInclude());
+    serviceMetadata.setAnnotationElements(annoElements);
+    serviceMetadata.setDataServiceVersion("4.0");
+    
+    Map<String, String> predefinedNamespaces = new HashMap<String, String>();
+    predefinedNamespaces.put("edmx", "http://docs.oasis-open.org/odata/ns/edmx");
+    predefinedNamespaces.put(null, "http://docs.oasis-open.org/odata/ns/edmx");
+    
+    ODataResponse response = provider.writeMetadata(serviceMetadata, predefinedNamespaces);
+    assertNotNull(response);
+    assertNotNull(response.getEntity());
+    assertNull("BasicProvider should not set content header", response.getContentHeader());
+    String metadata = StringHelper.inputStreamToString((InputStream) response.getEntity());
+    assertTrue(metadata.contains(
+        "edmx:Reference xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\" Uri=\"http://someurl.com\""));
+    assertTrue(metadata.contains("edmx:Include xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\""));
+    assertTrue(metadata.contains("edmx:Edmx xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\" Version=\"4.0\""));
+  }
+
+  private AnnotationElement createElementWithInclude() {
+    List<AnnotationAttribute> childAttributes = new ArrayList<AnnotationAttribute>();
+    childAttributes.add(new AnnotationAttribute().setName("Namespace").setText("Org.OData.Core.V1"));
+    childAttributes.add(new AnnotationAttribute().setName("Alias").setText("UI"));
+    List<AnnotationElement> childElements = new ArrayList<AnnotationElement>();
+    childElements.add(new AnnotationElement().setName("Include").setNamespace(
+        "http://docs.oasis-open.org/odata/ns/edmx").setPrefix("edmx").setAttributes(childAttributes));
+    List<AnnotationAttribute> referenceAttributes = new ArrayList<AnnotationAttribute>();
+    referenceAttributes.add(new AnnotationAttribute().setName("Uri").setText("http://someurl2.com"));
+    return new AnnotationElement().setName("Reference").setPrefix("edmx").setNamespace(
+        "http://docs.oasis-open.org/odata/ns/edmx").setAttributes(referenceAttributes).setChildElements(childElements);
+  }
+
+  private AnnotationElement createElementWithoutInclude() {
+    List<AnnotationAttribute> referenceAttributes = new ArrayList<AnnotationAttribute>();
+    referenceAttributes.add(new AnnotationAttribute().setName("Uri").setText("http://someurl.com"));
+    return new AnnotationElement().setName("Reference").setPrefix("edmx").setNamespace(
+        "http://docs.oasis-open.org/odata/ns/edmx").setAttributes(referenceAttributes);
+  }
+
+  @Test
   public void writeMetadata3() throws Exception {
     EdmProvider testProvider = new EdmTestProvider();
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumerTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumerTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumerTest.java
index 83d234f..ec8e96c 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumerTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlMetadataConsumerTest.java
@@ -26,12 +26,14 @@ import static org.junit.Assert.fail;
 
 import java.io.InputStream;
 import java.io.StringReader;
+import java.util.ArrayList;
 import java.util.List;
 
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 
+import org.apache.olingo.odata2.api.ODataServiceVersion;
 import org.apache.olingo.odata2.api.edm.Edm;
 import org.apache.olingo.odata2.api.edm.EdmAction;
 import org.apache.olingo.odata2.api.edm.EdmConcurrencyMode;
@@ -177,7 +179,7 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
       + "<EntityType Name= \"Photo\"><Key><PropertyRef Name=\"Id\"/></Key><Property Name=\"Id\" Type=\"Edm.Int32\" " +
       "Nullable=\"false\" MaxLength=\"Max\"/><Property Name=\"Name\" Type=\"Edm.Int32\" MaxLength=\"max\"/>"
       + "</EntityType></Schema></edmx:DataServices></edmx:Edmx>";
-  
+
   @Test
   public void testMetadataDokumentWithWhitepaces() throws Exception {
     final String metadata = ""
@@ -197,11 +199,11 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
         + "       </Schema>"
         + "  </edmx:DataServices>"
         + "</edmx:Edmx>";
-    
+
     XmlMetadataConsumer parser = new XmlMetadataConsumer();
     XMLStreamReader reader = createStreamReader(metadata);
     DataServices result = parser.readMetadata(reader, true);
-    
+
     assertEquals(1, result.getSchemas().size());
     List<EntityType> entityTypes = result.getSchemas().get(0).getEntityTypes();
     assertEquals(1, entityTypes.size());
@@ -211,11 +213,11 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
     AnnotationElement annotationElement = annotationElements.get(0);
     List<AnnotationElement> childElements = annotationElement.getChildElements();
     assertEquals(2, childElements.size());
-    
+
     assertEquals(" value1", childElements.get(0).getText());
     assertEquals("value2", childElements.get(1).getText());
   }
-  
+
   @Test
   public void testMetadataDokumentWithWhitepacesMultiline() throws Exception {
     final String metadata = ""
@@ -236,11 +238,11 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
         + "       </Schema>"
         + "  </edmx:DataServices>"
         + "</edmx:Edmx>";
-    
+
     XmlMetadataConsumer parser = new XmlMetadataConsumer();
     XMLStreamReader reader = createStreamReader(metadata);
     DataServices result = parser.readMetadata(reader, true);
-    
+
     assertEquals(1, result.getSchemas().size());
     List<EntityType> entityTypes = result.getSchemas().get(0).getEntityTypes();
     assertEquals(1, entityTypes.size());
@@ -250,12 +252,12 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
     AnnotationElement annotationElement = annotationElements.get(0);
     List<AnnotationElement> childElements = annotationElement.getChildElements();
     assertEquals(2, childElements.size());
-    
-    assertEquals(" value1\n" + 
+
+    assertEquals(" value1\n" +
         "                 long long long multiline attribute", childElements.get(0).getText());
     assertEquals("value2", childElements.get(1).getText());
   }
-  
+
   @Test
   public void testMetadataDokumentWithWhitepaces2() throws Exception {
     final String metadata = ""
@@ -274,11 +276,11 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
         + "       </Schema>"
         + "  </edmx:DataServices>"
         + "</edmx:Edmx>";
-    
+
     XmlMetadataConsumer parser = new XmlMetadataConsumer();
     XMLStreamReader reader = createStreamReader(metadata);
     DataServices result = parser.readMetadata(reader, true);
-    
+
     assertEquals(1, result.getSchemas().size());
     List<EntityType> entityTypes = result.getSchemas().get(0).getEntityTypes();
     assertEquals(1, entityTypes.size());
@@ -288,10 +290,10 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
     AnnotationElement annotationElement = annotationElements.get(0);
     List<AnnotationElement> childElements = annotationElement.getChildElements();
     assertEquals(1, childElements.size());
-    
+
     assertEquals(" value1", childElements.get(0).getText());
   }
-  
+
   @Test
   public void stringValueForMaxLegthFacet() throws Exception {
     XmlMetadataConsumer parser = new XmlMetadataConsumer();
@@ -736,7 +738,6 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
         assertEquals(EdmSimpleTypeKind.Int32, functionImport1.getParameters().get(1).getType());
         assertEquals(Boolean.FALSE, functionImport1.getParameters().get(1).getFacets().isNullable());
 
-
         FunctionImport functionImport2 = container.getFunctionImports().get(1);
         assertEquals("RoomSearch", functionImport2.getName());
         assertEquals("Rooms", functionImport2.getEntitySet());
@@ -745,12 +746,12 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
         assertEquals(EdmMultiplicity.MANY, functionImport2.getReturnType().getMultiplicity());
         assertEquals("GET", functionImport2.getHttpMethod());
         assertEquals(2, functionImport2.getParameters().size());
-        assertEquals(new FullQualifiedName("RefScenario","Room"),
+        assertEquals(new FullQualifiedName("RefScenario", "Room"),
             functionImport2.getReturnType().getTypeName());
         assertEquals(EdmMultiplicity.MANY, functionImport2.getReturnType().getMultiplicity());
 
         FunctionImportParameter functionImportParameter = functionImport2.getParameters().get(0);
-    		assertEquals("q1", functionImportParameter.getName());
+        assertEquals("q1", functionImportParameter.getName());
         assertEquals(EdmSimpleTypeKind.String, functionImport2.getParameters().get(0).getType());
         assertEquals(Boolean.TRUE, functionImport2.getParameters().get(0).getFacets().isNullable());
         assertEquals("In", functionImportParameter.getMode());
@@ -758,7 +759,7 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
         assertEquals("q2", functionImport2.getParameters().get(1).getName());
         assertEquals(EdmSimpleTypeKind.Int32, functionImport2.getParameters().get(1).getType());
         assertEquals(Boolean.FALSE, functionImport2.getParameters().get(1).getFacets().isNullable());
-        assertEquals(null, functionImport2.getParameters().get(1).getMode()); 
+        assertEquals(null, functionImport2.getParameters().get(1).getMode());
 
         FunctionImport functionImport3 = container.getFunctionImports().get(2);
         assertEquals("NoParamters", functionImport3.getName());
@@ -1464,6 +1465,39 @@ public class XmlMetadataConsumerTest extends AbstractXmlConsumerTest {
     }
   }
 
+  @Test
+  public void edmxReferences() throws Exception {
+    DataServices serviceMetadata = new DataServices();
+    List<AnnotationElement> annoElements = new ArrayList<AnnotationElement>();
+    annoElements.add(createElementWithoutInclude());
+    annoElements.add(createElementWithInclude());
+    serviceMetadata.setAnnotationElements(annoElements);
+    serviceMetadata.setDataServiceVersion(ODataServiceVersion.V20);
+    ODataResponse response = EntityProvider.writeMetadata(serviceMetadata, null);
+
+    EntityProvider.readMetadata(response.getEntityAsStream(), false);
+  }
+
+  private AnnotationElement createElementWithInclude() {
+    List<AnnotationAttribute> childAttributes = new ArrayList<AnnotationAttribute>();
+    childAttributes.add(new AnnotationAttribute().setName("Namespace").setText("Org.OData.Core.V1"));
+    childAttributes.add(new AnnotationAttribute().setName("Alias").setText("UI"));
+    List<AnnotationElement> childElements = new ArrayList<AnnotationElement>();
+    childElements.add(new AnnotationElement().setName("Include").setNamespace(
+        "http://docs.oasis-open.org/odata/ns/edmx").setPrefix("edmx").setAttributes(childAttributes));
+    List<AnnotationAttribute> referenceAttributes = new ArrayList<AnnotationAttribute>();
+    referenceAttributes.add(new AnnotationAttribute().setName("Uri").setText("http://someurl2.com"));
+    return new AnnotationElement().setName("Reference").setPrefix("edmx").setNamespace(
+        "http://docs.oasis-open.org/odata/ns/edmx").setAttributes(referenceAttributes).setChildElements(childElements);
+  }
+
+  private AnnotationElement createElementWithoutInclude() {
+    List<AnnotationAttribute> referenceAttributes = new ArrayList<AnnotationAttribute>();
+    referenceAttributes.add(new AnnotationAttribute().setName("Uri").setText("http://someurl.com"));
+    return new AnnotationElement().setName("Reference").setPrefix("edmx").setNamespace(
+        "http://docs.oasis-open.org/odata/ns/edmx").setAttributes(referenceAttributes);
+  }
+
   private XMLStreamReader createStreamReader(final String xml) throws XMLStreamException {
     XMLInputFactory factory = XMLInputFactory.newInstance();
     factory.setProperty(XMLInputFactory.IS_VALIDATING, false);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/546466ce/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
index dec3ff8..80a2be6 100644
--- a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
+++ b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
@@ -53,25 +53,26 @@ public class BatchTest extends AbstractRefTest {
     String responseBody = execute("/simple.batch");
     assertFalse(responseBody
         .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">"));
-    assertTrue(responseBody.contains("<edmx:Edmx Version=\"1.0\""));
+    assertTrue(responseBody.contains(
+        "<edmx:Edmx xmlns:edmx=\"http://schemas.microsoft.com/ado/2007/06/edmx\" Version=\"1.0\""));
   }
-  
+
   @Test
   public void functionImportBatch() throws Exception {
-	    String responseBody = execute("/functionImport.batch");
-	    assertFalse(responseBody
-	        .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">"));
-	    assertTrue(responseBody.contains("HTTP/1.1 200 OK"));
-	    assertTrue(responseBody.contains("<?xml version='1.0' encoding='utf-8'?><ManagerPhoto xmlns="));
+    String responseBody = execute("/functionImport.batch");
+    assertFalse(responseBody
+        .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">"));
+    assertTrue(responseBody.contains("HTTP/1.1 200 OK"));
+    assertTrue(responseBody.contains("<?xml version='1.0' encoding='utf-8'?><ManagerPhoto xmlns="));
   }
-  
+
   @Test
   public void employeesWithFilterBatch() throws Exception {
-	    String responseBody = execute("/employeesWithFilter.batch");
-	    assertFalse(responseBody
-	        .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">"));
-	    assertTrue(responseBody.contains("HTTP/1.1 200 OK"));
-	    assertTrue(responseBody.contains("<d:EmployeeName>Walter Winter</d:EmployeeName>"));
+    String responseBody = execute("/employeesWithFilter.batch");
+    assertFalse(responseBody
+        .contains("<error xmlns=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\">"));
+    assertTrue(responseBody.contains("HTTP/1.1 200 OK"));
+    assertTrue(responseBody.contains("<d:EmployeeName>Walter Winter</d:EmployeeName>"));
   }
 
   @Test


[2/2] olingo-odata2 git commit: [OLINGO-1006] Fix batch issue with additional segments

Posted by ch...@apache.org.
[OLINGO-1006] Fix batch issue with additional segments


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/8d90a160
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/8d90a160
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/8d90a160

Branch: refs/heads/master
Commit: 8d90a160634b6df41b011825bbbb9bc038d95bd7
Parents: 546466c
Author: Christian Amend <ch...@sap.com>
Authored: Thu Aug 4 16:25:49 2016 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Wed Aug 17 14:32:20 2016 +0200

----------------------------------------------------------------------
 .../apache/olingo/odata2/api/uri/PathInfo.java  |   2 +-
 .../odata2/core/batch/BatchHandlerImpl.java     |   8 +-
 .../odata2/core/batch/v2/BatchParser.java       |  13 +-
 .../odata2/core/batch/BatchHandlerTest.java     | 248 +++++++++++++++++++
 .../resources/batchContentIdReferencing.batch   |  27 ++
 .../odata2/fit/client/ClientBatchTest.java      |  12 +-
 6 files changed, 286 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/8d90a160/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/PathInfo.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/PathInfo.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/PathInfo.java
index 0e59a24..8df6ee2 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/PathInfo.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/uri/PathInfo.java
@@ -41,7 +41,7 @@ public interface PathInfo {
   List<PathSegment> getODataSegments();
 
   /**
-   * Gets the root URI of this service.
+   * Gets the root URI of this service. This includes any segments which can be found in the preceding segments list.
    * @return absolute base URI of the request
    */
   URI getServiceRoot();

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/8d90a160/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
index 75eb265..64f8e22 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
@@ -109,7 +109,7 @@ public class BatchHandlerImpl implements BatchHandler {
 
   private void fillContentIdMap(final ODataResponse response, final String contentId, final String baseUri) {
     String location = response.getHeader(HttpHeaders.LOCATION);
-    if(location != null) {
+    if (location != null) {
       String relLocation = location.replace(baseUri + "/", "");
       contentIdMap.put("$" + contentId, relLocation);
     }
@@ -119,7 +119,7 @@ public class BatchHandlerImpl implements BatchHandler {
       throws ODataException {
     String contentId = contentIdMap.get(odataSegments.get(0).getPath());
     if (contentId == null) {
-      //invalid content ID. But throwing an exception here is wrong so we use the base request and fail later
+      // invalid content ID. But throwing an exception here is wrong so we use the base request and fail later
       return request;
     }
     PathInfoImpl pathInfo = new PathInfoImpl();
@@ -171,13 +171,11 @@ public class BatchHandlerImpl implements BatchHandler {
   }
 
   private String getBaseUri(final ODataRequest request) {
+    // The service root already contains any additional path parameters
     String baseUri = request.getPathInfo().getServiceRoot().toASCIIString();
     if (baseUri.endsWith("/")) {
       baseUri = baseUri.substring(0, baseUri.length() - 1);
     }
-    for (PathSegment segment : request.getPathInfo().getPrecedingSegments()) {
-      baseUri += "/" + segment.getPath();
-    }
     return baseUri;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/8d90a160/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java
index 7f53e0d..a79714b 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParser.java
@@ -29,7 +29,6 @@ import org.apache.olingo.odata2.api.batch.BatchRequestPart;
 import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
 import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
 import org.apache.olingo.odata2.api.uri.PathInfo;
-import org.apache.olingo.odata2.api.uri.PathSegment;
 import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
 
 public class BatchParser {
@@ -103,18 +102,10 @@ public class BatchParser {
   private String getBaseUri() throws BatchException {
     String baseUri = "";
 
+    //The service root already contains any additional path parameters
     if (batchRequestPathInfo != null && batchRequestPathInfo.getServiceRoot() != null) {
       final String uri = batchRequestPathInfo.getServiceRoot().toASCIIString();
-
-      baseUri = addPathSegements(removeLastSlash(uri));
-    }
-
-    return baseUri;
-  }
-
-  private String addPathSegements(String baseUri) {
-    for (PathSegment precedingPS : batchRequestPathInfo.getPrecedingSegments()) {
-      baseUri = baseUri + "/" + precedingPS.getPath();
+      baseUri = removeLastSlash(uri);
     }
 
     return baseUri;

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/8d90a160/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchHandlerTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchHandlerTest.java
new file mode 100644
index 0000000..218e163
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchHandlerTest.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * 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.batch;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.ODataServiceFactory;
+import org.apache.olingo.odata2.api.batch.BatchHandler;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
+import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataProcessor;
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.processor.part.BatchProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityMediaProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntityProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntitySetProcessor;
+import org.apache.olingo.odata2.api.processor.part.EntitySimplePropertyProcessor;
+import org.apache.olingo.odata2.api.uri.PathInfo;
+import org.apache.olingo.odata2.api.uri.PathSegment;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
+import org.apache.olingo.odata2.api.uri.info.GetSimplePropertyUriInfo;
+import org.apache.olingo.odata2.api.uri.info.PostUriInfo;
+import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo;
+import org.apache.olingo.odata2.core.ODataPathSegmentImpl;
+import org.apache.olingo.odata2.core.PathInfoImpl;
+import org.apache.olingo.odata2.testutil.helper.StringHelper;
+import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Before;
+import org.junit.Test;
+
+public class BatchHandlerTest {
+
+  private BatchHandler handler;
+  private static final String CONTENT_TYPE = "multipart/mixed; boundary=batch_123";
+  private static final String CRLF = "\r\n";
+  private static String SERVICE_BASE = "http://localhost/odata/";
+  private static String SERVICE_ROOT = null;
+
+  @Before
+  public void setupBatchHandler() throws Exception {
+    ODataProcessor processor = new LocalProcessor();
+    ODataService serviceMock = mock(ODataService.class);
+    when(serviceMock.getBatchProcessor()).thenReturn((BatchProcessor) processor);
+    when(serviceMock.getEntitySetProcessor()).thenReturn((EntitySetProcessor) processor);
+    when(serviceMock.getEntitySimplePropertyProcessor()).thenReturn((EntitySimplePropertyProcessor) processor);
+    when(serviceMock.getProcessor()).thenReturn(processor);
+    Edm mockEdm = MockFacade.getMockEdm();
+    when(serviceMock.getEntityDataModel()).thenReturn(mockEdm);
+    List<String> supportedContentTypes = Arrays.asList("application/json;charset=utf-8", "application/json");
+    when(serviceMock.getSupportedContentTypes(EntityMediaProcessor.class)).thenReturn(supportedContentTypes);
+    when(serviceMock.getSupportedContentTypes(EntityProcessor.class)).thenReturn(supportedContentTypes);
+    when(serviceMock.getSupportedContentTypes(EntitySimplePropertyProcessor.class)).thenReturn(supportedContentTypes);
+    handler = new BatchHandlerImpl(mock(ODataServiceFactory.class), serviceMock);
+  }
+
+  @Test
+  public void contentIdReferencing() throws Exception {
+    SERVICE_ROOT = SERVICE_BASE;
+    PathInfoImpl pathInfo = new PathInfoImpl();
+    pathInfo.setServiceRoot(new URI(SERVICE_ROOT));
+    List<PathSegment> odataPathSegements = new ArrayList<PathSegment>();
+    odataPathSegements.add(new ODataPathSegmentImpl("$batch", null));
+    pathInfo.setODataPathSegment(odataPathSegements);
+    EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
+    InputStream content = readFile("/batchContentIdReferencing.batch");
+    List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties);
+
+    PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo();
+    assertFirst(firstPathInfo);
+
+    handler.handleBatchPart(parsedRequest.get(0));
+  }
+
+  @Test
+  public void contentIdReferencingWithAdditionalSegments() throws Exception {
+    SERVICE_ROOT = SERVICE_BASE + "seg1/seg2/";
+    PathInfoImpl pathInfo = new PathInfoImpl();
+    List<PathSegment> precedingPathSegements = new ArrayList<PathSegment>();
+    precedingPathSegements.add(new ODataPathSegmentImpl("seg1", null));
+    precedingPathSegements.add(new ODataPathSegmentImpl("seg2", null));
+    pathInfo.setPrecedingPathSegment(precedingPathSegements);
+    pathInfo.setServiceRoot(new URI(SERVICE_ROOT));
+    List<PathSegment> odataPathSegements = new ArrayList<PathSegment>();
+    odataPathSegements.add(new ODataPathSegmentImpl("$batch", null));
+    pathInfo.setODataPathSegment(odataPathSegements);
+    EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
+    InputStream content = readFile("/batchContentIdReferencing.batch");
+    List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties);
+
+    PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo();
+    assertFirst(firstPathInfo);
+
+    handler.handleBatchPart(parsedRequest.get(0));
+  }
+  
+  @Test
+  public void contentIdReferencingWithAdditionalSegmentsAndMatrixParameter() throws Exception {
+    SERVICE_ROOT = SERVICE_BASE + "seg1;v=1/seg2;v=2/";
+    PathInfoImpl pathInfo = new PathInfoImpl();
+    List<PathSegment> precedingPathSegements = new ArrayList<PathSegment>();
+    HashMap<String, List<String>> matrixParameters1 = new HashMap<String, List<String>>();
+    matrixParameters1.put("v", Arrays.asList("1"));
+    HashMap<String, List<String>> matrixParameters2 = new HashMap<String, List<String>>();
+    matrixParameters1.put("v", Arrays.asList("2"));
+    precedingPathSegements.add(new ODataPathSegmentImpl("seg1", matrixParameters1));
+    precedingPathSegements.add(new ODataPathSegmentImpl("seg2", matrixParameters2));
+    pathInfo.setPrecedingPathSegment(precedingPathSegements);
+    pathInfo.setServiceRoot(new URI(SERVICE_ROOT));
+    List<PathSegment> odataPathSegements = new ArrayList<PathSegment>();
+    odataPathSegements.add(new ODataPathSegmentImpl("$batch", null));
+    pathInfo.setODataPathSegment(odataPathSegements);
+    EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
+    InputStream content = readFile("/batchContentIdReferencing.batch");
+    List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties);
+
+    PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo();
+    assertFirst(firstPathInfo);
+
+    handler.handleBatchPart(parsedRequest.get(0));
+  }
+
+  private void assertFirst(PathInfo pathInfo) {
+    assertEquals(SERVICE_ROOT + "Employees", pathInfo.getRequestUri().toString());
+    assertEquals(SERVICE_ROOT, pathInfo.getServiceRoot().toString());
+  }
+
+  private InputStream readFile(String fileName) throws IOException {
+    InputStream in = ClassLoader.class.getResourceAsStream(fileName);
+    if (in == null) {
+      throw new IOException("Requested file '" + fileName + "' was not found.");
+    }
+
+    return StringHelper.toStream(in).asStreamWithLineSeparation(CRLF);
+  }
+
+  public class LocalProcessor implements BatchProcessor, EntitySetProcessor, EntitySimplePropertyProcessor {
+
+    private ODataContext context;
+
+    @Override
+    public void setContext(ODataContext context) throws ODataException {
+      this.context = context;
+    }
+
+    @Override
+    public ODataContext getContext() throws ODataException {
+      return context;
+    }
+
+    @Override
+    public BatchResponsePart executeChangeSet(BatchHandler handler, List<ODataRequest> requests) throws ODataException {
+      List<ODataResponse> responses = new ArrayList<ODataResponse>();
+
+      // handle create
+      ODataResponse response = handler.handleRequest(requests.get(0));
+      assertEquals(HttpStatusCodes.OK, response.getStatus());
+      assertEquals(SERVICE_ROOT + "Employees('1')", response.getIdLiteral());
+      responses.add(response);
+
+      // handle update
+      response = handler.handleRequest(requests.get(1));
+      assertEquals(HttpStatusCodes.OK, response.getStatus());
+      responses.add(response);
+
+      return BatchResponsePart.responses(responses).changeSet(true).build();
+    }
+
+    @Override
+    public ODataResponse createEntity(PostUriInfo uriInfo, InputStream content, String requestContentType,
+        String contentType) throws ODataException {
+      PathInfo pathInfo = getContext().getPathInfo();
+      assertFirst(pathInfo);
+      assertEquals("Employees", uriInfo.getTargetEntitySet().getName());
+      return ODataResponse.newBuilder().status(HttpStatusCodes.OK).idLiteral(SERVICE_ROOT + "Employees('1')").build();
+    }
+
+    @Override
+    public ODataResponse updateEntitySimpleProperty(PutMergePatchUriInfo uriInfo, InputStream content,
+        String requestContentType, String contentType) throws ODataException {
+      PathInfo pathInfo = getContext().getPathInfo();
+      assertEquals(SERVICE_ROOT + "Employees('1')/EmployeeName", pathInfo.getRequestUri().toString());
+      assertEquals(SERVICE_ROOT, pathInfo.getServiceRoot().toString());
+      assertEquals("Employees", uriInfo.getTargetEntitySet().getName());
+      return ODataResponse.newBuilder().status(HttpStatusCodes.OK).build();
+    }
+
+    @Override
+    public ODataResponse readEntitySimpleProperty(GetSimplePropertyUriInfo uriInfo, String contentType)
+        throws ODataException {
+      // this method is not needed.
+      return null;
+    }
+
+    @Override
+    public ODataResponse readEntitySet(GetEntitySetUriInfo uriInfo, String contentType) throws ODataException {
+      // this method is not needed.
+      return null;
+    }
+
+    @Override
+    public ODataResponse countEntitySet(GetEntitySetCountUriInfo uriInfo, String contentType) throws ODataException {
+      // this method is not needed.
+      return null;
+    }
+
+    @Override
+    public ODataResponse executeBatch(BatchHandler handler, String contentType, InputStream content)
+        throws ODataException {
+      // this method is not needed.
+      return null;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/8d90a160/odata2-lib/odata-core/src/test/resources/batchContentIdReferencing.batch
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/resources/batchContentIdReferencing.batch b/odata2-lib/odata-core/src/test/resources/batchContentIdReferencing.batch
new file mode 100644
index 0000000..087f662
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/resources/batchContentIdReferencing.batch
@@ -0,0 +1,27 @@
+--batch_123
+Content-Type: multipart/mixed; boundary=changeset_b4d2651f-4c8e-4707-8ac3-5bdde1e25760
+
+--changeset_b4d2651f-4c8e-4707-8ac3-5bdde1e25760
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-Id: 1
+
+POST Employees HTTP/1.1
+Content-Length: 23
+Accept: application/json
+content-type: application/json
+
+gAAAAgABwESAAMAAAABAAEA
+--changeset_b4d2651f-4c8e-4707-8ac3-5bdde1e25760
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-Id: 2
+
+PUT $1/EmployeeName HTTP/1.1
+Content-Length: 41
+Accept: application/json
+content-type: application/json
+
+{"EmployeeName":"Frederic Fall MODIFIED"}
+--changeset_b4d2651f-4c8e-4707-8ac3-5bdde1e25760--
+--batch_123--
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/8d90a160/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
index 3ab22f6..83dff6f 100644
--- a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
+++ b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
@@ -45,10 +45,8 @@ import org.apache.olingo.odata2.api.ep.EntityProvider;
 import org.apache.olingo.odata2.fit.ref.AbstractRefTest;
 import org.apache.olingo.odata2.testutil.helper.StringHelper;
 import org.apache.olingo.odata2.testutil.server.ServletType;
-import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore
 public class ClientBatchTest extends AbstractRefTest {
   public ClientBatchTest(final ServletType servletType) {
     super(servletType);
@@ -66,7 +64,7 @@ public class ClientBatchTest extends AbstractRefTest {
     batch.add(request);
 
     InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
-    String batchRequestBody = StringHelper.inputStreamToString(body, true);
+    String batchRequestBody = StringHelper.inputStreamToStringCRLFLineBreaks(body);
     checkMimeHeaders(batchRequestBody);
     checkBoundaryDelimiters(batchRequestBody);
     assertTrue(batchRequestBody.contains("GET $metadata HTTP/1.1"));
@@ -78,7 +76,7 @@ public class ClientBatchTest extends AbstractRefTest {
     for (BatchSingleResponse response : responses) {
       assertEquals("200", response.getStatusCode());
       assertEquals("OK", response.getStatusInfo());
-      assertTrue(response.getBody().contains("<edmx:Edmx Version=\"1.0\""));
+      assertTrue(response.getBody().contains("<edmx:Edmx"));
       assertEquals("application/xml;charset=utf-8", response.getHeader(HttpHeaders.CONTENT_TYPE));
       assertNotNull(response.getHeader(HttpHeaders.CONTENT_LENGTH));
     }
@@ -106,7 +104,7 @@ public class ClientBatchTest extends AbstractRefTest {
     batch.add(request);
 
     InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
-    String bodyAsString = StringHelper.inputStreamToString(body, true);
+    String bodyAsString = StringHelper.inputStreamToStringCRLFLineBreaks(body);
     checkMimeHeaders(bodyAsString);
     checkBoundaryDelimiters(bodyAsString);
 
@@ -214,7 +212,7 @@ public class ClientBatchTest extends AbstractRefTest {
     batch.add(request);
 
     InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
-    String bodyAsString = StringHelper.inputStreamToString(body, true);
+    String bodyAsString = StringHelper.inputStreamToStringCRLFLineBreaks(body);
     checkMimeHeaders(bodyAsString);
     checkBoundaryDelimiters(bodyAsString);
     assertTrue(bodyAsString.contains("POST Employees HTTP/1.1"));
@@ -250,7 +248,7 @@ public class ClientBatchTest extends AbstractRefTest {
     batch.add(request);
 
     InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
-    String bodyAsString = StringHelper.inputStreamToString(body, true);
+    String bodyAsString = StringHelper.inputStreamToStringCRLFLineBreaks(body);
     checkMimeHeaders(bodyAsString);
     checkBoundaryDelimiters(bodyAsString);