Header class refactoring

Signed-off-by: Christian Amend <[email protected]>


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/master
Commit: 05d20c1fa078f2c445b4fe30ab96d4a5f8d2b585
Parents: 1f90b73
Author: Christian Holzer <[email protected]>
Authored: Fri Oct 3 01:34:45 2014 +0200
Committer: Christian Amend <[email protected]>
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));
+  }
+}

Reply via email to