[OLINGO-1018] Introduced ODataJPADefaultProcessor
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPADefaultProcessor.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPADefaultProcessor.java
new file mode 100644
index 0000000..ca89e13
--- /dev/null
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPADefaultProcessor.java
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.jpa.processor.api;
+
+import org.apache.olingo.odata2.api.batch.BatchHandler;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
+import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.uri.PathInfo;
+import org.apache.olingo.odata2.api.uri.info.*;
+import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAException;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ODataJPADefaultProcessor extends ODataJPAProcessor {
+
+  public ODataJPADefaultProcessor(final ODataJPAContext oDataJPAContext) {
+    super(oDataJPAContext);
+    if (oDataJPAContext == null) {
+      throw new IllegalArgumentException(ODataJPAException.ODATA_JPACTX_NULL);
+    }
+  }
+
+  @Override
+  public ODataResponse readEntitySet(final GetEntitySetUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      List<Object> jpaEntities = jpaProcessor.process(uriParserResultView);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, jpaEntities, contentType);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse readEntity(final GetEntityUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      Object jpaEntity = jpaProcessor.process(uriParserResultView);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, jpaEntity, contentType);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse countEntitySet(final GetEntitySetCountUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      long jpaEntityCount = jpaProcessor.process(uriParserResultView);
+      oDataResponse = responseBuilder.build(jpaEntityCount);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse existsEntity(final GetEntityCountUriInfo uriInfo, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      long jpaEntityCount = jpaProcessor.process(uriInfo);
+      oDataResponse = responseBuilder.build(jpaEntityCount);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse createEntity(final PostUriInfo uriParserResultView, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      Object createdJpaEntity = jpaProcessor.process(uriParserResultView, content, requestContentType);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, createdJpaEntity, contentType);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse updateEntity(final PutMergePatchUriInfo uriParserResultView, final InputStream content,
+      final String requestContentType, final boolean merge, final String contentType) throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      Object jpaEntity = jpaProcessor.process(uriParserResultView, content, requestContentType);
+      oDataResponse = responseBuilder.build(uriParserResultView, jpaEntity);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse deleteEntity(final DeleteUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      Object deletedObj = jpaProcessor.process(uriParserResultView, contentType);
+      oDataResponse = responseBuilder.build(uriParserResultView, deletedObj);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse executeFunctionImport(final GetFunctionImportUriInfo uriParserResultView,
+      final String contentType) throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      List<Object> resultEntity = jpaProcessor.process(uriParserResultView);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, resultEntity, contentType);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse executeFunctionImportValue(final GetFunctionImportUriInfo uriParserResultView,
+      final String contentType) throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      List<Object> result = jpaProcessor.process(uriParserResultView);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, result.get(0));
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse readEntityLink(final GetEntityLinkUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      Object jpaEntity = jpaProcessor.process(uriParserResultView);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, jpaEntity, contentType);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse readEntityLinks(final GetEntitySetLinksUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    ODataResponse oDataResponse = null;
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      List<Object> jpaEntity = jpaProcessor.process(uriParserResultView);
+      oDataResponse =
+          responseBuilder.build(uriParserResultView, jpaEntity, contentType);
+    } finally {
+      close();
+    }
+    return oDataResponse;
+  }
+
+  @Override
+  public ODataResponse createEntityLink(final PostUriInfo uriParserResultView, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      jpaProcessor.process(uriParserResultView, content, requestContentType, contentType);
+      return ODataResponse.newBuilder().build();
+    } finally {
+      close();
+    }
+  }
+
+  @Override
+  public ODataResponse updateEntityLink(final PutMergePatchUriInfo uriParserResultView, final InputStream content,
+      final String requestContentType, final String contentType) throws ODataException {
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      jpaProcessor.process(uriParserResultView, content, requestContentType, contentType);
+      return ODataResponse.newBuilder().build();
+    } finally {
+      close();
+    }
+  }
+
+  @Override
+  public ODataResponse deleteEntityLink(final DeleteUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+    try {
+      oDataJPAContext.setODataContext(getContext());
+      jpaProcessor.process(uriParserResultView, contentType);
+      return ODataResponse.newBuilder().build();
+    } finally {
+      close();
+    }
+  }
+
+  @Override
+  public ODataResponse executeBatch(final BatchHandler handler, final String contentType, final InputStream content)
+      throws ODataException {
+    try {
+      oDataJPAContext.setODataContext(getContext());
+
+      ODataResponse batchResponse;
+      List<BatchResponsePart> batchResponseParts = new ArrayList<BatchResponsePart>();
+      PathInfo pathInfo = getContext().getPathInfo();
+      EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
+      List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
+
+      for (BatchRequestPart batchPart : batchParts) {
+        batchResponseParts.add(handler.handleBatchPart(batchPart));
+      }
+      batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
+      return batchResponse;
+    } finally {
+      close(true);
+    }
+  }
+
+  @Override
+  public BatchResponsePart executeChangeSet(final BatchHandler handler, final List<ODataRequest> requests)
+      throws ODataException {
+    List<ODataResponse> responses = new ArrayList<ODataResponse>();
+    try {
+      oDataJPAContext.getODataJPATransaction().begin();
+
+      for (ODataRequest request : requests) {
+        oDataJPAContext.setODataContext(getContext());
+        ODataResponse response = handler.handleRequest(request);
+        if (response.getStatus().getStatusCode() >= HttpStatusCodes.BAD_REQUEST.getStatusCode()) {
+          // Rollback
+          oDataJPAContext.getODataJPATransaction().rollback();
+          List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
+          errorResponses.add(response);
+          return BatchResponsePart.responses(errorResponses).changeSet(false).build();
+        }
+        responses.add(response);
+      }
+      oDataJPAContext.getODataJPATransaction().commit();
+
+      return BatchResponsePart.responses(responses).changeSet(true).build();
+    } catch (Exception e) {
+
+      List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
+      errorResponses.add(ODataResponse.entity(e).status(HttpStatusCodes.INTERNAL_SERVER_ERROR).build());
+      return BatchResponsePart.responses(errorResponses).changeSet(false).build();
+    } finally {
+      close(true);
+    }
+  }
+}
\ No newline at end of file
diff --git a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAServiceFactory.java b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAServiceFactory.java
index 5566ada..64444b5 100644
--- a/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAServiceFactory.java
+++ b/odata2-jpa-processor/jpa-api/src/main/java/org/apache/olingo/odata2/jpa/processor/api/ODataJPAServiceFactory.java
@@ -134,14 +134,20 @@
       oDataJPAContext.setODataContext(ctx);
     }
 
-    ODataSingleProcessor odataJPAProcessor = accessFactory.createODataProcessor(oDataJPAContext);
-
+    ODataSingleProcessor odataJPAProcessor = createCustomODataProcessor(oDataJPAContext);
+    if(odataJPAProcessor == null) {
+      odataJPAProcessor = accessFactory.createODataProcessor(oDataJPAContext);
+    }
     // OData Entity Data Model Provider based on JPA
     EdmProvider edmProvider = accessFactory.createJPAEdmProvider(oDataJPAContext);
 
     return createODataSingleProcessorService(edmProvider, odataJPAProcessor);
   }
 
+  public ODataSingleProcessor createCustomODataProcessor(ODataJPAContext oDataJPAContext) {
+    return null;
+  }
+
   /**
    * @return an instance of type {@link ODataJPAContext}
    * @throws ODataJPARuntimeException
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAProcessorDefault.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAProcessorDefault.java
index c09864e..8daf88e 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAProcessorDefault.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/ODataJPAProcessorDefault.java
@@ -18,291 +18,12 @@
  ******************************************************************************/
 package org.apache.olingo.odata2.jpa.processor.core;
 
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.batch.BatchHandler;
-import org.apache.olingo.odata2.api.batch.BatchRequestPart;
-import org.apache.olingo.odata2.api.batch.BatchResponsePart;
-import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
-import org.apache.olingo.odata2.api.ep.EntityProvider;
-import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
-import org.apache.olingo.odata2.api.exception.ODataException;
-import org.apache.olingo.odata2.api.processor.ODataRequest;
-import org.apache.olingo.odata2.api.processor.ODataResponse;
-import org.apache.olingo.odata2.api.uri.PathInfo;
-import org.apache.olingo.odata2.api.uri.info.DeleteUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityCountUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityLinkUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetLinksUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetEntityUriInfo;
-import org.apache.olingo.odata2.api.uri.info.GetFunctionImportUriInfo;
-import org.apache.olingo.odata2.api.uri.info.PostUriInfo;
-import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
-import org.apache.olingo.odata2.jpa.processor.api.ODataJPAProcessor;
-import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAException;
+import org.apache.olingo.odata2.jpa.processor.api.ODataJPADefaultProcessor;
 
-public class ODataJPAProcessorDefault extends ODataJPAProcessor {
+public class ODataJPAProcessorDefault extends ODataJPADefaultProcessor {
 
   public ODataJPAProcessorDefault(final ODataJPAContext oDataJPAContext) {
     super(oDataJPAContext);
-    if (oDataJPAContext == null) {
-      throw new IllegalArgumentException(ODataJPAException.ODATA_JPACTX_NULL);
-    }
-  }
-
-  @Override
-  public ODataResponse readEntitySet(final GetEntitySetUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      List<Object> jpaEntities = jpaProcessor.process(uriParserResultView);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, jpaEntities, contentType);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse readEntity(final GetEntityUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      Object jpaEntity = jpaProcessor.process(uriParserResultView);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, jpaEntity, contentType);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse countEntitySet(final GetEntitySetCountUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      long jpaEntityCount = jpaProcessor.process(uriParserResultView);
-      oDataResponse = responseBuilder.build(jpaEntityCount);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse existsEntity(final GetEntityCountUriInfo uriInfo, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      long jpaEntityCount = jpaProcessor.process(uriInfo);
-      oDataResponse = responseBuilder.build(jpaEntityCount);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse createEntity(final PostUriInfo uriParserResultView, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      Object createdJpaEntity = jpaProcessor.process(uriParserResultView, content, requestContentType);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, createdJpaEntity, contentType);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse updateEntity(final PutMergePatchUriInfo uriParserResultView, final InputStream content,
-      final String requestContentType, final boolean merge, final String contentType) throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      Object jpaEntity = jpaProcessor.process(uriParserResultView, content, requestContentType);
-      oDataResponse = responseBuilder.build(uriParserResultView, jpaEntity);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse deleteEntity(final DeleteUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      Object deletedObj = jpaProcessor.process(uriParserResultView, contentType);
-      oDataResponse = responseBuilder.build(uriParserResultView, deletedObj);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse executeFunctionImport(final GetFunctionImportUriInfo uriParserResultView,
-      final String contentType) throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      List<Object> resultEntity = jpaProcessor.process(uriParserResultView);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, resultEntity, contentType);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse executeFunctionImportValue(final GetFunctionImportUriInfo uriParserResultView,
-      final String contentType) throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      List<Object> result = jpaProcessor.process(uriParserResultView);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, result.get(0));
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse readEntityLink(final GetEntityLinkUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      Object jpaEntity = jpaProcessor.process(uriParserResultView);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, jpaEntity, contentType);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse readEntityLinks(final GetEntitySetLinksUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    ODataResponse oDataResponse = null;
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      List<Object> jpaEntity = jpaProcessor.process(uriParserResultView);
-      oDataResponse =
-          responseBuilder.build(uriParserResultView, jpaEntity, contentType);
-    } finally {
-      close();
-    }
-    return oDataResponse;
-  }
-
-  @Override
-  public ODataResponse createEntityLink(final PostUriInfo uriParserResultView, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      jpaProcessor.process(uriParserResultView, content, requestContentType, contentType);
-      return ODataResponse.newBuilder().build();
-    } finally {
-      close();
-    }
-  }
-
-  @Override
-  public ODataResponse updateEntityLink(final PutMergePatchUriInfo uriParserResultView, final InputStream content,
-      final String requestContentType, final String contentType) throws ODataException {
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      jpaProcessor.process(uriParserResultView, content, requestContentType, contentType);
-      return ODataResponse.newBuilder().build();
-    } finally {
-      close();
-    }
-  }
-
-  @Override
-  public ODataResponse deleteEntityLink(final DeleteUriInfo uriParserResultView, final String contentType)
-      throws ODataException {
-    try {
-      oDataJPAContext.setODataContext(getContext());
-      jpaProcessor.process(uriParserResultView, contentType);
-      return ODataResponse.newBuilder().build();
-    } finally {
-      close();
-    }
-  }
-
-  @Override
-  public ODataResponse executeBatch(final BatchHandler handler, final String contentType, final InputStream content)
-      throws ODataException {
-    try {
-      oDataJPAContext.setODataContext(getContext());
-
-      ODataResponse batchResponse;
-      List<BatchResponsePart> batchResponseParts = new ArrayList<BatchResponsePart>();
-      PathInfo pathInfo = getContext().getPathInfo();
-      EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
-      List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
-
-      for (BatchRequestPart batchPart : batchParts) {
-        batchResponseParts.add(handler.handleBatchPart(batchPart));
-      }
-      batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
-      return batchResponse;
-    } finally {
-      close(true);
-    }
-  }
-
-  @Override
-  public BatchResponsePart executeChangeSet(final BatchHandler handler, final List<ODataRequest> requests)
-      throws ODataException {
-    List<ODataResponse> responses = new ArrayList<ODataResponse>();
-    try {
-      oDataJPAContext.getODataJPATransaction().begin();
-
-      for (ODataRequest request : requests) {
-        oDataJPAContext.setODataContext(getContext());
-        ODataResponse response = handler.handleRequest(request);
-        if (response.getStatus().getStatusCode() >= HttpStatusCodes.BAD_REQUEST.getStatusCode()) {
-          // Rollback
-          oDataJPAContext.getODataJPATransaction().rollback();
-          List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
-          errorResponses.add(response);
-          return BatchResponsePart.responses(errorResponses).changeSet(false).build();
-        }
-        responses.add(response);
-      }
-      oDataJPAContext.getODataJPATransaction().commit();
-
-      return BatchResponsePart.responses(responses).changeSet(true).build();
-    } catch (Exception e) {
-
-      List<ODataResponse> errorResponses = new ArrayList<ODataResponse>(1);
-      errorResponses.add(ODataResponse.entity(e).status(HttpStatusCodes.INTERNAL_SERVER_ERROR).build());
-      return BatchResponsePart.responses(errorResponses).changeSet(false).build();
-    } finally {
-      close(true);
-    }
   }
 }
\ No newline at end of file
diff --git a/odata2-jpa-processor/jpa-ref/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/util/CustomODataJPAProcessor.java b/odata2-jpa-processor/jpa-ref/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/util/CustomODataJPAProcessor.java
new file mode 100644
index 0000000..385bb50
--- /dev/null
+++ b/odata2-jpa-processor/jpa-ref/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/util/CustomODataJPAProcessor.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.jpa.processor.ref.util;
+
+import org.apache.olingo.odata2.api.exception.ODataException;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo;
+import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
+import org.apache.olingo.odata2.jpa.processor.api.ODataJPADefaultProcessor;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class CustomODataJPAProcessor extends ODataJPADefaultProcessor {
+
+  private static final Logger LOG = Logger.getLogger(CustomODataJPAProcessor.class.getName());
+  private static final AtomicInteger READ_COUNT = new AtomicInteger(0);
+
+  public CustomODataJPAProcessor(ODataJPAContext oDataJPAContext) {
+    super(oDataJPAContext);
+  }
+
+  @Override
+  public ODataResponse readEntitySet(final GetEntitySetUriInfo uriParserResultView, final String contentType)
+      throws ODataException {
+
+    int readCount = READ_COUNT.incrementAndGet();
+    LOG.log(Level.INFO, "Start read access number '" + readCount + "' for '" +
+        uriParserResultView.getTargetEntitySet().getName() + "'.");
+    long start = System.currentTimeMillis();
+    List<Object> jpaEntities = jpaProcessor.process(uriParserResultView);
+    ODataResponse oDataResponse = responseBuilder.build(uriParserResultView, jpaEntities, contentType);
+    long duration = System.currentTimeMillis() - start;
+    LOG.log(Level.INFO, "Finished read access number '" + readCount + "' after '" + duration + "'ms.");
+
+    return oDataResponse;
+  }
+
+}
\ No newline at end of file
diff --git a/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java b/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
index 6e59903..845875b 100644
--- a/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
+++ b/odata2-jpa-processor/jpa-web/src/main/java/org/apache/olingo/odata2/jpa/processor/ref/web/JPAReferenceServiceFactory.java
@@ -22,13 +22,16 @@
 
 import org.apache.olingo.odata2.api.ODataCallback;
 import org.apache.olingo.odata2.api.ODataDebugCallback;
+import org.apache.olingo.odata2.api.processor.ODataSingleProcessor;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAContext;
 import org.apache.olingo.odata2.jpa.processor.api.ODataJPAServiceFactory;
 import org.apache.olingo.odata2.jpa.processor.api.OnJPAWriteContent;
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
+import org.apache.olingo.odata2.jpa.processor.api.factory.ODataJPAAccessFactory;
 import org.apache.olingo.odata2.jpa.processor.ref.extension.OnDBWriteContent;
 import org.apache.olingo.odata2.jpa.processor.ref.extension.SalesOrderProcessingExtension;
 import org.apache.olingo.odata2.jpa.processor.ref.factory.JPAEntityManagerFactory;
+import org.apache.olingo.odata2.jpa.processor.ref.util.CustomODataJPAProcessor;
 
 public class JPAReferenceServiceFactory extends ODataJPAServiceFactory {
   private static final String PUNIT_NAME = "salesorderprocessing";
@@ -54,6 +57,11 @@
     return oDataJPAContext;
   }
 
+  @Override
+  public ODataSingleProcessor createCustomODataProcessor(ODataJPAContext context) {
+    return new CustomODataJPAProcessor(context);
+  }
+
   private void setErrorLevel() {
     ResourceBundle config = ResourceBundle.getBundle(CONFIG);
     boolean error = Boolean.parseBoolean(config.getString(SHOW_DETAIL_ERROR));