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 2014/10/06 13:58:27 UTC

[1/4] git commit: Code Review - Bug fix and refactoring

Repository: olingo-odata2
Updated Branches:
  refs/heads/olingo436BatchRefactoring ffb21db2d -> f0dc0f745


Code Review - Bug fix and refactoring

Signed-off-by: Christian Amend <ch...@apache.org>


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

Branch: refs/heads/olingo436BatchRefactoring
Commit: 1f90b733a25a41c43f93ceb0f78369e6c27ef753
Parents: ffb21db
Author: Christian Holzer <c....@sap.com>
Authored: Thu Oct 2 19:12:38 2014 +0200
Committer: Christian Amend <ch...@apache.org>
Committed: Mon Oct 6 13:54:37 2014 +0200

----------------------------------------------------------------------
 .../olingo/odata2/core/batch/AcceptParser.java  |  64 +++++--
 .../odata2/core/batch/v2/BatchBodyPart.java     |  27 +--
 .../odata2/core/batch/v2/BatchChangeSet.java    |  55 ------
 .../core/batch/v2/BatchChangeSetPart.java       |  55 ++++++
 .../odata2/core/batch/v2/BatchParser.java       |   2 +-
 .../odata2/core/batch/v2/BatchParserCommon.java | 122 +++++++------
 .../core/batch/v2/BatchQueryOperation.java      |  10 +-
 .../batch/v2/BatchRequestTransformator.java     |  16 +-
 .../batch/v2/BatchResponseTransformator.java    |  13 +-
 .../core/batch/v2/BatchTransformatorCommon.java |  24 +--
 .../odata2/core/batch/AcceptParserTest.java     |  77 +++++---
 .../core/batch/BatchParserCommonTest.java       | 182 +++++++++++++++----
 .../core/batch/BatchRequestParserTest.java      | 124 +++++++++----
 .../batch/BatchTransformatorCommonTest.java     |  12 +-
 14 files changed, 516 insertions(+), 267 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java
index 946fccf..48bfb1b 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/AcceptParser.java
@@ -6,9 +6,9 @@
  * 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
@@ -20,6 +20,7 @@ package org.apache.olingo.odata2.core.batch;
 
 import java.util.ArrayList;
 import java.util.Comparator;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Scanner;
@@ -30,10 +31,11 @@ import java.util.regex.Pattern;
 import org.apache.olingo.odata2.api.batch.BatchException;
 
 /**
- *  
+ *
  */
 public class AcceptParser {
 
+  private static final String COMMA = ",";
   private static final String BAD_REQUEST = "400";
   private static final String ALL = "*";
   private static final String REG_EX_QUALITY_FACTOR = "q=((?:1\\.0{0,3})|(?:0\\.[0-9]{0,2}[1-9]))";
@@ -48,10 +50,15 @@ public class AcceptParser {
 
   private static final double QUALITY_PARAM_FACTOR = 0.001;
 
-  public static List<String> parseAcceptHeaders(final String headerValue) throws BatchException {
-    TreeSet<Accept> acceptTree = getAcceptTree();
-    List<String> acceptHeaders = new ArrayList<String>();
-    Scanner acceptHeaderScanner = new Scanner(headerValue);
+  private List<String> acceptHeaderValues = new ArrayList<String>();
+  private List<String> acceptLanguageHeaderValues = new ArrayList<String>();
+
+  public List<String> parseAcceptHeaders() throws BatchException {
+    final String headerValue = concatenateHeaderLines(acceptHeaderValues);
+    final TreeSet<Accept> acceptTree = getAcceptTree();
+    final List<String> acceptHeaders = new ArrayList<String>();
+    final Scanner acceptHeaderScanner = new Scanner(headerValue);
+
     acceptHeaderScanner.useDelimiter(",\\s?");
     while (acceptHeaderScanner.hasNext()) {
       if (acceptHeaderScanner.hasNext(REG_EX_ACCEPT_WITH_Q_FACTOR)) {
@@ -75,18 +82,21 @@ public class AcceptParser {
       }
     }
     for (Accept accept : acceptTree) {
-      acceptHeaders.add(accept.getValue());
+      if (!acceptHeaders.contains(accept.getValue())) {
+        acceptHeaders.add(accept.getValue());
+      }
     }
     acceptHeaderScanner.close();
     return acceptHeaders;
   }
 
-  private static double getQualityFactor(final String acceptHeaderValue, double qualityFactor) {
+  private double getQualityFactor(final String acceptHeaderValue, double qualityFactor) {
     int paramNumber = 0;
     double typeFactor = 0.0;
     double subtypeFactor = 0.0;
     String[] mediaRange = acceptHeaderValue.split("(?=[^;]+);");
     String[] mediaTypes = mediaRange[0].split("/");
+
     if (mediaTypes.length == 2) {
       String type = mediaTypes[0];
       String subtype = mediaTypes[1];
@@ -101,13 +111,15 @@ public class AcceptParser {
       String[] parameters = mediaRange[1].split(";\\s?");
       paramNumber = parameters.length;
     }
+
     qualityFactor = qualityFactor + paramNumber * QUALITY_PARAM_FACTOR + typeFactor + subtypeFactor;
     return qualityFactor;
   }
 
-  public static List<String> parseAcceptableLanguages(final String headerValue) throws BatchException {
-    List<String> acceptLanguages = new LinkedList<String>();
-    TreeSet<Accept> acceptTree = getAcceptTree();
+  public List<String> parseAcceptableLanguages() throws BatchException {
+    final String headerValue = concatenateHeaderLines(acceptLanguageHeaderValues);
+    final List<String> acceptLanguages = new LinkedList<String>();
+    final TreeSet<Accept> acceptTree = getAcceptTree();
     Scanner acceptLanguageScanner = new Scanner(headerValue);
     acceptLanguageScanner.useDelimiter(",\\s?");
 
@@ -132,13 +144,37 @@ public class AcceptParser {
       }
     }
     for (Accept accept : acceptTree) {
-      acceptLanguages.add(accept.getValue());
+      if (!acceptLanguages.contains(accept.getValue())) {
+        acceptLanguages.add(accept.getValue());
+      }
     }
     acceptLanguageScanner.close();
     return acceptLanguages;
   }
 
-  private static TreeSet<Accept> getAcceptTree() {
+  private String concatenateHeaderLines(final List<String> headerValues) {
+    final StringBuilder builder = new StringBuilder();
+    final Iterator<String> iter = headerValues.iterator();
+
+    while (iter.hasNext()) {
+      builder.append(iter.next());
+      if (iter.hasNext()) {
+        builder.append(COMMA);
+      }
+    }
+
+    return builder.toString();
+  }
+
+  public void addAcceptHeaderValue(final String headerValue) {
+    acceptHeaderValues.add(headerValue);
+  }
+
+  public void addAcceptLanguageHeaderValue(final String headerValue) {
+    acceptLanguageHeaderValues.add(headerValue);
+  }
+
+  private TreeSet<Accept> getAcceptTree() {
     TreeSet<Accept> treeSet = new TreeSet<Accept>(new Comparator<Accept>() {
       @Override
       public int compare(final Accept o1, final Accept o2) {

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
index e355f84..4edcf45 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
@@ -24,18 +24,16 @@ import java.util.Locale;
 import java.util.Map;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
-import org.apache.olingo.odata2.api.commons.HttpContentType;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
-import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
 
 public class BatchBodyPart implements BatchPart {
-  final private Map<String, HeaderField> headers;
   final private String boundary;
-  final private boolean isChangeSet;
   final private boolean isStrict;
-  final private List<String> body;
-  private boolean isParsed = false;
+  final List<String> remainingMessage = new LinkedList<String>();
+
+  private Map<String, HeaderField> headers;
+  private boolean isChangeSet;
   private List<BatchQueryOperation> requests;
 
   public BatchBodyPart(final List<String> bodyPartMessage, final String boundary, final boolean isStrict)
@@ -43,19 +41,14 @@ public class BatchBodyPart implements BatchPart {
     this.boundary = boundary;
     this.isStrict = isStrict;
 
-    List<String> remainingMessage = new LinkedList<String>();
     remainingMessage.addAll(bodyPartMessage);
+  }
 
+  public BatchBodyPart parse() throws BatchException {
     headers = BatchParserCommon.consumeHeaders(remainingMessage);
     BatchParserCommon.consumeBlankLine(remainingMessage, isStrict);
     isChangeSet = isChangeSet(headers);
-    body = remainingMessage;
-  }
-
-  public BatchBodyPart parse(final int contentLength) throws BatchException {
-    List<String> remainingMessage = BatchParserCommon.trimStringListToLength(body, contentLength);
     requests = consumeRequest(remainingMessage);
-    isParsed = true;
 
     return this;
   }
@@ -78,7 +71,7 @@ public class BatchBodyPart implements BatchPart {
   }
 
   private boolean isContentTypeMultiPartMixed(final String contentType) {
-    return contentType.contains(HttpContentType.MULTIPART_MIXED);
+    return BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches();
   }
 
   private List<BatchQueryOperation> consumeRequest(final List<String> remainingMessage) throws BatchException {
@@ -95,7 +88,7 @@ public class BatchBodyPart implements BatchPart {
     final List<BatchQueryOperation> requestList = new LinkedList<BatchQueryOperation>();
 
     for (List<String> changeRequest : changeRequests) {
-      requestList.add(new BatchChangeSet(changeRequest, isStrict).parse());
+      requestList.add(new BatchChangeSetPart(changeRequest, isStrict).parse());
     }
 
     return requestList;
@@ -146,10 +139,6 @@ public class BatchBodyPart implements BatchPart {
   }
 
   public List<BatchQueryOperation> getRequests() {
-    if (!isParsed) {
-      throw new ODataRuntimeException("Batch part must be parsed first");
-    }
-
     return requests;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java
deleted file mode 100644
index 5331ff8..0000000
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSet.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*******************************************************************************
- * 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.v2;
-
-import java.util.List;
-
-import org.apache.olingo.odata2.api.batch.BatchException;
-
-public class BatchChangeSet extends BatchQueryOperation {
-  private BatchQueryOperation request;
-
-  public BatchChangeSet(final List<String> message, final boolean isStrict) throws BatchException {
-    super(message, isStrict);
-  }
-
-  @Override
-  public BatchChangeSet parse() throws BatchException {
-    headers = BatchParserCommon.consumeHeaders(message);
-    BatchParserCommon.consumeBlankLine(message, isStrict);
-
-    request = new BatchQueryOperation(message, isStrict).parse();
-
-    return this;
-  }
-
-  public BatchQueryOperation getRequest() {
-    return request;
-  }
-
-  @Override
-  public List<String> getBody() {
-    return request.getBody();
-  }
-
-  @Override
-  public String getHttpMethod() {
-    return request.getHttpMethod();
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
new file mode 100644
index 0000000..746c368
--- /dev/null
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * 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.v2;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+
+public class BatchChangeSetPart extends BatchQueryOperation {
+  private BatchQueryOperation request;
+
+  public BatchChangeSetPart(final List<String> message, final boolean isStrict) throws BatchException {
+    super(message, isStrict);
+  }
+
+  @Override
+  public BatchChangeSetPart parse() throws BatchException {
+    headers = BatchParserCommon.consumeHeaders(message);
+    BatchParserCommon.consumeBlankLine(message, isStrict);
+
+    request = new BatchQueryOperation(message, isStrict).parse();
+
+    return this;
+  }
+
+  public BatchQueryOperation getRequest() {
+    return request;
+  }
+
+  @Override
+  public List<String> getBody() {
+    return request.getBody();
+  }
+
+  @Override
+  public String getHttpStatusLine() {
+    return request.getHttpStatusLine();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/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 b64453b..6fb7dbd 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
@@ -83,7 +83,7 @@ public class BatchParser {
     final List<List<String>> bodyPartStrings = splitBodyParts(in, boundary);
 
     for (List<String> bodyPartString : bodyPartStrings) {
-      BatchBodyPart bodyPart = new BatchBodyPart(bodyPartString, boundary, isStrict);
+      BatchBodyPart bodyPart = new BatchBodyPart(bodyPartString, boundary, isStrict).parse();
       resultList.addAll(transformator.transform(bodyPart, batchRequestPathInfo, baseUri));
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
index 51314dd..8b7f62a 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
@@ -44,32 +44,23 @@ import org.apache.olingo.odata2.core.batch.AcceptParser;
 import org.apache.olingo.odata2.core.commons.Decoder;
 
 public class BatchParserCommon {
-  private static final String BOUNDARY_IDENTIFIER = "boundary=";
   private static final String REG_EX_BOUNDARY =
       "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\" +
           "(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046
 
-  private static final Pattern REG_EX_HEADER = Pattern.compile("([a-zA-Z\\-]+):\\s?(.*)\\s*");
+  private static final String REX_EX_MULTIPART_BOUNDARY = "multipart/mixed;\\s*boundary=(.+)";
+  private static final String REG_EX_APPLICATION_HTTP = "application/http";
+  public static final Pattern PATTERN_MULTIPART_BOUNDARY = Pattern.compile(REX_EX_MULTIPART_BOUNDARY,
+      Pattern.CASE_INSENSITIVE);
+  public static final Pattern PATTERN_HEADER_LINE = Pattern.compile("([a-zA-Z\\-]+):\\s?(.*)\\s*");
+  public static final Pattern PATTERN_CONTENT_TYPE_APPLICATION_HTTP = Pattern.compile(REG_EX_APPLICATION_HTTP,
+      Pattern.CASE_INSENSITIVE);
 
-  public static List<String> trimStringListToLength(final List<String> list, final int length) {
-    final Iterator<String> iter = list.iterator();
-    final List<String> result = new ArrayList<String>();
-    boolean isEndReached = false;
-    int currentLength = 0;
-
-    while (!isEndReached && iter.hasNext()) {
-      String currentLine = iter.next();
-
-      if (currentLength + currentLine.length() <= length) {
-        result.add(currentLine);
-        currentLength += currentLine.length();
-      } else {
-        result.add(currentLine.substring(0, length - currentLength));
-        isEndReached = true;
-      }
-    }
+  public static String trimStringListToStringLength(final List<String> list, final int length) {
+    final String message = stringListToString(list);
+    final int lastIndex = Math.min(length, message.length());
 
-    return result;
+    return (lastIndex > 0) ? message.substring(0, lastIndex) : "";
   }
 
   public static String stringListToString(final List<String> list) {
@@ -82,13 +73,21 @@ public class BatchParserCommon {
     return builder.toString();
   }
 
-  public static InputStream convertMessageToInputStream(final List<String> message, final int contentLength)
+  public static InputStream convertMessageToInputStream(final List<String> messageList, final int contentLength)
       throws BatchException {
-    List<String> shortenedMessage = BatchParserCommon.trimStringListToLength(message, contentLength);
+    final String message = trimStringListToStringLength(messageList, contentLength);
 
-    return new ByteArrayInputStream(BatchParserCommon.stringListToString(shortenedMessage).getBytes());
+    return new ByteArrayInputStream(message.getBytes());
   }
 
+  public static InputStream convertMessageToInputStream(final List<String> messageList)
+      throws BatchException {
+    final String message = stringListToString(messageList);
+
+    return new ByteArrayInputStream(message.getBytes());
+  }
+
+  // TODO Splitten von InputStream, sodass nur eine Iteration erfolgen muss
   static List<List<String>> splitMessageByBoundary(final List<String> message, final String boundary)
       throws BatchException {
     final List<List<String>> messageParts = new LinkedList<List<String>>();
@@ -149,15 +148,16 @@ public class BatchParserCommon {
     }
   }
 
-  static Map<String, HeaderField> consumeHeaders(final List<String> remainingMessage) throws BatchException {
+  public static Map<String, HeaderField> consumeHeaders(final List<String> remainingMessage) throws BatchException {
     final Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
     boolean isHeader = true;
+    final Iterator<String> iter = remainingMessage.iterator();
+    final AcceptParser acceptParser = new AcceptParser();
     String currentLine;
-    Iterator<String> iter = remainingMessage.iterator();
 
     while (iter.hasNext() && isHeader) {
       currentLine = iter.next();
-      Matcher headerMatcher = REG_EX_HEADER.matcher(currentLine);
+      Matcher headerMatcher = PATTERN_HEADER_LINE.matcher(currentLine);
 
       if (headerMatcher.matches() && headerMatcher.groupCount() == 2) {
         iter.remove();
@@ -167,38 +167,55 @@ public class BatchParserCommon {
         String headerValue = headerMatcher.group(2).trim();
 
         if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerNameLowerCase)) {
-          List<String> acceptHeaders = AcceptParser.parseAcceptHeaders(headerValue);
-          headers.put(headerNameLowerCase, new HeaderField(headerName, acceptHeaders));
+          acceptParser.addAcceptHeaderValue(headerValue);
         } else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerNameLowerCase)) {
-          List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages(headerValue);
-          headers.put(headerNameLowerCase, new HeaderField(headerName, acceptLanguageHeaders));
+          acceptParser.addAcceptLanguageHeaderValue(headerValue);
         } else {
-          HeaderField headerField = headers.get(headerNameLowerCase);
-          headerField = headerField == null ? new HeaderField(headerName) : headerField;
-          headers.put(headerNameLowerCase, headerField);
-          headerField.getValues().add(headerValue);
+          addHeaderValue(headers, headerName, headerNameLowerCase, headerValue);
         }
       } else {
         isHeader = false;
       }
     }
 
+    final List<String> acceptHeader = acceptParser.parseAcceptHeaders();
+    headers.put(HttpHeaders.ACCEPT.toLowerCase(), new HeaderField(HttpHeaders.ACCEPT, acceptHeader));
+
+    final List<String> acceptLanguageHeader = acceptParser.parseAcceptableLanguages();
+    headers.put(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase(), new HeaderField(HttpHeaders.ACCEPT_LANGUAGE,
+        acceptLanguageHeader));
+
     return Collections.unmodifiableMap(headers);
   }
 
-  static void consumeBlankLine(final List<String> remainingMessage, final boolean isStrict) throws BatchException {
-    if (remainingMessage.size() > 0 && "".equals(remainingMessage.get(0).trim())) {
-      remainingMessage.remove(0);
-    } else {
-      if (isStrict) {
-        throw new BatchException(BatchException.MISSING_BLANK_LINE);
+  private static void addHeaderValue(final Map<String, HeaderField> headers, final String headerName,
+      final String headerNameLowerCase, final String headerValue) {
+    HeaderField headerField = headers.get(headerNameLowerCase);
+    headerField = headerField == null ? new HeaderField(headerName) : headerField;
+    headers.put(headerNameLowerCase, headerField);
+
+    for (final String singleValue : splitHeaderValuesByComma(headerValue)) {
+      if (!headerField.getValues().contains(singleValue)) {
+        headerField.getValues().add(singleValue);
       }
     }
   }
 
-  static void consumeLastBlankLine(final List<String> message, final boolean isStrict) throws BatchException {
-    if (message.size() > 0 && "".equals(message.get(message.size() - 1).trim())) {
-      message.remove(message.size() - 1);
+  private static List<String> splitHeaderValuesByComma(final String headerValue) {
+    final List<String> singleValues = new ArrayList<String>();
+
+    String[] parts = headerValue.split(",");
+    for (final String value : parts) {
+      singleValues.add(value.trim());
+    }
+
+    return singleValues;
+  }
+
+  public static void consumeBlankLine(final List<String> remainingMessage, final boolean isStrict)
+      throws BatchException {
+    if (remainingMessage.size() > 0 && "".equals(remainingMessage.get(0).trim())) {
+      remainingMessage.remove(0);
     } else {
       if (isStrict) {
         throw new BatchException(BatchException.MISSING_BLANK_LINE);
@@ -206,25 +223,22 @@ public class BatchParserCommon {
     }
   }
 
-  static String getBoundary(final String contentType) throws BatchException {
-    if (contentType.contains(HttpContentType.MULTIPART_MIXED)) {
-      String[] parts = contentType.split(BOUNDARY_IDENTIFIER);
+  public static String getBoundary(final String contentType) throws BatchException {
+    final Matcher boundaryMatcher = PATTERN_MULTIPART_BOUNDARY.matcher(contentType);
 
-      if (parts.length == 2) {
-        if (parts[1].matches(REG_EX_BOUNDARY)) {
-          return trimQuota(parts[1].trim());
-        } else {
-          throw new BatchException(BatchException.INVALID_BOUNDARY);
-        }
+    if (boundaryMatcher.matches()) {
+      final String boundary = boundaryMatcher.group(1);
+      if (boundary.matches(REG_EX_BOUNDARY)) {
+        return trimQuota(boundary);
       } else {
-        throw new BatchException(BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE);
+        throw new BatchException(BatchException.INVALID_BOUNDARY);
       }
     } else {
       throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED));
     }
   }
 
-  static Map<String, List<String>> parseQueryParameter(final String httpRequest) {
+  public static Map<String, List<String>> parseQueryParameter(final String httpRequest) {
     Map<String, List<String>> queryParameter = new HashMap<String, List<String>>();
 
     String[] requestParts = httpRequest.split(" ");

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
index 179fffb..5176bb8 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
@@ -27,7 +27,7 @@ import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 public class BatchQueryOperation implements BatchPart {
 
   protected final boolean isStrict;
-  protected String httpMethod;
+  protected String httpStatusLine;
   protected Map<String, HeaderField> headers;
   protected List<String> body;
   protected int bodySize;
@@ -39,7 +39,7 @@ public class BatchQueryOperation implements BatchPart {
   }
 
   public BatchQueryOperation parse() throws BatchException {
-    httpMethod = consumeHttpMethod(message);
+    httpStatusLine = consumeHttpStatusLine(message);
     headers = BatchParserCommon.consumeHeaders(message);
     BatchParserCommon.consumeBlankLine(message, isStrict);
     body = message;
@@ -47,7 +47,7 @@ public class BatchQueryOperation implements BatchPart {
     return this;
   }
 
-  protected String consumeHttpMethod(final List<String> message) throws BatchException {
+  protected String consumeHttpStatusLine(final List<String> message) throws BatchException {
     if (message.size() > 0 && !message.get(0).trim().equals("")) {
       String method = message.get(0);
       message.remove(0);
@@ -58,8 +58,8 @@ public class BatchQueryOperation implements BatchPart {
     }
   }
 
-  public String getHttpMethod() {
-    return httpMethod;
+  public String getHttpStatusLine() {
+    return httpStatusLine;
   }
 
   public List<String> getBody() {

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
index 3626686..5169575 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
@@ -55,7 +55,6 @@ public class BatchRequestTransformator implements BatchTransformator {
     final List<ODataRequest> requests = new LinkedList<ODataRequest>();
     final List<BatchParserResult> resultList = new ArrayList<BatchParserResult>();
 
-    BatchTransformatorCommon.parsePartSyntax(bodyPart);
     validateBodyPartHeaders(bodyPart);
 
     for (BatchQueryOperation queryOperation : bodyPart.getRequests()) {
@@ -77,7 +76,7 @@ public class BatchRequestTransformator implements BatchTransformator {
       final String baseUri, final BatchQueryOperation queryOperation) throws BatchException {
 
     if (bodyPart.isChangeSet()) {
-      BatchQueryOperation encapsulatedQueryOperation = ((BatchChangeSet) queryOperation).getRequest();
+      BatchQueryOperation encapsulatedQueryOperation = ((BatchChangeSetPart) queryOperation).getRequest();
       Map<String, HeaderField> headers = transformHeader(encapsulatedQueryOperation, queryOperation);
       validateChangeSetMultipartMimeHeaders(queryOperation, encapsulatedQueryOperation);
 
@@ -98,7 +97,7 @@ public class BatchRequestTransformator implements BatchTransformator {
   private ODataRequest createRequest(final BatchQueryOperation operation, final Map<String, HeaderField> headers,
       final PathInfo pathInfo, final String baseUri, final boolean isChangeSet) throws BatchException {
 
-    ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpMethod());
+    ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpStatusLine());
     validateHttpMethod(httpMethod, isChangeSet);
     validateBody(httpMethod, operation);
     InputStream bodyStrean = getBodyStream(operation, headers, httpMethod);
@@ -106,10 +105,10 @@ public class BatchRequestTransformator implements BatchTransformator {
     ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod)
         .acceptableLanguages(getAcceptLanguageHeaders(headers))
         .acceptHeaders(getAcceptHeaders(headers))
-        .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpMethod()))
+        .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpStatusLine()))
         .body(bodyStrean)
         .requestHeaders(BatchParserCommon.headerFieldMapToMultiMap(headers))
-        .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpMethod(), pathInfo, baseUri));
+        .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpStatusLine(), pathInfo, baseUri));
 
     addContentTypeHeader(requestBuilder, headers);
 
@@ -135,9 +134,12 @@ public class BatchRequestTransformator implements BatchTransformator {
       return new ByteArrayInputStream(new byte[0]);
     } else {
       int contentLength = BatchTransformatorCommon.getContentLength(headers);
-      contentLength = (contentLength >= 0) ? contentLength : Integer.MAX_VALUE;
 
-      return BatchParserCommon.convertMessageToInputStream(operation.getBody(), contentLength);
+      if (contentLength == -1) {
+        return BatchParserCommon.convertMessageToInputStream(operation.getBody());
+      } else {
+        return BatchParserCommon.convertMessageToInputStream(operation.getBody(), contentLength);
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
index 88f5064..d82d09e 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
@@ -51,7 +51,6 @@ public class BatchResponseTransformator implements BatchTransformator {
 
     List<BatchParserResult> resultList = new ArrayList<BatchParserResult>();
 
-    BatchTransformatorCommon.parsePartSyntax(bodyPart);
     BatchTransformatorCommon.validateContentType(bodyPart.getHeaders());
 
     resultList.addAll(handleBodyPart(bodyPart));
@@ -64,7 +63,7 @@ public class BatchResponseTransformator implements BatchTransformator {
 
     if (bodyPart.isChangeSet()) {
       for (BatchQueryOperation operation : bodyPart.getRequests()) {
-        bodyPartResult.add(transformChangeSet((BatchChangeSet) operation));
+        bodyPartResult.add(transformChangeSet((BatchChangeSetPart) operation));
       }
     } else {
       bodyPartResult.add(transformQueryOperation(bodyPart.getRequests().get(0), getContentId(bodyPart.getHeaders())));
@@ -73,7 +72,7 @@ public class BatchResponseTransformator implements BatchTransformator {
     return bodyPartResult;
   }
 
-  private BatchSingleResponse transformChangeSet(final BatchChangeSet changeSet) throws BatchException {
+  private BatchSingleResponse transformChangeSet(final BatchChangeSetPart changeSet) throws BatchException {
     BatchTransformatorCommon.validateContentTransferEncoding(changeSet.getHeaders(), true);
 
     return transformQueryOperation(changeSet.getRequest(), getContentId(changeSet.getHeaders()));
@@ -84,8 +83,8 @@ public class BatchResponseTransformator implements BatchTransformator {
     BatchSingleResponseImpl response = new BatchSingleResponseImpl();
     response.setContentId(contentId);
     response.setHeaders(BatchParserCommon.headerFieldMapToSingleMap(operation.getHeaders()));
-    response.setStatusCode(getStatusCode(operation.httpMethod));
-    response.setStatusInfo(getStatusInfo(operation.getHttpMethod()));
+    response.setStatusCode(getStatusCode(operation.httpStatusLine));
+    response.setStatusInfo(getStatusInfo(operation.getHttpStatusLine()));
     response.setBody(getBody(operation));
 
     return response;
@@ -105,8 +104,8 @@ public class BatchResponseTransformator implements BatchTransformator {
 
   private String getBody(final BatchQueryOperation operation) throws BatchException {
     int contentLength = BatchTransformatorCommon.getContentLength(operation.getHeaders());
-    List<String> body = BatchParserCommon.trimStringListToLength(operation.getBody(), contentLength);
-    return BatchParserCommon.stringListToString(body);
+
+    return BatchParserCommon.trimStringListToStringLength(operation.getBody(), contentLength);
   }
 
   private String getStatusCode(final String httpMethod) throws BatchException {

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
index 2098708..c9c8e0f 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
@@ -12,20 +12,16 @@ import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 public class BatchTransformatorCommon {
 
   public static void validateContentType(final Map<String, HeaderField> headers) throws BatchException {
-    if (headers.containsKey(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH))) {
-      HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
-
+    final HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
+    if (contentTypeField != null) {
       if (contentTypeField.getValues().size() == 1) {
-        String contentType = contentTypeField.getValues().get(0);
-
-        if (!(HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)
-        || contentType.contains(HttpContentType.MULTIPART_MIXED))) {
+        final String contentType = contentTypeField.getValues().get(0);
 
+        if (!BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()
+            && !BatchParserCommon.PATTERN_CONTENT_TYPE_APPLICATION_HTTP.matcher(contentType).matches()) {
           throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED
               + " or " + HttpContentType.APPLICATION_HTTP));
         }
-      } else if (contentTypeField.getValues().size() == 0) {
-        throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
       } else {
         throw new BatchException(BatchException.INVALID_HEADER);
       }
@@ -34,7 +30,8 @@ public class BatchTransformatorCommon {
     }
   }
 
-  public static void validateContentTransferEncoding(final Map<String, HeaderField> headers, boolean isChangeRequest)
+  public static void validateContentTransferEncoding(final Map<String, HeaderField> headers,
+      final boolean isChangeRequest)
       throws BatchException {
     if (headers.containsKey(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH))) {
       HeaderField encodingField = headers.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH));
@@ -57,11 +54,6 @@ public class BatchTransformatorCommon {
     }
   }
 
-  public static void parsePartSyntax(final BatchBodyPart bodyPart) throws BatchException {
-    int contentLength = BatchTransformatorCommon.getContentLength(bodyPart.getHeaders());
-    bodyPart.parse(contentLength);
-  }
-
   public static int getContentLength(final Map<String, HeaderField> headers) throws BatchException {
 
     if (headers.containsKey(HttpHeaders.CONTENT_LENGTH.toLowerCase(Locale.ENGLISH))) {
@@ -79,6 +71,6 @@ public class BatchTransformatorCommon {
       }
     }
 
-    return Integer.MAX_VALUE;
+    return -1;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
index a3c0512..b7d7fac 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java
@@ -31,8 +31,10 @@ public class AcceptParserTest {
 
   @Test
   public void testAcceptHeader() throws BatchException {
-    List<String> acceptHeaders =
-        AcceptParser.parseAcceptHeaders("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+    
     assertNotNull(acceptHeaders);
     assertEquals(4, acceptHeaders.size());
     assertEquals("text/html", acceptHeaders.get(0));
@@ -43,48 +45,58 @@ public class AcceptParserTest {
 
   @Test
   public void testAcceptHeaderWithParameter() throws BatchException {
-    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;odata=verbose;q=1.0, */*;q=0.1");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("application/json;odata=verbose;q=1.0, */*;q=0.1");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+    
     assertNotNull(acceptHeaders);
     assertEquals(2, acceptHeaders.size());
     assertEquals("application/json;odata=verbose", acceptHeaders.get(0));
-    ;
     assertEquals("*/*", acceptHeaders.get(1));
   }
 
   @Test
   public void testAcceptHeaderWithParameterAndLws() throws BatchException {
-    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;  odata=verbose;q=1.0, */*;q=0.1");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("application/json;  odata=verbose;q=1.0, */*;q=0.1");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+
     assertNotNull(acceptHeaders);
     assertEquals(2, acceptHeaders.size());
     assertEquals("application/json;  odata=verbose", acceptHeaders.get(0));
-    ;
     assertEquals("*/*", acceptHeaders.get(1));
   }
 
   @Test
   public void testAcceptHeaderWithTabulator() throws BatchException {
-    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;\todata=verbose;q=1.0, */*;q=0.1");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("application/json;\todata=verbose;q=1.0, */*;q=0.1");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+    
     assertNotNull(acceptHeaders);
     assertEquals(2, acceptHeaders.size());
     assertEquals("application/json;" + TAB + "odata=verbose", acceptHeaders.get(0));
-    ;
     assertEquals("*/*", acceptHeaders.get(1));
   }
 
   @Test
   public void testAcceptHeaderWithTwoParameters() throws BatchException {
-    List<String> acceptHeaders =
-        AcceptParser.parseAcceptHeaders("application/xml;another=test ; param=alskdf, */*;q=0.1");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("application/xml;another=test ; param=alskdf, */*;q=0.1");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+
     assertNotNull(acceptHeaders);
     assertEquals(2, acceptHeaders.size());
     assertEquals("application/xml;another=test ; param=alskdf", acceptHeaders.get(0));
-    ;
     assertEquals("*/*", acceptHeaders.get(1));
   }
 
   @Test
   public void testAcceptHeader2() throws BatchException {
-    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("text/html;level=1, application/*, */*;q=0.1");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("text/html;level=1, application/*, */*;q=0.1");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+
     assertNotNull(acceptHeaders);
     assertEquals(3, acceptHeaders.size());
     assertEquals("text/html;level=1", acceptHeaders.get(0));
@@ -94,7 +106,10 @@ public class AcceptParserTest {
 
   @Test
   public void testMoreSpecificMediaType() throws BatchException {
-    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, application/xml");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("application/*, application/xml");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+    
     assertNotNull(acceptHeaders);
     assertEquals(2, acceptHeaders.size());
     assertEquals("application/xml", acceptHeaders.get(0));
@@ -103,28 +118,40 @@ public class AcceptParserTest {
 
   @Test
   public void testQualityParameter() throws BatchException {
-    List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, */*; q=0.012");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("application/*, */*; q=0.012");
+    List<String> acceptHeaders = parser.parseAcceptHeaders();
+    
     assertNotNull(acceptHeaders);
   }
 
   @Test(expected = BatchException.class)
   public void testInvalidAcceptHeader() throws BatchException {
-    AcceptParser.parseAcceptHeaders("appi cation/*, */*;q=0.1");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("appi cation/*, */*;q=0.1");
+    parser.parseAcceptHeaders();
   }
 
   @Test(expected = BatchException.class)
   public void testInvalidQualityParameter() throws BatchException {
-    AcceptParser.parseAcceptHeaders("appication/*, */*;q=0,9");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("appication/*, */*;q=0,9");
+    parser.parseAcceptHeaders();
   }
 
   @Test(expected = BatchException.class)
   public void testInvalidQualityParameter2() throws BatchException {
-    AcceptParser.parseAcceptHeaders("appication/*, */*;q=1.0001");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptHeaderValue("appication/*, */*;q=1.0001");
+    parser.parseAcceptHeaders();
   }
 
   @Test
   public void testAcceptLanguages() throws BatchException {
-    List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("en-US,en;q=0.7,en-UK;q=0.9");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptLanguageHeaderValue("en-US,en;q=0.7,en-UK;q=0.9");
+    List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages();
+
     assertNotNull(acceptLanguageHeaders);
     assertEquals(3, acceptLanguageHeaders.size());
     assertEquals("en-US", acceptLanguageHeaders.get(0));
@@ -134,20 +161,28 @@ public class AcceptParserTest {
 
   @Test
   public void testAllAcceptLanguages() throws BatchException {
-    List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("*");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptLanguageHeaderValue("*");
+    List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages();
+    
     assertNotNull(acceptLanguageHeaders);
     assertEquals(1, acceptLanguageHeaders.size());
   }
 
   @Test
   public void testLongAcceptLanguageValue() throws BatchException {
-    List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("english");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptLanguageHeaderValue("english");
+    List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages();
+    
     assertNotNull(acceptLanguageHeaders);
     assertEquals("english", acceptLanguageHeaders.get(0));
   }
 
   @Test(expected = BatchException.class)
   public void testInvalidAcceptLanguageValue() throws BatchException {
-    AcceptParser.parseAcceptableLanguages("en_US");
+    AcceptParser parser = new AcceptParser();
+    parser.addAcceptLanguageHeaderValue("en_US");
+    parser.parseAcceptableLanguages();
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
index c9e9a6b..8451c55 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
@@ -1,54 +1,170 @@
 package org.apache.olingo.odata2.core.batch;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Locale;
+import java.util.Map;
 
+import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon;
+import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 import org.junit.Test;
 
 public class BatchParserCommonTest {
-
+  
+  private static final String CRLF = "\r\n";
+  
   @Test
-  public void testTrimList() {
-    final List<String> list = Arrays.asList(new String[] { "123\r\n", "abc", "a\n", "\r", "123" });
-    final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 7);
-
-    assertEquals(2, trimedList.size());
-    assertEquals("123\r\n", trimedList.get(0));
-    assertEquals("ab", trimedList.get(1));
+  public void testMultipleHeader() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Content-Id: 1" + CRLF,
+        "Content-Id: 2" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField contentIdHeaders = header.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+    assertNotNull(contentIdHeaders);
+    assertEquals(2, contentIdHeaders.getValues().size());
+    assertEquals("1", contentIdHeaders.getValues().get(0));
+    assertEquals("2", contentIdHeaders.getValues().get(1));
   }
-
+  
   @Test
-  public void testTrimListWithEmptyString() {
-    final List<String> list = Arrays.asList(new String[] { "123\r\n", "", "abc", "a\n", "\r", "123" });
-    final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 7);
-
-    assertEquals(3, trimedList.size());
-    assertEquals("123\r\n", trimedList.get(0));
-    assertEquals("", trimedList.get(1));
-    assertEquals("ab", trimedList.get(2));
+  public void testMultipleHeaderSameValue() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Content-Id: 1" + CRLF,
+        "Content-Id: 1" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField contentIdHeaders = header.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+    assertNotNull(contentIdHeaders);
+    assertEquals(1, contentIdHeaders.getValues().size());
+    assertEquals("1", contentIdHeaders.getValues().get(0));
   }
-
+  
   @Test
-  public void testTrimListTryToReadMoreThanStringLength() {
-    final List<String> list = Arrays.asList(new String[] { "abc\r\n", "123" });
-    final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 100);
-
-    assertEquals(2, trimedList.size());
-    assertEquals("abc\r\n", trimedList.get(0));
-    assertEquals("123", trimedList.get(1));
+  public void testHeaderSperatedByComma() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Content-Id: 1" + CRLF,
+        "Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField upgradeHeader = header.get("upgrade");
+    assertNotNull(upgradeHeader);
+    assertEquals(4, upgradeHeader.getValues().size());
+    assertEquals("HTTP/2.0", upgradeHeader.getValues().get(0));
+    assertEquals("SHTTP/1.3", upgradeHeader.getValues().get(1));
+    assertEquals("IRC/6.9", upgradeHeader.getValues().get(2));
+    assertEquals("RTA/x11", upgradeHeader.getValues().get(3));
   }
-
+  
   @Test
-  public void testTrimListEmpty() {
-    final List<String> list = Arrays.asList(new String[0]);
-    final List<String> trimedList = BatchParserCommon.trimStringListToLength(list, 7);
-
-    assertEquals(0, trimedList.size());
+  public void testMultipleAcceptHeader() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF,
+        "Accept: text/plain;q=0.3" + CRLF,
+        "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField acceptHeader = header.get(HttpHeaders.ACCEPT.toLowerCase());
+    assertNotNull(acceptHeader);
+    assertEquals(4, acceptHeader.getValues().size());
   }
-
+  
+  @Test
+  public void testMultipleAcceptHeaderSameValue() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF,
+        "Accept: application/atomsvc+xml;q=0.8" + CRLF,
+        "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField acceptHeader = header.get(HttpHeaders.ACCEPT.toLowerCase());
+    assertNotNull(acceptHeader);
+    assertEquals(3, acceptHeader.getValues().size());
+  }
+  
+  @Test
+  public void testMultipleAccepLanguagetHeader() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF,
+        "Accept-Language: de-DE;q=0.3" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField acceptLanguageHeader = header.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase());
+    assertNotNull(acceptLanguageHeader);
+    assertEquals(4, acceptLanguageHeader.getValues().size());
+  }
+  
+  @Test
+  public void testMultipleAccepLanguagetHeaderSameValue() throws BatchException {
+    String[] messageRaw = new String[] {
+        "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF,
+        "Accept-Language:en-US,en;q=0.7" + CRLF,
+        "content-type: Application/http" + CRLF,
+        "content-transfer-encoding: Binary" + CRLF
+      };
+    List<String> message = new ArrayList<String>();
+    message.addAll(Arrays.asList(messageRaw));
+    
+    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    assertNotNull(header);
+    
+    final HeaderField acceptLanguageHeader = header.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase());
+    assertNotNull(acceptLanguageHeader);
+    assertEquals(3, acceptLanguageHeader.getValues().size());
+  }
+  
   @Test
   public void testRemoveEndingCRLF() {
     String line = "Test\r\n";

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
index 7866004..4cd0b67 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
@@ -431,7 +431,7 @@ public class BatchRequestParserTest {
         + "--batch_8194-cf13-1f56--";
     parseInvalidBatchBody(batch);
   }
-  
+
   @Test(expected = BatchException.class)
   public void testMissingContentTransferEncoding() throws BatchException {
     String batch = "--batch_8194-cf13-1f56" + CRLF
@@ -439,7 +439,7 @@ public class BatchRequestParserTest {
         + CRLF
         + "--changeset_f980-1cb6-94dd" + CRLF
         + "Content-Type: application/http" + CRLF
-        //+ "Content-Transfer-Encoding: binary" + CRLF
+        // + "Content-Transfer-Encoding: binary" + CRLF
         + CRLF
         + "POST Employees('2') HTTP/1.1" + CRLF
         + "Content-Type: application/json;odata=verbose" + CRLF
@@ -449,14 +449,14 @@ public class BatchRequestParserTest {
         + "--batch_8194-cf13-1f56--";
     parseInvalidBatchBody(batch);
   }
-  
+
   @Test(expected = BatchException.class)
   public void testMissingContentType() throws BatchException {
     String batch = "--batch_8194-cf13-1f56" + CRLF
         + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF
         + CRLF
         + "--changeset_f980-1cb6-94dd" + CRLF
-        //+ "Content-Type: application/http" + CRLF
+        // + "Content-Type: application/http" + CRLF
         + "Content-Transfer-Encoding: binary" + CRLF
         + CRLF
         + "POST Employees('2') HTTP/1.1" + CRLF
@@ -467,7 +467,7 @@ public class BatchRequestParserTest {
         + "--batch_8194-cf13-1f56--";
     parseInvalidBatchBody(batch);
   }
-  
+
   @Test(expected = BatchException.class)
   public void testNoCloseDelimiter() throws BatchException {
     String batch = "--batch_8194-cf13-1f56" + CRLF
@@ -605,32 +605,33 @@ public class BatchRequestParserTest {
 
     }
   }
-  
+
   @SuppressWarnings("unused")
-  @Test(expected=BatchException.class)
+  @Test(expected = BatchException.class)
+  @Ignore("This header should not be validated")
   public void testNegativeContentLength() throws BatchException, IOException {
-      String batch = ""
-          + "--batch_8194-cf13-1f56" + CRLF
-          + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF
-          + "Content-Length: -2" + CRLF
-          + CRLF
-          + "--changeset_f980-1cb6-94dd" + CRLF
-          + MIME_HEADERS
-          + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
-          + CRLF
-          + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
-          + "Content-Type: application/json;odata=verbose" + CRLF
-          + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
-          + CRLF
-          + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
-          + "--changeset_f980-1cb6-94dd--" + CRLF
-          + CRLF
-          + "--batch_8194-cf13-1f56--";
-      InputStream in = new ByteArrayInputStream(batch.getBytes());
-      BatchParser parser = new BatchParser(contentType, batchProperties, true);
-      List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
+    String batch = ""
+        + "--batch_8194-cf13-1f56" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF
+        + "Content-Length: -2" + CRLF
+        + CRLF
+        + "--changeset_f980-1cb6-94dd" + CRLF
+        + MIME_HEADERS
+        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
+        + CRLF
+        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
+        + CRLF
+        + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
+        + "--changeset_f980-1cb6-94dd--" + CRLF
+        + CRLF
+        + "--batch_8194-cf13-1f56--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchParser parser = new BatchParser(contentType, batchProperties, true);
+    List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
   }
-  
+
   @SuppressWarnings("unused")
   @Test
   public void testNegativeContentLengthChangeSet() throws BatchException, IOException {
@@ -655,9 +656,9 @@ public class BatchRequestParserTest {
     BatchParser parser = new BatchParser(contentType, batchProperties, true);
     List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
   }
-  
+
   @SuppressWarnings("unused")
-  @Test(expected=BatchException.class)
+  @Test(expected = BatchException.class)
   public void testNegativeContentLengthRequest() throws BatchException, IOException {
     String batch = ""
         + "--batch_8194-cf13-1f56" + CRLF
@@ -680,7 +681,7 @@ public class BatchRequestParserTest {
     BatchParser parser = new BatchParser(contentType, batchProperties, true);
     List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
   }
-  
+
   @Test
   public void testContentLengthGreatherThanBodyLength() throws BatchException, IOException {
     String batch = ""
@@ -746,6 +747,7 @@ public class BatchRequestParserTest {
   }
 
   @Test(expected = BatchException.class)
+  @Ignore("This header should not be validated")
   public void testCutChangeSetDelimiter() throws BatchException, IOException {
     String batch = ""
         + "--batch_8194-cf13-1f56" + CRLF
@@ -918,7 +920,7 @@ public class BatchRequestParserTest {
       }
     }
   }
-  
+
   @Test
   public void testNoContentId() throws BatchException {
     String batch = "--batch_8194-cf13-1f56" + CRLF
@@ -950,10 +952,10 @@ public class BatchRequestParserTest {
         + "--batch_8194-cf13-1f56--";
     InputStream in = new ByteArrayInputStream(batch.getBytes());
     BatchParser parser = new BatchParser(contentType, batchProperties, true);
-    List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);  // No exception should be thrown
+    List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); // No exception should be thrown
     assertNotNull(batchRequestParts);
   }
-  
+
   @Test
   public void testPreamble() throws BatchException, IOException {
     String batch = ""
@@ -1017,6 +1019,60 @@ public class BatchRequestParserTest {
         inputStreamToString(changeSetPart.getRequests().get(1).getBody()));
   }
 
+  @SuppressWarnings("unused")
+  @Test
+  public void testContentTypeCaseInsensitive() throws BatchException, IOException {
+    String batch = ""
+        + "--batch_8194-cf13-1f56" + CRLF
+        + "Content-Type: muLTiParT/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF
+        + CRLF
+        + "--changeset_f980-1cb6-94dd" + CRLF
+        + MIME_HEADERS
+        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
+        + "Content-Length: -2" + CRLF
+        + CRLF
+        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
+        + CRLF
+        + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
+        + "--changeset_f980-1cb6-94dd--" + CRLF
+        + CRLF
+        + "--batch_8194-cf13-1f56--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchParser parser = new BatchParser(contentType, batchProperties, true);
+    List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
+  }
+
+  @Test
+  public void testContentTypeBoundaryCaseInsensitive() throws BatchException, IOException {
+    String batch = ""
+        + "--batch_8194-cf13-1f56" + CRLF
+        + "Content-Type: multipart/mixed; bOunDaRy=changeset_f980-1cb6-94dd" + CRLF
+        + CRLF
+        + "--changeset_f980-1cb6-94dd" + CRLF
+        + MIME_HEADERS
+        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
+        + "Content-Length: -2" + CRLF
+        + CRLF
+        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
+        + CRLF
+        + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
+        + "--changeset_f980-1cb6-94dd--" + CRLF
+        + CRLF
+        + "--batch_8194-cf13-1f56--";
+    InputStream in = new ByteArrayInputStream(batch.getBytes());
+    BatchParser parser = new BatchParser(contentType, batchProperties, true);
+    List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
+
+    assertNotNull(batchRequestParts);
+    assertEquals(1, batchRequestParts.size());
+    assertTrue(batchRequestParts.get(0).isChangeSet());
+    assertEquals(1, batchRequestParts.get(0).getRequests().size());
+  }
+
   @Test
   public void testEpilog() throws BatchException, IOException {
     String batch = ""

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/1f90b733/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
index a0ab9f4..a70d15a 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
@@ -26,7 +26,17 @@ public class BatchTransformatorCommonTest {
 
   @Test
   public void testValidateContentTypeMultipartMixed() throws BatchException {
-    List<String> contentTypeValues = Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED });
+    List<String> contentTypeValues =
+        Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED + "; boundary=batch_32332_32323_fdsf" });
+    Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
+
+    BatchTransformatorCommon.validateContentType(headers);
+  }
+
+  @Test
+  public void testValidateContentTypeMultipartMixedCaseInsensitiv() throws BatchException {
+    List<String> contentTypeValues =
+        Arrays.asList(new String[] { "mulTiPart/MiXed; boundary=batch_32332_32323_fdsf" });
     Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
 
     BatchTransformatorCommon.validateContentType(headers);


[4/4] git commit: Line number tracking and exception messages

Posted by ch...@apache.org.
Line number tracking and exception messages

Signed-off-by: Christian Amend <ch...@apache.org>


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

Branch: refs/heads/olingo436BatchRefactoring
Commit: f0dc0f74593a3184c84dbf43337b23ec52f57abb
Parents: 05d20c1
Author: Christian Holzer <c....@sap.com>
Authored: Mon Oct 6 13:01:40 2014 +0200
Committer: Christian Amend <ch...@apache.org>
Committed: Mon Oct 6 13:54:39 2014 +0200

----------------------------------------------------------------------
 .../olingo/odata2/api/batch/BatchException.java |    2 +-
 .../odata2/core/batch/v2/BatchBodyPart.java     |   31 +-
 .../core/batch/v2/BatchChangeSetPart.java       |    7 +-
 .../odata2/core/batch/v2/BatchParser.java       |   11 +-
 .../odata2/core/batch/v2/BatchParserCommon.java |  101 +-
 .../core/batch/v2/BatchQueryOperation.java      |   22 +-
 .../batch/v2/BatchRequestTransformator.java     |   74 +-
 .../batch/v2/BatchResponseTransformator.java    |   10 +-
 .../core/batch/v2/BatchTransformatorCommon.java |   31 +-
 .../v2/BufferedReaderIncludingLineEndings.java  |   60 +-
 .../olingo/odata2/core/batch/v2/Header.java     |  142 +-
 .../src/main/resources/i18n.properties          |   37 +-
 .../core/batch/BatchParserCommonTest.java       |   55 +-
 .../core/batch/BatchRequestParserTest.java      |   82 +-
 .../odata2/core/batch/BatchRequestTest.java     |    5 +-
 .../batch/BatchTransformatorCommonTest.java     |    8 +-
 .../BufferedReaderIncludingLineEndingsTest.java |   25 +-
 .../olingo/odata2/core/batch/HeaderTest.java    |   54 +-
 .../src/test/resources/batchLarge.batch         | 2505 ++++++++++++++++++
 19 files changed, 2911 insertions(+), 351 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
index 1171719..96aa4dd 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
@@ -94,7 +94,7 @@ public class BatchException extends ODataMessageException {
   public static final MessageReference INVALID_ACCEPT_LANGUAGE_HEADER = createMessageReference(BatchException.class,
       "INVALID_ACCEPT_LANGUAGE_HEADER");
 
-  /** INVALID_CONTENT_TRANSFER_ENCODING requires no content value */
+  /** INVALID_CONTENT_TRANSFER_ENCODING requires 1 content value */
   public static final MessageReference INVALID_CONTENT_TRANSFER_ENCODING = createMessageReference(BatchException.class,
       "INVALID_CONTENT_TRANSFER_ENCODING");
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
index f74ea85..288ca1c 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
@@ -23,17 +23,19 @@ import java.util.List;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
+import org.apache.olingo.odata2.core.batch.v2.Header.HeaderField;
 
 public class BatchBodyPart implements BatchPart {
   final private String boundary;
   final private boolean isStrict;
-  final List<String> remainingMessage = new LinkedList<String>();
+  final List<Line> remainingMessage = new LinkedList<Line>();
 
   private Header headers;
   private boolean isChangeSet;
   private List<BatchQueryOperation> requests;
 
-  public BatchBodyPart(final List<String> bodyPartMessage, final String boundary, final boolean isStrict)
+  public BatchBodyPart(final List<Line> bodyPartMessage, final String boundary, final boolean isStrict)
       throws BatchException {
     this.boundary = boundary;
     this.isStrict = isStrict;
@@ -55,7 +57,7 @@ public class BatchBodyPart implements BatchPart {
     boolean isChangeSet = false;
 
     if (contentTypes.size() == 0) {
-      throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
+      throw new BatchException(BatchException.MISSING_CONTENT_TYPE.addContent(headers.getLineNumber()));
     }
 
     for (String contentType : contentTypes) {
@@ -71,7 +73,7 @@ public class BatchBodyPart implements BatchPart {
     return BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches();
   }
 
-  private List<BatchQueryOperation> consumeRequest(final List<String> remainingMessage) throws BatchException {
+  private List<BatchQueryOperation> consumeRequest(final List<Line> remainingMessage) throws BatchException {
     if (isChangeSet) {
       return consumeChangeSet(remainingMessage);
     } else {
@@ -79,28 +81,30 @@ public class BatchBodyPart implements BatchPart {
     }
   }
 
-  private List<BatchQueryOperation> consumeChangeSet(final List<String> remainingMessage)
+  private List<BatchQueryOperation> consumeChangeSet(final List<Line> remainingMessage)
       throws BatchException {
-    final List<List<String>> changeRequests = splitChangeSet(remainingMessage);
+    final List<List<Line>> changeRequests = splitChangeSet(remainingMessage);
     final List<BatchQueryOperation> requestList = new LinkedList<BatchQueryOperation>();
 
-    for (List<String> changeRequest : changeRequests) {
+    for (List<Line> changeRequest : changeRequests) {
       requestList.add(new BatchChangeSetPart(changeRequest, isStrict).parse());
     }
 
     return requestList;
   }
 
-  private List<List<String>> splitChangeSet(final List<String> remainingMessage)
+  private List<List<Line>> splitChangeSet(final List<Line> remainingMessage)
       throws BatchException {
 
-    final String changeSetBoundary = BatchParserCommon.getBoundary(headers.getHeaderNotNull(HttpHeaders.CONTENT_TYPE));
-    validateChangeSetBoundary(changeSetBoundary);
+    final HeaderField contentTypeField = headers.getHeaderField(HttpHeaders.CONTENT_TYPE);
+    final String changeSetBoundary =
+        BatchParserCommon.getBoundary(contentTypeField.getValueNotNull(), contentTypeField.getLineNumber());
+    validateChangeSetBoundary(changeSetBoundary, headers);
 
     return BatchParserCommon.splitMessageByBoundary(remainingMessage, changeSetBoundary);
   }
 
-  private List<BatchQueryOperation> consumeQueryOperation(final List<String> remainingMessage)
+  private List<BatchQueryOperation> consumeQueryOperation(final List<Line> remainingMessage)
       throws BatchException {
     final List<BatchQueryOperation> requestList = new LinkedList<BatchQueryOperation>();
     requestList.add(new BatchQueryOperation(remainingMessage, isStrict).parse());
@@ -108,9 +112,10 @@ public class BatchBodyPart implements BatchPart {
     return requestList;
   }
 
-  private void validateChangeSetBoundary(final String changeSetBoundary) throws BatchException {
+  private void validateChangeSetBoundary(final String changeSetBoundary, Header header) throws BatchException {
     if (changeSetBoundary.equals(boundary)) {
-      throw new BatchException(BatchException.INVALID_BOUNDARY);
+      throw new BatchException(BatchException.INVALID_BOUNDARY.addContent(header.getHeaderField(
+          HttpHeaders.CONTENT_TYPE).getLineNumber()));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
index 746c368..f3b0699 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchChangeSetPart.java
@@ -21,11 +21,12 @@ package org.apache.olingo.odata2.core.batch.v2;
 import java.util.List;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchChangeSetPart extends BatchQueryOperation {
   private BatchQueryOperation request;
 
-  public BatchChangeSetPart(final List<String> message, final boolean isStrict) throws BatchException {
+  public BatchChangeSetPart(final List<Line> message, final boolean isStrict) throws BatchException {
     super(message, isStrict);
   }
 
@@ -44,12 +45,12 @@ public class BatchChangeSetPart extends BatchQueryOperation {
   }
 
   @Override
-  public List<String> getBody() {
+  public List<Line> getBody() {
     return request.getBody();
   }
 
   @Override
-  public String getHttpStatusLine() {
+  public Line getHttpStatusLine() {
     return request.getHttpStatusLine();
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/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 6fb7dbd..00a1f2a 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
@@ -31,6 +31,7 @@ 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.batch.v2.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
 
 public class BatchParser {
@@ -78,11 +79,11 @@ public class BatchParser {
       final BatchTransformator transformator) throws BatchException, IOException {
 
     final String baseUri = getBaseUri();
-    final String boundary = BatchParserCommon.getBoundary(contentTypeMime);
+    final String boundary = BatchParserCommon.getBoundary(contentTypeMime, 1);
     final List<BatchParserResult> resultList = new LinkedList<BatchParserResult>();
-    final List<List<String>> bodyPartStrings = splitBodyParts(in, boundary);
+    final List<List<Line>> bodyPartStrings = splitBodyParts(in, boundary);
 
-    for (List<String> bodyPartString : bodyPartStrings) {
+    for (List<Line> bodyPartString : bodyPartStrings) {
       BatchBodyPart bodyPart = new BatchBodyPart(bodyPartString, boundary, isStrict).parse();
       resultList.addAll(transformator.transform(bodyPart, batchRequestPathInfo, baseUri));
     }
@@ -90,11 +91,11 @@ public class BatchParser {
     return resultList;
   }
 
-  private List<List<String>> splitBodyParts(final InputStream in, final String boundary)
+  private List<List<Line>> splitBodyParts(final InputStream in, final String boundary)
       throws IOException, BatchException {
 
     final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(new InputStreamReader(in));
-    final List<String> message = reader.toList();
+    final List<Line> message = reader.toList();
     reader.close();
 
     return BatchParserCommon.splitMessageByBoundary(message, boundary);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
index df62994..b028759 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
@@ -40,6 +40,7 @@ import org.apache.olingo.odata2.api.uri.PathSegment;
 import org.apache.olingo.odata2.core.ODataPathSegmentImpl;
 import org.apache.olingo.odata2.core.PathInfoImpl;
 import org.apache.olingo.odata2.core.batch.AcceptParser;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.odata2.core.commons.Decoder;
 
 public class BatchParserCommon {
@@ -55,53 +56,52 @@ public class BatchParserCommon {
   public static final Pattern PATTERN_CONTENT_TYPE_APPLICATION_HTTP = Pattern.compile(REG_EX_APPLICATION_HTTP,
       Pattern.CASE_INSENSITIVE);
 
-  public static String trimStringListToStringLength(final List<String> list, final int length) {
+  public static String trimLineListToLength(final List<Line> list, final int length) {
     final String message = stringListToString(list);
     final int lastIndex = Math.min(length, message.length());
 
     return (lastIndex > 0) ? message.substring(0, lastIndex) : "";
   }
 
-  public static String stringListToString(final List<String> list) {
+  public static String stringListToString(final List<Line> list) {
     StringBuilder builder = new StringBuilder();
 
-    for (String currentLine : list) {
-      builder.append(currentLine);
+    for (Line currentLine : list) {
+      builder.append(currentLine.toString());
     }
 
     return builder.toString();
   }
 
-  public static InputStream convertMessageToInputStream(final List<String> messageList, final int contentLength)
+  public static InputStream convertMessageToInputStream(final List<Line> messageList, final int contentLength)
       throws BatchException {
-    final String message = trimStringListToStringLength(messageList, contentLength);
+    final String message = trimLineListToLength(messageList, contentLength);
 
     return new ByteArrayInputStream(message.getBytes());
   }
 
-  public static InputStream convertMessageToInputStream(final List<String> messageList)
+  public static InputStream convertMessageToInputStream(final List<Line> messageList)
       throws BatchException {
     final String message = stringListToString(messageList);
 
     return new ByteArrayInputStream(message.getBytes());
   }
 
-  // TODO Splitten von InputStream, sodass nur eine Iteration erfolgen muss
-  static List<List<String>> splitMessageByBoundary(final List<String> message, final String boundary)
+  static List<List<Line>> splitMessageByBoundary(final List<Line> message, final String boundary)
       throws BatchException {
-    final List<List<String>> messageParts = new LinkedList<List<String>>();
-    List<String> currentPart = new ArrayList<String>();
+    final List<List<Line>> messageParts = new LinkedList<List<Line>>();
+    List<Line> currentPart = new ArrayList<Line>();
     boolean isEndReached = false;
 
-    for (String currentLine : message) {
-      if (currentLine.contains("--" + boundary + "--")) {
+    for (Line currentLine : message) {
+      if (currentLine.toString().contains("--" + boundary + "--")) {
         removeEndingCRLFFromList(currentPart);
         messageParts.add(currentPart);
         isEndReached = true;
-      } else if (currentLine.contains("--" + boundary)) {
+      } else if (currentLine.toString().contains("--" + boundary)) {
         removeEndingCRLFFromList(currentPart);
         messageParts.add(currentPart);
-        currentPart = new LinkedList<String>();
+        currentPart = new LinkedList<Line>();
       } else {
         currentPart.add(currentLine);
       }
@@ -111,52 +111,57 @@ public class BatchParserCommon {
       }
     }
 
+    final int lineNumer = (message.size() > 0) ? message.get(0).getLineNumber() : 0;
     // Remove preamble
     if (messageParts.size() > 0) {
       messageParts.remove(0);
     } else {
-      throw new BatchException(BatchException.MISSING_BOUNDARY_DELIMITER);
-    }
 
-    if (messageParts.size() == 0) {
-      throw new BatchException(BatchException.NO_MATCH_WITH_BOUNDARY_STRING);
+      throw new BatchException(BatchException.MISSING_BOUNDARY_DELIMITER.addContent(lineNumer));
     }
 
     if (!isEndReached) {
-      throw new BatchException(BatchException.MISSING_CLOSE_DELIMITER);
+      throw new BatchException(BatchException.MISSING_CLOSE_DELIMITER.addContent(lineNumer));
+    }
+
+    if (messageParts.size() == 0) {
+      throw new BatchException(BatchException.NO_MATCH_WITH_BOUNDARY_STRING.addContent(boundary).addContent(lineNumer));
     }
 
     return messageParts;
   }
 
-  private static void removeEndingCRLFFromList(final List<String> list) {
+  private static void removeEndingCRLFFromList(final List<Line> list) {
     if (list.size() > 0) {
-      String lastLine = list.remove(list.size() - 1);
+      Line lastLine = list.remove(list.size() - 1);
       list.add(removeEndingCRLF(lastLine));
     }
   }
 
-  public static String removeEndingCRLF(final String line) {
+  public static Line removeEndingCRLF(final Line line) {
     Pattern pattern = Pattern.compile("(.*)(\r\n){1}( *)", Pattern.DOTALL);
-    Matcher matcher = pattern.matcher(line);
+    Matcher matcher = pattern.matcher(line.toString());
 
     if (matcher.matches()) {
-      return matcher.group(1);
+      return new Line(matcher.group(1), line.getLineNumber());
     } else {
       return line;
     }
   }
 
-  public static Header consumeHeaders(final List<String> remainingMessage) throws BatchException {
-    final Header headers = new Header();
+  public static Header consumeHeaders(final List<Line> remainingMessage) throws BatchException {
+    final int lineNumberOfHeader = remainingMessage.size() != 0 ? remainingMessage.get(0).getLineNumber() : 0;
+    final Header headers = new Header(lineNumberOfHeader);
     boolean isHeader = true;
-    final Iterator<String> iter = remainingMessage.iterator();
+    final Iterator<Line> iter = remainingMessage.iterator();
     final AcceptParser acceptParser = new AcceptParser();
-    String currentLine;
+    Line currentLine;
+    int acceptLineNumber = 0;
+    int acceptLanguageLineNumber = 0;
 
     while (iter.hasNext() && isHeader) {
       currentLine = iter.next();
-      final Matcher headerMatcher = PATTERN_HEADER_LINE.matcher(currentLine);
+      final Matcher headerMatcher = PATTERN_HEADER_LINE.matcher(currentLine.toString());
 
       if (headerMatcher.matches() && headerMatcher.groupCount() == 2) {
         iter.remove();
@@ -166,34 +171,37 @@ public class BatchParserCommon {
 
         if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerName)) {
           acceptParser.addAcceptHeaderValue(headerValue);
+          acceptLineNumber = currentLine.getLineNumber();
         } else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerName)) {
           acceptParser.addAcceptLanguageHeaderValue(headerValue);
+          acceptLanguageLineNumber = currentLine.getLineNumber();
         } else {
-          headers.addHeader(headerName, Header.splitValuesByComma(headerValue));
+          headers.addHeader(headerName, Header.splitValuesByComma(headerValue), currentLine.getLineNumber());
         }
       } else {
         isHeader = false;
       }
     }
 
-    headers.addHeader(HttpHeaders.ACCEPT, acceptParser.parseAcceptHeaders());
-    headers.addHeader(HttpHeaders.ACCEPT_LANGUAGE, acceptParser.parseAcceptableLanguages());
+    headers.addHeader(HttpHeaders.ACCEPT, acceptParser.parseAcceptHeaders(), acceptLineNumber);
+    headers.addHeader(HttpHeaders.ACCEPT_LANGUAGE, acceptParser.parseAcceptableLanguages(), acceptLanguageLineNumber);
 
     return headers;
   }
 
-  public static void consumeBlankLine(final List<String> remainingMessage, final boolean isStrict)
+  public static void consumeBlankLine(final List<Line> remainingMessage, final boolean isStrict)
       throws BatchException {
-    if (remainingMessage.size() > 0 && "".equals(remainingMessage.get(0).trim())) {
+    if (remainingMessage.size() > 0 && "".equals(remainingMessage.get(0).toString().trim())) {
       remainingMessage.remove(0);
     } else {
       if (isStrict) {
-        throw new BatchException(BatchException.MISSING_BLANK_LINE);
+        final int lineNumber = (remainingMessage.size() > 0) ? remainingMessage.get(0).getLineNumber() : 0;
+        throw new BatchException(BatchException.MISSING_BLANK_LINE.addContent("[None]").addContent(lineNumber));
       }
     }
   }
 
-  public static String getBoundary(final String contentType) throws BatchException {
+  public static String getBoundary(final String contentType, final int line) throws BatchException {
     final Matcher boundaryMatcher = PATTERN_MULTIPART_BOUNDARY.matcher(contentType);
 
     if (boundaryMatcher.matches()) {
@@ -201,17 +209,17 @@ public class BatchParserCommon {
       if (boundary.matches(REG_EX_BOUNDARY)) {
         return trimQuota(boundary);
       } else {
-        throw new BatchException(BatchException.INVALID_BOUNDARY);
+        throw new BatchException(BatchException.INVALID_BOUNDARY.addContent(line));
       }
     } else {
       throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED));
     }
   }
 
-  public static Map<String, List<String>> parseQueryParameter(final String httpRequest) {
+  public static Map<String, List<String>> parseQueryParameter(final Line httpRequest) {
     Map<String, List<String>> queryParameter = new HashMap<String, List<String>>();
 
-    String[] requestParts = httpRequest.split(" ");
+    String[] requestParts = httpRequest.toString().split(" ");
     if (requestParts.length == 3) {
 
       String[] parts = requestParts[1].split("\\?");
@@ -239,8 +247,8 @@ public class BatchParserCommon {
     return queryParameter;
   }
 
-  public static PathInfo parseRequestUri(final String httpRequest, final PathInfo batchRequestPathInfo,
-      final String baseUri)
+  public static PathInfo parseRequestUri(final Line httpStatusLine, final PathInfo batchRequestPathInfo,
+      final String baseUri, final int line)
       throws BatchException {
 
     final String odataPathSegmentsAsString;
@@ -250,7 +258,7 @@ public class BatchParserCommon {
     pathInfo.setServiceRoot(batchRequestPathInfo.getServiceRoot());
     pathInfo.setPrecedingPathSegment(batchRequestPathInfo.getPrecedingSegments());
 
-    String[] requestParts = httpRequest.split(" ");
+    String[] requestParts = httpStatusLine.toString().split(" ");
     if (requestParts.length == 3) {
       String uri = requestParts[1];
       Pattern regexRequestUri;
@@ -277,14 +285,15 @@ public class BatchParserCommon {
           }
 
         } else {
-          throw new BatchException(BatchException.INVALID_URI);
+          throw new BatchException(BatchException.INVALID_URI.addContent(httpStatusLine.getLineNumber()));
         }
 
       } catch (URISyntaxException e) {
-        throw new BatchException(BatchException.INVALID_URI, e);
+        throw new BatchException(BatchException.INVALID_URI.addContent(line), e);
       }
     } else {
-      throw new BatchException(BatchException.INVALID_REQUEST_LINE);
+      throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(httpStatusLine.toString())
+          .addContent(line));
     }
 
     return pathInfo;

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
index 87dcb23..9bbd019 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
@@ -21,17 +21,18 @@ package org.apache.olingo.odata2.core.batch.v2;
 import java.util.List;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchQueryOperation implements BatchPart {
 
   protected final boolean isStrict;
-  protected String httpStatusLine;
+  protected Line httpStatusLine;
   protected Header headers;
-  protected List<String> body;
+  protected List<Line> body;
   protected int bodySize;
-  protected List<String> message;
+  protected List<Line> message;
 
-  public BatchQueryOperation(final List<String> message, final boolean isStrict) {
+  public BatchQueryOperation(final List<Line> message, final boolean isStrict) {
     this.isStrict = isStrict;
     this.message = message;
   }
@@ -45,22 +46,23 @@ public class BatchQueryOperation implements BatchPart {
     return this;
   }
 
-  protected String consumeHttpStatusLine(final List<String> message) throws BatchException {
-    if (message.size() > 0 && !message.get(0).trim().equals("")) {
-      String method = message.get(0);
+  protected Line consumeHttpStatusLine(final List<Line> message) throws BatchException {
+    if (message.size() > 0 && !message.get(0).toString().trim().equals("")) {
+      final Line method = message.get(0);
       message.remove(0);
 
       return method;
     } else {
-      throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD);
+      final int line = (message.size() > 0) ? message.get(0).getLineNumber() : 0;
+      throw new BatchException(BatchException.MISSING_METHOD.addContent(line));
     }
   }
 
-  public String getHttpStatusLine() {
+  public Line getHttpStatusLine() {
     return httpStatusLine;
   }
 
-  public List<String> getBody() {
+  public List<Line> getBody() {
     return body;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
index a49a2e5..c7ffa88 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
@@ -32,12 +32,13 @@ import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.batch.BatchParserResult;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
-import org.apache.olingo.odata2.api.exception.MessageReference;
 import org.apache.olingo.odata2.api.processor.ODataRequest;
 import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder;
 import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.core.batch.BatchHelper;
 import org.apache.olingo.odata2.core.batch.BatchRequestPartImpl;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
+import org.apache.olingo.odata2.core.batch.v2.Header.HeaderField;
 
 public class BatchRequestTransformator implements BatchTransformator {
 
@@ -88,9 +89,10 @@ public class BatchRequestTransformator implements BatchTransformator {
   private ODataRequest createRequest(final BatchQueryOperation operation, final Header headers,
       final PathInfo pathInfo, final String baseUri, final boolean isChangeSet) throws BatchException {
 
+    final int httpLineNumber = operation.getHttpStatusLine().getLineNumber();
     ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpStatusLine());
-    validateHttpMethod(httpMethod, isChangeSet);
-    validateBody(httpMethod, operation);
+    validateHttpMethod(httpMethod, isChangeSet, httpLineNumber);
+    validateBody(httpMethod, operation, httpLineNumber);
     InputStream bodyStrean = getBodyStream(operation, headers, httpMethod);
 
     ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod)
@@ -99,27 +101,26 @@ public class BatchRequestTransformator implements BatchTransformator {
         .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpStatusLine()))
         .body(bodyStrean)
         .requestHeaders(headers.toMultiMap())
-        .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpStatusLine(), pathInfo, baseUri));
-    
-    final String contentType =headers.getHeader(HttpHeaders.CONTENT_TYPE);
-    if(contentType != null) {
+        .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpStatusLine(), pathInfo, baseUri, 0));
+
+    final String contentType = headers.getHeader(HttpHeaders.CONTENT_TYPE);
+    if (contentType != null) {
       requestBuilder.contentType(contentType);
     }
-      
-    
+
     return requestBuilder.build();
   }
 
-  private void validateBody(final ODataHttpMethod httpMethod, final BatchQueryOperation operation)
+  private void validateBody(final ODataHttpMethod httpStatusLine, final BatchQueryOperation operation, final int line)
       throws BatchException {
-    if (HTTP_BATCH_METHODS.contains(httpMethod.toString()) && isUnvalidGetRequestBody(operation)) {
-      throw new BatchException(BatchException.INVALID_REQUEST_LINE);
+    if (HTTP_BATCH_METHODS.contains(httpStatusLine.toString()) && isUnvalidGetRequestBody(operation)) {
+      throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(httpStatusLine).addContent(line));
     }
   }
 
   private boolean isUnvalidGetRequestBody(final BatchQueryOperation operation) {
     return (operation.getBody().size() > 1)
-        || (operation.getBody().size() == 1 && !operation.getBody().get(0).trim().equals(""));
+        || (operation.getBody().size() == 1 && !operation.getBody().get(0).toString().trim().equals(""));
   }
 
   private InputStream getBodyStream(final BatchQueryOperation operation, Header headers,
@@ -140,28 +141,32 @@ public class BatchRequestTransformator implements BatchTransformator {
 
   private Header transformHeader(final BatchPart operation, final BatchPart parentPart) {
     final Header headers = operation.getHeaders().clone();
-    headers.removeHeaders(BatchHelper.HTTP_CONTENT_ID);
-    final List<String> operationContentIds = operation.getHeaders().getHeaders(BatchHelper.HTTP_CONTENT_ID);
-    final List<String> parentContentIds = parentPart.getHeaders().getHeaders(BatchHelper.HTTP_CONTENT_ID);
+    headers.removeHeader(BatchHelper.HTTP_CONTENT_ID);
+    final HeaderField operationHeader = operation.getHeaders().getHeaderField(BatchHelper.HTTP_CONTENT_ID);
+    final HeaderField parentHeader = parentPart.getHeaders().getHeaderField(BatchHelper.HTTP_CONTENT_ID);
 
-    if (operationContentIds.size() != 0) {
-      headers.addHeader(BatchHelper.REQUEST_HEADER_CONTENT_ID, operationContentIds);
+    if (operationHeader != null && operationHeader.getValues().size() != 0) {
+      headers.addHeader(BatchHelper.REQUEST_HEADER_CONTENT_ID, operationHeader.getValues(), operationHeader
+          .getLineNumber());
     }
 
-    if (parentContentIds.size() != 0) {
-      headers.addHeader(BatchHelper.MIME_HEADER_CONTENT_ID, parentContentIds);
+    if (parentHeader != null && parentHeader.getValues().size() != 0) {
+      headers.addHeader(BatchHelper.MIME_HEADER_CONTENT_ID, parentHeader.getValues(), parentHeader.getLineNumber());
     }
 
     return headers;
   }
 
-  private void validateHttpMethod(final ODataHttpMethod httpMethod, final boolean isChangeSet) throws BatchException {
+  private void validateHttpMethod(final ODataHttpMethod httpMethod, final boolean isChangeSet, final int line)
+      throws BatchException {
     Set<String> validMethods = (isChangeSet) ? HTTP_CHANGE_SET_METHODS : HTTP_BATCH_METHODS;
 
     if (!validMethods.contains(httpMethod.toString())) {
-      MessageReference message =
-          (isChangeSet) ? BatchException.INVALID_CHANGESET_METHOD : BatchException.INVALID_QUERY_OPERATION_METHOD;
-      throw new BatchException(message);
+      if (isChangeSet) {
+        throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(line));
+      } else {
+        throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD.addContent(line));
+      }
     }
   }
 
@@ -183,23 +188,20 @@ public class BatchRequestTransformator implements BatchTransformator {
     return acceptLanguages;
   }
 
-  private ODataHttpMethod getHttpMethod(final String httpRequest) throws BatchException {
+  private ODataHttpMethod getHttpMethod(final Line httpRequest) throws BatchException {
     ODataHttpMethod result = null;
 
-    if (httpRequest != null) {
-      String[] parts = httpRequest.split(" ");
+    String[] parts = httpRequest.toString().split(" ");
 
-      if (parts.length == 3) {
-        try {
-          result = ODataHttpMethod.valueOf(parts[0]);
-        } catch (IllegalArgumentException e) {
-          throw new BatchException(BatchException.MISSING_METHOD, e);
-        }
-      } else {
-        throw new BatchException(BatchException.INVALID_REQUEST_LINE);
+    if (parts.length == 3) {
+      try {
+        result = ODataHttpMethod.valueOf(parts[0]);
+      } catch (IllegalArgumentException e) {
+        throw new BatchException(BatchException.MISSING_METHOD.addContent(httpRequest.getLineNumber()), e);
       }
     } else {
-      throw new BatchException(BatchException.INVALID_REQUEST_LINE);
+      throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(httpRequest.toString()).addContent(
+          httpRequest.getLineNumber()));
     }
 
     return result;

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
index ab983ac..e800673 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
@@ -29,6 +29,7 @@ import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
 import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.core.batch.BatchHelper;
 import org.apache.olingo.odata2.core.batch.BatchSingleResponseImpl;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchResponseTransformator implements BatchTransformator {
 
@@ -92,14 +93,15 @@ public class BatchResponseTransformator implements BatchTransformator {
     return response;
   }
 
-  private Matcher prepareStatusLineMatcher(String httpStatusLine) throws BatchException {
+  private Matcher prepareStatusLineMatcher(final Line httpStatusLine) throws BatchException {
     final Pattern regexPattern = Pattern.compile(REG_EX_STATUS_LINE);
-    final Matcher matcher = regexPattern.matcher(httpStatusLine);
+    final Matcher matcher = regexPattern.matcher(httpStatusLine.toString());
 
     if (matcher.find()) {
       return matcher;
     } else {
-      throw new BatchException(BatchException.INVALID_STATUS_LINE);
+      throw new BatchException(BatchException.INVALID_STATUS_LINE.addContent(httpStatusLine.toString())
+          .addContent(httpStatusLine.getLineNumber()));
     }
   }
 
@@ -109,7 +111,7 @@ public class BatchResponseTransformator implements BatchTransformator {
     if (contentLength == -1) {
       return BatchParserCommon.stringListToString(operation.getBody());
     } else {
-      return BatchParserCommon.trimStringListToStringLength(operation.getBody(), contentLength);
+      return BatchParserCommon.trimLineListToLength(operation.getBody(), contentLength);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
index 9c67f49..498dd2d 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
@@ -6,6 +6,7 @@ import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpContentType;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.core.batch.BatchHelper;
+import org.apache.olingo.odata2.core.batch.v2.Header.HeaderField;
 
 public class BatchTransformatorCommon {
 
@@ -24,39 +25,45 @@ public class BatchTransformatorCommon {
 
   public static void validateContentTransferEncoding(final Header headers, final boolean isChangeRequest)
       throws BatchException {
-    final List<String> contentTransferEncodings = headers.getHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING);
+    final HeaderField contentTransferField = headers.getHeaderField(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING);
 
-    if (contentTransferEncodings.size() != 0) {
-      if (contentTransferEncodings.size() == 1) {
-        String encoding = contentTransferEncodings.get(0);
+    if (contentTransferField != null) {
+      final List<String> contentTransferValues = contentTransferField.getValues();
+      if (contentTransferValues.size() == 1) {
+        String encoding = contentTransferValues.get(0);
 
         if (!BatchHelper.BINARY_ENCODING.equalsIgnoreCase(encoding)) {
-          throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
+          throw new BatchException(
+              BatchException.INVALID_CONTENT_TRANSFER_ENCODING.addContent(contentTransferField.getLineNumber()));
         }
       } else {
-        throw new BatchException(BatchException.INVALID_HEADER);
+        throw new BatchException(BatchException.INVALID_HEADER.addContent(contentTransferField.getLineNumber()));
       }
     } else {
       if (isChangeRequest) {
-        throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
+        throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING.addContent(headers.getLineNumber()));
       }
     }
   }
 
   public static int getContentLength(final Header headers) throws BatchException {
-    final List<String> contentLengths = headers.getHeaders(HttpHeaders.CONTENT_LENGTH);
+    final HeaderField contentLengthField = headers.getHeaderField(HttpHeaders.CONTENT_LENGTH);
+
+    if (contentLengthField != null && contentLengthField.getValues().size() == 1) {
+      final List<String> contentLengthValues = contentLengthField.getValues();
 
-    if (contentLengths.size() == 1) {
       try {
-        int contentLength = Integer.parseInt(contentLengths.get(0));
+        int contentLength = Integer.parseInt(contentLengthValues.get(0));
 
         if (contentLength < 0) {
-          throw new BatchException(BatchException.INVALID_HEADER);
+          throw new BatchException(BatchException.INVALID_HEADER.addContent(contentLengthField.getValue()).addContent(
+              contentLengthField.getLineNumber()));
         }
 
         return contentLength;
       } catch (NumberFormatException e) {
-        throw new BatchException(BatchException.INVALID_HEADER, e);
+        throw new BatchException(BatchException.INVALID_HEADER.addContent(contentLengthField.getValue()).addContent(
+            contentLengthField.getLineNumber()), e);
       }
     }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BufferedReaderIncludingLineEndings.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BufferedReaderIncludingLineEndings.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BufferedReaderIncludingLineEndings.java
index 5e411ff..295f4c6 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BufferedReaderIncludingLineEndings.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BufferedReaderIncludingLineEndings.java
@@ -92,12 +92,13 @@ public class BufferedReaderIncludingLineEndings extends Reader {
     return bytesRead;
   }
 
-  public List<String> toList() throws IOException {
-    final List<String> result = new ArrayList<String>();
+  public List<Line> toList() throws IOException {
+    final List<Line> result = new ArrayList<Line>();
     String currentLine;
+    int counter = 1;
 
     while ((currentLine = readLine()) != null) {
-      result.add(currentLine);
+      result.add(new Line(currentLine, counter++));
     }
 
     return result;
@@ -217,4 +218,57 @@ public class BufferedReaderIncludingLineEndings extends Reader {
 
     return limit;
   }
+
+  public static class Line {
+    private final int lineNumber;
+    private final String content;
+
+    public Line(final String content, final int lineNumber) {
+      this.content = content;
+      this.lineNumber = lineNumber;
+    }
+
+    public int getLineNumber() {
+      return lineNumber;
+    }
+
+    @Override
+    public String toString() {
+      return content;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((content == null) ? 0 : content.hashCode());
+      result = prime * result + lineNumber;
+      return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+      if (this == obj) {
+        return true;
+      }
+      if (obj == null) {
+        return false;
+      }
+      if (getClass() != obj.getClass()) {
+        return false;
+      }
+      Line other = (Line) obj;
+      if (content == null) {
+        if (other.content != null) {
+          return false;
+        }
+      } else if (!content.equals(other.content)) {
+        return false;
+      }
+      if (lineNumber != other.lineNumber) {
+        return false;
+      }
+      return true;
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
index 7901b7b..c9daa6a 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
@@ -10,20 +10,14 @@ import java.util.regex.Pattern;
 public class Header implements Cloneable {
 
   private final Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
+  private int lineNumber;
   
-  public static List<String> splitValuesByComma(final String headerValue) {
-    final List<String> singleValues = new ArrayList<String>();
-
-    String[] parts = headerValue.split(",");
-    for (final String value : parts) {
-      singleValues.add(value.trim());
-    }
-
-    return singleValues;
+  public Header(int lineNumer) {
+    this.lineNumber = lineNumer;
   }
   
-  public void addHeader(final String name, final String value) {
-    final HeaderField headerField = getHeaderFieldOrDefault(name);
+  public void addHeader(final String name, final String value, final int lineNumber) {
+    final HeaderField headerField = getHeaderFieldOrDefault(name, lineNumber);
     final List<String> headerValues = headerField.getValues();
 
     if (!headerValues.contains(value)) {
@@ -31,8 +25,8 @@ public class Header implements Cloneable {
     }
   }
 
-  public void addHeader(final String name, final List<String> values) {
-    final HeaderField headerField = getHeaderFieldOrDefault(name);
+  public void addHeader(final String name, final List<String> values, final int lineNumber) {
+    final HeaderField headerField = getHeaderFieldOrDefault(name, lineNumber);
     final List<String> headerValues = headerField.getValues();
 
     for (final String value : values) {
@@ -41,45 +35,29 @@ public class Header implements Cloneable {
       }
     }
   }
-  
+
   public boolean isHeaderMatching(final String name, final Pattern pattern) {
-    if(getHeaders(name).size() != 1 ) {
+    if (getHeaders(name).size() != 1) {
       return false;
     } else {
       return pattern.matcher(getHeaders(name).get(0)).matches();
     }
   }
-  
-  public void removeHeaders(final String name) {
+
+  public void removeHeader(final String name) {
     headers.remove(name.toLowerCase(Locale.ENGLISH));
   }
 
   public String getHeader(final String name) {
     final HeaderField headerField = getHeaderField(name);
-
-    if (headerField == null) {
-      return null;
-    } else {
-      final List<String> headerValues = headerField.getValues();
-      final StringBuilder result = new StringBuilder();
-
-      for (final String value : headerValues) {
-        result.append(value);
-        result.append(", ");
-      }
-      
-      if(result.length()>0) {
-        result.delete(result.length() - 2, result.length());
-      }
-      
-      return result.toString();
-    }
+    
+    return (headerField == null) ? null : headerField.getValue();
   }
 
   public String getHeaderNotNull(final String name) {
-    final String value = getHeader(name);
-
-    return (value == null) ? "" : value;
+    final HeaderField headerField = getHeaderField(name);
+    
+    return (headerField == null) ? "" : headerField.getValueNotNull();
   }
 
   public List<String> getHeaders(final String name) {
@@ -91,7 +69,11 @@ public class Header implements Cloneable {
   public HeaderField getHeaderField(final String name) {
     return headers.get(name.toLowerCase(Locale.ENGLISH));
   }
-
+  
+  public int getLineNumber() {
+    return lineNumber;
+  }
+  
   public Map<String, String> toSingleMap() {
     final Map<String, String> singleMap = new HashMap<String, String>();
 
@@ -114,11 +96,11 @@ public class Header implements Cloneable {
     return singleMap;
   }
 
-  private HeaderField getHeaderFieldOrDefault(final String name) {
+  private HeaderField getHeaderFieldOrDefault(final String name, final int lineNumber) {
     HeaderField headerField = headers.get(name.toLowerCase(Locale.ENGLISH));
 
     if (headerField == null) {
-      headerField = new HeaderField(name);
+      headerField = new HeaderField(name, lineNumber);
       headers.put(name.toLowerCase(Locale.ENGLISH), headerField);
     }
 
@@ -127,7 +109,7 @@ public class Header implements Cloneable {
 
   @Override
   public Header clone() {
-    final Header newInstance = new Header();
+    final Header newInstance = new Header(lineNumber);
 
     for (final String key : headers.keySet()) {
       newInstance.headers.put(key, headers.get(key).clone());
@@ -136,17 +118,30 @@ public class Header implements Cloneable {
     return newInstance;
   }
 
+  public static List<String> splitValuesByComma(final String headerValue) {
+    final List<String> singleValues = new ArrayList<String>();
+
+    String[] parts = headerValue.split(",");
+    for (final String value : parts) {
+      singleValues.add(value.trim());
+    }
+
+    return singleValues;
+  }
+
   public static class HeaderField implements Cloneable {
-    private String fieldName;
-    private List<String> values;
+    private final String fieldName;
+    private final List<String> values;
+    private final int lineNumber;
 
-    public HeaderField(final String fieldName) {
-      this(fieldName, new ArrayList<String>());
+    public HeaderField(final String fieldName, final int lineNumber) {
+      this(fieldName, new ArrayList<String>(), lineNumber);
     }
 
-    public HeaderField(final String fieldName, final List<String> values) {
+    public HeaderField(final String fieldName, final List<String> values, final int lineNumber) {
       this.fieldName = fieldName;
       this.values = values;
+      this.lineNumber = lineNumber;
     }
 
     public String getFieldName() {
@@ -157,8 +152,37 @@ public class Header implements Cloneable {
       return values;
     }
 
-    public void setValues(final List<String> values) {
-      this.values = values;
+    public String getValue() {
+      final StringBuilder result = new StringBuilder();
+
+      for (final String value : values) {
+        result.append(value);
+        result.append(", ");
+      }
+
+      if (result.length() > 0) {
+        result.delete(result.length() - 2, result.length());
+      }
+
+      return result.toString();
+    }
+
+    public String getValueNotNull() {
+      final String value = getValue();
+
+      return (value == null) ? "" : value;
+    }
+
+    @Override
+    public HeaderField clone() {
+      List<String> newValues = new ArrayList<String>();
+      newValues.addAll(values);
+
+      return new HeaderField(fieldName, newValues, lineNumber);
+    }
+
+    public int getLineNumber() {
+      return lineNumber;
     }
 
     @Override
@@ -166,6 +190,8 @@ public class Header implements Cloneable {
       final int prime = 31;
       int result = 1;
       result = prime * result + ((fieldName == null) ? 0 : fieldName.hashCode());
+      result = prime * result + lineNumber;
+      result = prime * result + ((values == null) ? 0 : values.hashCode());
       return result;
     }
 
@@ -188,15 +214,17 @@ public class Header implements Cloneable {
       } else if (!fieldName.equals(other.fieldName)) {
         return false;
       }
+      if (lineNumber != other.lineNumber) {
+        return false;
+      }
+      if (values == null) {
+        if (other.values != null) {
+          return false;
+        }
+      } else if (!values.equals(other.values)) {
+        return false;
+      }
       return true;
     }
-
-    @Override
-    public HeaderField clone() {
-      List<String> newValues = new ArrayList<String>();
-      newValues.addAll(values);
-
-      return new HeaderField(fieldName, newValues);
-    }
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/main/resources/i18n.properties
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/resources/i18n.properties b/odata2-lib/odata-core/src/main/resources/i18n.properties
index a89c3e9..47e50a2 100644
--- a/odata2-lib/odata-core/src/main/resources/i18n.properties
+++ b/odata2-lib/odata-core/src/main/resources/i18n.properties
@@ -118,31 +118,30 @@ org.apache.olingo.odata2.api.ep.EntityProviderException.INVALID_DELETED_ENTRY_ME
 ##################################
 # BatchParserexceptions
 ##################################
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_BOUNDARY=The boundary of the ChangeSet should be different from that used by the Batch: line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_LANGUAGE_HEADER=Invalid Accept-Language: '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_HEADER=Invalid Accept header: '%1$s'.
 org.apache.olingo.odata2.api.batch.BatchException.INVALID_BOUNDARY_DELIMITER=The boundary delimiter must begin with two hyphen characters: line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.MISSING_BOUNDARY_DELIMITER=Missing boundary delimiter at line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.MISSING_CLOSE_DELIMITER=Missing close delimiter at line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_QUERY_OPERATION_METHOD=Invalid method: a Query Operation cannot contain insert, update or delete requests at line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_METHOD= Invalid method: a ChangeSet cannot contain retrieve requests at line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_QUERY_PARAMETER=Invalid query parameters.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_URI=Invalid URI: line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.UNSUPPORTED_ABSOLUTE_PATH = An absolute-path in request line is not supported: line '%1$s'.
 org.apache.olingo.odata2.api.batch.BatchException.INVALID_BOUNDARY=Invalid boundary at line '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.NO_MATCH_WITH_BOUNDARY_STRING=The boundary string does not match the boundary from the Content-Type header field '%1$s': line '%2$s'.
-org.apache.olingo.odata2.api.batch.BatchException.MISSING_CONTENT_TYPE=No Content-Type field for MIME-header is present.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TYPE=Content-Type should be '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE=The Content-Type field for multipart entities requires boundary parameter.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TRANSFER_ENCODING=The Content-Transfer-Encoding should be binary.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_HEADER=Invalid Accept header: '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_LANGUAGE_HEADER=Invalid Accept-Language: '%1$s'.
 org.apache.olingo.odata2.api.batch.BatchException.INVALID_HEADER=Invalid header: '%1$s' at line '%2$s'.
-org.apache.olingo.odata2.api.batch.BatchException.MISSING_BLANK_LINE=Expected empty line but was '%1$s': line '%2$s'  .
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TRANSFER_ENCODING=The Content-Transfer-Encoding should be binary: line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TYPE=Content-Type should be '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_BOUNDARY=The boundary of the ChangeSet should be different from that used by the Batch: line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_METHOD= Invalid method: a ChangeSet cannot contain retrieve requests at line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_REQUEST_LINE=Invalid request line '%1$s' at line '%2$s'.
 org.apache.olingo.odata2.api.batch.BatchException.INVALID_PATHINFO=PathInfo should not be null.
-org.apache.olingo.odata2.api.batch.BatchException.MISSING_METHOD=Missing method in request line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_URI=Invalid URI: line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_QUERY_OPERATION_METHOD=Invalid method: a Query Operation cannot contain insert, update or delete requests at line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_QUERY_PARAMETER=Invalid query parameters.
+org.apache.olingo.odata2.api.batch.BatchException.MISSING_BLANK_LINE=Expected empty line but was '%1$s': line '%2$s'  .
+org.apache.olingo.odata2.api.batch.BatchException.MISSING_BOUNDARY_DELIMITER=Missing boundary delimiter at line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.MISSING_CONTENT_TYPE=No Content-Type field for MIME-header is present.
+org.apache.olingo.odata2.api.batch.BatchException.MISSING_CLOSE_DELIMITER=Missing close delimiter at line '%1$s'.
 org.apache.olingo.odata2.api.batch.BatchException.MISSING_MANDATORY_HEADER=Missing mandatory header '%1$s'.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_REQUEST_LINE=Invalid request line '%1$s' at line '%2$s'.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_REQUEST_LINE=Invalid status line '%1$s' at line '%2$s'.
+org.apache.olingo.odata2.api.batch.BatchException.MISSING_METHOD=Missing method in request line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE=The Content-Type field for multipart entities requires boundary parameter.
+org.apache.olingo.odata2.api.batch.BatchException.NO_MATCH_WITH_BOUNDARY_STRING=The boundary string does not match the boundary from the Content-Type header field '%1$s': line '%2$s'.
 org.apache.olingo.odata2.api.batch.BatchException.TRUNCATED_BODY=Body is truncated: line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.UNSUPPORTED_ABSOLUTE_PATH = An absolute-path in request line is not supported: line '%1$s'.
 
 ##################################
 # HttpExceptions

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
index 56cbeeb..4369c1e 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
@@ -3,12 +3,12 @@ package org.apache.olingo.odata2.core.batch;
 import static org.junit.Assert.*;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.odata2.core.batch.v2.Header;
 import org.junit.Test;
 
@@ -24,9 +24,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
-    
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -46,9 +44,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
-    
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -67,9 +63,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
-    
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -92,9 +86,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
-    
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -113,9 +105,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
-    
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -133,8 +123,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -152,8 +141,7 @@ public class BatchParserCommonTest {
         "content-type: Application/http" + CRLF,
         "content-transfer-encoding: Binary" + CRLF
       };
-    List<String> message = new ArrayList<String>();
-    message.addAll(Arrays.asList(messageRaw));
+    List<Line> message = toLineList(messageRaw);
     
     final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
@@ -166,48 +154,59 @@ public class BatchParserCommonTest {
   @Test
   public void testRemoveEndingCRLF() {
     String line = "Test\r\n";
-    assertEquals("Test", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("Test", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveLastEndingCRLF() {
     String line = "Test\r\n\r\n";
-    assertEquals("Test\r\n", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("Test\r\n", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveEndingCRLFWithWS() {
     String line = "Test\r\n            ";
-    assertEquals("Test", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("Test", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveEndingCRLFNothingToRemove() {
     String line = "Hallo\r\nBla";
-    assertEquals("Hallo\r\nBla", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("Hallo\r\nBla", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveEndingCRLFAll() {
     String line = "\r\n";
-    assertEquals("", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveEndingCRLFSpace() {
     String line = "\r\n                      ";
-    assertEquals("", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveLastEndingCRLFWithWS() {
     String line = "Test            \r\n";
-    assertEquals("Test            ", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("Test            ", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
   }
 
   @Test
   public void testRemoveLastEndingCRLFWithWSLong() {
     String line = "Test            \r\nTest2    \r\n";
-    assertEquals("Test            \r\nTest2    ", BatchParserCommon.removeEndingCRLF(line));
+    assertEquals("Test            \r\nTest2    ", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString());
+  }
+  
+  private List<Line> toLineList(String[] messageRaw) {
+    final List<Line> lineList = new ArrayList<Line>();
+    int counter = 1;
+    
+    for(final String currentLine : messageRaw) {
+      lineList.add(new Line(currentLine, counter++));
+    }
+    
+    return lineList;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
index 4cd0b67..142d355 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
@@ -44,9 +44,6 @@ import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
-/**
- *
- */
 public class BatchRequestParserTest {
 
   private static final String CRLF = "\r\n";
@@ -257,7 +254,7 @@ public class BatchRequestParserTest {
 
   @Test(expected = BatchException.class)
   public void testBoundaryParameterWithoutQuota() throws BatchException {
-    String invalidContentType = "multipart;boundary=batch_1740-bb:84-2f7f";
+    String invalidContentType = "multipart/mixed;boundary=batch_1740-bb:84-2f7f";
     String batch = "--batch_1740-bb:84-2f7f" + CRLF
         + GET_REQUEST
         + "--batch_1740-bb:84-2f7f--";
@@ -607,32 +604,6 @@ public class BatchRequestParserTest {
   }
 
   @SuppressWarnings("unused")
-  @Test(expected = BatchException.class)
-  @Ignore("This header should not be validated")
-  public void testNegativeContentLength() throws BatchException, IOException {
-    String batch = ""
-        + "--batch_8194-cf13-1f56" + CRLF
-        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF
-        + "Content-Length: -2" + CRLF
-        + CRLF
-        + "--changeset_f980-1cb6-94dd" + CRLF
-        + MIME_HEADERS
-        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
-        + CRLF
-        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
-        + "Content-Type: application/json;odata=verbose" + CRLF
-        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
-        + CRLF
-        + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
-        + "--changeset_f980-1cb6-94dd--" + CRLF
-        + CRLF
-        + "--batch_8194-cf13-1f56--";
-    InputStream in = new ByteArrayInputStream(batch.getBytes());
-    BatchParser parser = new BatchParser(contentType, batchProperties, true);
-    List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
-  }
-
-  @SuppressWarnings("unused")
   @Test
   public void testNegativeContentLengthChangeSet() throws BatchException, IOException {
     String batch = ""
@@ -747,44 +718,6 @@ public class BatchRequestParserTest {
   }
 
   @Test(expected = BatchException.class)
-  @Ignore("This header should not be validated")
-  public void testCutChangeSetDelimiter() throws BatchException, IOException {
-    String batch = ""
-        + "--batch_8194-cf13-1f56" + CRLF
-        + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF
-        + "Content-Length: 582" + CRLF
-        + CRLF
-        + "--changeset_f980-1cb6-94dd" + CRLF
-        + MIME_HEADERS
-        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
-        + CRLF
-        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
-        + "Content-Type: application/json;odata=verbose" + CRLF
-        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
-        + "Content-Length: 10" + CRLF
-        + CRLF
-        + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
-        + CRLF
-        + "--changeset_f980-1cb6-94dd" + CRLF
-        + MIME_HEADERS
-        + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF
-        + CRLF
-        + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF
-        + "Content-Type: application/json;odata=verbose" + CRLF
-        + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF
-        + "Content-Length: 100000" + CRLF
-        + CRLF
-        + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF
-        + "--changeset_f980-1cb6-94dd--" + CRLF
-        + CRLF
-        + "--batch_8194-cf13-1f56--";
-
-    InputStream in = new ByteArrayInputStream(batch.getBytes());
-    BatchParser parser = new BatchParser(contentType, batchProperties, true);
-    parser.parseBatchRequest(in);
-  }
-
-  @Test(expected = BatchException.class)
   public void testNonNumericContentLength() throws BatchException {
     String batch = ""
         + "--batch_8194-cf13-1f56" + CRLF
@@ -1138,7 +1071,20 @@ public class BatchRequestParserTest {
     assertEquals("{\"EmployeeName\":\"Peter Fall\"}",
         inputStreamToString(changeSetPart.getRequests().get(1).getBody()));
   }
+  
+  @Test
+  public void testLargeBatch() throws BatchException, IOException {
+    String fileName = "/batchLarge.batch";
+    InputStream in = ClassLoader.class.getResourceAsStream(fileName);
+    if (in == null) {
+      throw new IOException("Requested file '" + fileName + "' was not found.");
+    }
+    
+    BatchParser parser = new BatchParser(contentType, batchProperties, true);
+    parser.parseBatchRequest(in);
+  }
 
+  
   private List<BatchRequestPart> parse(final String batch) throws BatchException {
     InputStream in = new ByteArrayInputStream(batch.getBytes());
     BatchParser parser = new BatchParser(contentType, batchProperties, true);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
index 6c604f8..bcf13e4 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
@@ -132,7 +132,6 @@ public class BatchRequestTest {
   }
 
   @Test
-  @Ignore
   // TODO
       /*
        * --batch_123
@@ -146,8 +145,8 @@ public class BatchRequestTest {
        * ...
        * ....
        */
-      public
-      void testBatchWithGetAndPost() throws BatchException, IOException {
+  @Ignore
+  public void testBatchWithGetAndPost() throws BatchException, IOException {
     List<BatchPart> batch = new ArrayList<BatchPart>();
     Map<String, String> headers = new HashMap<String, String>();
     headers.put("Accept", "application/json");

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
index e98a295..7437caf 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
@@ -50,7 +50,7 @@ public class BatchTransformatorCommonTest {
 
   @Test(expected = BatchException.class)
   public void testValidateContentTypeMissingHeader() throws BatchException {
-    final Header headers = new Header();
+    final Header headers = new Header(1);
     
     BatchTransformatorCommon.validateContentType(headers);
   }
@@ -82,7 +82,7 @@ public class BatchTransformatorCommonTest {
 
   @Test(expected = BatchException.class)
   public void testValidateContentTransferEncodingMissingHeader() throws BatchException {
-    final Header headers = new Header();
+    final Header headers = new Header(1);
     
     BatchTransformatorCommon.validateContentTransferEncoding(headers, true);
   }
@@ -96,8 +96,8 @@ public class BatchTransformatorCommonTest {
   }
 
   private Header makeHeaders(final String headerName, final List<String> values) {
-    final Header headers = new Header();
-    headers.addHeader(headerName, values);
+    final Header headers = new Header(1);
+    headers.addHeader(headerName, values, 1);
 
     return headers;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java
index bd3607a..482dc3b 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BufferedReaderIncludingLineEndingsTest.java
@@ -9,6 +9,7 @@ import java.io.UnsupportedEncodingException;
 import java.util.List;
 
 import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings;
+import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line;
 import org.junit.Test;
 
 public class BufferedReaderIncludingLineEndingsTest {
@@ -422,20 +423,20 @@ public class BufferedReaderIncludingLineEndingsTest {
   @Test
   public void testToList() throws IOException {
     BufferedReaderIncludingLineEndings reader = create(TEXT_COMBINED);
-    List<String> stringList = reader.toList();
+    List<Line> stringList = reader.toList();
 
     assertEquals(11, stringList.size());
-    assertEquals("Test\r", stringList.get(0));
-    assertEquals("Test2\r\n", stringList.get(1));
-    assertEquals("Test3\n", stringList.get(2));
-    assertEquals("Test4\r", stringList.get(3));
-    assertEquals("\r", stringList.get(4));
-    assertEquals("\r\n", stringList.get(5));
-    assertEquals("\r\n", stringList.get(6));
-    assertEquals("Test5\n", stringList.get(7));
-    assertEquals("Test6\r\n", stringList.get(8));
-    assertEquals("Test7\n", stringList.get(9));
-    assertEquals("\n", stringList.get(10));
+    assertEquals("Test\r", stringList.get(0).toString());
+    assertEquals("Test2\r\n", stringList.get(1).toString());
+    assertEquals("Test3\n", stringList.get(2).toString());
+    assertEquals("Test4\r", stringList.get(3).toString());
+    assertEquals("\r", stringList.get(4).toString());
+    assertEquals("\r\n", stringList.get(5).toString());
+    assertEquals("\r\n", stringList.get(6).toString());
+    assertEquals("Test5\n", stringList.get(7).toString());
+    assertEquals("Test6\r\n", stringList.get(8).toString());
+    assertEquals("Test7\n", stringList.get(9).toString());
+    assertEquals("\n", stringList.get(10).toString());
     reader.close();
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
index 128aa2e..bfe7b24 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
@@ -15,8 +15,8 @@ public class HeaderTest {
 
   @Test
   public void test() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 1);
 
     assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeader(HttpHeaders.CONTENT_TYPE));
     assertEquals(1, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
@@ -25,7 +25,7 @@ public class HeaderTest {
 
   @Test
   public void testNotAvailable() {
-    Header header = new Header();
+    Header header = new Header(1);
 
     assertNull(header.getHeader(HttpHeaders.CONTENT_TYPE));
     assertEquals(0, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
@@ -34,8 +34,8 @@ public class HeaderTest {
 
   @Test
   public void testCaseInsensitive() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 1);
 
     assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeader("cOnTenT-TyPE"));
     assertEquals(1, header.getHeaders("cOnTenT-TyPE").size());
@@ -44,9 +44,9 @@ public class HeaderTest {
 
   @Test
   public void testDuplicatedAdd() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 2);
 
     assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeader(HttpHeaders.CONTENT_TYPE));
     assertEquals(1, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
@@ -55,16 +55,16 @@ public class HeaderTest {
 
   @Test
   public void testMatcher() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123");
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123", 1);
 
     assertTrue(header.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_MULTIPART_BOUNDARY));
   }
 
   @Test
   public void testFieldName() {
-    Header header = new Header();
-    header.addHeader("MyFieldNamE", "myValue");
+    Header header = new Header(0);
+    header.addHeader("MyFieldNamE", "myValue", 1);
 
     assertEquals("MyFieldNamE", header.getHeaderField("myfieldname").getFieldName());
     assertEquals("MyFieldNamE", header.toSingleMap().keySet().toArray(new String[0])[0]);
@@ -76,8 +76,8 @@ public class HeaderTest {
 
   @Test
   public void testDeepCopy() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123");
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123", 1);
 
     Header copy = header.clone();
     assertEquals(header.getHeaders(HttpHeaders.CONTENT_TYPE), copy.getHeaders(HttpHeaders.CONTENT_TYPE));
@@ -90,25 +90,25 @@ public class HeaderTest {
 
   @Test
   public void testMatcherNoHeader() {
-    Header header = new Header();
+    Header header = new Header(1);
 
     assertFalse(header.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_MULTIPART_BOUNDARY));
   }
 
   @Test
   public void testMatcherFail() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123");
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123", 1);
 
     assertFalse(header.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_HEADER_LINE));
   }
 
   @Test
   public void testDuplicatedAddList() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 1);
     header.addHeader(HttpHeaders.CONTENT_TYPE, Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED,
-        HttpContentType.APPLICATION_ATOM_SVC }));
+        HttpContentType.APPLICATION_ATOM_SVC }), 2);
 
     assertEquals(HttpContentType.MULTIPART_MIXED + ", " + HttpContentType.APPLICATION_ATOM_SVC, header
         .getHeader(HttpHeaders.CONTENT_TYPE));
@@ -119,9 +119,9 @@ public class HeaderTest {
 
   @Test
   public void testRemove() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
-    header.removeHeaders(HttpHeaders.CONTENT_TYPE);
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 1);
+    header.removeHeader(HttpHeaders.CONTENT_TYPE);
 
     assertNull(header.getHeader(HttpHeaders.CONTENT_TYPE));
     assertEquals(0, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
@@ -129,10 +129,10 @@ public class HeaderTest {
 
   @Test
   public void testMultipleValues() {
-    Header header = new Header();
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.APPLICATION_ATOM_SVC);
-    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.APPLICATION_ATOM_XML);
+    Header header = new Header(1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED, 1);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.APPLICATION_ATOM_SVC, 2);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.APPLICATION_ATOM_XML, 3);
 
     final String fullHeaderString =
         HttpContentType.MULTIPART_MIXED + ", " + HttpContentType.APPLICATION_ATOM_SVC + ", "


[2/4] git commit: Header class refactoring

Posted by ch...@apache.org.
Header class refactoring

Signed-off-by: Christian Amend <ch...@apache.org>


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

Branch: refs/heads/olingo436BatchRefactoring
Commit: 05d20c1fa078f2c445b4fe30ab96d4a5f8d2b585
Parents: 1f90b73
Author: Christian Holzer <c....@sap.com>
Authored: Fri Oct 3 01:34:45 2014 +0200
Committer: Christian Amend <ch...@apache.org>
Committed: Mon Oct 6 13:54:38 2014 +0200

----------------------------------------------------------------------
 .../odata2/core/batch/v2/BatchBodyPart.java     |  24 +--
 .../odata2/core/batch/v2/BatchParserCommon.java | 135 +------------
 .../olingo/odata2/core/batch/v2/BatchPart.java  |   6 +-
 .../core/batch/v2/BatchQueryOperation.java      |   6 +-
 .../batch/v2/BatchRequestTransformator.java     | 121 ++++-------
 .../batch/v2/BatchResponseTransformator.java    |  61 +++---
 .../core/batch/v2/BatchTransformatorCommon.java |  47 ++---
 .../olingo/odata2/core/batch/v2/Header.java     | 202 +++++++++++++++++++
 .../core/batch/BatchParserCommonTest.java       |  60 +++---
 .../batch/BatchTransformatorCommonTest.java     |  34 ++--
 .../olingo/odata2/core/batch/HeaderTest.java    | 161 +++++++++++++++
 11 files changed, 509 insertions(+), 348 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
index 4edcf45..f74ea85 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchBodyPart.java
@@ -20,19 +20,16 @@ package org.apache.olingo.odata2.core.batch.v2;
 
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Locale;
-import java.util.Map;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 
 public class BatchBodyPart implements BatchPart {
   final private String boundary;
   final private boolean isStrict;
   final List<String> remainingMessage = new LinkedList<String>();
 
-  private Map<String, HeaderField> headers;
+  private Header headers;
   private boolean isChangeSet;
   private List<BatchQueryOperation> requests;
 
@@ -53,15 +50,15 @@ public class BatchBodyPart implements BatchPart {
     return this;
   }
 
-  private boolean isChangeSet(final Map<String, HeaderField> headers) throws BatchException {
-    final HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
+  private boolean isChangeSet(final Header headers) throws BatchException {
+    final List<String> contentTypes = headers.getHeaders(HttpHeaders.CONTENT_TYPE);
     boolean isChangeSet = false;
 
-    if (contentTypeField == null || contentTypeField.getValues().size() == 0) {
+    if (contentTypes.size() == 0) {
       throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
     }
 
-    for (String contentType : contentTypeField.getValues()) {
+    for (String contentType : contentTypes) {
       if (isContentTypeMultiPartMixed(contentType)) {
         isChangeSet = true;
       }
@@ -97,7 +94,7 @@ public class BatchBodyPart implements BatchPart {
   private List<List<String>> splitChangeSet(final List<String> remainingMessage)
       throws BatchException {
 
-    final String changeSetBoundary = BatchParserCommon.getBoundary(getContentType());
+    final String changeSetBoundary = BatchParserCommon.getBoundary(headers.getHeaderNotNull(HttpHeaders.CONTENT_TYPE));
     validateChangeSetBoundary(changeSetBoundary);
 
     return BatchParserCommon.splitMessageByBoundary(remainingMessage, changeSetBoundary);
@@ -117,15 +114,8 @@ public class BatchBodyPart implements BatchPart {
     }
   }
 
-  private String getContentType() {
-    HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
-
-    return (contentTypeField != null && contentTypeField.getValues().size() > 0) ? contentTypeField.getValues().get(0)
-        : "";
-  }
-
   @Override
-  public Map<String, HeaderField> getHeaders() {
+  public Header getHeaders() {
     return headers;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
index 8b7f62a..df62994 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
@@ -23,7 +23,6 @@ import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
@@ -148,8 +147,8 @@ public class BatchParserCommon {
     }
   }
 
-  public static Map<String, HeaderField> consumeHeaders(final List<String> remainingMessage) throws BatchException {
-    final Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
+  public static Header consumeHeaders(final List<String> remainingMessage) throws BatchException {
+    final Header headers = new Header();
     boolean isHeader = true;
     final Iterator<String> iter = remainingMessage.iterator();
     final AcceptParser acceptParser = new AcceptParser();
@@ -157,59 +156,30 @@ public class BatchParserCommon {
 
     while (iter.hasNext() && isHeader) {
       currentLine = iter.next();
-      Matcher headerMatcher = PATTERN_HEADER_LINE.matcher(currentLine);
+      final Matcher headerMatcher = PATTERN_HEADER_LINE.matcher(currentLine);
 
       if (headerMatcher.matches() && headerMatcher.groupCount() == 2) {
         iter.remove();
 
         String headerName = headerMatcher.group(1).trim();
-        String headerNameLowerCase = headerName.toLowerCase(Locale.ENGLISH);
         String headerValue = headerMatcher.group(2).trim();
 
-        if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerNameLowerCase)) {
+        if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerName)) {
           acceptParser.addAcceptHeaderValue(headerValue);
-        } else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerNameLowerCase)) {
+        } else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerName)) {
           acceptParser.addAcceptLanguageHeaderValue(headerValue);
         } else {
-          addHeaderValue(headers, headerName, headerNameLowerCase, headerValue);
+          headers.addHeader(headerName, Header.splitValuesByComma(headerValue));
         }
       } else {
         isHeader = false;
       }
     }
 
-    final List<String> acceptHeader = acceptParser.parseAcceptHeaders();
-    headers.put(HttpHeaders.ACCEPT.toLowerCase(), new HeaderField(HttpHeaders.ACCEPT, acceptHeader));
+    headers.addHeader(HttpHeaders.ACCEPT, acceptParser.parseAcceptHeaders());
+    headers.addHeader(HttpHeaders.ACCEPT_LANGUAGE, acceptParser.parseAcceptableLanguages());
 
-    final List<String> acceptLanguageHeader = acceptParser.parseAcceptableLanguages();
-    headers.put(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase(), new HeaderField(HttpHeaders.ACCEPT_LANGUAGE,
-        acceptLanguageHeader));
-
-    return Collections.unmodifiableMap(headers);
-  }
-
-  private static void addHeaderValue(final Map<String, HeaderField> headers, final String headerName,
-      final String headerNameLowerCase, final String headerValue) {
-    HeaderField headerField = headers.get(headerNameLowerCase);
-    headerField = headerField == null ? new HeaderField(headerName) : headerField;
-    headers.put(headerNameLowerCase, headerField);
-
-    for (final String singleValue : splitHeaderValuesByComma(headerValue)) {
-      if (!headerField.getValues().contains(singleValue)) {
-        headerField.getValues().add(singleValue);
-      }
-    }
-  }
-
-  private static List<String> splitHeaderValuesByComma(final String headerValue) {
-    final List<String> singleValues = new ArrayList<String>();
-
-    String[] parts = headerValue.split(",");
-    for (final String value : parts) {
-      singleValues.add(value.trim());
-    }
-
-    return singleValues;
+    return headers;
   }
 
   public static void consumeBlankLine(final List<String> remainingMessage, final boolean isStrict)
@@ -338,91 +308,4 @@ public class BatchParserCommon {
 
     return boundary;
   }
-
-  public static Map<String, String> headerFieldMapToSingleMap(final Map<String, HeaderField> headers) {
-    final Map<String, String> singleMap = new HashMap<String, String>();
-
-    for (final String key : headers.keySet()) {
-      HeaderField field = headers.get(key);
-      String value = field.getValues().size() > 0 ? field.getValues().get(0) : "";
-      singleMap.put(field.getFieldName(), value);
-    }
-
-    return singleMap;
-  }
-
-  public static Map<String, List<String>> headerFieldMapToMultiMap(final Map<String, HeaderField> headers) {
-    final Map<String, List<String>> singleMap = new HashMap<String, List<String>>();
-
-    for (final String key : headers.keySet()) {
-      HeaderField field = headers.get(key);
-      singleMap.put(field.getFieldName(), field.getValues());
-    }
-
-    return singleMap;
-  }
-
-  public static class HeaderField implements Cloneable {
-    private String fieldName;
-    private List<String> values;
-
-    public HeaderField(final String fieldName) {
-      this(fieldName, new ArrayList<String>());
-    }
-
-    public HeaderField(final String fieldName, final List<String> values) {
-      this.fieldName = fieldName;
-      this.values = values;
-    }
-
-    public String getFieldName() {
-      return fieldName;
-    }
-
-    public List<String> getValues() {
-      return values;
-    }
-
-    public void setValues(final List<String> values) {
-      this.values = values;
-    }
-
-    @Override
-    public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + ((fieldName == null) ? 0 : fieldName.hashCode());
-      return result;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-      if (this == obj) {
-        return true;
-      }
-      if (obj == null) {
-        return false;
-      }
-      if (getClass() != obj.getClass()) {
-        return false;
-      }
-      HeaderField other = (HeaderField) obj;
-      if (fieldName == null) {
-        if (other.fieldName != null) {
-          return false;
-        }
-      } else if (!fieldName.equals(other.fieldName)) {
-        return false;
-      }
-      return true;
-    }
-
-    @Override
-    public HeaderField clone() {
-      List<String> newValues = new ArrayList<String>();
-      newValues.addAll(values);
-
-      return new HeaderField(fieldName, newValues);
-    }
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchPart.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchPart.java
index 258f48a..69f211f 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchPart.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchPart.java
@@ -18,12 +18,8 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.core.batch.v2;
 
-import java.util.Map;
-
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
-
 public interface BatchPart {
-  public Map<String, HeaderField> getHeaders();
+  public Header getHeaders();
 
   public boolean isStrict();
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
index 5176bb8..87dcb23 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchQueryOperation.java
@@ -19,16 +19,14 @@
 package org.apache.olingo.odata2.core.batch.v2;
 
 import java.util.List;
-import java.util.Map;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 
 public class BatchQueryOperation implements BatchPart {
 
   protected final boolean isStrict;
   protected String httpStatusLine;
-  protected Map<String, HeaderField> headers;
+  protected Header headers;
   protected List<String> body;
   protected int bodySize;
   protected List<String> message;
@@ -71,7 +69,7 @@ public class BatchQueryOperation implements BatchPart {
   }
 
   @Override
-  public Map<String, HeaderField> getHeaders() {
+  public Header getHeaders() {
     return headers;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
index 5169575..a49a2e5 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
@@ -22,12 +22,10 @@ import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
@@ -40,7 +38,6 @@ import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder;
 import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.core.batch.BatchHelper;
 import org.apache.olingo.odata2.core.batch.BatchRequestPartImpl;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 
 public class BatchRequestTransformator implements BatchTransformator {
 
@@ -55,7 +52,7 @@ public class BatchRequestTransformator implements BatchTransformator {
     final List<ODataRequest> requests = new LinkedList<ODataRequest>();
     final List<BatchParserResult> resultList = new ArrayList<BatchParserResult>();
 
-    validateBodyPartHeaders(bodyPart);
+    validateHeader(bodyPart, false);
 
     for (BatchQueryOperation queryOperation : bodyPart.getRequests()) {
       requests.add(processQueryOperation(bodyPart, pathInfo, baseUri, queryOperation));
@@ -65,11 +62,11 @@ public class BatchRequestTransformator implements BatchTransformator {
     return resultList;
   }
 
-  private void validateBodyPartHeaders(final BatchBodyPart bodyPart) throws BatchException {
-    Map<String, HeaderField> headers = bodyPart.getHeaders();
+  private void validateHeader(final BatchPart bodyPart, boolean isChangeSet) throws BatchException {
+    Header headers = bodyPart.getHeaders();
 
     BatchTransformatorCommon.validateContentType(headers);
-    BatchTransformatorCommon.validateContentTransferEncoding(headers, false);
+    BatchTransformatorCommon.validateContentTransferEncoding(headers, isChangeSet);
   }
 
   private ODataRequest processQueryOperation(final BatchBodyPart bodyPart, final PathInfo pathInfo,
@@ -77,24 +74,18 @@ public class BatchRequestTransformator implements BatchTransformator {
 
     if (bodyPart.isChangeSet()) {
       BatchQueryOperation encapsulatedQueryOperation = ((BatchChangeSetPart) queryOperation).getRequest();
-      Map<String, HeaderField> headers = transformHeader(encapsulatedQueryOperation, queryOperation);
-      validateChangeSetMultipartMimeHeaders(queryOperation, encapsulatedQueryOperation);
+      Header headers = transformHeader(encapsulatedQueryOperation, queryOperation);
+      validateHeader(queryOperation, true);
 
       return createRequest(queryOperation, headers, pathInfo, baseUri, bodyPart.isChangeSet());
     } else {
 
-      Map<String, HeaderField> headers = transformHeader(queryOperation, bodyPart);
+      Header headers = transformHeader(queryOperation, bodyPart);
       return createRequest(queryOperation, headers, pathInfo, baseUri, bodyPart.isChangeSet());
     }
   }
 
-  private void validateChangeSetMultipartMimeHeaders(final BatchQueryOperation queryOperation,
-      final BatchQueryOperation encapsulatedQueryOperation) throws BatchException {
-    BatchTransformatorCommon.validateContentType(queryOperation.getHeaders());
-    BatchTransformatorCommon.validateContentTransferEncoding(queryOperation.getHeaders(), true);
-  }
-
-  private ODataRequest createRequest(final BatchQueryOperation operation, final Map<String, HeaderField> headers,
+  private ODataRequest createRequest(final BatchQueryOperation operation, final Header headers,
       final PathInfo pathInfo, final String baseUri, final boolean isChangeSet) throws BatchException {
 
     ODataHttpMethod httpMethod = getHttpMethod(operation.getHttpStatusLine());
@@ -104,14 +95,18 @@ public class BatchRequestTransformator implements BatchTransformator {
 
     ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod)
         .acceptableLanguages(getAcceptLanguageHeaders(headers))
-        .acceptHeaders(getAcceptHeaders(headers))
+        .acceptHeaders(headers.getHeaders(HttpHeaders.ACCEPT))
         .allQueryParameters(BatchParserCommon.parseQueryParameter(operation.getHttpStatusLine()))
         .body(bodyStrean)
-        .requestHeaders(BatchParserCommon.headerFieldMapToMultiMap(headers))
+        .requestHeaders(headers.toMultiMap())
         .pathInfo(BatchParserCommon.parseRequestUri(operation.getHttpStatusLine(), pathInfo, baseUri));
-
-    addContentTypeHeader(requestBuilder, headers);
-
+    
+    final String contentType =headers.getHeader(HttpHeaders.CONTENT_TYPE);
+    if(contentType != null) {
+      requestBuilder.contentType(contentType);
+    }
+      
+    
     return requestBuilder.build();
   }
 
@@ -127,7 +122,7 @@ public class BatchRequestTransformator implements BatchTransformator {
         || (operation.getBody().size() == 1 && !operation.getBody().get(0).trim().equals(""));
   }
 
-  private InputStream getBodyStream(final BatchQueryOperation operation, final Map<String, HeaderField> headers,
+  private InputStream getBodyStream(final BatchQueryOperation operation, Header headers,
       final ODataHttpMethod httpMethod) throws BatchException {
 
     if (HTTP_BATCH_METHODS.contains(httpMethod.toString())) {
@@ -143,27 +138,18 @@ public class BatchRequestTransformator implements BatchTransformator {
     }
   }
 
-  private Map<String, HeaderField> transformHeader(final BatchPart operation, final BatchPart parentPart) {
-    final Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
-    final Map<String, HeaderField> operationHeader = operation.getHeaders();
-    final Map<String, HeaderField> parentHeaders = parentPart.getHeaders();
+  private Header transformHeader(final BatchPart operation, final BatchPart parentPart) {
+    final Header headers = operation.getHeaders().clone();
+    headers.removeHeaders(BatchHelper.HTTP_CONTENT_ID);
+    final List<String> operationContentIds = operation.getHeaders().getHeaders(BatchHelper.HTTP_CONTENT_ID);
+    final List<String> parentContentIds = parentPart.getHeaders().getHeaders(BatchHelper.HTTP_CONTENT_ID);
 
-    for (final String key : operation.getHeaders().keySet()) {
-      headers.put(key, operation.getHeaders().get(key).clone());
+    if (operationContentIds.size() != 0) {
+      headers.addHeader(BatchHelper.REQUEST_HEADER_CONTENT_ID, operationContentIds);
     }
 
-    headers.remove(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
-
-    if (operationHeader.containsKey(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH))) {
-      HeaderField operationContentField = operationHeader.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase());
-      headers.put(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), new HeaderField(
-          BatchHelper.REQUEST_HEADER_CONTENT_ID, operationContentField.getValues()));
-    }
-
-    if (parentHeaders.containsKey(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH))) {
-      HeaderField parentContentField = parentHeaders.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase());
-      headers.put(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), new HeaderField(
-          BatchHelper.MIME_HEADER_CONTENT_ID, parentContentField.getValues()));
+    if (parentContentIds.size() != 0) {
+      headers.addHeader(BatchHelper.MIME_HEADER_CONTENT_ID, parentContentIds);
     }
 
     return headers;
@@ -179,52 +165,19 @@ public class BatchRequestTransformator implements BatchTransformator {
     }
   }
 
-  private void addContentTypeHeader(final ODataRequestBuilder requestBuilder, final Map<String, HeaderField> header) {
-    String contentType = getContentTypeHeader(header);
-
-    if (contentType != null) {
-      requestBuilder.contentType(contentType);
-    }
-  }
-
-  private String getContentTypeHeader(final Map<String, HeaderField> headers) {
-    HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
-    String contentType = null;
-    if (contentTypeField != null) {
-      for (String requestContentType : contentTypeField.getValues()) {
-        contentType = contentType != null ? contentType + "," + requestContentType : requestContentType;
-      }
-    }
-
-    return contentType;
-  }
-
-  private List<String> getAcceptHeaders(final Map<String, HeaderField> headers) {
-    List<String> acceptHeaders = new ArrayList<String>();
-    HeaderField requestAcceptHeaderField = headers.get(HttpHeaders.ACCEPT.toLowerCase(Locale.ENGLISH));
-
-    if (requestAcceptHeaderField != null) {
-      acceptHeaders = requestAcceptHeaderField.getValues();
-    }
-
-    return acceptHeaders;
-  }
-
-  private List<Locale> getAcceptLanguageHeaders(final Map<String, HeaderField> headers) {
-    final HeaderField requestAcceptLanguageField = headers.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase(Locale.ENGLISH));
+  private List<Locale> getAcceptLanguageHeaders(final Header headers) {
+    final List<String> acceptLanguageValues = headers.getHeaders(HttpHeaders.ACCEPT_LANGUAGE);
     List<Locale> acceptLanguages = new ArrayList<Locale>();
 
-    if (requestAcceptLanguageField != null) {
-      for (String acceptLanguage : requestAcceptLanguageField.getValues()) {
-        String[] part = acceptLanguage.split("-");
-        String language = part[0];
-        String country = "";
-        if (part.length == 2) {
-          country = part[part.length - 1];
-        }
-        Locale locale = new Locale(language, country);
-        acceptLanguages.add(locale);
+    for (String acceptLanguage : acceptLanguageValues) {
+      String[] part = acceptLanguage.split("-");
+      String language = part[0];
+      String country = "";
+      if (part.length == 2) {
+        country = part[part.length - 1];
       }
+      Locale locale = new Locale(language, country);
+      acceptLanguages.add(locale);
     }
 
     return acceptLanguages;

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
index d82d09e..ab983ac 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchResponseTransformator.java
@@ -20,8 +20,6 @@ package org.apache.olingo.odata2.core.batch.v2;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
-import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -31,7 +29,6 @@ import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
 import org.apache.olingo.odata2.api.uri.PathInfo;
 import org.apache.olingo.odata2.core.batch.BatchHelper;
 import org.apache.olingo.odata2.core.batch.BatchSingleResponseImpl;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 
 public class BatchResponseTransformator implements BatchTransformator {
 
@@ -52,7 +49,6 @@ public class BatchResponseTransformator implements BatchTransformator {
     List<BatchParserResult> resultList = new ArrayList<BatchParserResult>();
 
     BatchTransformatorCommon.validateContentType(bodyPart.getHeaders());
-
     resultList.addAll(handleBodyPart(bodyPart));
 
     return resultList;
@@ -66,7 +62,9 @@ public class BatchResponseTransformator implements BatchTransformator {
         bodyPartResult.add(transformChangeSet((BatchChangeSetPart) operation));
       }
     } else {
-      bodyPartResult.add(transformQueryOperation(bodyPart.getRequests().get(0), getContentId(bodyPart.getHeaders())));
+      final String contentId = bodyPart.getHeaders().getHeader(BatchHelper.HTTP_CONTENT_ID);
+
+      bodyPartResult.add(transformQueryOperation(bodyPart.getRequests().get(0), contentId));
     }
 
     return bodyPartResult;
@@ -74,60 +72,53 @@ public class BatchResponseTransformator implements BatchTransformator {
 
   private BatchSingleResponse transformChangeSet(final BatchChangeSetPart changeSet) throws BatchException {
     BatchTransformatorCommon.validateContentTransferEncoding(changeSet.getHeaders(), true);
+    final String contentId = changeSet.getHeaders().getHeader(BatchHelper.HTTP_CONTENT_ID);
 
-    return transformQueryOperation(changeSet.getRequest(), getContentId(changeSet.getHeaders()));
+    return transformQueryOperation(changeSet.getRequest(), contentId);
   }
 
   private BatchSingleResponse transformQueryOperation(final BatchQueryOperation operation, final String contentId)
       throws BatchException {
+
+    final Matcher statusMatcher = prepareStatusLineMatcher(operation.getHttpStatusLine());
+
     BatchSingleResponseImpl response = new BatchSingleResponseImpl();
     response.setContentId(contentId);
-    response.setHeaders(BatchParserCommon.headerFieldMapToSingleMap(operation.getHeaders()));
-    response.setStatusCode(getStatusCode(operation.httpStatusLine));
-    response.setStatusInfo(getStatusInfo(operation.getHttpStatusLine()));
+    response.setHeaders(operation.getHeaders().toSingleMap());
+    response.setStatusCode(getStatusCode(statusMatcher));
+    response.setStatusInfo(getStatusInfo(statusMatcher));
     response.setBody(getBody(operation));
 
     return response;
   }
 
-  private String getContentId(final Map<String, HeaderField> headers) {
-    HeaderField contentIdField = headers.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+  private Matcher prepareStatusLineMatcher(String httpStatusLine) throws BatchException {
+    final Pattern regexPattern = Pattern.compile(REG_EX_STATUS_LINE);
+    final Matcher matcher = regexPattern.matcher(httpStatusLine);
 
-    if (contentIdField != null) {
-      if (contentIdField.getValues().size() > 0) {
-        return contentIdField.getValues().get(0);
-      }
+    if (matcher.find()) {
+      return matcher;
+    } else {
+      throw new BatchException(BatchException.INVALID_STATUS_LINE);
     }
-
-    return null;
   }
 
   private String getBody(final BatchQueryOperation operation) throws BatchException {
     int contentLength = BatchTransformatorCommon.getContentLength(operation.getHeaders());
 
-    return BatchParserCommon.trimStringListToStringLength(operation.getBody(), contentLength);
-  }
-
-  private String getStatusCode(final String httpMethod) throws BatchException {
-    Pattern regexPattern = Pattern.compile(REG_EX_STATUS_LINE);
-    Matcher matcher = regexPattern.matcher(httpMethod);
-
-    if (matcher.find()) {
-      return matcher.group(1);
+    if (contentLength == -1) {
+      return BatchParserCommon.stringListToString(operation.getBody());
     } else {
-      throw new BatchException(BatchException.INVALID_STATUS_LINE);
+      return BatchParserCommon.trimStringListToStringLength(operation.getBody(), contentLength);
     }
   }
 
-  private String getStatusInfo(final String httpMethod) throws BatchException {
-    Pattern regexPattern = Pattern.compile(REG_EX_STATUS_LINE);
-    Matcher matcher = regexPattern.matcher(httpMethod);
+  private String getStatusCode(final Matcher matcher) throws BatchException {
+    return matcher.group(1);
+  }
 
-    if (matcher.find()) {
-      return matcher.group(2);
-    } else {
-      throw new BatchException(BatchException.INVALID_STATUS_LINE);
-    }
+  private String getStatusInfo(final Matcher matcher) throws BatchException {
+    return matcher.group(2);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
index c9c8e0f..9c67f49 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchTransformatorCommon.java
@@ -1,49 +1,38 @@
 package org.apache.olingo.odata2.core.batch.v2;
 
-import java.util.Locale;
-import java.util.Map;
+import java.util.List;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpContentType;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.core.batch.BatchHelper;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 
 public class BatchTransformatorCommon {
 
-  public static void validateContentType(final Map<String, HeaderField> headers) throws BatchException {
-    final HeaderField contentTypeField = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
-    if (contentTypeField != null) {
-      if (contentTypeField.getValues().size() == 1) {
-        final String contentType = contentTypeField.getValues().get(0);
+  public static void validateContentType(final Header headers) throws BatchException {
+    List<String> contentTypes = headers.getHeaders(HttpHeaders.CONTENT_TYPE);
 
-        if (!BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()
-            && !BatchParserCommon.PATTERN_CONTENT_TYPE_APPLICATION_HTTP.matcher(contentType).matches()) {
-          throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED
-              + " or " + HttpContentType.APPLICATION_HTTP));
-        }
-      } else {
-        throw new BatchException(BatchException.INVALID_HEADER);
-      }
-    } else {
+    if (contentTypes.size() == 0) {
       throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
     }
+    if (!headers.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_MULTIPART_BOUNDARY)
+      & !headers.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_CONTENT_TYPE_APPLICATION_HTTP)) {
+      throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(
+          HttpContentType.MULTIPART_MIXED + " or " + HttpContentType.APPLICATION_HTTP));
+    }
   }
 
-  public static void validateContentTransferEncoding(final Map<String, HeaderField> headers,
-      final boolean isChangeRequest)
+  public static void validateContentTransferEncoding(final Header headers, final boolean isChangeRequest)
       throws BatchException {
-    if (headers.containsKey(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH))) {
-      HeaderField encodingField = headers.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH));
+    final List<String> contentTransferEncodings = headers.getHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING);
 
-      if (encodingField.getValues().size() == 1) {
-        String encoding = encodingField.getValues().get(0);
+    if (contentTransferEncodings.size() != 0) {
+      if (contentTransferEncodings.size() == 1) {
+        String encoding = contentTransferEncodings.get(0);
 
         if (!BatchHelper.BINARY_ENCODING.equalsIgnoreCase(encoding)) {
           throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
         }
-      } else if (encodingField.getValues().size() == 0) {
-        throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
       } else {
         throw new BatchException(BatchException.INVALID_HEADER);
       }
@@ -54,12 +43,12 @@ public class BatchTransformatorCommon {
     }
   }
 
-  public static int getContentLength(final Map<String, HeaderField> headers) throws BatchException {
+  public static int getContentLength(final Header headers) throws BatchException {
+    final List<String> contentLengths = headers.getHeaders(HttpHeaders.CONTENT_LENGTH);
 
-    if (headers.containsKey(HttpHeaders.CONTENT_LENGTH.toLowerCase(Locale.ENGLISH))) {
+    if (contentLengths.size() == 1) {
       try {
-        int contentLength =
-            Integer.parseInt(headers.get(HttpHeaders.CONTENT_LENGTH.toLowerCase(Locale.ENGLISH)).getValues().get(0));
+        int contentLength = Integer.parseInt(contentLengths.get(0));
 
         if (contentLength < 0) {
           throw new BatchException(BatchException.INVALID_HEADER);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
new file mode 100644
index 0000000..7901b7b
--- /dev/null
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/Header.java
@@ -0,0 +1,202 @@
+package org.apache.olingo.odata2.core.batch.v2;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+public class Header implements Cloneable {
+
+  private final Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
+  
+  public static List<String> splitValuesByComma(final String headerValue) {
+    final List<String> singleValues = new ArrayList<String>();
+
+    String[] parts = headerValue.split(",");
+    for (final String value : parts) {
+      singleValues.add(value.trim());
+    }
+
+    return singleValues;
+  }
+  
+  public void addHeader(final String name, final String value) {
+    final HeaderField headerField = getHeaderFieldOrDefault(name);
+    final List<String> headerValues = headerField.getValues();
+
+    if (!headerValues.contains(value)) {
+      headerValues.add(value);
+    }
+  }
+
+  public void addHeader(final String name, final List<String> values) {
+    final HeaderField headerField = getHeaderFieldOrDefault(name);
+    final List<String> headerValues = headerField.getValues();
+
+    for (final String value : values) {
+      if (!headerValues.contains(value)) {
+        headerValues.add(value);
+      }
+    }
+  }
+  
+  public boolean isHeaderMatching(final String name, final Pattern pattern) {
+    if(getHeaders(name).size() != 1 ) {
+      return false;
+    } else {
+      return pattern.matcher(getHeaders(name).get(0)).matches();
+    }
+  }
+  
+  public void removeHeaders(final String name) {
+    headers.remove(name.toLowerCase(Locale.ENGLISH));
+  }
+
+  public String getHeader(final String name) {
+    final HeaderField headerField = getHeaderField(name);
+
+    if (headerField == null) {
+      return null;
+    } else {
+      final List<String> headerValues = headerField.getValues();
+      final StringBuilder result = new StringBuilder();
+
+      for (final String value : headerValues) {
+        result.append(value);
+        result.append(", ");
+      }
+      
+      if(result.length()>0) {
+        result.delete(result.length() - 2, result.length());
+      }
+      
+      return result.toString();
+    }
+  }
+
+  public String getHeaderNotNull(final String name) {
+    final String value = getHeader(name);
+
+    return (value == null) ? "" : value;
+  }
+
+  public List<String> getHeaders(final String name) {
+    final HeaderField headerField = getHeaderField(name);
+
+    return (headerField == null) ? new ArrayList<String>() : headerField.getValues();
+  }
+
+  public HeaderField getHeaderField(final String name) {
+    return headers.get(name.toLowerCase(Locale.ENGLISH));
+  }
+
+  public Map<String, String> toSingleMap() {
+    final Map<String, String> singleMap = new HashMap<String, String>();
+
+    for (final String key : headers.keySet()) {
+      HeaderField field = headers.get(key);
+      singleMap.put(field.getFieldName(), getHeader(key));
+    }
+
+    return singleMap;
+  }
+
+  public Map<String, List<String>> toMultiMap() {
+    final Map<String, List<String>> singleMap = new HashMap<String, List<String>>();
+
+    for (final String key : headers.keySet()) {
+      HeaderField field = headers.get(key);
+      singleMap.put(field.getFieldName(), field.getValues());
+    }
+
+    return singleMap;
+  }
+
+  private HeaderField getHeaderFieldOrDefault(final String name) {
+    HeaderField headerField = headers.get(name.toLowerCase(Locale.ENGLISH));
+
+    if (headerField == null) {
+      headerField = new HeaderField(name);
+      headers.put(name.toLowerCase(Locale.ENGLISH), headerField);
+    }
+
+    return headerField;
+  }
+
+  @Override
+  public Header clone() {
+    final Header newInstance = new Header();
+
+    for (final String key : headers.keySet()) {
+      newInstance.headers.put(key, headers.get(key).clone());
+    }
+
+    return newInstance;
+  }
+
+  public static class HeaderField implements Cloneable {
+    private String fieldName;
+    private List<String> values;
+
+    public HeaderField(final String fieldName) {
+      this(fieldName, new ArrayList<String>());
+    }
+
+    public HeaderField(final String fieldName, final List<String> values) {
+      this.fieldName = fieldName;
+      this.values = values;
+    }
+
+    public String getFieldName() {
+      return fieldName;
+    }
+
+    public List<String> getValues() {
+      return values;
+    }
+
+    public void setValues(final List<String> values) {
+      this.values = values;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + ((fieldName == null) ? 0 : fieldName.hashCode());
+      return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+      if (this == obj) {
+        return true;
+      }
+      if (obj == null) {
+        return false;
+      }
+      if (getClass() != obj.getClass()) {
+        return false;
+      }
+      HeaderField other = (HeaderField) obj;
+      if (fieldName == null) {
+        if (other.fieldName != null) {
+          return false;
+        }
+      } else if (!fieldName.equals(other.fieldName)) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public HeaderField clone() {
+      List<String> newValues = new ArrayList<String>();
+      newValues.addAll(values);
+
+      return new HeaderField(fieldName, newValues);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
index 8451c55..56cbeeb 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java
@@ -5,13 +5,11 @@ import static org.junit.Assert.*;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Locale;
-import java.util.Map;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
 import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
+import org.apache.olingo.odata2.core.batch.v2.Header;
 import org.junit.Test;
 
 public class BatchParserCommonTest {
@@ -30,14 +28,14 @@ public class BatchParserCommonTest {
     message.addAll(Arrays.asList(messageRaw));
     
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField contentIdHeaders = header.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+    final List<String> contentIdHeaders = header.getHeaders(BatchHelper.HTTP_CONTENT_ID);
     assertNotNull(contentIdHeaders);
-    assertEquals(2, contentIdHeaders.getValues().size());
-    assertEquals("1", contentIdHeaders.getValues().get(0));
-    assertEquals("2", contentIdHeaders.getValues().get(1));
+    assertEquals(2, contentIdHeaders.size());
+    assertEquals("1", contentIdHeaders.get(0));
+    assertEquals("2", contentIdHeaders.get(1));
   }
   
   @Test
@@ -52,13 +50,13 @@ public class BatchParserCommonTest {
     message.addAll(Arrays.asList(messageRaw));
     
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField contentIdHeaders = header.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+    final List<String> contentIdHeaders = header.getHeaders(BatchHelper.HTTP_CONTENT_ID);
     assertNotNull(contentIdHeaders);
-    assertEquals(1, contentIdHeaders.getValues().size());
-    assertEquals("1", contentIdHeaders.getValues().get(0));
+    assertEquals(1, contentIdHeaders.size());
+    assertEquals("1", contentIdHeaders.get(0));
   }
   
   @Test
@@ -73,16 +71,16 @@ public class BatchParserCommonTest {
     message.addAll(Arrays.asList(messageRaw));
     
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField upgradeHeader = header.get("upgrade");
+    final List<String> upgradeHeader = header.getHeaders("upgrade");
     assertNotNull(upgradeHeader);
-    assertEquals(4, upgradeHeader.getValues().size());
-    assertEquals("HTTP/2.0", upgradeHeader.getValues().get(0));
-    assertEquals("SHTTP/1.3", upgradeHeader.getValues().get(1));
-    assertEquals("IRC/6.9", upgradeHeader.getValues().get(2));
-    assertEquals("RTA/x11", upgradeHeader.getValues().get(3));
+    assertEquals(4, upgradeHeader.size());
+    assertEquals("HTTP/2.0", upgradeHeader.get(0));
+    assertEquals("SHTTP/1.3", upgradeHeader.get(1));
+    assertEquals("IRC/6.9", upgradeHeader.get(2));
+    assertEquals("RTA/x11", upgradeHeader.get(3));
   }
   
   @Test
@@ -98,12 +96,12 @@ public class BatchParserCommonTest {
     message.addAll(Arrays.asList(messageRaw));
     
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField acceptHeader = header.get(HttpHeaders.ACCEPT.toLowerCase());
+    final List<String> acceptHeader = header.getHeaders(HttpHeaders.ACCEPT);
     assertNotNull(acceptHeader);
-    assertEquals(4, acceptHeader.getValues().size());
+    assertEquals(4, acceptHeader.size());
   }
   
   @Test
@@ -119,12 +117,12 @@ public class BatchParserCommonTest {
     message.addAll(Arrays.asList(messageRaw));
     
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField acceptHeader = header.get(HttpHeaders.ACCEPT.toLowerCase());
+    final List<String> acceptHeader = header.getHeaders(HttpHeaders.ACCEPT);
     assertNotNull(acceptHeader);
-    assertEquals(3, acceptHeader.getValues().size());
+    assertEquals(3, acceptHeader.size());
   }
   
   @Test
@@ -138,12 +136,12 @@ public class BatchParserCommonTest {
     List<String> message = new ArrayList<String>();
     message.addAll(Arrays.asList(messageRaw));
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField acceptLanguageHeader = header.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase());
+    final List<String> acceptLanguageHeader = header.getHeaders(HttpHeaders.ACCEPT_LANGUAGE);
     assertNotNull(acceptLanguageHeader);
-    assertEquals(4, acceptLanguageHeader.getValues().size());
+    assertEquals(4, acceptLanguageHeader.size());
   }
   
   @Test
@@ -157,12 +155,12 @@ public class BatchParserCommonTest {
     List<String> message = new ArrayList<String>();
     message.addAll(Arrays.asList(messageRaw));
     
-    final Map<String, HeaderField> header = BatchParserCommon.consumeHeaders(message);
+    final Header header = BatchParserCommon.consumeHeaders(message);
     assertNotNull(header);
     
-    final HeaderField acceptLanguageHeader = header.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase());
+    final List<String> acceptLanguageHeader = header.getHeaders(HttpHeaders.ACCEPT_LANGUAGE);
     assertNotNull(acceptLanguageHeader);
-    assertEquals(3, acceptLanguageHeader.getValues().size());
+    assertEquals(3, acceptLanguageHeader.size());
   }
   
   @Test

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
index a70d15a..e98a295 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchTransformatorCommonTest.java
@@ -1,15 +1,13 @@
 package org.apache.olingo.odata2.core.batch;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.apache.olingo.odata2.api.batch.BatchException;
 import org.apache.olingo.odata2.api.commons.HttpContentType;
 import org.apache.olingo.odata2.api.commons.HttpHeaders;
-import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon.HeaderField;
 import org.apache.olingo.odata2.core.batch.v2.BatchTransformatorCommon;
+import org.apache.olingo.odata2.core.batch.v2.Header;
 import org.junit.Test;
 
 public class BatchTransformatorCommonTest {
@@ -19,7 +17,7 @@ public class BatchTransformatorCommonTest {
   @Test
   public void testValidateContentTypeApplicationHTTP() throws BatchException {
     List<String> contentTypeValues = Arrays.asList(new String[] { HttpContentType.APPLICATION_HTTP });
-    Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
+    final Header headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
 
     BatchTransformatorCommon.validateContentType(headers);
   }
@@ -28,7 +26,7 @@ public class BatchTransformatorCommonTest {
   public void testValidateContentTypeMultipartMixed() throws BatchException {
     List<String> contentTypeValues =
         Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED + "; boundary=batch_32332_32323_fdsf" });
-    Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
+    final Header headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
 
     BatchTransformatorCommon.validateContentType(headers);
   }
@@ -37,7 +35,7 @@ public class BatchTransformatorCommonTest {
   public void testValidateContentTypeMultipartMixedCaseInsensitiv() throws BatchException {
     List<String> contentTypeValues =
         Arrays.asList(new String[] { "mulTiPart/MiXed; boundary=batch_32332_32323_fdsf" });
-    Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
+    final Header headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
 
     BatchTransformatorCommon.validateContentType(headers);
   }
@@ -45,14 +43,15 @@ public class BatchTransformatorCommonTest {
   @Test(expected = BatchException.class)
   public void testValidateContentTypeNoValue() throws BatchException {
     List<String> contentTypeValues = Arrays.asList(new String[] {});
-    Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
+    final Header headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
 
     BatchTransformatorCommon.validateContentType(headers);
   }
 
   @Test(expected = BatchException.class)
   public void testValidateContentTypeMissingHeader() throws BatchException {
-    Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
+    final Header headers = new Header();
+    
     BatchTransformatorCommon.validateContentType(headers);
   }
 
@@ -60,7 +59,7 @@ public class BatchTransformatorCommonTest {
   public void testValidateContentTypeMultipleValues() throws BatchException {
     List<String> contentTypeValues =
         Arrays.asList(new String[] { HttpContentType.APPLICATION_HTTP, HttpContentType.MULTIPART_MIXED });
-    Map<String, HeaderField> headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
+    final Header headers = makeHeaders(HttpHeaders.CONTENT_TYPE, contentTypeValues);
 
     BatchTransformatorCommon.validateContentType(headers);
   }
@@ -68,7 +67,7 @@ public class BatchTransformatorCommonTest {
   @Test
   public void testValidateContentTransferEncoding() throws BatchException {
     List<String> contentTransferEncoding = Arrays.asList(new String[] { BatchHelper.BINARY_ENCODING });
-    Map<String, HeaderField> headers = makeHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
+    final Header headers = makeHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
 
     BatchTransformatorCommon.validateContentTransferEncoding(headers, false);
   }
@@ -76,28 +75,29 @@ public class BatchTransformatorCommonTest {
   @Test(expected = BatchException.class)
   public void testValidateContentTransferEncodingMultipleValues() throws BatchException {
     List<String> contentTransferEncoding = Arrays.asList(new String[] { BatchHelper.BINARY_ENCODING, BASE64_ENCODING });
-    Map<String, HeaderField> headers = makeHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
+    final Header headers = makeHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
 
     BatchTransformatorCommon.validateContentTransferEncoding(headers, false);
   }
 
   @Test(expected = BatchException.class)
   public void testValidateContentTransferEncodingMissingHeader() throws BatchException {
-    Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
+    final Header headers = new Header();
+    
     BatchTransformatorCommon.validateContentTransferEncoding(headers, true);
   }
 
   @Test(expected = BatchException.class)
   public void testValidateContentTransferEncodingMissingValue() throws BatchException {
     List<String> contentTransferEncoding = Arrays.asList(new String[] {});
-    Map<String, HeaderField> headers = makeHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
+    final Header headers = makeHeaders(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING, contentTransferEncoding);
 
-    BatchTransformatorCommon.validateContentTransferEncoding(headers, false);
+    BatchTransformatorCommon.validateContentTransferEncoding(headers, true);
   }
 
-  private Map<String, HeaderField> makeHeaders(final String headerName, final List<String> values) {
-    Map<String, HeaderField> headers = new HashMap<String, HeaderField>();
-    headers.put(headerName.toLowerCase(), new HeaderField(headerName, values));
+  private Header makeHeaders(final String headerName, final List<String> values) {
+    final Header headers = new Header();
+    headers.addHeader(headerName, values);
 
     return headers;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/05d20c1f/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
new file mode 100644
index 0000000..128aa2e
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/HeaderTest.java
@@ -0,0 +1,161 @@
+package org.apache.olingo.odata2.core.batch;
+
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon;
+import org.apache.olingo.odata2.core.batch.v2.Header;
+import org.junit.Test;
+
+public class HeaderTest {
+
+  @Test
+  public void test() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(1, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(0));
+  }
+
+  @Test
+  public void testNotAvailable() {
+    Header header = new Header();
+
+    assertNull(header.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(0, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
+    assertEquals("", header.getHeaderNotNull(HttpHeaders.CONTENT_TYPE));
+  }
+
+  @Test
+  public void testCaseInsensitive() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeader("cOnTenT-TyPE"));
+    assertEquals(1, header.getHeaders("cOnTenT-TyPE").size());
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeaders("cOnTenT-TyPE").get(0));
+  }
+
+  @Test
+  public void testDuplicatedAdd() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(1, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(0));
+  }
+
+  @Test
+  public void testMatcher() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123");
+
+    assertTrue(header.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_MULTIPART_BOUNDARY));
+  }
+
+  @Test
+  public void testFieldName() {
+    Header header = new Header();
+    header.addHeader("MyFieldNamE", "myValue");
+
+    assertEquals("MyFieldNamE", header.getHeaderField("myfieldname").getFieldName());
+    assertEquals("MyFieldNamE", header.toSingleMap().keySet().toArray(new String[0])[0]);
+    assertEquals("MyFieldNamE", header.toMultiMap().keySet().toArray(new String[0])[0]);
+
+    assertEquals("myValue", header.toMultiMap().get("MyFieldNamE").get(0));
+    assertEquals("myValue", header.toSingleMap().get("MyFieldNamE"));
+  }
+
+  @Test
+  public void testDeepCopy() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123");
+
+    Header copy = header.clone();
+    assertEquals(header.getHeaders(HttpHeaders.CONTENT_TYPE), copy.getHeaders(HttpHeaders.CONTENT_TYPE));
+    assertEquals(header.getHeader(HttpHeaders.CONTENT_TYPE), copy.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(header.getHeaderField(HttpHeaders.CONTENT_TYPE), copy.getHeaderField(HttpHeaders.CONTENT_TYPE));
+
+    assertTrue(header.getHeaders(HttpHeaders.CONTENT_TYPE) != copy.getHeaders(HttpHeaders.CONTENT_TYPE));
+    assertTrue(header.getHeaderField(HttpHeaders.CONTENT_TYPE) != copy.getHeaderField(HttpHeaders.CONTENT_TYPE));
+  }
+
+  @Test
+  public void testMatcherNoHeader() {
+    Header header = new Header();
+
+    assertFalse(header.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_MULTIPART_BOUNDARY));
+  }
+
+  @Test
+  public void testMatcherFail() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + ";boundary=123");
+
+    assertFalse(header.isHeaderMatching(HttpHeaders.CONTENT_TYPE, BatchParserCommon.PATTERN_HEADER_LINE));
+  }
+
+  @Test
+  public void testDuplicatedAddList() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, Arrays.asList(new String[] { HttpContentType.MULTIPART_MIXED,
+        HttpContentType.APPLICATION_ATOM_SVC }));
+
+    assertEquals(HttpContentType.MULTIPART_MIXED + ", " + HttpContentType.APPLICATION_ATOM_SVC, header
+        .getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(2, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(0));
+    assertEquals(HttpContentType.APPLICATION_ATOM_SVC, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(1));
+  }
+
+  @Test
+  public void testRemove() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    header.removeHeaders(HttpHeaders.CONTENT_TYPE);
+
+    assertNull(header.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(0, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
+  }
+
+  @Test
+  public void testMultipleValues() {
+    Header header = new Header();
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.APPLICATION_ATOM_SVC);
+    header.addHeader(HttpHeaders.CONTENT_TYPE, HttpContentType.APPLICATION_ATOM_XML);
+
+    final String fullHeaderString =
+        HttpContentType.MULTIPART_MIXED + ", " + HttpContentType.APPLICATION_ATOM_SVC + ", "
+            + HttpContentType.APPLICATION_ATOM_XML;
+
+    assertEquals(fullHeaderString, header.getHeader(HttpHeaders.CONTENT_TYPE));
+    assertEquals(3, header.getHeaders(HttpHeaders.CONTENT_TYPE).size());
+    assertEquals(HttpContentType.MULTIPART_MIXED, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(0));
+    assertEquals(HttpContentType.APPLICATION_ATOM_SVC, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(1));
+    assertEquals(HttpContentType.APPLICATION_ATOM_XML, header.getHeaders(HttpHeaders.CONTENT_TYPE).get(2));
+  }
+  
+  @Test
+  public void testSplitValues() {
+    final String values = "abc, def,123,77,   99, ysd";
+    List<String> splittedValues = Header.splitValuesByComma(values);
+
+    assertEquals(6, splittedValues.size());
+    assertEquals("abc", splittedValues.get(0));
+    assertEquals("def", splittedValues.get(1));
+    assertEquals("123", splittedValues.get(2));
+    assertEquals("77", splittedValues.get(3));
+    assertEquals("99", splittedValues.get(4));
+    assertEquals("ysd", splittedValues.get(5));
+  }
+}


[3/4] Line number tracking and exception messages

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f0dc0f74/odata2-lib/odata-core/src/test/resources/batchLarge.batch
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/resources/batchLarge.batch b/odata2-lib/odata-core/src/test/resources/batchLarge.batch
new file mode 100644
index 0000000..3be0982
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/resources/batchLarge.batch
@@ -0,0 +1,2505 @@
+--batch_8194-cf13-1f56
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+
+GET Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Accept: application/atom+xml
+MaxDataServiceVersion: 2.0
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+DataServiceVersion: 2.0
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+
+--batch_8194-cf13-1f56
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+
+GET Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Accept: application/atom+xml
+MaxDataServiceVersion: 2.0
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+DataServiceVersion: 2.0
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+
+--batch_8194-cf13-1f56
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+
+GET Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Accept: application/atom+xml
+MaxDataServiceVersion: 2.0
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+DataServiceVersion: 2.0
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+
+--batch_8194-cf13-1f56
+Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+PUT Employees('1') HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<?xml version='1.0' encoding='utf-8'?>
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:19000/abc/EntryXmlChangeTest/">
+  <id>http://localhost:19000/abc/EntryXmlChangeTest/Employees('9')</id>
+  <title type="text">Mister X</title>
+  <updated m:null='true'>Z</updated>
+  <category term="RefScenario.Employee"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <content type="image/jpeg" src="Employees('1')/$value" />
+  <m:properties>
+    <d:EmployeeId>1</d:EmployeeId>
+    <d:EmployeeName>Mister X</d:EmployeeName>
+    <d:ManagerId>1</d:ManagerId>
+    <d:RoomId>2</d:RoomId>
+    <d:TeamId>1</d:TeamId>
+    <d:Location m:type="RefScenario.c_Location">
+      <d:City m:type="RefScenario.c_City">
+        <d:PostalCode>69190</d:PostalCode>
+        <d:CityName>Walldorf</d:CityName>
+      </d:City>
+      <d:Country>Germany</d:Country>
+    </d:Location>
+    <d:EntryDate m:null='true'></d:EntryDate>
+    <d:ImageUrl>Employees('1')/$value</d:ImageUrl>
+  </m:properties>
+</entry>
+--changeset_f980-1cb6-94dd--
+--batch_8194-cf13-1f56
+Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+PUT Employees('1') HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<?xml version='1.0' encoding='utf-8'?>
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:19000/abc/EntryXmlChangeTest/">
+  <id>http://localhost:19000/abc/EntryXmlChangeTest/Employees('9')</id>
+  <title type="text">Mister X</title>
+  <updated m:null='true'>Z</updated>
+  <category term="RefScenario.Employee"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <content type="image/jpeg" src="Employees('1')/$value" />
+  <m:properties>
+    <d:EmployeeId>1</d:EmployeeId>
+    <d:EmployeeName>Mister X</d:EmployeeName>
+    <d:ManagerId>1</d:ManagerId>
+    <d:RoomId>2</d:RoomId>
+    <d:TeamId>1</d:TeamId>
+    <d:Location m:type="RefScenario.c_Location">
+      <d:City m:type="RefScenario.c_City">
+        <d:PostalCode>69190</d:PostalCode>
+        <d:CityName>Walldorf</d:CityName>
+      </d:City>
+      <d:Country>Germany</d:Country>
+    </d:Location>
+    <d:EntryDate m:null='true'></d:EntryDate>
+    <d:ImageUrl>Employees('1')/$value</d:ImageUrl>
+  </m:properties>
+</entry>
+--changeset_f980-1cb6-94dd--
+--batch_8194-cf13-1f56
+Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+PUT Employees('1') HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<?xml version='1.0' encoding='utf-8'?>
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:19000/abc/EntryXmlChangeTest/">
+  <id>http://localhost:19000/abc/EntryXmlChangeTest/Employees('9')</id>
+  <title type="text">Mister X</title>
+  <updated m:null='true'>Z</updated>
+  <category term="RefScenario.Employee"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <content type="image/jpeg" src="Employees('1')/$value" />
+  <m:properties>
+    <d:EmployeeId>1</d:EmployeeId>
+    <d:EmployeeName>Mister X</d:EmployeeName>
+    <d:ManagerId>1</d:ManagerId>
+    <d:RoomId>2</d:RoomId>
+    <d:TeamId>1</d:TeamId>
+    <d:Location m:type="RefScenario.c_Location">
+      <d:City m:type="RefScenario.c_City">
+        <d:PostalCode>69190</d:PostalCode>
+        <d:CityName>Walldorf</d:CityName>
+      </d:City>
+      <d:Country>Germany</d:Country>
+    </d:Location>
+    <d:EntryDate m:null='true'></d:EntryDate>
+    <d:ImageUrl>Employees('1')/$value</d:ImageUrl>
+  </m:properties>
+</entry>
+--changeset_f980-1cb6-94dd--
+--batch_8194-cf13-1f56
+Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:ImageUrl>Employees('3')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('4')
+          </id>
+          <title type="text">Peter Burke</title>
+          <updated>2004-09-12T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('4')" rel="edit" title="Employee" />
+          <link href="Employees('4')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('4')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('4')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('4')/$value" />
+          <m:properties>
+            <d:EmployeeId>4</d:EmployeeId>
+            <d:EmployeeName>Peter Burke</d:EmployeeName>
+            <d:ManagerId>3</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>2</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>39</d:Age>
+            <d:EntryDate>2004-09-12T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('4')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('6')
+          </id>
+          <title type="text">Susan Bay</title>
+          <updated>2010-12-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('6')" rel="edit" title="Employee" />
+          <link href="Employees('6')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('6')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('6')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('6')/$value" />
+          <m:properties>
+            <d:EmployeeId>6</d:EmployeeId>
+            <d:EmployeeName>Susan Bay</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>3</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>29</d:Age>
+            <d:EntryDate>2010-12-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('6')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+      </feed>
+    </m:inline>
+  </link>
+  <link href="Rooms('2')/nr_Building"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Building"
+    title="nr_Building" type="application/atom+xml; type=entry" />
+  <content type="application/xml">
+    <m:properties>
+      <d:Id>2</d:Id>
+      <d:Name>Room 2</d:Name>
+      <d:Seats>5</d:Seats>
+      <d:Version>2</d:Version>
+    </m:properties>
+  </content>
+</entry>
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 1
+
+POST Employees HTTP/1.1
+Host: http://localhost/odata
+Connection: keep-alive
+Content-Length: 1117
+Authorization: Basic YW56ZWlnZXI6ZGlzcGxheQ==
+Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
+X-CSRF-Token: P6no0PBwygp1ie0Gz-YbEg==
+User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36
+Content-Type: application/atom+xml
+Accept: */*
+Accept-Encoding: gzip,deflate
+Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
+
+<entry xmlns="http://www.w3.org/2005/Atom"
+  xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+  xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+  xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/"
+  m:etag="W/2">
+  <id>
+    http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Rooms('2')
+  </id>
+  <title type="text">Room 2</title>
+  <updated>2013-04-03T10:53:26.021+02:00</updated>
+  <category term="RefScenario.Room"
+    scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+  <link href="Rooms('2')" rel="edit" title="Room" />
+  <link href="Rooms('2')/nr_Employees"
+    rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/nr_Employees"
+    title="nr_Employees" type="application/atom+xml; type=feed">
+    <m:inline>
+      <feed xmlns="http://www.w3.org/2005/Atom"
+        xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
+        xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
+        xml:base="http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/">
+        <id>
+          http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees
+        </id>
+        <title type="text">Employees</title>
+        <updated>2013-04-03T10:53:26.024+02:00</updated>
+        <author>
+          <name />
+        </author>
+        <link href="Employees" rel="self" title="Employees" />
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('2')
+          </id>
+          <title type="text">Frederic Fall</title>
+          <updated>2003-07-01T00:00:00Z</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('2')" rel="edit" title="Employee" />
+          <link href="Employees('2')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('2')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('2')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('2')/$value" />
+          <m:properties>
+            <d:EmployeeId>2</d:EmployeeId>
+            <d:EmployeeName>Frederic Fall</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>32</d:Age>
+            <d:EntryDate>2003-07-01T00:00:00</d:EntryDate>
+            <d:ImageUrl>Employees('2')/$value</d:ImageUrl>
+          </m:properties>
+        </entry>
+        <entry>
+          <id>
+            http://localhost:8080/org.apache.olingo.odata2.ref.web/ReferenceScenario.svc/Employees('3')
+          </id>
+          <title type="text">Jonathan Smith</title>
+          <updated>2013-04-03T10:53:26.025+02:00</updated>
+          <category term="RefScenario.Employee"
+            scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+          <link href="Employees('3')" rel="edit" title="Employee" />
+          <link href="Employees('3')/$value" rel="edit-media"
+            type="application/octet-stream" />
+          <link href="Employees('3')/ne_Manager"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Manager"
+            title="ne_Manager" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Team"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Team"
+            title="ne_Team" type="application/atom+xml; type=entry" />
+          <link href="Employees('3')/ne_Room"
+            rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ne_Room"
+            title="ne_Room" type="application/atom+xml; type=entry" />
+          <content type="application/octet-stream" src="Employees('3')/$value" />
+          <m:properties>
+            <d:EmployeeId>3</d:EmployeeId>
+            <d:EmployeeName>Jonathan Smith</d:EmployeeName>
+            <d:ManagerId>1</d:ManagerId>
+            <d:RoomId>2</d:RoomId>
+            <d:TeamId>1</d:TeamId>
+            <d:Location m:type="RefScenario.c_Location">
+              <d:City m:type="RefScenario.c_City">
+                <d:PostalCode>69190</d:PostalCode>
+                <d:CityName>Walldorf</d:CityName>
+              </d:City>
+              <d:Country>Germany</d:Country>
+            </d:Location>
+            <d:Age>56</d:Age>
+            <d:EntryDate m:null="true" />
+            <d:Im

<TRUNCATED>