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/11/13 17:17:30 UTC

[1/9] olingo-odata4 git commit: Tech Servlet

Repository: olingo-odata4
Updated Branches:
  refs/heads/olingo472 32247295f -> ad177ac11


Tech Servlet

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


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

Branch: refs/heads/olingo472
Commit: 15bd15267a36ab2318e0824f6fcbb06f3d7a3351
Parents: 3224729
Author: Christian Holzer <c....@sap.com>
Authored: Tue Oct 28 16:55:57 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:10:54 2014 +0100

----------------------------------------------------------------------
 .../olingo/server/api/batch/BatchException.java |  65 +++++++++
 .../olingo/server/api/batch/BatchOperation.java |  36 +++++
 .../server/api/processor/BatchProcessor.java    |  31 ++++
 .../apache/olingo/server/core/ODataHandler.java |  12 +-
 .../server/core/batch/BatchException.java       |  65 ---------
 .../batch/handler/BatchChangeSetSorter.java     | 145 +++++++++++++++++++
 .../server/core/batch/handler/BatchHandler.java |  68 +++++++++
 .../core/batch/handler/BatchOperationImpl.java  |  74 ++++++++++
 .../core/batch/handler/BatchPartHandler.java    |  66 +++++++++
 .../batch/handler/ODataResponsePartImpl.java    |  44 ++++++
 .../server/core/batch/parser/BatchBodyPart.java |   2 +-
 .../core/batch/parser/BatchChangeSetPart.java   |   2 +-
 .../server/core/batch/parser/BatchParser.java   |   2 +-
 .../core/batch/parser/BatchParserCommon.java    |   5 +-
 .../core/batch/parser/BatchQueryOperation.java  |   2 +-
 .../BatchRequestTransformator.java              |   8 +-
 .../batch/transformator/BatchTransformator.java |   2 +-
 .../transformator/BatchTransformatorCommon.java |   4 +-
 .../core/batch/writer/BatchResponseWriter.java  |   4 +-
 .../core/batch/BatchRequestParserTest.java      |   3 +-
 .../batch/parser/BatchParserCommonTest.java     |   2 +-
 .../batch/writer/BatchResponseWriterTest.java   |   2 +-
 .../tecsvc/processor/TechnicalProcessor.java    |  39 ++++-
 23 files changed, 598 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchException.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchException.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchException.java
new file mode 100644
index 0000000..8da47a8
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchException.java
@@ -0,0 +1,65 @@
+/*
+ * 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.server.api.batch;
+
+import org.apache.olingo.server.api.ODataTranslatedException;
+
+public class BatchException extends ODataTranslatedException {
+  public static enum MessageKeys implements MessageKey {
+    INVALID_BOUNDARY,
+    INVALID_CHANGESET_METHOD,
+    INVALID_CONTENT,
+    INVALID_CONTENT_LENGTH,
+    INVALID_CONTENT_TRANSFER_ENCODING,
+    INVALID_CONTENT_TYPE,
+    INVALID_HEADER,
+    INVALID_HTTP_VERSION,
+    INVALID_METHOD,
+    INVALID_QUERY_OPERATION_METHOD,
+    INVALID_STATUS_LINE,
+    INVALID_URI,
+    MISSING_BLANK_LINE,
+    MISSING_BOUNDARY_DELIMITER,
+    MISSING_CLOSE_DELIMITER,
+    MISSING_CONTENT_ID,
+    MISSING_CONTENT_TRANSFER_ENCODING,
+    MISSING_CONTENT_TYPE,
+    MISSING_MANDATORY_HEADER, FORBIDDEN_HEADER, INVALID_CONTENT_ID;
+
+    @Override
+    public String getKey() {
+      return name();
+    }
+  }
+
+  private static final long serialVersionUID = -907752788975531134L;
+
+  public BatchException(final String developmentMessage, final MessageKey messageKey, final int lineNumber) {
+    this(developmentMessage, messageKey, "" + lineNumber);
+  }
+
+  public BatchException(final String developmentMessage, final MessageKey messageKey, final String... parameters) {
+    super(developmentMessage, messageKey, parameters);
+  }
+
+  @Override
+  protected String getBundleName() {
+    return DEFAULT_SERVER_BUNDLE_NAME;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
new file mode 100644
index 0000000..8e438cf
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
@@ -0,0 +1,36 @@
+/*
+ * 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.server.api.batch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+
+public interface BatchOperation {
+  public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException;
+
+  public ODataResponse handleODataRequest(ODataRequest request);
+
+  public ODataResponsePart handleBatchRequest(BatchRequestPart request);
+
+  public void writeResponseParts(List<ODataResponsePart> batchResponses, ODataResponse response) throws BatchException,
+      IOException;
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
new file mode 100644
index 0000000..5a9518d
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
@@ -0,0 +1,31 @@
+/*
+ * 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.server.api.processor;
+
+import java.util.List;
+
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchOperation;
+
+public interface BatchProcessor extends Processor {
+  void executeBatch(BatchOperation operation, ODataRequest requst, ODataResponse response);
+
+  List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests);
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index a13ef6f..48d75de 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -35,6 +35,8 @@ import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.processor.BatchProcessor;
 import org.apache.olingo.server.api.processor.DefaultProcessor;
 import org.apache.olingo.server.api.processor.EntitySetProcessor;
 import org.apache.olingo.server.api.processor.EntityProcessor;
@@ -52,6 +54,7 @@ import org.apache.olingo.server.api.uri.UriResourceKind;
 import org.apache.olingo.server.api.uri.UriResourceNavigation;
 import org.apache.olingo.server.api.uri.UriResourcePartTyped;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
+import org.apache.olingo.server.core.batch.handler.BatchHandler;
 import org.apache.olingo.server.core.uri.parser.Parser;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
@@ -115,7 +118,7 @@ public class ODataHandler {
 
   private void processInternal(final ODataRequest request, final ODataResponse response)
       throws ODataHandlerException, UriParserException, UriValidationException, ContentNegotiatorException,
-      ODataApplicationException, SerializerException {
+      ODataApplicationException, SerializerException, BatchException {
     validateODataVersion(request, response);
 
     uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(), null,
@@ -158,6 +161,13 @@ public class ODataHandler {
     case resource:
       handleResourceDispatching(request, response);
       break;
+    case batch:
+      BatchProcessor bp = selectProcessor(BatchProcessor.class);
+      
+      final BatchHandler handler = new BatchHandler(this, request, bp, true);
+      handler.process(response);
+      
+      break;
     default:
       throw new ODataHandlerException("not implemented",
           ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/BatchException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/BatchException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/BatchException.java
deleted file mode 100644
index aafe141..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/BatchException.java
+++ /dev/null
@@ -1,65 +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.server.core.batch;
-
-import org.apache.olingo.server.api.ODataTranslatedException;
-
-public class BatchException extends ODataTranslatedException {
-  public static enum MessageKeys implements MessageKey {
-    INVALID_BOUNDARY,
-    INVALID_CHANGESET_METHOD,
-    INVALID_CONTENT,
-    INVALID_CONTENT_LENGTH,
-    INVALID_CONTENT_TRANSFER_ENCODING,
-    INVALID_CONTENT_TYPE,
-    INVALID_HEADER,
-    INVALID_HTTP_VERSION,
-    INVALID_METHOD,
-    INVALID_QUERY_OPERATION_METHOD,
-    INVALID_STATUS_LINE,
-    INVALID_URI,
-    MISSING_BLANK_LINE,
-    MISSING_BOUNDARY_DELIMITER,
-    MISSING_CLOSE_DELIMITER,
-    MISSING_CONTENT_ID,
-    MISSING_CONTENT_TRANSFER_ENCODING,
-    MISSING_CONTENT_TYPE,
-    MISSING_MANDATORY_HEADER, FORBIDDEN_HEADER;
-
-    @Override
-    public String getKey() {
-      return name();
-    }
-  }
-
-  private static final long serialVersionUID = -907752788975531134L;
-
-  public BatchException(final String developmentMessage, final MessageKey messageKey, final int lineNumber) {
-    this(developmentMessage, messageKey, "" + lineNumber);
-  }
-
-  public BatchException(final String developmentMessage, final MessageKey messageKey, final String... parameters) {
-    super(developmentMessage, messageKey, parameters);
-  }
-
-  @Override
-  protected String getBundleName() {
-    return DEFAULT_SERVER_BUNDLE_NAME;
-  }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
new file mode 100644
index 0000000..c348512
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
@@ -0,0 +1,145 @@
+/*
+ * 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.server.core.batch.handler;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
+
+public class BatchChangeSetSorter {
+  private static final String REG_EX_REFERENCE = "\\$(.*)(/.*)?";
+
+  final List<ODataRequest> orderdList = new ArrayList<ODataRequest>();
+
+  private static Pattern referencePattern = Pattern.compile(REG_EX_REFERENCE);
+  private Set<String> knownContentId = new HashSet<String>();
+  private Map<String, List<ODataRequest>> requestContentIdMapping = new HashMap<String, List<ODataRequest>>();
+
+  public BatchChangeSetSorter(List<ODataRequest> requests) throws BatchException {
+    sort(requests);
+  }
+
+  public List<ODataRequest> getOrderdRequests() {
+    return orderdList;
+  }
+
+  private List<ODataRequest> sort(final List<ODataRequest> requests) throws BatchException {
+    extractUrlContentId(requests);
+    orderdList.addAll(getRequestsWithoutReferences());
+
+    boolean areRequestsProcessed = true;
+    while (requestsToProcessAvailable() && areRequestsProcessed) {
+      areRequestsProcessed = processRemainingRequests(orderdList);
+    }
+
+    if (requestsToProcessAvailable()) {
+      throw new BatchException("Invalid content id", MessageKeys.INVALID_CONTENT_ID, 0);
+    }
+
+    return orderdList;
+  }
+
+  private boolean requestsToProcessAvailable() {
+    return requestContentIdMapping.keySet().size() != 0;
+  }
+
+  private boolean processRemainingRequests(List<ODataRequest> orderdList) {
+    final List<ODataRequest> addedRequests = getRemainingRequestsWithKownContentId();
+    addRequestsToKnownContentIds(addedRequests);
+    orderdList.addAll(addedRequests);
+
+    return addedRequests.size() != 0;
+  }
+
+  private List<ODataRequest> getRemainingRequestsWithKownContentId() {
+    List<ODataRequest> result = new ArrayList<ODataRequest>();
+
+    for (String contextId : knownContentId) {
+      List<ODataRequest> processedRequests = requestContentIdMapping.get(contextId);
+      if (processedRequests != null && processedRequests.size() != 0) {
+        result.addAll(processedRequests);
+        requestContentIdMapping.remove(contextId);
+      }
+    }
+
+    return result;
+  }
+
+  private List<ODataRequest> getRequestsWithoutReferences() {
+    final List<ODataRequest> requestsWithoutReference = requestContentIdMapping.get(null);
+    requestContentIdMapping.remove(null);
+
+    addRequestsToKnownContentIds(requestsWithoutReference);
+    return requestsWithoutReference;
+  }
+
+  private void addRequestsToKnownContentIds(List<ODataRequest> requestsWithoutReference) {
+    for (ODataRequest request : requestsWithoutReference) {
+      final String contentId = getContentIdFromHeader(request);
+      if (contentId != null) {
+        knownContentId.add(contentId);
+      }
+    }
+  }
+
+  private String getContentIdFromHeader(ODataRequest request) {
+    return request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
+  }
+
+  private void extractUrlContentId(List<ODataRequest> requests) {
+    for (ODataRequest request : requests) {
+      final String reference = getReferenceInURI(request);
+      addRequestToMapping(reference, request);
+    }
+  }
+
+  private void addRequestToMapping(final String reference, final ODataRequest request) {
+    List<ODataRequest> requestList = requestContentIdMapping.get(reference);
+    requestList = (requestList == null) ? new ArrayList<ODataRequest>() : requestList;
+
+    requestList.add(request);
+    requestContentIdMapping.put(reference, requestList);
+  }
+
+  public static String getReferenceInURI(ODataRequest request) {
+    Matcher matcher = referencePattern.matcher(removeFollingPathSegments(request.getRawODataPath()));
+    return (matcher.matches()) ? matcher.group(1) : null;
+  }
+
+  private static String removeFollingPathSegments(String rawODataPath) {
+    final int indexOfSlash = rawODataPath.indexOf("/");
+    return (indexOfSlash != -1) ? rawODataPath.substring(0, indexOfSlash) : rawODataPath;
+  }
+
+  public static void replaceContentIdReference(ODataRequest request, String contentId, String resourceUri) {
+    final String newUri = request.getRawODataPath().replace("$" + contentId, resourceUri);
+    request.setRawODataPath(newUri);
+    request.setRawRequestUri(request.getRawBaseUri() + "/" + newUri);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java
new file mode 100644
index 0000000..01a149e
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java
@@ -0,0 +1,68 @@
+/*
+ * 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.server.core.batch.handler;
+
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.api.processor.BatchProcessor;
+import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
+
+public class BatchHandler {
+  private final BatchOperation operation;
+  private final BatchProcessor batchProcessor;
+  private ODataRequest request;
+
+  public BatchHandler(final ODataHandler oDataHandler, final ODataRequest request, final BatchProcessor batchProcessor,
+      final boolean isStrict) {
+    
+    this.request = request;
+    this.batchProcessor = batchProcessor;
+    operation = new BatchOperationImpl(oDataHandler, request, batchProcessor, isStrict);
+  }
+
+  public void process(ODataResponse response) throws BatchException {
+    validateRequest();
+    batchProcessor.executeBatch(operation, request, response);
+  }
+  
+  private void validateRequest() throws BatchException {
+    validateHttpMethod();
+    validateContentType();
+  }
+
+  private void validateContentType() throws BatchException {
+    final String contentType = request.getHeader(HttpHeader.CONTENT_TYPE);
+    
+    if(contentType == null || !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
+      throw new BatchException("Invalid content type", MessageKeys.INVALID_CONTENT_TYPE, 0);
+    }
+  }
+
+  private void validateHttpMethod() throws BatchException {
+    if(request.getMethod() != HttpMethod.POST) {
+      throw new BatchException("Invalid HTTP method", MessageKeys.INVALID_METHOD, 0);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
new file mode 100644
index 0000000..bc148f0
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
@@ -0,0 +1,74 @@
+/*
+ * 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.server.core.batch.handler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchRequestPart;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
+import org.apache.olingo.server.api.processor.BatchProcessor;
+import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.batch.parser.BatchParser;
+import org.apache.olingo.server.core.batch.writer.BatchResponseWriter;
+
+public class BatchOperationImpl implements BatchOperation {
+  private final BatchPartHandler partHandler;
+  private final BatchResponseWriter writer;
+  private final BatchParser parser;
+
+  public BatchOperationImpl(ODataHandler oDataHandler, ODataRequest request, BatchProcessor batchProcessor,
+      final boolean isStrict) {
+    partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this);
+    writer = new BatchResponseWriter();
+    parser = new BatchParser(getContentType(request), request.getRawBaseUri(),
+                              request.getRawServiceResolutionUri(), isStrict);
+  }
+
+  @Override
+  public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException {
+    return parser.parseBatchRequest(in);
+  }
+
+  @Override
+  public ODataResponse handleODataRequest(ODataRequest request) {
+    return partHandler.handleODataRequest(request);
+  }
+
+  @Override
+  public ODataResponsePart handleBatchRequest(BatchRequestPart request) {
+    return partHandler.handleBatchRequest(request);
+  }
+
+  @Override
+  public void writeResponseParts(List<ODataResponsePart> batchResponses, ODataResponse response) throws BatchException,
+      IOException {
+    writer.toODataResponse(batchResponses, response);
+  }
+
+  private String getContentType(ODataRequest request) {
+    return request.getHeader(HttpHeader.CONTENT_TYPE);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
new file mode 100644
index 0000000..a78d585
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
@@ -0,0 +1,66 @@
+/*
+ * 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.server.core.batch.handler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchRequestPart;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
+import org.apache.olingo.server.api.processor.BatchProcessor;
+import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
+
+public class BatchPartHandler {
+
+  private ODataHandler oDataHandler;
+  private BatchProcessor batchProcessor;
+  private BatchOperation batchOperation;
+
+  public BatchPartHandler(final ODataHandler oDataHandler, final BatchProcessor processor,
+      final BatchOperation batchOperation) {
+    this.oDataHandler = oDataHandler;
+    this.batchProcessor = processor;
+    this.batchOperation = batchOperation;
+  }
+
+  public ODataResponse handleODataRequest(ODataRequest request) {
+    final ODataResponse response = oDataHandler.process(request);
+    response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, request.getHeader(BatchParserCommon.HTTP_CONTENT_ID));
+    
+    return  response;
+  }
+
+  public ODataResponsePart handleBatchRequest(BatchRequestPart request) {
+    final List<ODataResponse> responses = new ArrayList<ODataResponse>();
+
+    if (request.isChangeSet()) {
+      responses.addAll(batchProcessor.executeChangeSet(batchOperation, request.getRequests()));
+      return new ODataResponsePartImpl(responses, true);
+    } else {
+      responses.add(handleODataRequest(request.getRequests().get(0)));
+      return new ODataResponsePartImpl(responses, false);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java
new file mode 100644
index 0000000..da52a37
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.server.core.batch.handler;
+
+import java.util.List;
+
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
+
+public class ODataResponsePartImpl implements ODataResponsePart {
+  private List<ODataResponse> responses;
+  private boolean isChangeSet;
+  
+  public ODataResponsePartImpl(List<ODataResponse> responses, boolean isChangeSet) {
+    this.responses = responses;
+    this.isChangeSet = isChangeSet;
+  }
+
+  @Override
+  public List<ODataResponse> getResponses() {
+    return responses;
+  }
+
+  @Override
+  public boolean isChangeSet() {
+    return isChangeSet;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchBodyPart.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchBodyPart.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchBodyPart.java
index c2d2e0f..2b93783 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchBodyPart.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchBodyPart.java
@@ -22,7 +22,7 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.server.core.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchBodyPart implements BatchPart {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchChangeSetPart.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchChangeSetPart.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchChangeSetPart.java
index 1d0bd6f..aaa2660 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchChangeSetPart.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchChangeSetPart.java
@@ -20,7 +20,7 @@ package org.apache.olingo.server.core.batch.parser;
 
 import java.util.List;
 
-import org.apache.olingo.server.core.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchChangeSetPart extends BatchQueryOperation {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
index 37b1a9c..75c0084 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
@@ -25,9 +25,9 @@ import java.util.LinkedList;
 import java.util.List;
 
 import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.BatchParserResult;
 import org.apache.olingo.server.api.batch.BatchRequestPart;
-import org.apache.olingo.server.core.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.server.core.batch.transformator.BatchRequestTransformator;
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
index e2dc5e5..43a09b6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
@@ -29,7 +29,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.olingo.commons.api.http.HttpContentType;
-import org.apache.olingo.server.core.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchParserCommon {
@@ -186,7 +186,8 @@ public class BatchParserCommon {
   }
 
   public static void consumeBlankLine(final List<Line> remainingMessage, final boolean isStrict) throws BatchException {
-    if (remainingMessage.size() > 0 && remainingMessage.get(0).toString().matches("\\s*\r\n\\s*")) {
+    //TODO is \r\n to strict?
+    if (remainingMessage.size() > 0 && remainingMessage.get(0).toString().matches("\\s*(\r\n|\n)\\s*")) {
       remainingMessage.remove(0);
     } else {
       if (isStrict) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchQueryOperation.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchQueryOperation.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchQueryOperation.java
index 5ff7faf..6a5309e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchQueryOperation.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchQueryOperation.java
@@ -20,7 +20,7 @@ package org.apache.olingo.server.core.batch.parser;
 
 import java.util.List;
 
-import org.apache.olingo.server.core.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 
 public class BatchQueryOperation implements BatchPart {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
index 02c8118..94d5226 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
@@ -27,9 +27,9 @@ import java.util.List;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.BatchParserResult;
-import org.apache.olingo.server.core.batch.BatchException;
-import org.apache.olingo.server.core.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
 import org.apache.olingo.server.core.batch.parser.BatchBodyPart;
 import org.apache.olingo.server.core.batch.parser.BatchChangeSetPart;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
@@ -84,10 +84,10 @@ public class BatchRequestTransformator implements BatchTransformator {
     final HeaderField contentIdRequest = getContentId(request);
 
     if (contentIdChangeRequestPart == null && contentIdRequest == null) {
-      throw new BatchException("Missing content type", MessageKeys.MISSING_CONTENT_ID, changeRequestPart.getHeaders()
+      throw new BatchException("Missing content id", MessageKeys.MISSING_CONTENT_ID, changeRequestPart.getHeaders()
           .getLineNumber());
     } else if (contentIdChangeRequestPart != null) {
-      request.getHeaders().replaceHeaderField(contentIdChangeRequestPart);
+        request.getHeaders().replaceHeaderField(contentIdChangeRequestPart);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformator.java
index becb6c7..286c0cc 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformator.java
@@ -20,8 +20,8 @@ package org.apache.olingo.server.core.batch.transformator;
 
 import java.util.List;
 
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.BatchParserResult;
-import org.apache.olingo.server.core.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BatchBodyPart;
 
 public interface BatchTransformator {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
index a351cca..c9da563 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
@@ -28,8 +28,8 @@ import java.util.regex.Pattern;
 import org.apache.olingo.commons.api.http.HttpContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
-import org.apache.olingo.server.core.batch.BatchException;
-import org.apache.olingo.server.core.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.server.core.batch.parser.Header;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
index a063747..812ea8b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
@@ -31,9 +31,9 @@ import org.apache.olingo.commons.api.http.HttpContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.ODataResponsePart;
-import org.apache.olingo.server.core.batch.BatchException;
-import org.apache.olingo.server.core.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
index 1d68307..c9778e3 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
@@ -33,8 +33,9 @@ import java.util.List;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.BatchRequestPart;
-import org.apache.olingo.server.core.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
 import org.apache.olingo.server.core.batch.parser.BatchParser;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/parser/BatchParserCommonTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/parser/BatchParserCommonTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/parser/BatchParserCommonTest.java
index 6fb0796..e3a1acc 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/parser/BatchParserCommonTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/parser/BatchParserCommonTest.java
@@ -24,7 +24,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.server.core.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.server.core.batch.parser.Header;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
index ec45a22..b7169b9 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
@@ -30,8 +30,8 @@ import java.util.List;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.ODataResponsePart;
-import org.apache.olingo.server.core.batch.BatchException;
 import org.apache.olingo.server.core.batch.StringUtil;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
 import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/15bd1526/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index d88a02f..b59c92e 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -19,11 +19,14 @@
 package org.apache.olingo.server.tecsvc.processor;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 
+import org.apache.olingo.commons.api.ODataRuntimeException;
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.ContextURL.Suffix;
 import org.apache.olingo.commons.api.data.Entity;
@@ -46,6 +49,11 @@ import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchRequestPart;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
+import org.apache.olingo.server.api.processor.BatchProcessor;
 import org.apache.olingo.server.api.processor.EntityProcessor;
 import org.apache.olingo.server.api.processor.EntitySetProcessor;
 import org.apache.olingo.server.api.processor.PropertyProcessor;
@@ -66,7 +74,7 @@ import org.apache.olingo.server.tecsvc.data.DataProvider;
 /**
  * Technical Processor which provides currently implemented processor functionality.
  */
-public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, PropertyProcessor {
+public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, PropertyProcessor, BatchProcessor {
 
   private OData odata;
   private DataProvider dataProvider;
@@ -326,4 +334,33 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
       }
     }
   }
+
+  @Override
+  public void executeBatch(BatchOperation operation, ODataRequest requst, ODataResponse response) {
+    try {
+      final List<BatchRequestPart> parts = operation.parseBatchRequest(requst.getBody());
+      final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
+      
+      for(BatchRequestPart part : parts) {
+        responseParts.add(operation.handleBatchRequest(part));
+      }
+      
+      operation.writeResponseParts(responseParts, response);
+    } catch (BatchException e) {
+      throw new ODataRuntimeException(e);
+    } catch (IOException e) {
+      throw new ODataRuntimeException(e);
+    }
+  }
+
+  @Override
+  public List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests) {
+    List<ODataResponse> responses = new ArrayList<ODataResponse>();
+    
+    for(ODataRequest request : requests) {
+      responses.add(operation.handleODataRequest(request));
+    }
+    
+    return responses;
+  }
 }


[4/9] olingo-odata4 git commit: Batch handler clean up

Posted by ch...@apache.org.
Batch handler clean up

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


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

Branch: refs/heads/olingo472
Commit: 6c7d11f4d77cb3d95684543b79c039c11990c63a
Parents: 0bd3295
Author: Christian Holzer <c....@sap.com>
Authored: Wed Nov 5 16:02:12 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:10:57 2014 +0100

----------------------------------------------------------------------
 .../apache/olingo/server/core/ODataHandler.java |  6 +-
 .../batch/handler/BatchChangeSetSorter.java     | 35 ++++++------
 .../server/core/batch/handler/BatchHandler.java | 40 +++++++-------
 .../core/batch/handler/BatchPartHandler.java    | 17 +++++-
 .../server/core/batch/handler/UriMapping.java   | 34 ------------
 .../batch/handler/MockedBatchHandlerTest.java   | 58 ++++++++------------
 6 files changed, 79 insertions(+), 111 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6c7d11f4/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
index 48d75de..af092cf 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
@@ -162,10 +162,10 @@ public class ODataHandler {
       handleResourceDispatching(request, response);
       break;
     case batch:
-      BatchProcessor bp = selectProcessor(BatchProcessor.class);
+      final BatchProcessor bp = selectProcessor(BatchProcessor.class);
+      final BatchHandler handler = new BatchHandler(this, bp);
       
-      final BatchHandler handler = new BatchHandler(this, request, bp, true);
-      handler.process(response);
+      handler.process(request, response, true);
       
       break;
     default:

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6c7d11f4/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
index f8ac653..408159e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
@@ -38,7 +38,7 @@ public class BatchChangeSetSorter {
   final List<ODataRequest> orderdList = new ArrayList<ODataRequest>();
 
   private static Pattern referencePattern = Pattern.compile(REG_EX_REFERENCE);
-  private Set<String> knownContentId = new HashSet<String>();
+  private Set<String> knownContentIds = new HashSet<String>();
   private Map<String, List<ODataRequest>> requestReferenceMapping = new HashMap<String, List<ODataRequest>>();
 
   public BatchChangeSetSorter(List<ODataRequest> requests) throws BatchException {
@@ -52,15 +52,19 @@ public class BatchChangeSetSorter {
   private List<ODataRequest> sort(final List<ODataRequest> requests) throws BatchException {
     extractUrlReference(requests);
     
+    // Add requests without reference (roots)
     final List<ODataRequest> requestsWithoutReferences = getRequestsWithoutReferences();
     orderdList.addAll(requestsWithoutReferences);
     addRequestsToKnownContentIds(requestsWithoutReferences);
     
+    // Find all requests which can be processed (parent request has been processed)
+    // Compare level order
     boolean areRequestsProcessed = true;
     while (requestsToProcessAvailable() && areRequestsProcessed) {
-      areRequestsProcessed = processRemainingRequests(orderdList);
+      areRequestsProcessed = processNextLevel();
     }
 
+    // Check if there are some requests which are not connected to a tree
     if (requestsToProcessAvailable()) {
       throw new BatchException("Invalid content id", MessageKeys.INVALID_CONTENT_ID, 0);
     }
@@ -72,7 +76,7 @@ public class BatchChangeSetSorter {
     return requestReferenceMapping.keySet().size() != 0;
   }
 
-  private boolean processRemainingRequests(List<ODataRequest> orderdList) {
+  private boolean processNextLevel() {
     final List<ODataRequest> addedRequests = getRemainingRequestsWithKownContentId();
     addRequestsToKnownContentIds(addedRequests);
     orderdList.addAll(addedRequests);
@@ -83,10 +87,10 @@ public class BatchChangeSetSorter {
   private List<ODataRequest> getRemainingRequestsWithKownContentId() {
     List<ODataRequest> result = new ArrayList<ODataRequest>();
 
-    for (String contextId : knownContentId) {
-      List<ODataRequest> processedRequests = requestReferenceMapping.get(contextId);
-      if (processedRequests != null && processedRequests.size() != 0) {
-        result.addAll(processedRequests);
+    for (String contextId : knownContentIds) {
+      final List<ODataRequest> requestsToProcess = requestReferenceMapping.get(contextId);
+      if (requestsToProcess != null && requestsToProcess.size() != 0) {
+        result.addAll(requestsToProcess);
         requestReferenceMapping.remove(contextId);
       }
     }
@@ -105,7 +109,7 @@ public class BatchChangeSetSorter {
     for (ODataRequest request : requestsWithoutReference) {
       final String contentId = getContentIdFromHeader(request);
       if (contentId != null) {
-        knownContentId.add(contentId);
+        knownContentIds.add(contentId);
       }
     }
   }
@@ -130,18 +134,17 @@ public class BatchChangeSetSorter {
   }
 
   public static String getReferenceInURI(ODataRequest request) {
-    Matcher matcher = referencePattern.matcher(removeFollingPathSegments(removeFirstSplash(request.getRawODataPath())));
+    Matcher matcher = referencePattern.matcher(removeSlash(removeSlash(request.getRawODataPath(), true), false));
     return (matcher.matches()) ? matcher.group(1) : null;
   }
 
-  private static String removeFirstSplash(String rawODataPath) {
+  private static String removeSlash(String rawODataPath, boolean first) {
     final int indexOfSlash = rawODataPath.indexOf("/");
-    return (indexOfSlash == 0) ? rawODataPath.substring(1) : rawODataPath;
-  }
-
-  private static String removeFollingPathSegments(String rawODataPath) {
-    final int indexOfSlash = rawODataPath.indexOf("/");
-    return (indexOfSlash != -1) ? rawODataPath.substring(0, indexOfSlash) : rawODataPath;
+    if(first) {
+      return (indexOfSlash == 0) ? rawODataPath.substring(1) : rawODataPath;
+    } else {
+      return (indexOfSlash != -1) ? rawODataPath.substring(0, indexOfSlash) : rawODataPath;
+    }
   }
 
   public static void replaceContentIdReference(ODataRequest request, String contentId, String resourceUri) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6c7d11f4/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java
index 01a149e..df16c90 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchHandler.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
@@ -30,38 +30,38 @@ import org.apache.olingo.server.core.ODataHandler;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
 
 public class BatchHandler {
-  private final BatchOperation operation;
   private final BatchProcessor batchProcessor;
-  private ODataRequest request;
+  private final ODataHandler oDataHandler;
+
+  public BatchHandler(final ODataHandler oDataHandler, final BatchProcessor batchProcessor) {
 
-  public BatchHandler(final ODataHandler oDataHandler, final ODataRequest request, final BatchProcessor batchProcessor,
-      final boolean isStrict) {
-    
-    this.request = request;
     this.batchProcessor = batchProcessor;
-    operation = new BatchOperationImpl(oDataHandler, request, batchProcessor, isStrict);
+    this.oDataHandler = oDataHandler;
   }
 
-  public void process(ODataResponse response) throws BatchException {
-    validateRequest();
+  public void process(final ODataRequest request, final ODataResponse response, final boolean isStrict)
+      throws BatchException {
+    validateRequest(request);
+    
+    final BatchOperation operation = new BatchOperationImpl(oDataHandler, request, batchProcessor, isStrict);
     batchProcessor.executeBatch(operation, request, response);
   }
-  
-  private void validateRequest() throws BatchException {
-    validateHttpMethod();
-    validateContentType();
+
+  private void validateRequest(final ODataRequest request) throws BatchException {
+    validateHttpMethod(request);
+    validateContentType(request);
   }
 
-  private void validateContentType() throws BatchException {
+  private void validateContentType(final ODataRequest request) throws BatchException {
     final String contentType = request.getHeader(HttpHeader.CONTENT_TYPE);
-    
-    if(contentType == null || !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
+
+    if (contentType == null || !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
       throw new BatchException("Invalid content type", MessageKeys.INVALID_CONTENT_TYPE, 0);
     }
   }
 
-  private void validateHttpMethod() throws BatchException {
-    if(request.getMethod() != HttpMethod.POST) {
+  private void validateHttpMethod(final ODataRequest request) throws BatchException {
+    if (request.getMethod() != HttpMethod.POST) {
       throw new BatchException("Invalid HTTP method", MessageKeys.INVALID_METHOD, 0);
     }
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6c7d11f4/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
index c678355..5bec30b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
@@ -58,7 +58,8 @@ public class BatchPartHandler {
       final UriMapping mapping = replaceReference(request, requestPart);
 
       response = oDataHandler.process(request);
-       
+      
+      // Store resource URI
       final String resourceUri = getODataPath(request, response);
       final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
 
@@ -67,6 +68,7 @@ public class BatchPartHandler {
       response = oDataHandler.process(request);
     }
     
+    // Add content id to response
     final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
     if(contentId != null) {
       response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
@@ -85,7 +87,7 @@ public class BatchPartHandler {
       resourceUri = uri.getRawODataPath();
     } else {
       // Update, Upsert (PUT, PATCH, Delete)
-      // These methods still addresses a given URI, so we use the URI given by the request
+      // These methods still addresses a given resource, so we use the URI given by the request
       resourceUri = request.getRawODataPath();
     }
     
@@ -140,4 +142,15 @@ public class BatchPartHandler {
     return new ODataResponsePartImpl(responses, true);
   }
 
+  private static class UriMapping {
+    private Map<String, String> uriMapping = new HashMap<String, String>();
+    
+    public void addMapping(final String contentId, final String uri) {
+      uriMapping.put(contentId, uri);
+    }
+    
+    public String getUri(final String contentId) {
+      return uriMapping.get(contentId);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6c7d11f4/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java
deleted file mode 100644
index 0123320..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java
+++ /dev/null
@@ -1,34 +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.server.core.batch.handler;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class UriMapping {
-  private Map<String, String> uriMapping = new HashMap<String, String>();
-  
-  public void addMapping(final String contentId, final String uri) {
-    uriMapping.put(contentId, uri);
-  }
-  
-  public String getUri(final String contentId) {
-    return uriMapping.get(contentId);
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6c7d11f4/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
index ac111e0..d772fbc 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
@@ -61,9 +61,19 @@ public class MockedBatchHandlerTest {
   private static final String BATCH_REQUEST_URI = "http://localhost:8080/odata/$batch";
   private static final String BASE_URI = "http://localhost:8080/odata";
   private static final String CRLF = "\r\n";
-  private ODataHandler handler;
+  private ODataHandler oDataHandler;
+  private BatchHandler batchHandler;
   private int entityCounter = 1;
 
+  @Before
+  public void setup() {
+    final BatchProcessor batchProcessor = new BatchTestProcessorImpl();
+
+    entityCounter = 1;
+    oDataHandler = mock(ODataHandler.class);
+    batchHandler = new BatchHandler(oDataHandler, batchProcessor);
+  }
+
   @Test
   public void test() throws BatchException, IOException {
     final String content = "--batch_12345" + CRLF
@@ -130,9 +140,9 @@ public class MockedBatchHandlerTest {
         + "--batch_12345--";
     final Map<String, List<String>> header = getMimeHeader();
     final ODataResponse response = new ODataResponse();
-    final BatchHandler batchHandler = buildBatchHandler(content, header);
+    final ODataRequest request = buildODataRequest(content, header);
 
-    batchHandler.process(response);
+    batchHandler.process(request, response, true);
 
     BufferedReaderIncludingLineEndings reader =
         new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
@@ -244,9 +254,9 @@ public class MockedBatchHandlerTest {
         + "--batch_12345--";
     final Map<String, List<String>> header = getMimeHeader();
     final ODataResponse response = new ODataResponse();
-    final BatchHandler batchHandler = buildBatchHandler(content, header);
+    final ODataRequest request = buildODataRequest(content, header);
 
-    batchHandler.process(response);
+    batchHandler.process(request, response, true);
 
     BufferedReaderIncludingLineEndings reader =
         new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
@@ -365,9 +375,9 @@ public class MockedBatchHandlerTest {
 
     final Map<String, List<String>> header = getMimeHeader();
     final ODataResponse response = new ODataResponse();
-    final BatchHandler batchHandler = buildBatchHandler(content, header);
+    final ODataRequest request = buildODataRequest(content, header);
 
-    batchHandler.process(response);
+    batchHandler.process(request, response, true);
 
     BufferedReaderIncludingLineEndings reader =
         new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
@@ -418,12 +428,6 @@ public class MockedBatchHandlerTest {
     assertEquals(45, line);
   }
 
-  @Before
-  public void setup() {
-    handler = null;
-    entityCounter = 1;
-  }
-
   private String checkChangeSetPartHeader(final List<String> response, int line) {
     assertEquals(CRLF, response.get(line++));
     assertTrue(response.get(line++).contains("--changeset_"));
@@ -442,7 +446,6 @@ public class MockedBatchHandlerTest {
   /*
    * Helper methods
    */
-
   private Map<String, List<String>> getMimeHeader() {
     final Map<String, List<String>> header = new HashMap<String, List<String>>();
     header.put(HttpHeader.CONTENT_TYPE, Arrays.asList(new String[] { BATCH_CONTENT_TYPE }));
@@ -450,24 +453,7 @@ public class MockedBatchHandlerTest {
     return header;
   }
 
-  private BatchHandler buildBatchHandler(final String content, Map<String, List<String>> header) throws BatchException,
-      UnsupportedEncodingException {
-
-    final ODataRequest request = buildODataRequest(content, header);
-    final ODataHandler oDataHandler = buildODataHandler(request);
-    final BatchProcessor batchProcessor = new BatchProcessorImpl();
-
-    return new BatchHandler(oDataHandler, request, batchProcessor, true);
-  }
-
-  private ODataHandler buildODataHandler(ODataRequest request) {
-    handler = mock(ODataHandler.class);
-    when(handler.process(request)).thenCallRealMethod();
-
-    return handler;
-  }
-
-  private ODataRequest buildODataRequest(String content, Map<String, List<String>> header)
+  private ODataRequest buildODataRequest(final String content, final Map<String, List<String>> header)
       throws UnsupportedEncodingException {
     final ODataRequest request = new ODataRequest();
 
@@ -490,7 +476,7 @@ public class MockedBatchHandlerTest {
   /**
    * Batch processor
    */
-  private class BatchProcessorImpl implements BatchProcessor {
+  private class BatchTestProcessorImpl implements BatchProcessor {
     @Override
     public void init(OData odata, ServiceMetadata serviceMetadata) {}
 
@@ -500,8 +486,8 @@ public class MockedBatchHandlerTest {
       List<ODataResponse> responses = new ArrayList<ODataResponse>();
 
       for (ODataRequest request : requests) {
-        // Mock the processor of the changeset requests
-        when(handler.process(request)).then(new Answer<ODataResponse>() {
+        // Mock the processor for a given requests
+        when(oDataHandler.process(request)).then(new Answer<ODataResponse>() {
           @Override
           public ODataResponse answer(InvocationOnMock invocation) throws Throwable {
             Object[] arguments = invocation.getArguments();
@@ -565,7 +551,7 @@ public class MockedBatchHandlerTest {
       // Entity Collection
       oDataPath = parts[1];
     } else {
-      // Navigationproperty
+      // Navigation property
 
       final String navProperty = parts[parts.length - 1];
       if (navProperty.equals("NavPropertyETTwoPrimMany")) {


[7/9] olingo-odata4 git commit: Batch IT test case

Posted by ch...@apache.org.
Batch IT test case

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


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

Branch: refs/heads/olingo472
Commit: 4ff5fb9c8ce045e87657dec69f76db52001f1508
Parents: 5f4eb03
Author: Christian Holzer <c....@sap.com>
Authored: Mon Nov 10 17:30:18 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:11:00 2014 +0100

----------------------------------------------------------------------
 .../fit/tecsvc/client/BatchClientITCase.java    | 459 +++++++++++++++++++
 .../server/api/batch/ODataResponsePart.java     |  52 ++-
 .../server/api/processor/BatchProcessor.java    |   3 +-
 .../server/api/processor/DefaultProcessor.java  |  93 +++-
 .../core/batch/handler/BatchPartHandler.java    |   7 +-
 .../batch/handler/ODataResponsePartImpl.java    |  44 --
 .../core/batch/parser/BatchParserCommon.java    |   8 -
 .../core/batch/writer/BatchResponseWriter.java  |   2 +-
 .../batch/writer/ODataResponsePartImpl.java     |  44 --
 .../core/batch/BatchRequestParserTest.java      |  28 +-
 .../batch/handler/MockedBatchHandlerTest.java   |   4 +-
 .../batch/writer/BatchResponseWriterTest.java   |   8 +-
 12 files changed, 627 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java
new file mode 100644
index 0000000..f2e1ab6
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BatchClientITCase.java
@@ -0,0 +1,459 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import java.net.URI;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.olingo.client.api.ODataBatchConstants;
+import org.apache.olingo.client.api.communication.request.batch.BatchManager;
+import org.apache.olingo.client.api.communication.request.batch.ODataBatchResponseItem;
+import org.apache.olingo.client.api.communication.request.batch.ODataChangeset;
+import org.apache.olingo.client.api.communication.request.batch.v4.ODataBatchRequest;
+import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
+import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
+import org.apache.olingo.client.api.communication.request.cud.v4.UpdateType;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
+import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
+import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
+import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse;
+import org.apache.olingo.client.api.communication.response.ODataResponse;
+import org.apache.olingo.client.api.uri.v4.URIBuilder;
+import org.apache.olingo.client.core.communication.request.batch.ODataChangesetResponseItem;
+import org.apache.olingo.client.core.uri.URIUtils;
+import org.apache.olingo.commons.api.domain.v4.ODataEntity;
+import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.apache.olingo.fit.v4.AbstractTestITCase;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class BatchClientITCase extends AbstractTestITCase {
+  private final static String ACCEPT = ContentType.APPLICATION_OCTET_STREAM.toContentTypeString();
+  private static final String SERVICE_URI = TecSvcConst.BASE_URI;
+
+  @Before
+  public void setup() {
+    client.getConfiguration().setContinueOnError(false);
+  }
+
+  @Test
+  public void emptyBatchRequest() {
+    // create your request
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+    request.setAccept(ACCEPT);
+
+    final BatchManager payload = request.payloadManager();
+    final ODataBatchResponse response = payload.getResponse();
+
+    assertEquals(202, response.getStatusCode());
+    assertEquals("Accepted", response.getStatusMessage());
+
+    final Iterator<ODataBatchResponseItem> iter = response.getBody();
+    assertFalse(iter.hasNext());
+  }
+
+  @Test
+  public void getBatchRequest() {
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+    request.setAccept(ACCEPT);
+
+    final BatchManager payload = request.payloadManager();
+
+    // create new request
+    appendGetRequest(payload, "ESAllPrim", 32767);
+
+    // Fetch result
+    final ODataBatchResponse response = payload.getResponse();
+
+    assertEquals(202, response.getStatusCode());
+    assertEquals("Accepted", response.getStatusMessage());
+
+    final Iterator<ODataBatchResponseItem> iter = response.getBody();
+    assertTrue(iter.hasNext());
+
+    ODataBatchResponseItem item = iter.next();
+    assertFalse(item.isChangeset());
+
+    ODataResponse oDataResonse = item.next();
+    assertNotNull(oDataResonse);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResonse.getStatusCode());
+    assertEquals(1, oDataResonse.getHeader("OData-Version").size());
+    assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
+    assertEquals(1, oDataResonse.getHeader("Content-Length").size());
+    assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
+    assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
+  }
+
+  @Test
+  public void testErrorWithoutContinueOnErrorPreferHeader() {
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+    request.setAccept(ACCEPT);
+
+    final BatchManager payload = request.payloadManager();
+
+    appendGetRequest(payload, "ESAllPrim", 32767); // Without error
+    appendGetRequest(payload, "ESAllPrim", 42); // Error ( Key does not exist )
+    appendGetRequest(payload, "ESAllPrim", 0); // Without error
+
+    // Fetch result
+    final ODataBatchResponse response = payload.getResponse();
+    assertEquals(202, response.getStatusCode());
+
+    final Iterator<ODataBatchResponseItem> iter = response.getBody();
+
+    // Check first get request
+    assertTrue(iter.hasNext());
+    ODataBatchResponseItem item = iter.next();
+    assertFalse(item.isChangeset());
+
+    ODataResponse oDataResonse = item.next();
+    assertNotNull(oDataResonse);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResonse.getStatusCode());
+    assertEquals(1, oDataResonse.getHeader("OData-Version").size());
+    assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
+    assertEquals(1, oDataResonse.getHeader("Content-Length").size());
+    assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
+    assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
+
+    // Check second get request
+    assertTrue(iter.hasNext());
+    item = iter.next();
+    assertFalse(item.isChangeset());
+
+    oDataResonse = item.next();
+    assertNotNull(oDataResonse);
+    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), oDataResonse.getStatusCode());
+
+    // Check if third request is available
+    assertFalse(iter.hasNext());
+  }
+
+  @Test
+  public void testErrorWithContinueOnErrorPreferHeader() {
+    client.getConfiguration().setContinueOnError(true);
+
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+    request.setAccept(ACCEPT);
+
+    final BatchManager payload = request.payloadManager();
+
+    appendGetRequest(payload, "ESAllPrim", 32767); // Without error
+    appendGetRequest(payload, "ESAllPrim", 42); // Error ( Key does not exist )
+    appendGetRequest(payload, "ESAllPrim", 0); // Without error
+
+    // Fetch result
+    final ODataBatchResponse response = payload.getResponse();
+    assertEquals(202, response.getStatusCode());
+
+    final Iterator<ODataBatchResponseItem> bodyIterator = response.getBody();
+
+    // Check first get request
+    assertTrue(bodyIterator.hasNext());
+    ODataBatchResponseItem item = bodyIterator.next();
+    assertFalse(item.isChangeset());
+
+    ODataResponse oDataResonse = item.next();
+    assertNotNull(oDataResonse);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResonse.getStatusCode());
+    assertEquals(1, oDataResonse.getHeader("OData-Version").size());
+    assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
+    assertEquals(1, oDataResonse.getHeader("Content-Length").size());
+    assertEquals("538", oDataResonse.getHeader("Content-Length").toArray()[0]);
+    assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
+
+    // Check second get request
+    assertTrue(bodyIterator.hasNext());
+    item = bodyIterator.next();
+    assertFalse(item.isChangeset());
+
+    oDataResonse = item.next();
+    assertNotNull(oDataResonse);
+    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), oDataResonse.getStatusCode());
+
+    // Check if third request is available
+    assertTrue(bodyIterator.hasNext());
+    item = bodyIterator.next();
+    assertFalse(item.isChangeset());
+
+    oDataResonse = item.next();
+    assertNotNull(oDataResonse);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), oDataResonse.getStatusCode());
+    assertEquals(1, oDataResonse.getHeader("OData-Version").size());
+    assertEquals("4.0", oDataResonse.getHeader("OData-Version").toArray()[0]);
+    assertEquals(1, oDataResonse.getHeader("Content-Length").size());
+    assertEquals("446", oDataResonse.getHeader("Content-Length").toArray()[0]);
+    assertEquals("application/json;odata.metadata=minimal", oDataResonse.getContentType());
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  @Ignore("Not implemented")
+  public void changesetWithReferences() throws EdmPrimitiveTypeException {
+    // create your request
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+    request.setAccept(ACCEPT);
+    final BatchManager streamManager = request.payloadManager();
+
+    final ODataChangeset changeset = streamManager.addChangeset();
+    ODataEntity esAllPrim = newESAllPrim((short) 23);
+
+    final URIBuilder uriBuilder = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim");
+
+    // add create request
+    final ODataEntityCreateRequest<ODataEntity> createReq =
+        client.getCUDRequestFactory().getEntityCreateRequest(uriBuilder.build(), esAllPrim);
+
+    changeset.addRequest(createReq);
+
+    // retrieve request reference
+    int createRequestRef = changeset.getLastContentId();
+
+    // add update request
+    final ODataEntity customerChanges = client.getObjectFactory().newEntity(esAllPrim.getTypeName());
+    customerChanges.addLink(client.getObjectFactory().newEntitySetNavigationLink(
+        "NavPropertyETTwoPrimMany",
+        client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("NavPropertyETTwoPrimMany").
+            appendKeySegment(new HashMap<String, Object>() {
+              private static final long serialVersionUID = 3109256773218160485L;
+
+              {
+                put("PropertyInt16", 4242);
+                put("PropertyString", "Test");
+              }
+            }).build()));
+
+    final ODataEntityUpdateRequest<ODataEntity> updateReq = client.getCUDRequestFactory().getEntityUpdateRequest(
+        URI.create("$" + createRequestRef), UpdateType.PATCH, customerChanges);
+
+    changeset.addRequest(updateReq);
+
+    final ODataBatchResponse response = streamManager.getResponse();
+    assertEquals(200, response.getStatusCode());
+    assertEquals("OK", response.getStatusMessage());
+
+    // verify response payload ...
+    final Iterator<ODataBatchResponseItem> iter = response.getBody();
+
+    final ODataBatchResponseItem item = iter.next();
+    assertTrue(item instanceof ODataChangesetResponseItem);
+
+    final ODataChangesetResponseItem chgitem = (ODataChangesetResponseItem) item;
+
+    ODataResponse res = chgitem.next();
+    assertEquals(201, res.getStatusCode());
+    assertTrue(res instanceof ODataEntityCreateResponse);
+
+    esAllPrim = ((ODataEntityCreateResponse<ODataEntity>) res).getBody();
+    final ODataEntitySetRequest<ODataEntitySet> req = client.getRetrieveRequestFactory().getEntitySetRequest(
+        URIUtils.getURI(SERVICE_URI, esAllPrim.getEditLink().toASCIIString() + "/NavPropertyETTwoPrimMany"));
+
+    assertEquals(Integer.valueOf(4242),
+        req.execute().getBody().getEntities().get(0).getProperty("PropertyInt16").getPrimitiveValue().
+            toCastValue(Integer.class));
+
+    res = chgitem.next();
+    assertEquals(204, res.getStatusCode());
+    assertTrue(res instanceof ODataEntityUpdateResponse);
+
+    // clean ...
+    assertEquals(204, client.getCUDRequestFactory().getDeleteRequest(
+        URIUtils.getURI(SERVICE_URI, esAllPrim.getEditLink().toASCIIString())).execute().
+        getStatusCode());
+
+    try {
+      client.getRetrieveRequestFactory().getEntityRequest(
+          URIUtils.getURI(SERVICE_URI, esAllPrim.getEditLink().toASCIIString())).
+          execute().getBody();
+      fail("Entity not deleted");
+    } catch (Exception e) {
+      // ignore
+    }
+  }
+
+  private ODataEntity newESAllPrim(short id) {
+    final ODataEntity entity = getClient().getObjectFactory().
+        newEntity(new FullQualifiedName("olingo.odata.test1.ESAllPrim"));
+
+    entity.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
+        "PropertyInt16",
+        client.getObjectFactory().newPrimitiveValueBuilder().buildInt16(id)));
+
+    entity.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
+        "PropertyDouble",
+        client.getObjectFactory().newPrimitiveValueBuilder().buildDouble(3.1415)));
+
+    return entity;
+  }
+
+  //TODO If write support is implemented, remove ignore tag
+  @Test
+  @Ignore("Not implemented")
+  public void changesetBatchRequest() {
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+    request.setAccept(ACCEPT);
+
+    final BatchManager payload = request.payloadManager();
+    // -----------------------------
+    // - Append get request
+    // -----------------------------
+    appendGetRequest(payload, "ESAllPrim", 32767); // Without error
+
+    // -----------------------------
+    // - Append change set
+    // -----------------------------
+    final ODataChangeset changeset = payload.addChangeset();
+
+    // ------------------------
+    // POST request (Insert)
+    URIBuilder targetURI =
+        client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim");
+    URI editLink = targetURI.build();
+
+    ODataEntity post = client.getObjectFactory().newEntity(
+        new FullQualifiedName("olingo.odata.test1.ESAllPrim"));
+
+    post.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
+        "PropertyInt16",
+        client.getObjectFactory().newPrimitiveValueBuilder().buildInt16((short) 15)));
+
+    post.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
+        "PropertyDouble",
+        client.getObjectFactory().newPrimitiveValueBuilder().buildDouble(3.1415)));
+
+    final ODataEntityCreateRequest<ODataEntity> createRequest =
+        client.getCUDRequestFactory().getEntityCreateRequest(editLink, post);
+    createRequest.setFormat(ODataFormat.JSON_FULL_METADATA);
+    createRequest.setContentType("1");
+
+    changeset.addRequest(createRequest);
+
+    // ------------------------
+    // Patch request (Update)
+    targetURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").appendKeySegment(0);
+    editLink = targetURI.build();
+
+    ODataEntity patch = client.getObjectFactory().newEntity(new FullQualifiedName("olingo.odata.test1.ESAllPrim"));
+    patch.setEditLink(editLink);
+
+    patch.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
+        "PropertyDouble",
+        client.getObjectFactory().newPrimitiveValueBuilder().buildDouble(3.1415)));
+
+    ODataEntityUpdateRequest<ODataEntity> changeReq =
+        client.getCUDRequestFactory().getEntityUpdateRequest(UpdateType.PATCH, patch);
+    changeReq.setFormat(ODataFormat.JSON_FULL_METADATA);
+    changeReq.setContentType("2");
+    changeset.addRequest(changeReq);
+
+    // ------------------------
+    // Patch request (Upsert)
+    targetURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").appendKeySegment(35);
+    editLink = targetURI.build();
+
+    patch = client.getObjectFactory().newEntity(new FullQualifiedName("olingo.odata.test1.ESAllPrim"));
+    patch.setEditLink(editLink);
+
+    patch.getProperties().add(client.getObjectFactory().newPrimitiveProperty(
+        "PropertyDouble",
+        client.getObjectFactory().newPrimitiveValueBuilder().buildDouble(3.1415)));
+
+    changeReq = client.getCUDRequestFactory().getEntityUpdateRequest(UpdateType.PATCH, patch);
+    changeReq.setFormat(ODataFormat.JSON_FULL_METADATA);
+    changeReq.setContentType("3");
+    changeset.addRequest(changeReq);
+
+    // -----------------------------
+    // - Append get request
+    // -----------------------------
+    appendGetRequest(payload, "ESAllPrim", 32767); // Without error
+
+    // -----------------------------
+    // - Fetch result
+    // -----------------------------
+    final ODataBatchResponse response = payload.getResponse();
+    assertEquals(202, response.getStatusCode());
+    final Iterator<ODataBatchResponseItem> bodyIterator = response.getBody();
+
+    // Check first get request
+    assertTrue(bodyIterator.hasNext());
+    ODataBatchResponseItem item = bodyIterator.next();
+    assertFalse(item.isChangeset());
+
+    // Check change set
+    assertTrue(bodyIterator.hasNext());
+    item = bodyIterator.next();
+    assertTrue(item.isChangeset());
+
+    for (int i = 0; i < 3; i++) {
+      assertTrue(item.hasNext());
+      assertTrue(item instanceof ODataChangesetResponseItem);
+      ODataChangesetResponseItem changeSetResponseItem = (ODataChangesetResponseItem) item.next();
+      assertNotNull(changeSetResponseItem);
+
+      ODataResponse chgRequest = changeSetResponseItem.next();
+      final String contentId = chgRequest.getHeader(ODataBatchConstants.CHANGESET_CONTENT_ID_NAME).iterator().next();
+
+      if (contentId == "1") {
+        // Insert
+        assertEquals(HttpStatusCode.CREATED.getStatusCode(), chgRequest.getStatusCode());
+      } else if (contentId == "2") {
+        // Update
+        assertEquals(HttpStatusCode.OK.getStatusCode(), chgRequest.getStatusCode());
+      } else if (contentId == "3") {
+        // Upsert
+        assertEquals(HttpStatusCode.CREATED.getStatusCode(), chgRequest.getStatusCode());
+      } else {
+        fail("Unkonwn content id " + contentId);
+      }
+    }
+    assertFalse(item.hasNext());
+
+    // Check second get request
+    assertTrue(bodyIterator.hasNext());
+    item = bodyIterator.next();
+    assertFalse(item.isChangeset());
+  }
+
+  private void appendGetRequest(final BatchManager manager, final String segment, final Object key) {
+    URIBuilder targetURI = client.newURIBuilder(SERVICE_URI);
+    targetURI.appendEntitySetSegment(segment).appendKeySegment(key);
+
+    ODataEntityRequest<ODataEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(targetURI.build());
+    queryReq.setFormat(ODataFormat.JSON);
+    manager.addRequest(queryReq);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/ODataResponsePart.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/ODataResponsePart.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/ODataResponsePart.java
index 8dd7480..c9a914a 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/ODataResponsePart.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/ODataResponsePart.java
@@ -18,25 +18,63 @@
  */
 package org.apache.olingo.server.api.batch;
 
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.olingo.server.api.ODataResponse;
 
-public interface ODataResponsePart {
+public class ODataResponsePart {
+  private List<ODataResponse> responses;
+  private boolean isChangeSet;
+  
   /**
-   * Returns a collection of ODataResponses.
-   * Each collections contains at least one {@link ODataResponse}.
+   * Creates a new ODataResponsePart.
    * 
-   * If this instance represents a change set, there are may many ODataResponses
+   * An ODataResponsePart represents a collections of ODataResponses.
+   * A list of ODataResponseParts can be combined by the BatchSerializer to a single
+   * OData batch response.
    *  
-   * @return a list of {@link ODataResponse}
+   * @param responses     A list of {@link ODataResponse}
+   * @param isChangeSet   True this ODataResponsePart represents a change set, otherwise false
+   */
+  public ODataResponsePart(List<ODataResponse> responses, boolean isChangeSet) {
+    this.responses = responses;
+    this.isChangeSet = isChangeSet;
+  }
+  
+  /**
+   * Creates a new ODataResponsePart.
+   * 
+   * An ODataResponsePart represents a collections of ODataResponses.
+   * A list of ODataResponseParts can be combined by the BatchSerializer to a single
+   * OData batch response.
+   *  
+   * @param responses     A single {@link ODataResponse}
+   * @param isChangeSet   True this ODataResponsePart represents a change set, otherwise false
    */
-  public List<ODataResponse> getResponses();
+  public ODataResponsePart(ODataResponse response, boolean isChangeSet) {
+    this.responses = Arrays.asList(new ODataResponse[] { response });
+    this.isChangeSet = isChangeSet;
+  }
   
   /**
    * Returns true if the current instance represents a change set.
    * 
    * @return true or false
    */
-  public boolean isChangeSet();
+  public List<ODataResponse> getResponses() {
+    return responses;
+  }
+  
+  /**
+   * Returns a collection of ODataResponses.
+   * Each collections contains at least one {@link ODataResponse}.
+   * 
+   * If this instance represents a change set, there are may many ODataResponses
+   *  
+   * @return a list of {@link ODataResponse}
+   */
+  public boolean isChangeSet() {
+    return isChangeSet;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
index a0a7135..843fa28 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
@@ -24,10 +24,11 @@ import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.batch.BatchOperation;
 import org.apache.olingo.server.api.batch.BatchRequestPart;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
 
 public interface BatchProcessor extends Processor {
   void executeBatch(BatchOperation operation, ODataRequest request, ODataResponse response);
 
-  List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
+  ODataResponsePart executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
       BatchRequestPart requestPart);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
index 473c904..25778e3 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
@@ -19,7 +19,11 @@
 package org.apache.olingo.server.api.processor;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
+import org.apache.olingo.commons.api.ODataRuntimeException;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.format.ODataFormat;
 import org.apache.olingo.commons.api.http.HttpHeader;
@@ -30,6 +34,10 @@ import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchRequestPart;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriInfo;
@@ -42,8 +50,12 @@ import org.apache.olingo.server.api.uri.UriInfo;
  * <p>This implementation is registered in the ODataHandler by default.
  * The default can be replaced by re-registering a custom implementation.</p>
  */
-public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProcessor, ExceptionProcessor {
-
+public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProcessor, ExceptionProcessor,
+    BatchProcessor {
+  
+  private static final String PREFERENCE_CONTINUE_ON_ERROR = "odata.continue-on-error";
+  private static final String PREFER_HEADER = "Prefer";
+  
   private OData odata;
   private ServiceMetadata serviceMetadata;
 
@@ -89,4 +101,81 @@ public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProce
       response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_JSON.toContentTypeString());
     }
   }
+
+  @Override
+  public void executeBatch(BatchOperation operation, ODataRequest request, ODataResponse response) {
+    boolean continueOnError = shouldContinueOnError(request);
+
+    try {
+      final List<BatchRequestPart> parts = operation.parseBatchRequest(request.getBody());
+      final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
+
+      for (BatchRequestPart part : parts) {
+        final ODataResponsePart responsePart = operation.handleBatchRequest(part);
+        responseParts.add(responsePart);    // Also add failed responses
+
+        if (responsePart.getResponses().get(0).getStatusCode() >= 400
+            && !continueOnError) {
+
+          // Perform some additions actions
+          // ...
+          
+          break; // Stop processing, but serialize all recent requests
+        }
+      }
+
+      operation.writeResponseParts(responseParts, response);  // Serialize responses
+    } catch (BatchException e) {
+      throw new ODataRuntimeException(e);
+    } catch (IOException e) {
+      throw new ODataRuntimeException(e);
+    }
+  }
+
+  private boolean shouldContinueOnError(ODataRequest request) {
+    final List<String> preferValues = request.getHeaders(PREFER_HEADER);
+
+    if (preferValues != null) {
+      for (final String preference : preferValues) {
+        if (PREFERENCE_CONTINUE_ON_ERROR.equals(preference)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public ODataResponsePart executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
+      BatchRequestPart requestPart) {
+    List<ODataResponse> responses = new ArrayList<ODataResponse>();
+
+    for (ODataRequest request : requests) {
+      try {
+        final ODataResponse oDataResponse = operation.handleODataRequest(request, requestPart);
+
+        if (oDataResponse.getStatusCode() < 400) {
+          responses.add(oDataResponse);
+        } else {
+          // Rollback
+          // ...
+
+          // OData Version 4.0 Part 1: Protocol Plus Errata 01
+          // 11.7.4 Responding to a Batch Request
+          //
+          // When a request within a change set fails, the change set response is not represented using
+          // the multipart/mixed media type. Instead, a single response, using the application/http media type
+          // and a Content-Transfer-Encoding header with a value of binary, is returned that applies to all requests
+          // in the change set and MUST be formatted according to the Error Handling defined
+          // for the particular response format.
+
+          return new ODataResponsePart(oDataResponse, false);
+        }
+      } catch (BatchException e) {
+        throw new ODataRuntimeException(e);
+      }
+    }
+
+    return new ODataResponsePart(responses, true);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
index 5bec30b..23ba106 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
@@ -129,17 +129,14 @@ public class BatchPartHandler {
       final List<ODataResponse> responses = new ArrayList<ODataResponse>();
       responses.add(handleODataRequest(request.getRequests().get(0), request));
       
-      return new ODataResponsePartImpl(responses, false);
+      return new ODataResponsePart(responses, false);
     }
   }
 
   private ODataResponsePart handleChangeSet(BatchRequestPart request) throws BatchException {
-    final List<ODataResponse> responses = new ArrayList<ODataResponse>();
     final BatchChangeSetSorter sorter = new BatchChangeSetSorter(request.getRequests());
-
-    responses.addAll(batchProcessor.executeChangeSet(batchOperation, sorter.getOrderdRequests(), request));
     
-    return new ODataResponsePartImpl(responses, true);
+    return batchProcessor.executeChangeSet(batchOperation, sorter.getOrderdRequests(), request);
   }
 
   private static class UriMapping {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java
deleted file mode 100644
index da52a37..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/ODataResponsePartImpl.java
+++ /dev/null
@@ -1,44 +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.server.core.batch.handler;
-
-import java.util.List;
-
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.batch.ODataResponsePart;
-
-public class ODataResponsePartImpl implements ODataResponsePart {
-  private List<ODataResponse> responses;
-  private boolean isChangeSet;
-  
-  public ODataResponsePartImpl(List<ODataResponse> responses, boolean isChangeSet) {
-    this.responses = responses;
-    this.isChangeSet = isChangeSet;
-  }
-
-  @Override
-  public List<ODataResponse> getResponses() {
-    return responses;
-  }
-
-  @Override
-  public boolean isChangeSet() {
-    return isChangeSet;
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
index 43a09b6..b87f8ef 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParserCommon.java
@@ -123,9 +123,6 @@ public class BatchParserCommon {
     // Remove preamble
     if (messageParts.size() > 0) {
       messageParts.remove(0);
-    } else {
-      throw new BatchException("Missing boundary delimiter", BatchException.MessageKeys.MISSING_BOUNDARY_DELIMITER, ""
-          + lineNumer);
     }
 
     if (!isEndReached) {
@@ -133,11 +130,6 @@ public class BatchParserCommon {
           "" + lineNumer);
     }
 
-    if (messageParts.size() == 0) {
-      throw new BatchException("No boundary delimiter found",
-          BatchException.MessageKeys.MISSING_BOUNDARY_DELIMITER, boundary, "" + lineNumer);
-    }
-
     return messageParts;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
index 812ea8b..0c13cb9 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriter.java
@@ -149,7 +149,7 @@ public class BatchResponseWriter {
     final Map<String, String> header = response.getHeaders();
 
     for (final String key : header.keySet()) {
-      // Requests do never have content id header
+      // Requests do never has a content id header
       if (!key.equalsIgnoreCase(BatchParserCommon.HTTP_CONTENT_ID)) {
         appendHeader(key, header.get(key), writer);
       }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/ODataResponsePartImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/ODataResponsePartImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/ODataResponsePartImpl.java
deleted file mode 100644
index a9711c9..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/writer/ODataResponsePartImpl.java
+++ /dev/null
@@ -1,44 +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.server.core.batch.writer;
-
-import java.util.List;
-
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.batch.ODataResponsePart;
-
-public class ODataResponsePartImpl implements ODataResponsePart {
-  private final List<ODataResponse> responses;
-  private final boolean isChangeSet;
-
-  public ODataResponsePartImpl(final List<ODataResponse> responses, final boolean isChangeSet) {
-    this.responses = responses;
-    this.isChangeSet = isChangeSet;
-  }
-
-  @Override
-  public List<ODataResponse> getResponses() {
-    return responses;
-  }
-
-  @Override
-  public boolean isChangeSet() {
-    return isChangeSet;
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
index c9778e3..88fdf08 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
@@ -274,7 +274,8 @@ public class BatchRequestParserTest {
         + GET_REQUEST
         + "--batch_8194-cf13-1f56--";
 
-    parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_BOUNDARY_DELIMITER);
+    final List<BatchRequestPart> parts = parse(batch);
+    assertEquals(0, parts.size());
   }
 
   @Test
@@ -450,14 +451,23 @@ public class BatchRequestParserTest {
         + "POST Employees('1')/EmployeeName HTTP/1.1" + CRLF
         + CRLF;
 
-    parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_BOUNDARY_DELIMITER);
+    parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_CLOSE_DELIMITER);
   }
-
+  
+  @Test
+  public void testEmptyRequest() throws BatchException, UnsupportedEncodingException {
+    final String batch = ""
+        + "--batch_8194-cf13-1f56--";
+    
+    final List<BatchRequestPart> parts = parse(batch);
+    assertEquals(0, parts.size());
+  }
+  
   @Test
   public void testBadRequest() throws UnsupportedEncodingException {
     final String batch = "This is a bad request. There is no syntax and also no semantic";
 
-    parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_BOUNDARY_DELIMITER);
+    parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_CLOSE_DELIMITER);
   }
 
   @Test
@@ -496,7 +506,7 @@ public class BatchRequestParserTest {
   }
 
   @Test
-  public void testInvalidChangeSetBoundary() throws UnsupportedEncodingException {
+  public void testInvalidChangeSetBoundary() throws UnsupportedEncodingException, BatchException {
     final String batch = "--batch_8194-cf13-1f56" + CRLF
         + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF
         + CRLF
@@ -511,7 +521,12 @@ public class BatchRequestParserTest {
         + CRLF
         + "--batch_8194-cf13-1f56--";
 
-    parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_BOUNDARY_DELIMITER);
+    final List<BatchRequestPart> parts = parse(batch);
+    assertEquals(1, parts.size());
+    
+    final BatchRequestPart part = parts.get(0);
+    assertTrue(part.isChangeSet());
+    assertEquals(0, part.getRequests().size());
   }
 
   @Test
@@ -1261,7 +1276,6 @@ public class BatchRequestParserTest {
     final List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
 
     assertNotNull(batchRequestParts);
-    assertFalse(batchRequestParts.isEmpty());
 
     return batchRequestParts;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
index e1864e2..7a85ffa 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
@@ -535,7 +535,7 @@ public class MockedBatchHandlerTest {
     public void init(OData odata, ServiceMetadata serviceMetadata) {}
 
     @Override
-    public List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
+    public ODataResponsePart executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
         BatchRequestPart requestPart) {
       List<ODataResponse> responses = new ArrayList<ODataResponse>();
 
@@ -557,7 +557,7 @@ public class MockedBatchHandlerTest {
         }
       }
 
-      return responses;
+      return new ODataResponsePart(responses, true);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4ff5fb9c/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
index b7169b9..ea05bfb 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/writer/BatchResponseWriterTest.java
@@ -50,14 +50,14 @@ public class BatchResponseWriterTest {
 
     List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
     responses.add(response);
-    parts.add(new ODataResponsePartImpl(responses, false));
+    parts.add(new ODataResponsePart(responses, false));
 
     ODataResponse changeSetResponse = new ODataResponse();
     changeSetResponse.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
     changeSetResponse.setHeader(BatchParserCommon.HTTP_CONTENT_ID, "1");
     responses = new ArrayList<ODataResponse>(1);
     responses.add(changeSetResponse);
-    parts.add(new ODataResponsePartImpl(responses, true));
+    parts.add(new ODataResponsePart(responses, true));
 
     BatchResponseWriter writer = new BatchResponseWriter();
     ODataResponse batchResponse = new ODataResponse();
@@ -109,7 +109,7 @@ public class BatchResponseWriterTest {
 
     List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
     responses.add(response);
-    parts.add(new ODataResponsePartImpl(responses, false));
+    parts.add(new ODataResponsePart(responses, false));
 
     ODataResponse batchResponse = new ODataResponse();
     new BatchResponseWriter().toODataResponse(parts, batchResponse);
@@ -144,7 +144,7 @@ public class BatchResponseWriterTest {
 
     List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
     responses.add(response);
-    parts.add(new ODataResponsePartImpl(responses, true));
+    parts.add(new ODataResponsePart(responses, true));
 
     BatchResponseWriter writer = new BatchResponseWriter();
     ODataResponse batchResponse = new ODataResponse();


[9/9] olingo-odata4 git commit: Api Refactoring

Posted by ch...@apache.org.
Api Refactoring

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


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

Branch: refs/heads/olingo472
Commit: ad177ac11e9cf43087167a9146fa0bcff0f6dc23
Parents: bc46b53
Author: Christian Holzer <c....@sap.com>
Authored: Tue Nov 11 16:50:03 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:11:02 2014 +0100

----------------------------------------------------------------------
 .../olingo/server/api/batch/BatchOperation.java |  3 +-
 .../server/api/processor/DefaultProcessor.java  |  2 +-
 .../core/batch/handler/BatchOperationImpl.java  |  9 ++-
 .../core/batch/handler/BatchPartHandler.java    | 59 ++++++++++----------
 .../server/core/batch/parser/BatchParser.java   | 23 ++++----
 .../core/batch/BatchRequestParserTest.java      | 53 +++++++++---------
 .../batch/handler/MockedBatchHandlerTest.java   |  2 +-
 7 files changed, 73 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
index 2d09a94..a9edef0 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
@@ -18,14 +18,13 @@
  */package org.apache.olingo.server.api.batch;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.List;
 
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 
 public interface BatchOperation {
-  public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException;
+  public List<BatchRequestPart> parseBatchRequest(ODataRequest request, boolean isStrict) throws BatchException;
 
   public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) throws BatchException;
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
index 25778e3..c4493a1 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
@@ -107,7 +107,7 @@ public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProce
     boolean continueOnError = shouldContinueOnError(request);
 
     try {
-      final List<BatchRequestPart> parts = operation.parseBatchRequest(request.getBody());
+      final List<BatchRequestPart> parts = operation.parseBatchRequest(request, true);
       final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
 
       for (BatchRequestPart part : parts) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
index cf7ad7c..b5a4eb4 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
@@ -19,7 +19,6 @@
 package org.apache.olingo.server.core.batch.handler;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.util.List;
 
 import org.apache.olingo.commons.api.http.HttpHeader;
@@ -43,13 +42,13 @@ public class BatchOperationImpl implements BatchOperation {
       final boolean isStrict) {
     partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this);
     writer = new BatchResponseWriter();
-    parser = new BatchParser(getContentType(request), request.getRawBaseUri(),
-        request.getRawServiceResolutionUri(), isStrict);
+    parser = new BatchParser();
   }
 
   @Override
-  public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException {
-    return parser.parseBatchRequest(in);
+  public List<BatchRequestPart> parseBatchRequest(ODataRequest request, boolean isStrict) throws BatchException {
+    return parser.parseBatchRequest(request.getBody(), getContentType(request), request.getRawBaseUri(),
+        request.getRawServiceResolutionUri(), isStrict);
   }
   
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
index 23ba106..2147a2e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.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
@@ -18,9 +18,7 @@
  */
 package org.apache.olingo.server.core.batch.handler;
 
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 import org.apache.olingo.commons.api.ODataRuntimeException;
@@ -43,7 +41,7 @@ public class BatchPartHandler {
   private BatchProcessor batchProcessor;
   private BatchOperation batchOperation;
   private Map<BatchRequestPart, UriMapping> uriMapping = new HashMap<BatchRequestPart, UriMapping>();
-  
+
   public BatchPartHandler(final ODataHandler oDataHandler, final BatchProcessor processor,
       final BatchOperation batchOperation) {
     this.oDataHandler = oDataHandler;
@@ -53,12 +51,12 @@ public class BatchPartHandler {
 
   public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) throws BatchException {
     final ODataResponse response;
-    
-    if(requestPart.isChangeSet()) {
+
+    if (requestPart.isChangeSet()) {
       final UriMapping mapping = replaceReference(request, requestPart);
 
       response = oDataHandler.process(request);
-      
+
       // Store resource URI
       final String resourceUri = getODataPath(request, response);
       final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
@@ -67,20 +65,20 @@ public class BatchPartHandler {
     } else {
       response = oDataHandler.process(request);
     }
-    
+
     // Add content id to response
     final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
-    if(contentId != null) {
+    if (contentId != null) {
       response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
     }
-    
-    return  response;
+
+    return response;
   }
 
   private String getODataPath(ODataRequest request, ODataResponse response) throws BatchException {
     String resourceUri = null;
-    
-    if(request.getMethod() == HttpMethod.POST) {
+
+    if (request.getMethod() == HttpMethod.POST) {
       // Create entity
       // The URI of the new resource will be generated by the server and published in the location header
       ODataURI uri = new ODataURI(response.getHeaders().get(HttpHeader.LOCATION), request.getRawBaseUri());
@@ -90,62 +88,61 @@ public class BatchPartHandler {
       // These methods still addresses a given resource, so we use the URI given by the request
       resourceUri = request.getRawODataPath();
     }
-    
+
     return resourceUri;
   }
 
   private UriMapping replaceReference(ODataRequest request, BatchRequestPart requestPart) {
     final UriMapping mapping = getUriMappingOrDefault(requestPart);
     final String reference = BatchChangeSetSorter.getReferenceInURI(request);
-    
-    if(reference != null) {
+
+    if (reference != null) {
       final String replacement = mapping.getUri(reference);
-      
-      if(replacement != null) {
+
+      if (replacement != null) {
         BatchChangeSetSorter.replaceContentIdReference(request, reference, replacement);
       } else {
         throw new ODataRuntimeException("Required Content-Id for reference \"" + reference + "\" not found.");
       }
     }
-    
+
     return mapping;
   }
-  
+
   private UriMapping getUriMappingOrDefault(final BatchRequestPart requestPart) {
     UriMapping mapping = uriMapping.get(requestPart);
-    
-    if(mapping == null) {
+
+    if (mapping == null) {
       mapping = new UriMapping();
     }
     uriMapping.put(requestPart, mapping);
-    
+
     return mapping;
   }
-  
+
   public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException {
     if (request.isChangeSet()) {
       return handleChangeSet(request);
     } else {
-      final List<ODataResponse> responses = new ArrayList<ODataResponse>();
-      responses.add(handleODataRequest(request.getRequests().get(0), request));
+      final ODataResponse response = handleODataRequest(request.getRequests().get(0), request);
       
-      return new ODataResponsePart(responses, false);
+      return new ODataResponsePart(response, false);
     }
   }
 
   private ODataResponsePart handleChangeSet(BatchRequestPart request) throws BatchException {
     final BatchChangeSetSorter sorter = new BatchChangeSetSorter(request.getRequests());
-    
+
     return batchProcessor.executeChangeSet(batchOperation, sorter.getOrderdRequests(), request);
   }
 
   private static class UriMapping {
     private Map<String, String> uriMapping = new HashMap<String, String>();
-    
+
     public void addMapping(final String contentId, final String uri) {
       uriMapping.put(contentId, uri);
     }
-    
+
     public String getUri(final String contentId) {
       return uriMapping.get(contentId);
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
index 75c0084..3a89440 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchParser.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
@@ -33,21 +33,18 @@ import org.apache.olingo.server.core.batch.transformator.BatchRequestTransformat
 
 public class BatchParser {
 
-  private final String contentTypeMime;
-  private final String baseUri;
-  private final String rawServiceResolutionUri;
-  private final boolean isStrict;
-  
-  public BatchParser(final String contentType, final String baseUri, final String serviceResolutionUri, 
-      final boolean isStrict) {
+  private String contentTypeMime;
+  private String rawServiceResolutionUri;
+  private boolean isStrict;
+
+  @SuppressWarnings("unchecked")
+  public List<BatchRequestPart> parseBatchRequest(final InputStream in, final String contentType, final String baseUri,
+      final String serviceResolutionUri, final boolean isStrict) throws BatchException {
+    
     contentTypeMime = contentType;
-    this.baseUri = BatchParserCommon.removeEndingSlash(baseUri);
     this.isStrict = isStrict;
     this.rawServiceResolutionUri = serviceResolutionUri;
-  }
 
-  @SuppressWarnings("unchecked")
-  public List<BatchRequestPart> parseBatchRequest(final InputStream in) throws BatchException {
     return (List<BatchRequestPart>) parse(in, new BatchRequestTransformator(baseUri, rawServiceResolutionUri));
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
index 88fdf08..cc249be 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/BatchRequestParserTest.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
@@ -196,8 +196,9 @@ public class BatchRequestParserTest {
         + "--batch_1.2+34:2j)0?" + CRLF
         + GET_REQUEST
         + "--batch_1.2+34:2j)0?--";
-    final BatchParser parser = new BatchParser(contentType, SERVICE_ROOT, "", true);
-    final List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(StringUtil.toInputStream(batch));
+    final BatchParser parser = new BatchParser();
+    final List<BatchRequestPart> batchRequestParts =
+        parser.parseBatchRequest(StringUtil.toInputStream(batch), contentType, SERVICE_ROOT, "", true);
 
     assertNotNull(batchRequestParts);
     assertFalse(batchRequestParts.isEmpty());
@@ -210,10 +211,10 @@ public class BatchRequestParserTest {
         + "--batch_1740-bb84-2f7f" + CRLF
         + GET_REQUEST
         + "--batch_1740-bb84-2f7f--";
-    final BatchParser parser = new BatchParser(invalidContentType, SERVICE_ROOT, "", true);
+    final BatchParser parser = new BatchParser();
 
     try {
-      parser.parseBatchRequest(StringUtil.toInputStream(batch));
+      parser.parseBatchRequest(StringUtil.toInputStream(batch), invalidContentType, SERVICE_ROOT, "", true);
       fail();
     } catch (BatchException e) {
       assertMessageKey(e, BatchException.MessageKeys.INVALID_CONTENT_TYPE);
@@ -224,15 +225,16 @@ public class BatchRequestParserTest {
   public void testContentTypeCharset() throws BatchException {
     final String contentType = "multipart/mixed; charset=UTF-8;boundary=batch_14d1-b293-b99a";
     final String batch = ""
-                    + "--batch_14d1-b293-b99a" + CRLF
-                    + GET_REQUEST
-                    + "--batch_14d1-b293-b99a--";
-    final BatchParser parser = new BatchParser(contentType, SERVICE_ROOT, "", true);
-    final List<BatchRequestPart> parts = parser.parseBatchRequest(StringUtil.toInputStream(batch));
-    
+        + "--batch_14d1-b293-b99a" + CRLF
+        + GET_REQUEST
+        + "--batch_14d1-b293-b99a--";
+    final BatchParser parser = new BatchParser();
+    final List<BatchRequestPart> parts =
+        parser.parseBatchRequest(StringUtil.toInputStream(batch), contentType, SERVICE_ROOT, "", true);
+
     assertEquals(1, parts.size());
   }
-  
+
   @Test
   public void testBatchWithoutBoundaryParameter() throws UnsupportedEncodingException {
     final String invalidContentType = "multipart/mixed";
@@ -240,10 +242,10 @@ public class BatchRequestParserTest {
         + "--batch_1740-bb84-2f7f" + CRLF
         + GET_REQUEST
         + "--batch_1740-bb84-2f7f--";
-    final BatchParser parser = new BatchParser(invalidContentType, SERVICE_ROOT, "", true);
+    final BatchParser parser = new BatchParser();
 
     try {
-      parser.parseBatchRequest(StringUtil.toInputStream(batch));
+      parser.parseBatchRequest(StringUtil.toInputStream(batch), invalidContentType, SERVICE_ROOT, "", true);
       fail();
     } catch (BatchException e) {
       assertMessageKey(e, BatchException.MessageKeys.INVALID_CONTENT_TYPE);
@@ -257,10 +259,10 @@ public class BatchRequestParserTest {
         + "--batch_1740-bb:84-2f7f" + CRLF
         + GET_REQUEST
         + "--batch_1740-bb:84-2f7f--";
-    final BatchParser parser = new BatchParser(invalidContentType, SERVICE_ROOT, "", true);
+    final BatchParser parser = new BatchParser();
 
     try {
-      parser.parseBatchRequest(StringUtil.toInputStream(batch));
+      parser.parseBatchRequest(StringUtil.toInputStream(batch), invalidContentType, SERVICE_ROOT, "", true);
       fail();
     } catch (BatchException e) {
       assertMessageKey(e, BatchException.MessageKeys.INVALID_BOUNDARY);
@@ -453,16 +455,16 @@ public class BatchRequestParserTest {
 
     parseInvalidBatchBody(batch, BatchException.MessageKeys.MISSING_CLOSE_DELIMITER);
   }
-  
+
   @Test
   public void testEmptyRequest() throws BatchException, UnsupportedEncodingException {
     final String batch = ""
         + "--batch_8194-cf13-1f56--";
-    
+
     final List<BatchRequestPart> parts = parse(batch);
     assertEquals(0, parts.size());
   }
-  
+
   @Test
   public void testBadRequest() throws UnsupportedEncodingException {
     final String batch = "This is a bad request. There is no syntax and also no semantic";
@@ -523,7 +525,7 @@ public class BatchRequestParserTest {
 
     final List<BatchRequestPart> parts = parse(batch);
     assertEquals(1, parts.size());
-    
+
     final BatchRequestPart part = parts.get(0);
     assertTrue(part.isChangeSet());
     assertEquals(0, part.getRequests().size());
@@ -1272,8 +1274,9 @@ public class BatchRequestParserTest {
   }
 
   private List<BatchRequestPart> parse(final InputStream in, final boolean isStrict) throws BatchException {
-    final BatchParser parser = new BatchParser(CONTENT_TYPE, SERVICE_ROOT, "", isStrict);
-    final List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in);
+    final BatchParser parser = new BatchParser();
+    final List<BatchRequestPart> batchRequestParts =
+        parser.parseBatchRequest(in, CONTENT_TYPE, SERVICE_ROOT, "", isStrict);
 
     assertNotNull(batchRequestParts);
 
@@ -1295,10 +1298,10 @@ public class BatchRequestParserTest {
 
   private void parseInvalidBatchBody(final String batch, final MessageKeys key, final boolean isStrict)
       throws UnsupportedEncodingException {
-    final BatchParser parser = new BatchParser(CONTENT_TYPE, SERVICE_ROOT, "", isStrict);
+    final BatchParser parser = new BatchParser();
 
     try {
-      parser.parseBatchRequest(StringUtil.toInputStream(batch));
+      parser.parseBatchRequest(StringUtil.toInputStream(batch), CONTENT_TYPE, SERVICE_ROOT, "", isStrict);
       fail("No exception thrown. Expect: " + key.toString());
     } catch (BatchException e) {
       assertMessageKey(e, key);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ad177ac1/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
index b81edb8..c68919c 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
@@ -593,7 +593,7 @@ public class MockedBatchHandlerTest {
     @Override
     public void executeBatch(BatchOperation operation, ODataRequest request, ODataResponse response) {
       try {
-        final List<BatchRequestPart> parts = operation.parseBatchRequest(request.getBody());
+        final List<BatchRequestPart> parts = operation.parseBatchRequest(request, true);
         final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
 
         for (BatchRequestPart part : parts) {


[3/9] olingo-odata4 git commit: MockedBatchHandler Test

Posted by ch...@apache.org.
MockedBatchHandler Test

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


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

Branch: refs/heads/olingo472
Commit: 0bd32951b8ebcfce895fa5d5eb8fd76954d6bfd3
Parents: ee2451c
Author: Christian Holzer <c....@sap.com>
Authored: Mon Nov 3 17:16:47 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:10:56 2014 +0100

----------------------------------------------------------------------
 .../olingo/server/api/batch/BatchOperation.java |   2 +-
 .../server/api/processor/BatchProcessor.java    |   2 +-
 .../batch/handler/BatchChangeSetSorter.java     |  41 +-
 .../core/batch/handler/BatchOperationImpl.java  |   2 +-
 .../core/batch/handler/BatchPartHandler.java    |  56 +-
 .../BatchRequestTransformator.java              |  17 +-
 .../transformator/BatchTransformatorCommon.java | 159 -----
 .../transformator/HttpRequestStatusLine.java    | 229 ++++++++
 .../batch/handler/BatchChangeSetSorterTest.java |   4 +-
 .../batch/handler/MockedBatchHandlerTest.java   | 582 +++++++++++++++++++
 10 files changed, 894 insertions(+), 200 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
index af7d9c1..2d09a94 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
@@ -27,7 +27,7 @@ import org.apache.olingo.server.api.ODataResponse;
 public interface BatchOperation {
   public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException;
 
-  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart);
+  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) throws BatchException;
 
   public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException;
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
index 221b38a..a0a7135 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
@@ -26,7 +26,7 @@ import org.apache.olingo.server.api.batch.BatchOperation;
 import org.apache.olingo.server.api.batch.BatchRequestPart;
 
 public interface BatchProcessor extends Processor {
-  void executeBatch(BatchOperation operation, ODataRequest requests, ODataResponse response);
+  void executeBatch(BatchOperation operation, ODataRequest request, ODataResponse response);
 
   List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
       BatchRequestPart requestPart);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
index c348512..f8ac653 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
@@ -39,7 +39,7 @@ public class BatchChangeSetSorter {
 
   private static Pattern referencePattern = Pattern.compile(REG_EX_REFERENCE);
   private Set<String> knownContentId = new HashSet<String>();
-  private Map<String, List<ODataRequest>> requestContentIdMapping = new HashMap<String, List<ODataRequest>>();
+  private Map<String, List<ODataRequest>> requestReferenceMapping = new HashMap<String, List<ODataRequest>>();
 
   public BatchChangeSetSorter(List<ODataRequest> requests) throws BatchException {
     sort(requests);
@@ -50,9 +50,12 @@ public class BatchChangeSetSorter {
   }
 
   private List<ODataRequest> sort(final List<ODataRequest> requests) throws BatchException {
-    extractUrlContentId(requests);
-    orderdList.addAll(getRequestsWithoutReferences());
-
+    extractUrlReference(requests);
+    
+    final List<ODataRequest> requestsWithoutReferences = getRequestsWithoutReferences();
+    orderdList.addAll(requestsWithoutReferences);
+    addRequestsToKnownContentIds(requestsWithoutReferences);
+    
     boolean areRequestsProcessed = true;
     while (requestsToProcessAvailable() && areRequestsProcessed) {
       areRequestsProcessed = processRemainingRequests(orderdList);
@@ -66,7 +69,7 @@ public class BatchChangeSetSorter {
   }
 
   private boolean requestsToProcessAvailable() {
-    return requestContentIdMapping.keySet().size() != 0;
+    return requestReferenceMapping.keySet().size() != 0;
   }
 
   private boolean processRemainingRequests(List<ODataRequest> orderdList) {
@@ -81,10 +84,10 @@ public class BatchChangeSetSorter {
     List<ODataRequest> result = new ArrayList<ODataRequest>();
 
     for (String contextId : knownContentId) {
-      List<ODataRequest> processedRequests = requestContentIdMapping.get(contextId);
+      List<ODataRequest> processedRequests = requestReferenceMapping.get(contextId);
       if (processedRequests != null && processedRequests.size() != 0) {
         result.addAll(processedRequests);
-        requestContentIdMapping.remove(contextId);
+        requestReferenceMapping.remove(contextId);
       }
     }
 
@@ -92,10 +95,9 @@ public class BatchChangeSetSorter {
   }
 
   private List<ODataRequest> getRequestsWithoutReferences() {
-    final List<ODataRequest> requestsWithoutReference = requestContentIdMapping.get(null);
-    requestContentIdMapping.remove(null);
+    final List<ODataRequest> requestsWithoutReference = requestReferenceMapping.get(null);
+    requestReferenceMapping.remove(null);
 
-    addRequestsToKnownContentIds(requestsWithoutReference);
     return requestsWithoutReference;
   }
 
@@ -112,33 +114,38 @@ public class BatchChangeSetSorter {
     return request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
   }
 
-  private void extractUrlContentId(List<ODataRequest> requests) {
+  private void extractUrlReference(List<ODataRequest> requests) {
     for (ODataRequest request : requests) {
       final String reference = getReferenceInURI(request);
-      addRequestToMapping(reference, request);
+      addRequestToReferenceMapping(reference, request);
     }
   }
 
-  private void addRequestToMapping(final String reference, final ODataRequest request) {
-    List<ODataRequest> requestList = requestContentIdMapping.get(reference);
+  private void addRequestToReferenceMapping(final String reference, final ODataRequest request) {
+    List<ODataRequest> requestList = requestReferenceMapping.get(reference);
     requestList = (requestList == null) ? new ArrayList<ODataRequest>() : requestList;
 
     requestList.add(request);
-    requestContentIdMapping.put(reference, requestList);
+    requestReferenceMapping.put(reference, requestList);
   }
 
   public static String getReferenceInURI(ODataRequest request) {
-    Matcher matcher = referencePattern.matcher(removeFollingPathSegments(request.getRawODataPath()));
+    Matcher matcher = referencePattern.matcher(removeFollingPathSegments(removeFirstSplash(request.getRawODataPath())));
     return (matcher.matches()) ? matcher.group(1) : null;
   }
 
+  private static String removeFirstSplash(String rawODataPath) {
+    final int indexOfSlash = rawODataPath.indexOf("/");
+    return (indexOfSlash == 0) ? rawODataPath.substring(1) : rawODataPath;
+  }
+
   private static String removeFollingPathSegments(String rawODataPath) {
     final int indexOfSlash = rawODataPath.indexOf("/");
     return (indexOfSlash != -1) ? rawODataPath.substring(0, indexOfSlash) : rawODataPath;
   }
 
   public static void replaceContentIdReference(ODataRequest request, String contentId, String resourceUri) {
-    final String newUri = request.getRawODataPath().replace("$" + contentId, resourceUri);
+    final String newUri = request.getRawODataPath().replace("/$" + contentId, resourceUri);
     request.setRawODataPath(newUri);
     request.setRawRequestUri(request.getRawBaseUri() + "/" + newUri);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
index 1f5e243..cf7ad7c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
@@ -53,7 +53,7 @@ public class BatchOperationImpl implements BatchOperation {
   }
   
   @Override
-  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) {
+  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) throws BatchException {
     return partHandler.handleODataRequest(request, requestPart);
   }
   

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
index df23c55..c678355 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
@@ -23,7 +23,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.olingo.commons.api.ODataRuntimeException;
 import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.batch.BatchException;
@@ -33,6 +35,7 @@ import org.apache.olingo.server.api.batch.ODataResponsePart;
 import org.apache.olingo.server.api.processor.BatchProcessor;
 import org.apache.olingo.server.core.ODataHandler;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
+import org.apache.olingo.server.core.batch.transformator.HttpRequestStatusLine.ODataURI;
 
 public class BatchPartHandler {
 
@@ -48,21 +51,18 @@ public class BatchPartHandler {
     this.batchOperation = batchOperation;
   }
 
-  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) {
+  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) throws BatchException {
     final ODataResponse response;
     
     if(requestPart.isChangeSet()) {
-      final UriMapping mapping = getUriMappingOrDefault(requestPart);
-      final String reference = BatchChangeSetSorter.getReferenceInURI(request);
-      if(reference != null) {
-        BatchChangeSetSorter.replaceContentIdReference(request, reference, mapping.getUri(reference));
-      }
-      
-       response = oDataHandler.process(request);
+      final UriMapping mapping = replaceReference(request, requestPart);
+
+      response = oDataHandler.process(request);
        
+      final String resourceUri = getODataPath(request, response);
       final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
-      final String locationHeader = request.getHeader(HttpHeader.LOCATION);
-      mapping.addMapping(contentId, locationHeader);
+
+      mapping.addMapping(contentId, resourceUri);
     } else {
       response = oDataHandler.process(request);
     }
@@ -74,11 +74,45 @@ public class BatchPartHandler {
     
     return  response;
   }
+
+  private String getODataPath(ODataRequest request, ODataResponse response) throws BatchException {
+    String resourceUri = null;
+    
+    if(request.getMethod() == HttpMethod.POST) {
+      // Create entity
+      // The URI of the new resource will be generated by the server and published in the location header
+      ODataURI uri = new ODataURI(response.getHeaders().get(HttpHeader.LOCATION), request.getRawBaseUri());
+      resourceUri = uri.getRawODataPath();
+    } else {
+      // Update, Upsert (PUT, PATCH, Delete)
+      // These methods still addresses a given URI, so we use the URI given by the request
+      resourceUri = request.getRawODataPath();
+    }
+    
+    return resourceUri;
+  }
+
+  private UriMapping replaceReference(ODataRequest request, BatchRequestPart requestPart) {
+    final UriMapping mapping = getUriMappingOrDefault(requestPart);
+    final String reference = BatchChangeSetSorter.getReferenceInURI(request);
+    
+    if(reference != null) {
+      final String replacement = mapping.getUri(reference);
+      
+      if(replacement != null) {
+        BatchChangeSetSorter.replaceContentIdReference(request, reference, replacement);
+      } else {
+        throw new ODataRuntimeException("Required Content-Id for reference \"" + reference + "\" not found.");
+      }
+    }
+    
+    return mapping;
+  }
   
   private UriMapping getUriMappingOrDefault(final BatchRequestPart requestPart) {
     UriMapping mapping = uriMapping.get(requestPart);
     
-    if(uriMapping == null) {
+    if(mapping == null) {
       mapping = new UriMapping();
     }
     uriMapping.put(requestPart, mapping);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
index 94d5226..0bf0104 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchRequestTransformator.java
@@ -38,7 +38,7 @@ import org.apache.olingo.server.core.batch.parser.BatchQueryOperation;
 import org.apache.olingo.server.core.batch.parser.BatchRequestPartImpl;
 import org.apache.olingo.server.core.batch.parser.Header;
 import org.apache.olingo.server.core.batch.parser.HeaderField;
-import org.apache.olingo.server.core.batch.transformator.BatchTransformatorCommon.HttpRequestStatusLine;
+import org.apache.olingo.server.core.batch.transformator.HttpRequestStatusLine.ODataURI;
 
 public class BatchRequestTransformator implements BatchTransformator {
   private final String baseUri;
@@ -111,20 +111,21 @@ public class BatchRequestTransformator implements BatchTransformator {
         new HttpRequestStatusLine(operation.getHttpStatusLine(), baseUri, rawServiceResolutionUri, operation
             .getHeaders());
     statusLine.validateHttpMethod(isChangeSet);
-
+    final ODataURI uri = statusLine.getUri();
+    
     validateBody(statusLine, operation);
     InputStream bodyStrean = getBodyStream(operation, statusLine);
 
     validateForbiddenHeader(operation);
-
+    
     final ODataRequest request = new ODataRequest();
     request.setBody(bodyStrean);
     request.setMethod(statusLine.getMethod());
-    request.setRawBaseUri(statusLine.getRawBaseUri());
-    request.setRawODataPath(statusLine.getRawODataPath());
-    request.setRawQueryPath(statusLine.getRawQueryPath());
-    request.setRawRequestUri(statusLine.getRawRequestUri());
-    request.setRawServiceResolutionUri(statusLine.getRawServiceResolutionUri());
+    request.setRawBaseUri(uri.getRawBaseUri());
+    request.setRawODataPath(uri.getRawODataPath());
+    request.setRawQueryPath(uri.getRawQueryPath());
+    request.setRawRequestUri(uri.getRawRequestUri());
+    request.setRawServiceResolutionUri(uri.getRawServiceResolutionUri());
 
     for (final HeaderField field : operation.getHeaders()) {
       request.addHeader(field.getFieldName(), field.getValues());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
index c9da563..fc2035a 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/BatchTransformatorCommon.java
@@ -18,20 +18,14 @@
  */
 package org.apache.olingo.server.core.batch.transformator;
 
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.olingo.commons.api.http.HttpContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
 import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
-import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
 import org.apache.olingo.server.core.batch.parser.Header;
 import org.apache.olingo.server.core.batch.parser.HeaderField;
 
@@ -94,157 +88,4 @@ public class BatchTransformatorCommon {
 
     return -1;
   }
-
-  public static class HttpRequestStatusLine {
-    private static final Pattern PATTERN_RELATIVE_URI = Pattern.compile("([^/][^?]*)(?:\\?(.*))?");
-    private static final Pattern PATTERN_ABSOLUTE_URI_WITH_HOST = Pattern.compile("(/[^?]*)(?:\\?(.*))?");
-    private static final Pattern PATTERN_ABSOLUTE_URI = Pattern.compile("(http[s]?://[^?]*)(?:\\?(.*))?");
-
-    private static final Set<String> HTTP_BATCH_METHODS = new HashSet<String>(Arrays.asList(new String[] { "GET" }));
-    private static final Set<String> HTTP_CHANGE_SET_METHODS = new HashSet<String>(Arrays.asList(new String[] { "POST",
-        "PUT", "DELETE", "MERGE", "PATCH" }));
-    private static final String HTTP_VERSION = "HTTP/1.1";
-
-    final private Line statusLine;
-    final String requestBaseUri;
-
-    private HttpMethod method;
-    private String httpVersion;
-    private String rawServiceResolutionUri;
-    private String rawQueryPath;
-    private String rawODataPath;
-    private String rawBaseUri;
-    private Header header;
-    private String rawRequestUri;
-
-    public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final String serviceResolutionUri,
-        final Header requestHeader)
-        throws BatchException {
-      statusLine = httpStatusLine;
-      requestBaseUri = baseUri;
-      header = requestHeader;
-      rawServiceResolutionUri = serviceResolutionUri;
-      
-      parse();
-    }
-
-    private void parse() throws BatchException {
-      final String[] parts = statusLine.toString().split(" ");
-
-      if (parts.length == 3) {
-        method = parseMethod(parts[0]);
-        parseRawPaths(parts[1]);
-        httpVersion = parseHttpVersion(parts[2]);
-      } else {
-        throw new BatchException("Invalid status line", MessageKeys.INVALID_STATUS_LINE, statusLine.getLineNumber());
-      }
-    }
-
-    private HttpMethod parseMethod(final String method) throws BatchException {
-      try {
-        return HttpMethod.valueOf(method.trim());
-      } catch (IllegalArgumentException e) {
-        throw new BatchException("Illegal http method", MessageKeys.INVALID_METHOD, statusLine.getLineNumber());
-      }
-    }
-
-    private void parseRawPaths(final String rawUrl) throws BatchException {
-      final Matcher absoluteUriMatcher = PATTERN_ABSOLUTE_URI.matcher(rawUrl);
-      final Matcher absoluteUriWtithHostMatcher = PATTERN_ABSOLUTE_URI_WITH_HOST.matcher(rawUrl);
-      final Matcher relativeUriMatcher = PATTERN_RELATIVE_URI.matcher(rawUrl);
-
-      if (absoluteUriMatcher.matches()) {
-        buildUri(absoluteUriMatcher.group(1), absoluteUriMatcher.group(2));
-
-      } else if (absoluteUriWtithHostMatcher.matches()) {
-        final List<String> hostHeader = header.getHeaders(HttpHeader.HOST);
-        if (hostHeader.size() == 1) {
-          buildUri(hostHeader.get(0) + absoluteUriWtithHostMatcher.group(1), absoluteUriWtithHostMatcher.group(2));
-        } else {
-          throw new BatchException("Exactly one host header is required", MessageKeys.MISSING_MANDATORY_HEADER,
-              statusLine.getLineNumber());
-        }
-
-      } else if (relativeUriMatcher.matches()) {
-        buildUri(requestBaseUri + "/" + relativeUriMatcher.group(1), relativeUriMatcher.group(2));
-
-      } else {
-        throw new BatchException("Invalid uri", MessageKeys.INVALID_URI, statusLine.getLineNumber());
-      }
-    }
-
-    private void buildUri(final String resourceUri, final String queryOptions) throws BatchException {
-      if(!resourceUri.startsWith(requestBaseUri)) {
-        throw new BatchException("Host do not match", MessageKeys.INVALID_URI, statusLine.getLineNumber());
-      }
-      
-      final int oDataPathIndex = resourceUri.indexOf(requestBaseUri);
-
-      rawBaseUri = requestBaseUri;
-      rawODataPath = resourceUri.substring(oDataPathIndex + requestBaseUri.length());
-      rawServiceResolutionUri = "";
-      rawRequestUri = requestBaseUri + rawODataPath;
-
-      if (queryOptions != null) {
-        rawRequestUri += "?" + queryOptions;
-        rawQueryPath = queryOptions;
-      } else {
-        rawQueryPath = "";
-      }
-    }
-
-    private String parseHttpVersion(final String httpVersion) throws BatchException {
-      if (!HTTP_VERSION.equals(httpVersion.trim())) {
-        throw new BatchException("Invalid http version", MessageKeys.INVALID_HTTP_VERSION, statusLine.getLineNumber());
-      } else {
-        return HTTP_VERSION;
-      }
-    }
-
-    public void validateHttpMethod(boolean isChangeSet) throws BatchException {
-      Set<String> validMethods = (isChangeSet) ? HTTP_CHANGE_SET_METHODS : HTTP_BATCH_METHODS;
-
-      if (!validMethods.contains(getMethod().toString())) {
-        if (isChangeSet) {
-          throw new BatchException("Invalid change set method", MessageKeys.INVALID_CHANGESET_METHOD, statusLine
-              .getLineNumber());
-        } else {
-          throw new BatchException("Invalid query operation method", MessageKeys.INVALID_QUERY_OPERATION_METHOD,
-              statusLine.getLineNumber());
-        }
-      }
-    }
-
-    public HttpMethod getMethod() {
-      return method;
-    }
-
-    public String getHttpVersion() {
-      return httpVersion;
-    }
-
-    public int getLineNumber() {
-      return statusLine.getLineNumber();
-    }
-
-    public String getRawBaseUri() {
-      return rawBaseUri;
-    }
-
-    public String getRawODataPath() {
-      return rawODataPath;
-    }
-
-    public String getRawQueryPath() {
-      return rawQueryPath;
-    }
-
-    public String getRawRequestUri() {
-      return rawRequestUri;
-    }
-
-    public String getRawServiceResolutionUri() {
-      return rawServiceResolutionUri;
-    }
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
new file mode 100644
index 0000000..416d593
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
@@ -0,0 +1,229 @@
+/*
+ * 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.server.core.batch.transformator;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchException.MessageKeys;
+import org.apache.olingo.server.core.batch.parser.Header;
+import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings.Line;
+
+public class HttpRequestStatusLine {
+  private static final Pattern PATTERN_RELATIVE_URI = Pattern.compile("([^/][^?]*)(?:\\?(.*))?");
+  private static final Pattern PATTERN_ABSOLUTE_URI_WITH_HOST = Pattern.compile("(/[^?]*)(?:\\?(.*))?");
+  private static final Pattern PATTERN_ABSOLUTE_URI = Pattern.compile("(http[s]?://[^?]*)(?:\\?(.*))?");
+
+  private static final Set<String> HTTP_BATCH_METHODS = new HashSet<String>(Arrays.asList(new String[] { "GET" }));
+  private static final Set<String> HTTP_CHANGE_SET_METHODS = new HashSet<String>(Arrays.asList(new String[] { "POST",
+      "PUT", "DELETE", "MERGE", "PATCH" }));
+  // TODO Is Merge still supported?
+  // What`s New in OData 4: 2.7.2 Pruned: MERGE
+  // MERGE was used to do PATCH before PATCH existed. Now that we have PATCH, we no longer need MERGE. => No
+  private static final String HTTP_VERSION = "HTTP/1.1";
+
+  final private Line statusLine;
+  final String requestBaseUri;
+
+  private HttpMethod method;
+  private String httpVersion;
+  private Header header;
+  private ODataURI uri;
+
+  public HttpRequestStatusLine(final Line httpStatusLine, final String baseUri, final String serviceResolutionUri,
+      final Header requestHeader)
+      throws BatchException {
+    statusLine = httpStatusLine;
+    requestBaseUri = baseUri;
+    header = requestHeader;
+
+    parse();
+  }
+
+  private void parse() throws BatchException {
+    final String[] parts = statusLine.toString().split(" ");
+
+    if (parts.length == 3) {
+      method = parseMethod(parts[0]);
+      uri = new ODataURI(parts[1], requestBaseUri, statusLine.getLineNumber(), header.getHeaders(HttpHeader.HOST));
+      httpVersion = parseHttpVersion(parts[2]);
+    } else {
+      throw new BatchException("Invalid status line", MessageKeys.INVALID_STATUS_LINE, statusLine.getLineNumber());
+    }
+  }
+
+  private HttpMethod parseMethod(final String method) throws BatchException {
+    try {
+      return HttpMethod.valueOf(method.trim());
+    } catch (IllegalArgumentException e) {
+      throw new BatchException("Illegal http method", MessageKeys.INVALID_METHOD, statusLine.getLineNumber());
+    }
+  }
+
+  private String parseHttpVersion(final String httpVersion) throws BatchException {
+    if (!HTTP_VERSION.equals(httpVersion.trim())) {
+      throw new BatchException("Invalid http version", MessageKeys.INVALID_HTTP_VERSION, statusLine.getLineNumber());
+    } else {
+      return HTTP_VERSION;
+    }
+  }
+
+  public void validateHttpMethod(boolean isChangeSet) throws BatchException {
+    Set<String> validMethods = (isChangeSet) ? HTTP_CHANGE_SET_METHODS : HTTP_BATCH_METHODS;
+
+    if (!validMethods.contains(getMethod().toString())) {
+      if (isChangeSet) {
+        throw new BatchException("Invalid change set method", MessageKeys.INVALID_CHANGESET_METHOD, statusLine
+            .getLineNumber());
+      } else {
+        throw new BatchException("Invalid query operation method", MessageKeys.INVALID_QUERY_OPERATION_METHOD,
+            statusLine.getLineNumber());
+      }
+    }
+  }
+
+  public HttpMethod getMethod() {
+    return method;
+  }
+
+  public String getHttpVersion() {
+    return httpVersion;
+  }
+
+  public int getLineNumber() {
+    return statusLine.getLineNumber();
+  }
+
+  public ODataURI getUri() {
+    return uri;
+  }
+
+  public static class ODataURI {
+    private String rawServiceResolutionUri;
+    private String rawQueryPath;
+    private String rawODataPath;
+    private String rawBaseUri;
+    private String rawRequestUri;
+    private final String requestBaseUri;
+    private final int lineNumber;
+
+    public ODataURI(final String rawUri, String requestBaseUri) throws BatchException {
+      this(rawUri, requestBaseUri, 0, new ArrayList<String>());
+    }
+
+    public ODataURI(final String rawUri, String requestBaseUri, int lineNumber, List<String> hostHeader)
+        throws BatchException {
+      this.lineNumber = lineNumber;
+      this.requestBaseUri = requestBaseUri;
+
+      final Matcher absoluteUriMatcher = PATTERN_ABSOLUTE_URI.matcher(rawUri);
+      final Matcher absoluteUriWtithHostMatcher = PATTERN_ABSOLUTE_URI_WITH_HOST.matcher(rawUri);
+      final Matcher relativeUriMatcher = PATTERN_RELATIVE_URI.matcher(rawUri);
+
+      if (absoluteUriMatcher.matches()) {
+        buildUri(absoluteUriMatcher.group(1), absoluteUriMatcher.group(2));
+
+      } else if (absoluteUriWtithHostMatcher.matches()) {
+        if (hostHeader != null && hostHeader.size() == 1) {
+          buildUri(hostHeader.get(0) + absoluteUriWtithHostMatcher.group(1), absoluteUriWtithHostMatcher.group(2));
+        } else {
+          throw new BatchException("Exactly one host header is required", MessageKeys.MISSING_MANDATORY_HEADER,
+              lineNumber);
+        }
+
+      } else if (relativeUriMatcher.matches()) {
+        buildUri(requestBaseUri + "/" + relativeUriMatcher.group(1), relativeUriMatcher.group(2));
+
+      } else {
+        throw new BatchException("Invalid uri", MessageKeys.INVALID_URI, lineNumber);
+      }
+    }
+
+    private void buildUri(final String resourceUri, final String queryOptions) throws BatchException {
+      if (!resourceUri.startsWith(requestBaseUri)) {
+        throw new BatchException("Host do not match", MessageKeys.INVALID_URI, lineNumber);
+      }
+
+      final int oDataPathIndex = resourceUri.indexOf(requestBaseUri);
+
+      rawBaseUri = requestBaseUri;
+      rawODataPath = resourceUri.substring(oDataPathIndex + requestBaseUri.length());
+      rawRequestUri = requestBaseUri + rawODataPath;
+
+      if (queryOptions != null) {
+        rawRequestUri += "?" + queryOptions;
+        rawQueryPath = queryOptions;
+      } else {
+        rawQueryPath = "";
+      }
+    }
+
+    public String getRawServiceResolutionUri() {
+      return rawServiceResolutionUri;
+    }
+
+    public void setRawServiceResolutionUri(String rawServiceResolutionUri) {
+      this.rawServiceResolutionUri = rawServiceResolutionUri;
+    }
+
+    public String getRawQueryPath() {
+      return rawQueryPath;
+    }
+
+    public void setRawQueryPath(String rawQueryPath) {
+      this.rawQueryPath = rawQueryPath;
+    }
+
+    public String getRawODataPath() {
+      return rawODataPath;
+    }
+
+    public void setRawODataPath(String rawODataPath) {
+      this.rawODataPath = rawODataPath;
+    }
+
+    public String getRawBaseUri() {
+      return rawBaseUri;
+    }
+
+    public void setRawBaseUri(String rawBaseUri) {
+      this.rawBaseUri = rawBaseUri;
+    }
+
+    public String getRawRequestUri() {
+      return rawRequestUri;
+    }
+
+    public void setRawRequestUri(String rawRequestUri) {
+      this.rawRequestUri = rawRequestUri;
+    }
+
+    public String getRequestBaseUri() {
+      return requestBaseUri;
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
index 9196514..c8b725a 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
@@ -39,7 +39,7 @@ public class BatchChangeSetSorterTest {
   public void test() throws BatchException {
     final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
     changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Adress", "2"));
-    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "/Employees", "1"));
     
    BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
    final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
@@ -110,7 +110,7 @@ public class BatchChangeSetSorterTest {
   @Test
   public void testRewriting() {
     final String CONTENT_ID = "1";
-    final String ODATA_PATH ="$" + CONTENT_ID + "/Address";
+    final String ODATA_PATH ="/$" + CONTENT_ID + "/Address";
     final String RESOURCE_URI = "Employee('1')";
     final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
     

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/0bd32951/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
new file mode 100644
index 0000000..ac111e0
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
@@ -0,0 +1,582 @@
+/*
+ * 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.server.core.batch.handler;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchRequestPart;
+import org.apache.olingo.server.api.batch.ODataResponsePart;
+import org.apache.olingo.server.api.processor.BatchProcessor;
+import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
+import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class MockedBatchHandlerTest {
+
+  private static final String BATCH_CONTENT_TYPE = "multipart/mixed;boundary=batch_12345";
+  private static final String BATCH_ODATA_PATH = "/$batch";
+  private static final String BATCH_REQUEST_URI = "http://localhost:8080/odata/$batch";
+  private static final String BASE_URI = "http://localhost:8080/odata";
+  private static final String CRLF = "\r\n";
+  private ODataHandler handler;
+  private int entityCounter = 1;
+
+  @Test
+  public void test() throws BatchException, IOException {
+    final String content = "--batch_12345" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_12345" + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 4" + CRLF
+        + CRLF
+        + "PUT /$3/PropertyInt32 HTTP/1.1" + CRLF // Absolute URI with separate Host header and ref.
+        + "Host: http://localhost:8080/odata" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 5" + CRLF
+        + CRLF
+        + "POST http://localhost:8080/odata/$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF // Absolute URI with ref.
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 2" + CRLF
+        + CRLF
+        + "POST $1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF // Relative URI with ref.
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 1" + CRLF
+        + CRLF
+        + "POST http://localhost:8080/odata/ESAllPrim HTTP/1.1" + CRLF // Absolute URI
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 3" + CRLF
+        + CRLF
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF // Relative URI
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 6" + CRLF
+        + CRLF
+        + "PUT /ESAllPrim(1) HTTP/1.1" + CRLF // Absolute URI with separate Host header
+        + "Host: http://localhost:8080/odata"
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345--" + CRLF
+        + CRLF
+        + "--batch_12345--";
+    final Map<String, List<String>> header = getMimeHeader();
+    final ODataResponse response = new ODataResponse();
+    final BatchHandler batchHandler = buildBatchHandler(content, header);
+
+    batchHandler.process(response);
+
+    BufferedReaderIncludingLineEndings reader =
+        new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
+
+    final List<String> responseContent = reader.toList();
+    reader.close();
+
+    int line = 0;
+    assertEquals(63, responseContent.size());
+
+    // Check change set
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertTrue(responseContent.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_"));
+
+    for (int i = 0; i < 6; i++) {
+      String contentId = checkChangeSetPartHeader(responseContent, line);
+      line += 6;
+
+      if ("1".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESAllPrim(1)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("2".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESTwoPrim(3)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("3".equals(contentId)) {
+        assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("4".equals(contentId)) {
+        assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("5".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESTwoPrim(2)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("6".equals(contentId)) {
+        assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else {
+        fail();
+      }
+
+      assertEquals(CRLF, responseContent.get(line++));
+    }
+
+    // Close body part (change set)
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--changeset_"));
+
+    // Close batch
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertEquals(63, line);
+  }
+
+  @Test
+  public void testMultipleChangeSets() throws BatchException, IOException {
+    final String content = ""
+        + "--batch_12345" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_12345" + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 2" + CRLF
+        + CRLF
+        + "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+        + "Host: http://localhost:8080/odata" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 1" + CRLF
+        + CRLF
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345--" + CRLF
+
+        + "--batch_12345" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_54321" + CRLF
+        + CRLF
+        + "--changeset_54321" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 2" + CRLF
+        + CRLF
+        + "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+        + "Host: http://localhost:8080/odata" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_54321" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 1" + CRLF
+        + CRLF
+        + "PUT ESAllPrim(2) HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_54321--" + CRLF
+
+        + CRLF
+        + "--batch_12345--";
+    final Map<String, List<String>> header = getMimeHeader();
+    final ODataResponse response = new ODataResponse();
+    final BatchHandler batchHandler = buildBatchHandler(content, header);
+
+    batchHandler.process(response);
+
+    BufferedReaderIncludingLineEndings reader =
+        new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
+
+    final List<String> responseContent = reader.toList();
+    reader.close();
+
+    int line = 0;
+    assertEquals(49, responseContent.size());
+
+    // Check first change set
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertTrue(responseContent.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_"));
+
+    for (int i = 0; i < 2; i++) {
+      String contentId = checkChangeSetPartHeader(responseContent, line);
+      line += 6;
+
+      if ("1".equals(contentId)) {
+        assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("2".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESTwoPrim(1)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else {
+        fail();
+      }
+
+      assertEquals(CRLF, responseContent.get(line++));
+    }
+    // Close body part (1st change set)
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--changeset_"));
+
+    // Check second change set
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertTrue(responseContent.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_"));
+
+    for (int i = 0; i < 2; i++) {
+      String contentId = checkChangeSetPartHeader(responseContent, line);
+      line += 6;
+
+      if ("1".equals(contentId)) {
+        assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("2".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESTwoPrim(2)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else {
+        fail();
+      }
+
+      assertEquals(CRLF, responseContent.get(line++));
+    }
+    // Close body part (2nd change set)
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--changeset_"));
+
+    // Close batch
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+
+    assertEquals(49, line);
+  }
+
+  @Test
+  public void testMineBodyPartTransitiv() throws BatchException, IOException {
+    final String content = ""
+        + "--batch_12345" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_12345" + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 4" + CRLF
+        + CRLF
+        + "POST $3/NavPropertyETTwoPrimOne HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 2" + CRLF
+        + CRLF
+        + "POST /$1/NavPropertyETTwoPrimMany HTTP/1.1" + CRLF
+        + "Host: http://localhost:8080/odata" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 1" + CRLF
+        + CRLF
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 3" + CRLF
+        + CRLF
+        + "POST $2/NavPropertyETAllPrimMany HTTP/1.1" + CRLF
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345--" + CRLF
+
+        + CRLF
+        + "--batch_12345--";
+
+    final Map<String, List<String>> header = getMimeHeader();
+    final ODataResponse response = new ODataResponse();
+    final BatchHandler batchHandler = buildBatchHandler(content, header);
+
+    batchHandler.process(response);
+
+    BufferedReaderIncludingLineEndings reader =
+        new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
+
+    final List<String> responseContent = reader.toList();
+    reader.close();
+
+    int line = 0;
+    assertEquals(45, responseContent.size());
+
+    // Check change set
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertTrue(responseContent.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_"));
+
+    for (int i = 0; i < 4; i++) {
+      String contentId = checkChangeSetPartHeader(responseContent, line);
+      line += 6;
+
+      if ("1".equals(contentId)) {
+        assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("2".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESTwoPrim(1)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("3".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESAllPrim(2)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else if ("4".equals(contentId)) {
+        assertEquals("HTTP/1.1 201 Created" + CRLF, responseContent.get(line++));
+        assertEquals("Location: " + BASE_URI + "/ESTwoPrim(3)" + CRLF, responseContent.get(line++));
+        assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+      } else {
+        fail();
+      }
+
+      assertEquals(CRLF, responseContent.get(line++));
+    }
+
+    // Close body part (change set)
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--changeset_"));
+
+    // Close batch
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertEquals(45, line);
+  }
+
+  @Before
+  public void setup() {
+    handler = null;
+    entityCounter = 1;
+  }
+
+  private String checkChangeSetPartHeader(final List<String> response, int line) {
+    assertEquals(CRLF, response.get(line++));
+    assertTrue(response.get(line++).contains("--changeset_"));
+    assertEquals("Content-Type: application/http" + CRLF, response.get(line++));
+    assertEquals("Content-Transfer-Encoding: binary" + CRLF, response.get(line++));
+
+    assertTrue(response.get(line).contains("Content-Id:"));
+    String contentId = response.get(line).split(":")[1].trim();
+    line++;
+
+    assertEquals(CRLF, response.get(line++));
+
+    return contentId;
+  }
+
+  /*
+   * Helper methods
+   */
+
+  private Map<String, List<String>> getMimeHeader() {
+    final Map<String, List<String>> header = new HashMap<String, List<String>>();
+    header.put(HttpHeader.CONTENT_TYPE, Arrays.asList(new String[] { BATCH_CONTENT_TYPE }));
+
+    return header;
+  }
+
+  private BatchHandler buildBatchHandler(final String content, Map<String, List<String>> header) throws BatchException,
+      UnsupportedEncodingException {
+
+    final ODataRequest request = buildODataRequest(content, header);
+    final ODataHandler oDataHandler = buildODataHandler(request);
+    final BatchProcessor batchProcessor = new BatchProcessorImpl();
+
+    return new BatchHandler(oDataHandler, request, batchProcessor, true);
+  }
+
+  private ODataHandler buildODataHandler(ODataRequest request) {
+    handler = mock(ODataHandler.class);
+    when(handler.process(request)).thenCallRealMethod();
+
+    return handler;
+  }
+
+  private ODataRequest buildODataRequest(String content, Map<String, List<String>> header)
+      throws UnsupportedEncodingException {
+    final ODataRequest request = new ODataRequest();
+
+    for (final String key : header.keySet()) {
+      request.addHeader(key, header.get(key));
+    }
+
+    request.setMethod(HttpMethod.POST);
+    request.setRawBaseUri(BASE_URI);
+    request.setRawODataPath(BATCH_ODATA_PATH);
+    request.setRawQueryPath("");
+    request.setRawRequestUri(BATCH_REQUEST_URI);
+    request.setRawServiceResolutionUri("");
+
+    request.setBody(new ByteArrayInputStream(content.getBytes("UTF-8")));
+
+    return request;
+  }
+
+  /**
+   * Batch processor
+   */
+  private class BatchProcessorImpl implements BatchProcessor {
+    @Override
+    public void init(OData odata, ServiceMetadata serviceMetadata) {}
+
+    @Override
+    public List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
+        BatchRequestPart requestPart) {
+      List<ODataResponse> responses = new ArrayList<ODataResponse>();
+
+      for (ODataRequest request : requests) {
+        // Mock the processor of the changeset requests
+        when(handler.process(request)).then(new Answer<ODataResponse>() {
+          @Override
+          public ODataResponse answer(InvocationOnMock invocation) throws Throwable {
+            Object[] arguments = invocation.getArguments();
+
+            return buildResponse((ODataRequest) arguments[0]);
+          }
+        });
+
+        try {
+          responses.add(operation.handleODataRequest(request, requestPart));
+        } catch (BatchException e) {
+          fail();
+        }
+      }
+
+      return responses;
+    }
+
+    @Override
+    public void executeBatch(BatchOperation operation, ODataRequest request, ODataResponse response) {
+      try {
+        final List<BatchRequestPart> parts = operation.parseBatchRequest(request.getBody());
+        final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
+
+        for (BatchRequestPart part : parts) {
+          responseParts.add(operation.handleBatchRequest(part));
+        }
+
+        operation.writeResponseParts(responseParts, response);
+      } catch (BatchException e) {
+        throw new ODataRuntimeException(e);
+      } catch (IOException e) {
+        throw new ODataRuntimeException(e);
+      }
+    }
+  }
+
+  private ODataResponse buildResponse(ODataRequest request) {
+    final ODataResponse oDataResponse = new ODataResponse();
+
+    if (request.getMethod() == HttpMethod.POST) {
+      oDataResponse.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+      oDataResponse.setHeader(HttpHeader.LOCATION, createResourceUri(request));
+    } else {
+      oDataResponse.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    }
+
+    final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
+    if (contentId != null) {
+      oDataResponse.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
+    }
+
+    return oDataResponse;
+  }
+
+  private String createResourceUri(final ODataRequest request) {
+    final String parts[] = request.getRawODataPath().split("/");
+    String oDataPath = "";
+
+    if (parts.length == 2) {
+      // Entity Collection
+      oDataPath = parts[1];
+    } else {
+      // Navigationproperty
+
+      final String navProperty = parts[parts.length - 1];
+      if (navProperty.equals("NavPropertyETTwoPrimMany")) {
+        oDataPath = "ESTwoPrim";
+      } else if (navProperty.equals("NavPropertyETAllPrimMany")) {
+        oDataPath = "ESAllPrim";
+      } else if (navProperty.equals("NavPropertyETTwoPrimOne")) {
+        oDataPath = "ESTwoPrim";
+      }
+    }
+
+    return BASE_URI + "/" + oDataPath + "(" + entityCounter++ + ")";
+  }
+}


[2/9] olingo-odata4 git commit: Changeset Sorter

Posted by ch...@apache.org.
Changeset Sorter

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


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

Branch: refs/heads/olingo472
Commit: ee2451cbd064e3a5b4585f37192c983f32fe5c55
Parents: 15bd152
Author: Christian Holzer <c....@sap.com>
Authored: Tue Oct 28 18:18:21 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:10:55 2014 +0100

----------------------------------------------------------------------
 .../olingo/server/api/batch/BatchOperation.java |   4 +-
 .../server/api/processor/BatchProcessor.java    |  10 +-
 .../olingo/server/core/batch/StringUtil.java    |  54 ------
 .../core/batch/handler/BatchOperationImpl.java  |  16 +-
 .../core/batch/handler/BatchPartHandler.java    |  65 ++++++--
 .../server/core/batch/handler/UriMapping.java   |  34 ++++
 .../core/batch/parser/BatchRequestPartImpl.java |   4 +
 .../olingo/server/core/batch/StringUtil.java    |  54 ++++++
 .../batch/handler/BatchChangeSetSorterTest.java | 164 +++++++++++++++++++
 .../tecsvc/processor/TechnicalProcessor.java    |  44 +----
 10 files changed, 333 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
index 8e438cf..af7d9c1 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/batch/BatchOperation.java
@@ -27,9 +27,9 @@ import org.apache.olingo.server.api.ODataResponse;
 public interface BatchOperation {
   public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException;
 
-  public ODataResponse handleODataRequest(ODataRequest request);
+  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart);
 
-  public ODataResponsePart handleBatchRequest(BatchRequestPart request);
+  public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException;
 
   public void writeResponseParts(List<ODataResponsePart> batchResponses, ODataResponse response) throws BatchException,
       IOException;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
index 5a9518d..221b38a 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/BatchProcessor.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
@@ -23,9 +23,11 @@ import java.util.List;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.batch.BatchOperation;
+import org.apache.olingo.server.api.batch.BatchRequestPart;
 
 public interface BatchProcessor extends Processor {
-  void executeBatch(BatchOperation operation, ODataRequest requst, ODataResponse response);
+  void executeBatch(BatchOperation operation, ODataRequest requests, ODataResponse response);
 
-  List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests);
+  List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
+      BatchRequestPart requestPart);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/StringUtil.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/StringUtil.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/StringUtil.java
deleted file mode 100644
index 2602852..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/StringUtil.java
+++ /dev/null
@@ -1,54 +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.server.core.batch;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-
-import org.apache.olingo.commons.api.ODataRuntimeException;
-import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings;
-
-public class StringUtil {
-  
-  
-  public static String toString(final InputStream in) throws IOException {
-    final StringBuilder builder = new StringBuilder();
-    final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(new InputStreamReader(in));
-    String currentLine;
-    
-    while((currentLine = reader.readLine()) != null) {
-      builder.append(currentLine);
-    }
-    
-    reader.close();
-    
-    return builder.toString();
-  }
-
-  public static InputStream toInputStream(final String string) {
-    try {
-      return new ByteArrayInputStream(string.getBytes("UTF-8"));
-    } catch (UnsupportedEncodingException e) {
-      throw new ODataRuntimeException("Charset UTF-8 not found");
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
index bc148f0..1f5e243 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchOperationImpl.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
@@ -44,21 +44,21 @@ public class BatchOperationImpl implements BatchOperation {
     partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this);
     writer = new BatchResponseWriter();
     parser = new BatchParser(getContentType(request), request.getRawBaseUri(),
-                              request.getRawServiceResolutionUri(), isStrict);
+        request.getRawServiceResolutionUri(), isStrict);
   }
 
   @Override
   public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException {
     return parser.parseBatchRequest(in);
   }
-
+  
   @Override
-  public ODataResponse handleODataRequest(ODataRequest request) {
-    return partHandler.handleODataRequest(request);
+  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) {
+    return partHandler.handleODataRequest(request, requestPart);
   }
-
+  
   @Override
-  public ODataResponsePart handleBatchRequest(BatchRequestPart request) {
+  public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException {
     return partHandler.handleBatchRequest(request);
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
index a78d585..df23c55 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchPartHandler.java
@@ -19,11 +19,14 @@
 package org.apache.olingo.server.core.batch.handler;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.batch.BatchException;
 import org.apache.olingo.server.api.batch.BatchOperation;
 import org.apache.olingo.server.api.batch.BatchRequestPart;
 import org.apache.olingo.server.api.batch.ODataResponsePart;
@@ -36,7 +39,8 @@ public class BatchPartHandler {
   private ODataHandler oDataHandler;
   private BatchProcessor batchProcessor;
   private BatchOperation batchOperation;
-
+  private Map<BatchRequestPart, UriMapping> uriMapping = new HashMap<BatchRequestPart, UriMapping>();
+  
   public BatchPartHandler(final ODataHandler oDataHandler, final BatchProcessor processor,
       final BatchOperation batchOperation) {
     this.oDataHandler = oDataHandler;
@@ -44,23 +48,62 @@ public class BatchPartHandler {
     this.batchOperation = batchOperation;
   }
 
-  public ODataResponse handleODataRequest(ODataRequest request) {
-    final ODataResponse response = oDataHandler.process(request);
-    response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, request.getHeader(BatchParserCommon.HTTP_CONTENT_ID));
+  public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) {
+    final ODataResponse response;
+    
+    if(requestPart.isChangeSet()) {
+      final UriMapping mapping = getUriMappingOrDefault(requestPart);
+      final String reference = BatchChangeSetSorter.getReferenceInURI(request);
+      if(reference != null) {
+        BatchChangeSetSorter.replaceContentIdReference(request, reference, mapping.getUri(reference));
+      }
+      
+       response = oDataHandler.process(request);
+       
+      final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
+      final String locationHeader = request.getHeader(HttpHeader.LOCATION);
+      mapping.addMapping(contentId, locationHeader);
+    } else {
+      response = oDataHandler.process(request);
+    }
+    
+    final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
+    if(contentId != null) {
+      response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
+    }
     
     return  response;
   }
-
-  public ODataResponsePart handleBatchRequest(BatchRequestPart request) {
-    final List<ODataResponse> responses = new ArrayList<ODataResponse>();
-
+  
+  private UriMapping getUriMappingOrDefault(final BatchRequestPart requestPart) {
+    UriMapping mapping = uriMapping.get(requestPart);
+    
+    if(uriMapping == null) {
+      mapping = new UriMapping();
+    }
+    uriMapping.put(requestPart, mapping);
+    
+    return mapping;
+  }
+  
+  public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException {
     if (request.isChangeSet()) {
-      responses.addAll(batchProcessor.executeChangeSet(batchOperation, request.getRequests()));
-      return new ODataResponsePartImpl(responses, true);
+      return handleChangeSet(request);
     } else {
-      responses.add(handleODataRequest(request.getRequests().get(0)));
+      final List<ODataResponse> responses = new ArrayList<ODataResponse>();
+      responses.add(handleODataRequest(request.getRequests().get(0), request));
+      
       return new ODataResponsePartImpl(responses, false);
     }
   }
 
+  private ODataResponsePart handleChangeSet(BatchRequestPart request) throws BatchException {
+    final List<ODataResponse> responses = new ArrayList<ODataResponse>();
+    final BatchChangeSetSorter sorter = new BatchChangeSetSorter(request.getRequests());
+
+    responses.addAll(batchProcessor.executeChangeSet(batchOperation, sorter.getOrderdRequests(), request));
+    
+    return new ODataResponsePartImpl(responses, true);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java
new file mode 100644
index 0000000..0123320
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/UriMapping.java
@@ -0,0 +1,34 @@
+/*
+ * 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.server.core.batch.handler;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class UriMapping {
+  private Map<String, String> uriMapping = new HashMap<String, String>();
+  
+  public void addMapping(final String contentId, final String uri) {
+    uriMapping.put(contentId, uri);
+  }
+  
+  public String getUri(final String contentId) {
+    return uriMapping.get(contentId);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchRequestPartImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchRequestPartImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchRequestPartImpl.java
index 6c80216..9765b37 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchRequestPartImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/parser/BatchRequestPartImpl.java
@@ -25,6 +25,10 @@ import java.util.List;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.batch.BatchRequestPart;
 
+/**
+ * Has to be immutable!
+ *
+ */
 public class BatchRequestPartImpl implements BatchRequestPart {
 
   private List<ODataRequest> requests = new ArrayList<ODataRequest>();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/StringUtil.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/StringUtil.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/StringUtil.java
new file mode 100644
index 0000000..2602852
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/StringUtil.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server.core.batch;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.server.core.batch.parser.BufferedReaderIncludingLineEndings;
+
+public class StringUtil {
+  
+  
+  public static String toString(final InputStream in) throws IOException {
+    final StringBuilder builder = new StringBuilder();
+    final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(new InputStreamReader(in));
+    String currentLine;
+    
+    while((currentLine = reader.readLine()) != null) {
+      builder.append(currentLine);
+    }
+    
+    reader.close();
+    
+    return builder.toString();
+  }
+
+  public static InputStream toInputStream(final String string) {
+    try {
+      return new ByteArrayInputStream(string.getBytes("UTF-8"));
+    } catch (UnsupportedEncodingException e) {
+      throw new ODataRuntimeException("Charset UTF-8 not found");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
new file mode 100644
index 0000000..9196514
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorterTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.server.core.batch.handler;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.batch.BatchException;
+import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
+import org.junit.Test;
+
+public class BatchChangeSetSorterTest {
+
+  private static final String BASE_URI = "http://localhost/odata.src";
+  
+  @Test
+  public void test() throws BatchException {
+    final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Adress", "2"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
+    
+   BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
+   final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
+   
+   assertEquals(2, sortedChangeSet.size());
+   assertEquals("1", getContentId(sortedChangeSet.get(0)));
+   assertEquals("2", getContentId(sortedChangeSet.get(1)));
+  }
+  
+  private String getContentId(ODataRequest request) {
+    return request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
+  }
+  
+  @Test
+  public void testNoContentId() throws BatchException {
+    final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Department", "2"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('2')/Address"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('3')/Address"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$2/Manager", "3"));
+    
+    BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
+   final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
+   
+   assertEquals(5, sortedChangeSet.size());
+   assertEquals("1", getContentId(sortedChangeSet.get(0)));
+   assertEquals(null, getContentId(sortedChangeSet.get(1)));
+   assertEquals(null, getContentId(sortedChangeSet.get(2)));
+   assertEquals("2", getContentId(sortedChangeSet.get(3)));
+   assertEquals("3", getContentId(sortedChangeSet.get(4)));
+  }
+  
+  @SuppressWarnings("unused")
+  @Test(expected=BatchException.class)
+  public void testContentIdNotAvailable() throws BatchException {
+    final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Department", "2"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('2')/Address"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('3')/Address"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$4/Manager", "3")); //4 is not available
+    
+   BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
+   final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
+  }
+  
+  @Test
+  public void testStringAsContentId() throws BatchException {
+    final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$One/Department", "Two"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "One"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('2')/Address"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('3')/Address"));
+    changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$Two/Manager", "Three"));
+    
+   BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
+   final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
+   
+   assertEquals(5, sortedChangeSet.size());
+   assertEquals("One", getContentId(sortedChangeSet.get(0)));
+   assertEquals(null, getContentId(sortedChangeSet.get(1)));
+   assertEquals(null, getContentId(sortedChangeSet.get(2)));
+   assertEquals("Two", getContentId(sortedChangeSet.get(3)));
+   assertEquals("Three", getContentId(sortedChangeSet.get(4)));
+  }
+  
+  @Test
+  public void testRewriting() {
+    final String CONTENT_ID = "1";
+    final String ODATA_PATH ="$" + CONTENT_ID + "/Address";
+    final String RESOURCE_URI = "Employee('1')";
+    final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
+    
+    BatchChangeSetSorter.replaceContentIdReference(request, CONTENT_ID, RESOURCE_URI);
+    assertEquals(BASE_URI + "/" + "Employee('1')/Address", request.getRawRequestUri());
+    assertEquals("Employee('1')/Address", request.getRawODataPath());
+  }
+  
+  @Test
+  public void testRewritingNoContentId() {
+    final String CONTENT_ID = "1";
+    final String ODATA_PATH = /* "$" + CONTENT_ID + */ "Address";
+    final String RESOURCE_URI = "Employee('1')";
+    final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
+    
+    BatchChangeSetSorter.replaceContentIdReference(request, CONTENT_ID, RESOURCE_URI);
+    assertEquals(BASE_URI + "/" + "Address", request.getRawRequestUri());
+    assertEquals("Address", request.getRawODataPath());
+  }
+  
+  @Test
+  public void testWrongRewriting() {
+    final String CONTENT_ID = "1";
+    final String ODATA_PATH = /*"$1" */ "$2" + "/Address";
+    final String RESOURCE_URI = "Employee('1')";
+    final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
+    
+    BatchChangeSetSorter.replaceContentIdReference(request, CONTENT_ID, RESOURCE_URI);
+    assertEquals(BASE_URI + "/" + "$2/Address", request.getRawRequestUri());
+    assertEquals("$2/Address", request.getRawODataPath());
+  }
+  
+  private ODataRequest createRequest(HttpMethod method, String baseUrl, String oDataPath) {
+    return createRequest(method, baseUrl, oDataPath, null);
+  }
+  
+  private ODataRequest createRequest(HttpMethod method, String baseUrl, String oDataPath, String contentId) {
+    final ODataRequest request = new ODataRequest();
+    request.setBody(new ByteArrayInputStream(new byte[0]));
+    request.setMethod(HttpMethod.GET);
+    request.setRawBaseUri(baseUrl);
+    request.setRawODataPath(oDataPath);
+    request.setRawRequestUri(baseUrl + "/" + oDataPath);
+    request.setRawQueryPath("");
+    
+    if(contentId != null) {
+      request.addHeader(BatchParserCommon.HTTP_CONTENT_ID, Arrays.asList(new String[] { contentId }));
+    }
+    return request;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ee2451cb/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index b59c92e..e5a0d44 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -21,7 +21,6 @@ package org.apache.olingo.server.tecsvc.processor;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
@@ -74,7 +73,7 @@ import org.apache.olingo.server.tecsvc.data.DataProvider;
 /**
  * Technical Processor which provides currently implemented processor functionality.
  */
-public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, PropertyProcessor, BatchProcessor {
+public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, PropertyProcessor {
 
   private OData odata;
   private DataProvider dataProvider;
@@ -198,12 +197,12 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
     List<UriResource> subResPaths = resourcePaths.subList(1, resourcePaths.size());
     for (UriResource subResPath : subResPaths) {
       UriResourceKind kind = subResPath.getKind();
-      if(kind != UriResourceKind.primitiveProperty
-              && kind != UriResourceKind.complexProperty
-              && kind != UriResourceKind.count
-              && kind != UriResourceKind.value) {
+      if (kind != UriResourceKind.primitiveProperty
+          && kind != UriResourceKind.complexProperty
+          && kind != UriResourceKind.count
+          && kind != UriResourceKind.value) {
         throw new ODataApplicationException("Invalid resource type.",
-                HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+            HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
       }
     }
 
@@ -219,6 +218,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
       final EdmEntitySet entitySet, final boolean isSingleEntity,
       final ExpandOption expand, final SelectOption select,
       final List<UriParameter> keys, final String propertyPath) throws SerializerException {
+
     return ContextURL.with().entitySet(entitySet)
         .selectList(serializer.buildContextURLSelectList(entitySet, expand, select))
         .suffix(isSingleEntity && propertyPath == null ? Suffix.ENTITY : null)
@@ -226,7 +226,6 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
         .navOrPropertyPath(propertyPath)
         .build();
   }
-
   @Override
   public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, SerializerException {
@@ -334,33 +333,4 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
       }
     }
   }
-
-  @Override
-  public void executeBatch(BatchOperation operation, ODataRequest requst, ODataResponse response) {
-    try {
-      final List<BatchRequestPart> parts = operation.parseBatchRequest(requst.getBody());
-      final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
-      
-      for(BatchRequestPart part : parts) {
-        responseParts.add(operation.handleBatchRequest(part));
-      }
-      
-      operation.writeResponseParts(responseParts, response);
-    } catch (BatchException e) {
-      throw new ODataRuntimeException(e);
-    } catch (IOException e) {
-      throw new ODataRuntimeException(e);
-    }
-  }
-
-  @Override
-  public List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests) {
-    List<ODataResponse> responses = new ArrayList<ODataResponse>();
-    
-    for(ODataRequest request : requests) {
-      responses.add(operation.handleODataRequest(request));
-    }
-    
-    return responses;
-  }
 }


[8/9] olingo-odata4 git commit: Test added to MockedBatchHandlerTest

Posted by ch...@apache.org.
Test added to MockedBatchHandlerTest

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


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

Branch: refs/heads/olingo472
Commit: bc46b5352e9cb9dae3e46478dab34287e2ea62bc
Parents: 4ff5fb9
Author: Christian Holzer <c....@sap.com>
Authored: Tue Nov 11 16:17:51 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:11:01 2014 +0100

----------------------------------------------------------------------
 .../batch/handler/MockedBatchHandlerTest.java   | 84 +++++++++++++++-----
 1 file changed, 63 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bc46b535/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
index 7a85ffa..b81edb8 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
@@ -200,6 +200,46 @@ public class MockedBatchHandlerTest {
   }
 
   @Test
+  public void testGetRequest() throws BatchException, IOException {
+    final String content = ""
+        + "--batch_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + CRLF
+        + "GET ESAllPrim(0) HTTP/1.1" + CRLF
+        + CRLF
+        + CRLF
+        + "--batch_12345--";
+
+    final Map<String, List<String>> header = getMimeHeader();
+    final ODataResponse response = new ODataResponse();
+    final ODataRequest request = buildODataRequest(content, header);
+
+    batchHandler.process(request, response, true);
+
+    BufferedReaderIncludingLineEndings reader =
+        new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
+
+    final List<String> responseContent = reader.toList();
+    int line = 0;
+
+    assertEquals(9, responseContent.size());
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+    assertEquals("Content-Type: application/http" + CRLF, responseContent.get(line++));
+    assertEquals("Content-Transfer-Encoding: binary" + CRLF, responseContent.get(line++));
+    assertEquals(CRLF, responseContent.get(line++));
+    assertEquals("HTTP/1.1 200 OK" + CRLF, responseContent.get(line++));
+    assertEquals("Content-Length: 0" + CRLF, responseContent.get(line++));
+    assertEquals(CRLF, responseContent.get(line++));
+    assertEquals(CRLF, responseContent.get(line++));
+    assertTrue(responseContent.get(line++).contains("--batch_"));
+
+    assertEquals(9, line);
+
+    reader.close();
+  }
+
+  @Test
   public void testMultipleChangeSets() throws BatchException, IOException {
     final String content = ""
         + "--batch_12345" + CRLF
@@ -442,8 +482,8 @@ public class MockedBatchHandlerTest {
 
     return contentId;
   }
-  
-  @Test(expected=BatchException.class)
+
+  @Test(expected = BatchException.class)
   public void testInvalidMethod() throws UnsupportedEncodingException, BatchException {
     final String content = ""
         + "--batch_12345" + CRLF
@@ -454,23 +494,23 @@ public class MockedBatchHandlerTest {
         + "Content-Transfer-Encoding: binary" + CRLF
         + "Content-Id: 1" + CRLF
         + CRLF
-        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF 
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF
         + "Content-Type: application/json;odata=verbose" + CRLF
         + CRLF
         + CRLF
         + "--changeset_12345--" + CRLF
         + CRLF
         + "--batch_12345--";
-    
+
     final Map<String, List<String>> header = getMimeHeader();
     final ODataResponse response = new ODataResponse();
     final ODataRequest request = buildODataRequest(content, header);
     request.setMethod(HttpMethod.GET);
-    
+
     batchHandler.process(request, response, true);
   }
-  
-  @Test(expected=BatchException.class)
+
+  @Test(expected = BatchException.class)
   public void testInvalidContentType() throws UnsupportedEncodingException, BatchException {
     final String content = ""
         + "--batch_12345" + CRLF
@@ -481,22 +521,22 @@ public class MockedBatchHandlerTest {
         + "Content-Transfer-Encoding: binary" + CRLF
         + "Content-Id: 1" + CRLF
         + CRLF
-        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF 
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF
         + "Content-Type: application/json;odata=verbose" + CRLF
         + CRLF
         + CRLF
         + "--changeset_12345--" + CRLF
         + CRLF
         + "--batch_12345--";
-    
+
     final Map<String, List<String>> header = new HashMap<String, List<String>>();
     header.put(HttpHeader.CONTENT_TYPE, Arrays.asList(new String[] { "application/http" }));
     final ODataResponse response = new ODataResponse();
     final ODataRequest request = buildODataRequest(content, header);
-    
+
     batchHandler.process(request, response, true);
   }
-  
+
   /*
    * Helper methods
    */
@@ -540,16 +580,6 @@ public class MockedBatchHandlerTest {
       List<ODataResponse> responses = new ArrayList<ODataResponse>();
 
       for (ODataRequest request : requests) {
-        // Mock the processor for a given requests
-        when(oDataHandler.process(request)).then(new Answer<ODataResponse>() {
-          @Override
-          public ODataResponse answer(InvocationOnMock invocation) throws Throwable {
-            Object[] arguments = invocation.getArguments();
-
-            return buildResponse((ODataRequest) arguments[0]);
-          }
-        });
-
         try {
           responses.add(operation.handleODataRequest(request, requestPart));
         } catch (BatchException e) {
@@ -567,6 +597,18 @@ public class MockedBatchHandlerTest {
         final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
 
         for (BatchRequestPart part : parts) {
+          for (final ODataRequest oDataRequest : part.getRequests()) {
+            // Mock the processor for a given requests
+            when(oDataHandler.process(oDataRequest)).then(new Answer<ODataResponse>() {
+              @Override
+              public ODataResponse answer(InvocationOnMock invocation) throws Throwable {
+                Object[] arguments = invocation.getArguments();
+
+                return buildResponse((ODataRequest) arguments[0]);
+              }
+            });
+          }
+
           responseParts.add(operation.handleBatchRequest(part));
         }
 


[6/9] olingo-odata4 git commit: Merge method removed

Posted by ch...@apache.org.
Merge method removed

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


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

Branch: refs/heads/olingo472
Commit: 5f4eb03df3e980dd2c4593ddb900e15290ac057d
Parents: bb4b554
Author: Christian Holzer <c....@sap.com>
Authored: Thu Nov 6 17:48:33 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:10:59 2014 +0100

----------------------------------------------------------------------
 .../server/core/batch/transformator/HttpRequestStatusLine.java  | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5f4eb03d/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
index 416d593..c08bb2e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/transformator/HttpRequestStatusLine.java
@@ -40,10 +40,7 @@ public class HttpRequestStatusLine {
 
   private static final Set<String> HTTP_BATCH_METHODS = new HashSet<String>(Arrays.asList(new String[] { "GET" }));
   private static final Set<String> HTTP_CHANGE_SET_METHODS = new HashSet<String>(Arrays.asList(new String[] { "POST",
-      "PUT", "DELETE", "MERGE", "PATCH" }));
-  // TODO Is Merge still supported?
-  // What`s New in OData 4: 2.7.2 Pruned: MERGE
-  // MERGE was used to do PATCH before PATCH existed. Now that we have PATCH, we no longer need MERGE. => No
+      "PUT", "DELETE", "PATCH" }));
   private static final String HTTP_VERSION = "HTTP/1.1";
 
   final private Line statusLine;


[5/9] olingo-odata4 git commit: Tests added

Posted by ch...@apache.org.
Tests added

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


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

Branch: refs/heads/olingo472
Commit: bb4b554116382e61519c6f7e98010aaff31eb441
Parents: 6c7d11f
Author: Christian Holzer <c....@sap.com>
Authored: Wed Nov 5 16:18:40 2014 +0100
Committer: Christian Amend <ch...@apache.org>
Committed: Thu Nov 13 17:10:58 2014 +0100

----------------------------------------------------------------------
 .../batch/handler/BatchChangeSetSorter.java     |  7 +--
 .../batch/handler/MockedBatchHandlerTest.java   | 56 +++++++++++++++++++-
 2 files changed, 59 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bb4b5541/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
index 408159e..5e1c276 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batch/handler/BatchChangeSetSorter.java
@@ -99,10 +99,11 @@ public class BatchChangeSetSorter {
   }
 
   private List<ODataRequest> getRequestsWithoutReferences() {
-    final List<ODataRequest> requestsWithoutReference = requestReferenceMapping.get(null);
+    List<ODataRequest> requests = requestReferenceMapping.get(null);
     requestReferenceMapping.remove(null);
-
-    return requestsWithoutReference;
+    
+    requests = (requests == null) ? new ArrayList<ODataRequest>() : requests;
+    return requests;
   }
 
   private void addRequestsToKnownContentIds(List<ODataRequest> requestsWithoutReference) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bb4b5541/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
index d772fbc..e1864e2 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batch/handler/MockedBatchHandlerTest.java
@@ -442,7 +442,61 @@ public class MockedBatchHandlerTest {
 
     return contentId;
   }
-
+  
+  @Test(expected=BatchException.class)
+  public void testInvalidMethod() throws UnsupportedEncodingException, BatchException {
+    final String content = ""
+        + "--batch_12345" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_12345" + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 1" + CRLF
+        + CRLF
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF 
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345--" + CRLF
+        + CRLF
+        + "--batch_12345--";
+    
+    final Map<String, List<String>> header = getMimeHeader();
+    final ODataResponse response = new ODataResponse();
+    final ODataRequest request = buildODataRequest(content, header);
+    request.setMethod(HttpMethod.GET);
+    
+    batchHandler.process(request, response, true);
+  }
+  
+  @Test(expected=BatchException.class)
+  public void testInvalidContentType() throws UnsupportedEncodingException, BatchException {
+    final String content = ""
+        + "--batch_12345" + CRLF
+        + "Content-Type: multipart/mixed; boundary=changeset_12345" + CRLF
+        + CRLF
+        + "--changeset_12345" + CRLF
+        + "Content-Type: application/http" + CRLF
+        + "Content-Transfer-Encoding: binary" + CRLF
+        + "Content-Id: 1" + CRLF
+        + CRLF
+        + "PUT ESAllPrim(1) HTTP/1.1" + CRLF 
+        + "Content-Type: application/json;odata=verbose" + CRLF
+        + CRLF
+        + CRLF
+        + "--changeset_12345--" + CRLF
+        + CRLF
+        + "--batch_12345--";
+    
+    final Map<String, List<String>> header = new HashMap<String, List<String>>();
+    header.put(HttpHeader.CONTENT_TYPE, Arrays.asList(new String[] { "application/http" }));
+    final ODataResponse response = new ODataResponse();
+    final ODataRequest request = buildODataRequest(content, header);
+    
+    batchHandler.process(request, response, true);
+  }
+  
   /*
    * Helper methods
    */