[OLINGO-856] Created ODataHandler Interface

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

Branch: refs/heads/master
Commit: e07abf0b0f463194976e0fdd4c389d5183d7f1a0
Parents: 3c205f9
Author: mibo <[email protected]>
Authored: Sat Feb 13 07:08:33 2016 +0100
Committer: mibo <[email protected]>
Committed: Sat Feb 13 07:08:33 2016 +0100

----------------------------------------------------------------------
 .../org/apache/olingo/server/api/OData.java     |   7 +
 .../apache/olingo/server/api/ODataHandler.java  |  63 ++
 .../olingo/server/api/ODataHttpHandler.java     |  29 +-
 .../apache/olingo/server/core/OData4Impl.java   |   4 +-
 .../olingo/server/core/ODataDispatcher.java     |   4 +-
 .../apache/olingo/server/core/ODataHandler.java | 232 ------
 .../olingo/server/core/ODataHandlerImpl.java    | 233 ++++++
 .../server/core/ODataHttpHandlerImpl.java       |  11 +-
 .../apache/olingo/server/core/ODataImpl.java    |  11 +-
 .../core/batchhandler/BatchFacadeImpl.java      |   6 +-
 .../server/core/batchhandler/BatchHandler.java  |   6 +-
 .../core/batchhandler/BatchPartHandler.java     |   8 +-
 .../batchhandler/MockedBatchHandlerTest.java    |   6 +-
 .../server/core/ODataHandlerImplTest.java       | 768 +++++++++++++++++++
 .../olingo/server/core/ODataHandlerTest.java    | 768 -------------------
 15 files changed, 1108 insertions(+), 1048 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
index 26f5f61..4921ac4 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java
@@ -98,6 +98,13 @@ public abstract class OData {
   public abstract ODataHttpHandler createHandler(ServiceMetadata 
serviceMetadata);
 
   /**
+   * Creates a new ODataHandler for handling OData requests.
+   *
+   * @param serviceMetadata - metadata object required to handle an OData 
request
+   */
+  public abstract ODataHandler createBasicHandler(ServiceMetadata 
serviceMetadata);
+
+  /**
    * Creates a metadata object for this service.
    *
    * @param edmProvider a custom or default implementation for creating 
metadata

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHandler.java 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHandler.java
new file mode 100644
index 0000000..d1ba14b
--- /dev/null
+++ 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHandler.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import org.apache.olingo.server.api.etag.CustomETagSupport;
+import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
+
+/**
+ * <p>Handles requests as OData requests.</p>
+ *
+ * <p>This includes URI parsing, content negotiation, dispatching the request
+ * to a specific custom processor implementation for handling data and
+ * creating the serialized content for the response object.</p>
+ */
+public interface ODataHandler {
+
+  /**
+   * <p>Processes an OData request.</p>
+   * <p>This includes URI parsing, content negotiation, dispatching the request
+   * to a specific custom processor implementation for handling data and
+   * creating the serialized content for the response object.</p>
+   * @param request the OData request
+   * @return OData response
+   */
+  ODataResponse process(final ODataRequest request);
+
+  /**
+   * <p>Registers additional custom processor implementations for handling 
OData requests.</p>
+   * <p>If request processing requires a processor that is not registered then 
a
+   * "not implemented" exception will happen.</p>
+   */
+  void register(Processor processor);
+
+  /**
+   * Registers a service implementation for modifying the standard list of 
supported
+   * content types.
+   * @see CustomContentTypeSupport
+   */
+  void register(CustomContentTypeSupport customContentTypeSupport);
+
+  /**
+   * Registers support for concurrency control for certain entity sets.
+   * @param customETagSupport handler to register
+   */
+  void register(CustomETagSupport customETagSupport);
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
index 26d14c3..da26074 100644
--- 
a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
+++ 
b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java
@@ -22,17 +22,14 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.olingo.server.api.debug.DebugSupport;
-import org.apache.olingo.server.api.etag.CustomETagSupport;
-import org.apache.olingo.server.api.processor.Processor;
-import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
 
 /**
  * Handles HTTP requests as OData requests.
  */
-public interface ODataHttpHandler {
+public interface ODataHttpHandler extends ODataHandler {
 
   /**
-   * <p>Processes an OData request.</p>
+   * <p>Processes a HttpServletRequest as an OData request.</p>
    * <p>This includes URI parsing, content negotiation, dispatching the request
    * to a specific custom processor implementation for handling data and
    * creating the serialized content for the response object.</p>
@@ -42,35 +39,15 @@ public interface ODataHttpHandler {
   void process(HttpServletRequest request, HttpServletResponse response);
 
   /**
-   * <p>Registers additional custom processor implementations for handling 
OData requests.</p>
-   * <p>If request processing requires a processor that is not registered then 
a
-   * "not implemented" exception will happen.</p>
-   */
-  void register(Processor processor);
-
-  /**
-   * Registers a service implementation for modifying the standard list of 
supported
-   * content types.
-   * @see CustomContentTypeSupport
-   */
-  void register(CustomContentTypeSupport customContentTypeSupport);
-
-  /**
    * Sets the split parameter which is used for service resolution.
    * @param split the number of path segments reserved for service resolution; 
default is 0
    */
   void setSplit(int split);
 
-  /**
-   * Registers support for concurrency control for certain entity sets.
-   * @param customETagSupport
-   */
-  void register(CustomETagSupport customConcurrencyControlSupport);
 
   /**
    * Registers the debug support handler.
-   * @param debugSupport
+   * @param debugSupport handler to register
    */
   void register(DebugSupport debugSupport);
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
 
b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
index 29cb551..c274fb8 100644
--- 
a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
+++ 
b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/OData4Impl.java
@@ -39,7 +39,7 @@ public class OData4Impl extends ODataImpl {
   }
 
   @Override
-  public ODataHttpHandler createHandler(final ServiceMetadata edm) {
-    return new OData4HttpHandler(this, edm);
+  public ODataHttpHandler createHandler(final ServiceMetadata serviceMetadata) 
{
+    return new OData4HttpHandler(this, serviceMetadata);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
index 4971c8e..1732500 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java
@@ -75,9 +75,9 @@ public class ODataDispatcher {
 
   private static final String NOT_IMPLEMENTED_MESSAGE = "not implemented";
   private final UriInfo uriInfo;
-  private final ODataHandler handler;
+  private final ODataHandlerImpl handler;
 
-  public ODataDispatcher(final UriInfo uriInfo, final ODataHandler handler) {
+  public ODataDispatcher(final UriInfo uriInfo, final ODataHandlerImpl 
handler) {
     this.uriInfo = uriInfo;
     this.handler = handler;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/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
deleted file mode 100644
index 3baaac7..0000000
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
+++ /dev/null
@@ -1,232 +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;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
-import org.apache.olingo.commons.api.format.ContentType;
-import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.commons.api.http.HttpMethod;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataApplicationException;
-import org.apache.olingo.server.api.ODataLibraryException;
-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.deserializer.DeserializerException;
-import org.apache.olingo.server.api.etag.CustomETagSupport;
-import org.apache.olingo.server.api.etag.PreconditionException;
-import org.apache.olingo.server.api.processor.DefaultProcessor;
-import org.apache.olingo.server.api.processor.ErrorProcessor;
-import org.apache.olingo.server.api.processor.Processor;
-import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
-import org.apache.olingo.server.api.serializer.RepresentationType;
-import org.apache.olingo.server.api.serializer.SerializerException;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.core.debug.ServerCoreDebugger;
-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;
-import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
-import org.apache.olingo.server.core.uri.validator.UriValidationException;
-import org.apache.olingo.server.core.uri.validator.UriValidator;
-
-public class ODataHandler {
-
-  private final OData odata;
-  private final ServiceMetadata serviceMetadata;
-  private final List<Processor> processors = new LinkedList<Processor>();
-  private final ServerCoreDebugger debugger;
-
-  private CustomContentTypeSupport customContentTypeSupport;
-  private CustomETagSupport customETagSupport;
-
-  private UriInfo uriInfo;
-  private Exception lastThrownException;
-
-  public ODataHandler(final OData server, final ServiceMetadata 
serviceMetadata, final ServerCoreDebugger debugger) {
-    odata = server;
-    this.serviceMetadata = serviceMetadata;
-    this.debugger = debugger;
-
-    register(new DefaultRedirectProcessor());
-    register(new DefaultProcessor());
-  }
-
-  public ODataResponse process(final ODataRequest request) {
-    ODataResponse response = new ODataResponse();
-    final int responseHandle = 
debugger.startRuntimeMeasurement("ODataHandler", "process");
-    try {
-      processInternal(request, response);
-    } catch (final UriValidationException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (final UriParserSemanticException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (final UriParserSyntaxException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (final UriParserException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (ContentNegotiatorException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (SerializerException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (DeserializerException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (PreconditionException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (ODataHandlerException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError, e);
-    } catch (ODataApplicationException e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e);
-      handleException(request, response, serverError, e);
-    } catch (Exception e) {
-      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e);
-      handleException(request, response, serverError, e);
-    }
-    debugger.stopRuntimeMeasurement(responseHandle);
-    return response;
-  }
-
-  private void processInternal(final ODataRequest request, final ODataResponse 
response)
-      throws ODataApplicationException, ODataLibraryException {
-    final int measurementHandle = 
debugger.startRuntimeMeasurement("ODataHandler", "processInternal");
-
-    response.setHeader(HttpHeader.ODATA_VERSION, 
ODataServiceVersion.V40.toString());
-    try {
-      validateODataVersion(request);
-    } catch (final ODataHandlerException e) {
-      debugger.stopRuntimeMeasurement(measurementHandle);
-      throw e;
-    }
-
-    final int measurementUriParser = 
debugger.startRuntimeMeasurement("UriParser", "parseUri");
-    try {
-      uriInfo = new Parser(serviceMetadata.getEdm(), odata)
-          .parseUri(request.getRawODataPath(), request.getRawQueryPath(), 
null);
-    } catch (final ODataLibraryException e) {
-      debugger.stopRuntimeMeasurement(measurementUriParser);
-      debugger.stopRuntimeMeasurement(measurementHandle);
-      throw e;
-    }
-    debugger.stopRuntimeMeasurement(measurementUriParser);
-
-    final int measurementUriValidator = 
debugger.startRuntimeMeasurement("UriValidator", "validate");
-    final HttpMethod method = request.getMethod();
-    try {
-      new UriValidator().validate(uriInfo, method);
-    } catch (final UriValidationException e) {
-      debugger.stopRuntimeMeasurement(measurementUriValidator);
-      debugger.stopRuntimeMeasurement(measurementHandle);
-      throw e;
-    }
-    debugger.stopRuntimeMeasurement(measurementUriValidator);
-
-    final int measurementDispatcher = 
debugger.startRuntimeMeasurement("ODataDispatcher", "dispatch");
-    try {
-      new ODataDispatcher(uriInfo, this).dispatch(request, response);
-    } finally {
-      debugger.stopRuntimeMeasurement(measurementDispatcher);
-      debugger.stopRuntimeMeasurement(measurementHandle);
-    }
-  }
-
-  public void handleException(final ODataRequest request, final ODataResponse 
response,
-      final ODataServerError serverError, final Exception exception) {
-    final int measurementHandle = 
debugger.startRuntimeMeasurement("ODataHandler", "handleException");
-    lastThrownException = exception;
-    ErrorProcessor exceptionProcessor;
-    try {
-      exceptionProcessor = selectProcessor(ErrorProcessor.class);
-    } catch (ODataHandlerException e) {
-      // This cannot happen since there is always an ExceptionProcessor 
registered.
-      exceptionProcessor = new DefaultProcessor();
-    }
-    ContentType requestedContentType;
-    try {
-      requestedContentType = ContentNegotiator.doContentNegotiation(
-          uriInfo == null ? null : uriInfo.getFormatOption(), request, 
getCustomContentTypeSupport(),
-              RepresentationType.ERROR);
-    } catch (final ContentNegotiatorException e) {
-      requestedContentType = ContentType.JSON;
-    }
-    final int measurementError = 
debugger.startRuntimeMeasurement("ErrorProcessor", "processError");
-    exceptionProcessor.processError(request, response, serverError, 
requestedContentType);
-    debugger.stopRuntimeMeasurement(measurementError);
-    debugger.stopRuntimeMeasurement(measurementHandle);
-  }
-
-  private void validateODataVersion(final ODataRequest request) throws 
ODataHandlerException {
-    final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
-    if (maxVersion != null && 
ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), 
maxVersion)) {
-      throw new ODataHandlerException("ODataVersion not supported: " + 
maxVersion,
-          ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, 
maxVersion);
-    }
-  }
-
-  <T extends Processor> T selectProcessor(final Class<T> cls) throws 
ODataHandlerException {
-    for (final Processor processor : processors) {
-      if (cls.isAssignableFrom(processor.getClass())) {
-        processor.init(odata, serviceMetadata);
-        return cls.cast(processor);
-      }
-    }
-    throw new ODataHandlerException("Processor: " + cls.getSimpleName() + " 
not registered.",
-        ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, 
cls.getSimpleName());
-  }
-
-  public void register(final Processor processor) {
-    processors.add(0, processor);
-  }
-
-  public void register(final CustomContentTypeSupport 
customContentTypeSupport) {
-    this.customContentTypeSupport = customContentTypeSupport;
-  }
-
-  public CustomContentTypeSupport getCustomContentTypeSupport() {
-    return customContentTypeSupport;
-  }
-
-  public void register(final CustomETagSupport customETagSupport) {
-    this.customETagSupport = customETagSupport;
-  }
-
-  public CustomETagSupport getCustomETagSupport() {
-    return customETagSupport;
-  }
-
-  public Exception getLastThrownException() {
-    return lastThrownException;
-  }
-
-  public UriInfo getUriInfo() {
-    return uriInfo;
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
new file mode 100644
index 0000000..0b5a8d8
--- /dev/null
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandlerImpl.java
@@ -0,0 +1,233 @@
+/*
+ * 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;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataHandler;
+import org.apache.olingo.server.api.ODataLibraryException;
+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.deserializer.DeserializerException;
+import org.apache.olingo.server.api.etag.CustomETagSupport;
+import org.apache.olingo.server.api.etag.PreconditionException;
+import org.apache.olingo.server.api.processor.DefaultProcessor;
+import org.apache.olingo.server.api.processor.ErrorProcessor;
+import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
+import org.apache.olingo.server.api.serializer.RepresentationType;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
+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;
+import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+import org.apache.olingo.server.core.uri.validator.UriValidator;
+
+public class ODataHandlerImpl implements ODataHandler {
+
+  private final OData odata;
+  private final ServiceMetadata serviceMetadata;
+  private final List<Processor> processors = new LinkedList<Processor>();
+  private final ServerCoreDebugger debugger;
+
+  private CustomContentTypeSupport customContentTypeSupport;
+  private CustomETagSupport customETagSupport;
+
+  private UriInfo uriInfo;
+  private Exception lastThrownException;
+
+  public ODataHandlerImpl(final OData odata, final ServiceMetadata 
serviceMetadata, final ServerCoreDebugger debugger) {
+    this.odata = odata;
+    this.serviceMetadata = serviceMetadata;
+    this.debugger = debugger;
+
+    register(new DefaultRedirectProcessor());
+    register(new DefaultProcessor());
+  }
+
+  public ODataResponse process(final ODataRequest request) {
+    ODataResponse response = new ODataResponse();
+    final int responseHandle = 
debugger.startRuntimeMeasurement("ODataHandler", "process");
+    try {
+      processInternal(request, response);
+    } catch (final UriValidationException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (final UriParserSemanticException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (final UriParserSyntaxException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (final UriParserException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (ContentNegotiatorException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (SerializerException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (DeserializerException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (PreconditionException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (ODataHandlerException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e, null);
+      handleException(request, response, serverError, e);
+    } catch (ODataApplicationException e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e);
+      handleException(request, response, serverError, e);
+    } catch (Exception e) {
+      ODataServerError serverError = 
ODataExceptionHelper.createServerErrorObject(e);
+      handleException(request, response, serverError, e);
+    }
+    debugger.stopRuntimeMeasurement(responseHandle);
+    return response;
+  }
+
+  private void processInternal(final ODataRequest request, final ODataResponse 
response)
+      throws ODataApplicationException, ODataLibraryException {
+    final int measurementHandle = 
debugger.startRuntimeMeasurement("ODataHandler", "processInternal");
+
+    response.setHeader(HttpHeader.ODATA_VERSION, 
ODataServiceVersion.V40.toString());
+    try {
+      validateODataVersion(request);
+    } catch (final ODataHandlerException e) {
+      debugger.stopRuntimeMeasurement(measurementHandle);
+      throw e;
+    }
+
+    final int measurementUriParser = 
debugger.startRuntimeMeasurement("UriParser", "parseUri");
+    try {
+      uriInfo = new Parser(serviceMetadata.getEdm(), odata)
+          .parseUri(request.getRawODataPath(), request.getRawQueryPath(), 
null);
+    } catch (final ODataLibraryException e) {
+      debugger.stopRuntimeMeasurement(measurementUriParser);
+      debugger.stopRuntimeMeasurement(measurementHandle);
+      throw e;
+    }
+    debugger.stopRuntimeMeasurement(measurementUriParser);
+
+    final int measurementUriValidator = 
debugger.startRuntimeMeasurement("UriValidator", "validate");
+    final HttpMethod method = request.getMethod();
+    try {
+      new UriValidator().validate(uriInfo, method);
+    } catch (final UriValidationException e) {
+      debugger.stopRuntimeMeasurement(measurementUriValidator);
+      debugger.stopRuntimeMeasurement(measurementHandle);
+      throw e;
+    }
+    debugger.stopRuntimeMeasurement(measurementUriValidator);
+
+    final int measurementDispatcher = 
debugger.startRuntimeMeasurement("ODataDispatcher", "dispatch");
+    try {
+      new ODataDispatcher(uriInfo, this).dispatch(request, response);
+    } finally {
+      debugger.stopRuntimeMeasurement(measurementDispatcher);
+      debugger.stopRuntimeMeasurement(measurementHandle);
+    }
+  }
+
+  public void handleException(final ODataRequest request, final ODataResponse 
response,
+      final ODataServerError serverError, final Exception exception) {
+    final int measurementHandle = 
debugger.startRuntimeMeasurement("ODataHandler", "handleException");
+    lastThrownException = exception;
+    ErrorProcessor exceptionProcessor;
+    try {
+      exceptionProcessor = selectProcessor(ErrorProcessor.class);
+    } catch (ODataHandlerException e) {
+      // This cannot happen since there is always an ExceptionProcessor 
registered.
+      exceptionProcessor = new DefaultProcessor();
+    }
+    ContentType requestedContentType;
+    try {
+      requestedContentType = ContentNegotiator.doContentNegotiation(
+          uriInfo == null ? null : uriInfo.getFormatOption(), request, 
getCustomContentTypeSupport(),
+              RepresentationType.ERROR);
+    } catch (final ContentNegotiatorException e) {
+      requestedContentType = ContentType.JSON;
+    }
+    final int measurementError = 
debugger.startRuntimeMeasurement("ErrorProcessor", "processError");
+    exceptionProcessor.processError(request, response, serverError, 
requestedContentType);
+    debugger.stopRuntimeMeasurement(measurementError);
+    debugger.stopRuntimeMeasurement(measurementHandle);
+  }
+
+  private void validateODataVersion(final ODataRequest request) throws 
ODataHandlerException {
+    final String maxVersion = request.getHeader(HttpHeader.ODATA_MAX_VERSION);
+    if (maxVersion != null && 
ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), 
maxVersion)) {
+      throw new ODataHandlerException("ODataVersion not supported: " + 
maxVersion,
+          ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, 
maxVersion);
+    }
+  }
+
+  <T extends Processor> T selectProcessor(final Class<T> cls) throws 
ODataHandlerException {
+    for (final Processor processor : processors) {
+      if (cls.isAssignableFrom(processor.getClass())) {
+        processor.init(odata, serviceMetadata);
+        return cls.cast(processor);
+      }
+    }
+    throw new ODataHandlerException("Processor: " + cls.getSimpleName() + " 
not registered.",
+        ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, 
cls.getSimpleName());
+  }
+
+  public void register(final Processor processor) {
+    processors.add(0, processor);
+  }
+
+  public void register(final CustomContentTypeSupport 
customContentTypeSupport) {
+    this.customContentTypeSupport = customContentTypeSupport;
+  }
+
+  public CustomContentTypeSupport getCustomContentTypeSupport() {
+    return customContentTypeSupport;
+  }
+
+  public void register(final CustomETagSupport customETagSupport) {
+    this.customETagSupport = customETagSupport;
+  }
+
+  public CustomETagSupport getCustomETagSupport() {
+    return customETagSupport;
+  }
+
+  public Exception getLastThrownException() {
+    return lastThrownException;
+  }
+
+  public UriInfo getUriInfo() {
+    return uriInfo;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
index 61581c0..492e4d4 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
@@ -55,14 +55,19 @@ public class ODataHttpHandlerImpl implements 
ODataHttpHandler {
 
   public static final int COPY_BUFFER_SIZE = 8192;
 
-  private final ODataHandler handler;
+  private final ODataHandlerImpl handler;
   private final ServerCoreDebugger debugger;
 
   private int split = 0;
 
   public ODataHttpHandlerImpl(final OData odata, final ServiceMetadata 
serviceMetadata) {
     debugger = new ServerCoreDebugger(odata);
-    handler = new ODataHandler(odata, serviceMetadata, debugger);
+    handler = new ODataHandlerImpl(odata, serviceMetadata, debugger);
+  }
+
+  @Override
+  public ODataResponse process(ODataRequest request) {
+    return handler.process(request);
   }
 
   @Override
@@ -76,7 +81,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler 
{
     try {
       fillODataRequest(odRequest, request, split);
 
-      odResponse = handler.process(odRequest);
+      odResponse = process(odRequest);
       // ALL future methods after process must not throw exceptions!
     } catch (Exception e) {
       exception = e;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
index e5c5437..e1e5553 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
@@ -27,6 +27,7 @@ import 
org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
 import org.apache.olingo.commons.api.format.ContentType;
 import 
org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataHandler;
 import org.apache.olingo.server.api.ODataHttpHandler;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.debug.DebugResponseHelper;
@@ -42,6 +43,7 @@ import 
org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriHelper;
 import org.apache.olingo.server.core.debug.DebugResponseHelperImpl;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
 import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl;
 import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer;
 import org.apache.olingo.server.core.deserializer.xml.ODataXmlDeserializer;
@@ -84,8 +86,13 @@ public class ODataImpl extends OData {
   }
 
   @Override
-  public ODataHttpHandler createHandler(final ServiceMetadata edm) {
-    return new ODataHttpHandlerImpl(this, edm);
+  public ODataHttpHandler createHandler(final ServiceMetadata serviceMetadata) 
{
+    return new ODataHttpHandlerImpl(this, serviceMetadata);
+  }
+
+  @Override
+  public ODataHandler createBasicHandler(ServiceMetadata serviceMetadata) {
+    return new ODataHandlerImpl(this, serviceMetadata, new 
ServerCoreDebugger(this));
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java
index 98bf563..787b7fd 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java
@@ -27,7 +27,7 @@ import 
org.apache.olingo.server.api.deserializer.batch.BatchDeserializerExceptio
 import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
 import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart;
 import org.apache.olingo.server.api.processor.BatchProcessor;
-import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.ODataHandlerImpl;
 import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
 
 public class BatchFacadeImpl implements BatchFacade {
@@ -39,8 +39,8 @@ public class BatchFacadeImpl implements BatchFacade {
    * @param batchProcessor batch processor
    * @param isStrict       mode switch (currently not used)
    */
-  public BatchFacadeImpl(final ODataHandler oDataHandler, final BatchProcessor 
batchProcessor,
-      final boolean isStrict) {
+  public BatchFacadeImpl(final ODataHandlerImpl oDataHandler, final 
BatchProcessor batchProcessor,
+                         final boolean isStrict) {
     partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this);
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
index 121734e..9b6c643 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java
@@ -29,14 +29,14 @@ import org.apache.olingo.server.api.batch.BatchFacade;
 import 
org.apache.olingo.server.api.deserializer.batch.BatchDeserializerException;
 import 
org.apache.olingo.server.api.deserializer.batch.BatchDeserializerException.MessageKeys;
 import org.apache.olingo.server.api.processor.BatchProcessor;
-import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.ODataHandlerImpl;
 import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
 
 public class BatchHandler {
   private final BatchProcessor batchProcessor;
-  private final ODataHandler oDataHandler;
+  private final ODataHandlerImpl oDataHandler;
 
-  public BatchHandler(final ODataHandler oDataHandler, final BatchProcessor 
batchProcessor) {
+  public BatchHandler(final ODataHandlerImpl oDataHandler, final 
BatchProcessor batchProcessor) {
 
     this.batchProcessor = batchProcessor;
     this.oDataHandler = oDataHandler;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java
 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java
index 712ff3e..9f03362 100644
--- 
a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchPartHandler.java
@@ -28,17 +28,17 @@ import 
org.apache.olingo.server.api.deserializer.batch.BatchDeserializerExceptio
 import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
 import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart;
 import org.apache.olingo.server.api.processor.BatchProcessor;
-import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.ODataHandlerImpl;
 import 
org.apache.olingo.server.core.batchhandler.referenceRewriting.BatchReferenceRewriter;
 
 public class BatchPartHandler {
-  private final ODataHandler oDataHandler;
+  private final ODataHandlerImpl oDataHandler;
   private final BatchProcessor batchProcessor;
   private final BatchFacade batchFacade;
   private final BatchReferenceRewriter rewriter;
 
-  public BatchPartHandler(final ODataHandler oDataHandler, final 
BatchProcessor processor,
-      final BatchFacade batchFacade) {
+  public BatchPartHandler(final ODataHandlerImpl oDataHandler, final 
BatchProcessor processor,
+                          final BatchFacade batchFacade) {
     this.oDataHandler = oDataHandler;
     batchProcessor = processor;
     this.batchFacade = batchFacade;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java
 
b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java
index 8b5513e..6347048 100644
--- 
a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java
+++ 
b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java
@@ -52,7 +52,7 @@ import 
org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
 import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart;
 import org.apache.olingo.server.api.processor.BatchProcessor;
 import org.apache.olingo.server.api.serializer.BatchSerializerException;
-import org.apache.olingo.server.core.ODataHandler;
+import org.apache.olingo.server.core.ODataHandlerImpl;
 import org.apache.olingo.server.core.deserializer.batch.BatchLineReader;
 import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
 import org.junit.Before;
@@ -67,7 +67,7 @@ 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 oDataHandler;
+  private ODataHandlerImpl oDataHandler;
   private BatchHandler batchHandler;
   private int entityCounter = 1;
 
@@ -77,7 +77,7 @@ public class MockedBatchHandlerTest {
     batchProcessor.init(OData.newInstance(), null);
 
     entityCounter = 1;
-    oDataHandler = mock(ODataHandler.class);
+    oDataHandler = mock(ODataHandlerImpl.class);
     batchHandler = new BatchHandler(oDataHandler, batchProcessor);
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/e07abf0b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
new file mode 100644
index 0000000..2b6ed69
--- /dev/null
+++ 
b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerImplTest.java
@@ -0,0 +1,768 @@
+/*
+ * 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;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import java.util.Collections;
+import java.util.Locale;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
+import org.apache.olingo.commons.api.ex.ODataException;
+import org.apache.olingo.commons.api.format.ContentType;
+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.ODataApplicationException;
+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.BatchFacade;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.apache.olingo.server.api.processor.ActionComplexCollectionProcessor;
+import org.apache.olingo.server.api.processor.ActionComplexProcessor;
+import org.apache.olingo.server.api.processor.ActionEntityCollectionProcessor;
+import org.apache.olingo.server.api.processor.ActionEntityProcessor;
+import 
org.apache.olingo.server.api.processor.ActionPrimitiveCollectionProcessor;
+import org.apache.olingo.server.api.processor.ActionPrimitiveProcessor;
+import org.apache.olingo.server.api.processor.ActionVoidProcessor;
+import org.apache.olingo.server.api.processor.BatchProcessor;
+import org.apache.olingo.server.api.processor.ComplexCollectionProcessor;
+import org.apache.olingo.server.api.processor.ComplexProcessor;
+import org.apache.olingo.server.api.processor.CountComplexCollectionProcessor;
+import org.apache.olingo.server.api.processor.CountEntityCollectionProcessor;
+import 
org.apache.olingo.server.api.processor.CountPrimitiveCollectionProcessor;
+import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
+import org.apache.olingo.server.api.processor.EntityProcessor;
+import org.apache.olingo.server.api.processor.ErrorProcessor;
+import org.apache.olingo.server.api.processor.MediaEntityProcessor;
+import org.apache.olingo.server.api.processor.MetadataProcessor;
+import org.apache.olingo.server.api.processor.PrimitiveCollectionProcessor;
+import org.apache.olingo.server.api.processor.PrimitiveProcessor;
+import org.apache.olingo.server.api.processor.PrimitiveValueProcessor;
+import org.apache.olingo.server.api.processor.Processor;
+import org.apache.olingo.server.api.processor.ReferenceCollectionProcessor;
+import org.apache.olingo.server.api.processor.ReferenceProcessor;
+import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
+import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
+import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+import org.junit.Test;
+
+public class ODataHandlerImplTest {
+
+  private static final String BASE_URI = "http://localhost/odata";;
+
+  @Test
+  public void serviceDocumentNonDefault() throws Exception {
+    final ServiceDocumentProcessor processor = 
mock(ServiceDocumentProcessor.class);
+    final ODataResponse response = dispatch(HttpMethod.GET, "/", processor);
+    assertEquals(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), 
response.getStatusCode());
+
+    verify(processor).readServiceDocument(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, "/", processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, "/", processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, "/", processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, "/", processor);
+  }
+
+  @Test
+  public void serviceDocumentDefault() throws Exception {
+    final ODataResponse response = dispatch(HttpMethod.GET, "/", null);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+
+    String ct = response.getHeader(HttpHeader.CONTENT_TYPE);
+    assertThat(ct, containsString("application/json"));
+    assertThat(ct, containsString("odata.metadata=minimal"));
+
+    assertNotNull(response.getContent());
+    String doc = IOUtils.toString(response.getContent());
+
+    assertThat(doc, containsString("\"@odata.context\":\"$metadata\""));
+    assertThat(doc, containsString("\"value\":"));
+  }
+
+  @Test
+  public void serviceDocumentRedirect() throws Exception {
+    final ODataResponse response = dispatch(HttpMethod.GET, "", null);
+    assertEquals(HttpStatusCode.TEMPORARY_REDIRECT.getStatusCode(), 
response.getStatusCode());
+    assertEquals(BASE_URI + "/", response.getHeader(HttpHeader.LOCATION));
+  }
+
+  @Test
+  public void metadataNonDefault() throws Exception {
+    final MetadataProcessor processor = mock(MetadataProcessor.class);
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", 
processor);
+    assertEquals(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), 
response.getStatusCode());
+
+    verify(processor).readMetadata(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, "$metadata", processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, "$metadata", processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, "$metadata", processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, "$metadata", processor);
+  }
+
+  @Test
+  public void metadataDefault() throws Exception {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", null);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+    assertEquals(ContentType.APPLICATION_XML.toContentTypeString(), 
response.getHeader(HttpHeader.CONTENT_TYPE));
+
+    assertNotNull(response.getContent());
+    assertThat(IOUtils.toString(response.getContent()),
+        containsString("<edmx:Edmx Version=\"4.0\""));
+  }
+
+  @Test
+  public void maxVersionNone() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", null);
+    assertEquals(ODataServiceVersion.V40.toString(), 
response.getHeader(HttpHeader.ODATA_VERSION));
+  }
+
+  @Test
+  public void maxVersionSupported() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", null,
+        HttpHeader.ODATA_MAX_VERSION, ODataServiceVersion.V40.toString(), 
null);
+    assertEquals(ODataServiceVersion.V40.toString(), 
response.getHeader(HttpHeader.ODATA_VERSION));
+  }
+
+  @Test
+  public void maxVersionNotSupported() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", null,
+        HttpHeader.ODATA_MAX_VERSION, ODataServiceVersion.V30.toString(), 
null);
+
+    assertEquals(ODataServiceVersion.V40.toString(), 
response.getHeader(HttpHeader.ODATA_VERSION));
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void contentNegotiationSupported() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", 
"$format=xml", null, null, null);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+  }
+
+  @Test
+  public void contentNegotiationNotSupported() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", 
"$format=not/Supported", null, null, null);
+    assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void contentNegotiationNotSupported2() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", 
"$format=notSupported", null, null, null);
+    assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void unregisteredProcessor() {
+    final ODataResponse response = dispatch(HttpMethod.GET, "ESAllPrim", null);
+    assertEquals(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void uriParserExceptionResultsInRightResponseNotFound() throws 
Exception {
+    final ODataResponse response = dispatch(HttpMethod.GET, "NotFound", null);
+    assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void uriParserExceptionResultsInRightResponseBadRequest() throws 
Exception {
+    final ODataResponse response = dispatch(HttpMethod.GET, 
"ESAllPrim('122')", null);
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void applicationExceptionInProcessor() throws Exception {
+    MetadataProcessor processor = mock(MetadataProcessor.class);
+    doThrow(new ODataApplicationException("msg", 425, 
Locale.ENGLISH)).when(processor).readMetadata(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+    final ODataResponse response = dispatch(HttpMethod.GET, "$metadata", 
processor);
+    assertEquals(425, response.getStatusCode());
+  }
+
+  @Test
+  public void uriParserExceptionResultsInRightResponseEdmCause() throws 
Exception {
+    final OData odata = OData.newInstance();
+    final ServiceMetadata serviceMetadata = odata.createServiceMetadata(
+        new CsdlAbstractEdmProvider() {
+          @Override
+          public CsdlEntitySet getEntitySet(final FullQualifiedName 
entityContainer, final String entitySetName)
+              throws ODataException {
+            throw new ODataException("msg");
+          }
+        },
+        Collections.<EdmxReference> emptyList());
+
+    ODataRequest request = new ODataRequest();
+    request.setMethod(HttpMethod.GET);
+    request.setRawODataPath("EdmException");
+
+    final ODataResponse response =
+        new ODataHandlerImpl(odata, serviceMetadata, new 
ServerCoreDebugger(odata)).process(request);
+    assertNotNull(response);
+    assertEquals(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void dispatchBatch() throws Exception {
+    final String uri = "$batch";
+    final BatchProcessor processor = mock(BatchProcessor.class);
+
+    dispatch(HttpMethod.POST, uri, null, HttpHeader.CONTENT_TYPE, 
ContentType.MULTIPART_MIXED.toContentTypeString(),
+        processor);
+    verify(processor).processBatch(any(BatchFacade.class), 
any(ODataRequest.class), any(ODataResponse.class));
+
+    dispatchMethodNotAllowed(HttpMethod.GET, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+
+  @Test
+  public void dispatchEntitySet() throws Exception {
+    final String uri = "ESAllPrim";
+    final EntityCollectionProcessor processor = 
mock(EntityCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+
+  @Test
+  public void dispatchEntitySetCount() throws Exception {
+    final String uri = "ESAllPrim/$count";
+    final CountEntityCollectionProcessor processor = 
mock(CountEntityCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).countEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+
+  @Test
+  public void dispatchCountWithNavigation() throws Exception {
+    final CountEntityCollectionProcessor processor = 
mock(CountEntityCollectionProcessor.class);
+    dispatch(HttpMethod.GET, "ESAllPrim(0)/NavPropertyETTwoPrimMany/$count", 
processor);
+
+    verify(processor).countEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+  }
+
+  @Test
+  public void dispatchFunction() throws Exception {
+    EntityProcessor entityProcessor = mock(EntityProcessor.class);
+    dispatch(HttpMethod.GET, "FICRTETKeyNav()", entityProcessor);
+    verify(entityProcessor).readEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    EntityCollectionProcessor entityCollectionProcessor = 
mock(EntityCollectionProcessor.class);
+    dispatch(HttpMethod.GET, "FICRTCollESTwoKeyNavParam(ParameterInt16=123)", 
entityCollectionProcessor);
+    verify(entityCollectionProcessor).readEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    final String entityCountUri = 
"FICRTCollESTwoKeyNavParam(ParameterInt16=123)/$count";
+    final CountEntityCollectionProcessor entityCountProcessor = 
mock(CountEntityCollectionProcessor.class);
+    dispatch(HttpMethod.GET, entityCountUri, entityCountProcessor);
+    verify(entityCountProcessor).countEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, entityCountUri, 
entityCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, entityCountUri, 
entityCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, entityCountUri, 
entityCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, entityCountUri, 
entityCountProcessor);
+
+    PrimitiveProcessor primitiveProcessor = mock(PrimitiveProcessor.class);
+    dispatch(HttpMethod.GET, "FICRTString()", primitiveProcessor);
+    verify(primitiveProcessor).readPrimitive(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+    
+    // FINRTInt16 is not composable so /$value is not allowed
+    final String valueUri = "FINRTInt16()/$value";
+    final PrimitiveValueProcessor primitiveValueProcessor = 
mock(PrimitiveValueProcessor.class);
+    dispatchMethodWithError(HttpMethod.GET, valueUri, primitiveValueProcessor, 
HttpStatusCode.BAD_REQUEST);
+    dispatchMethodWithError(HttpMethod.POST, valueUri, 
primitiveValueProcessor, HttpStatusCode.BAD_REQUEST);
+    dispatchMethodWithError(HttpMethod.PATCH, valueUri, 
primitiveValueProcessor, HttpStatusCode.BAD_REQUEST);
+    dispatchMethodWithError(HttpMethod.PUT, valueUri, primitiveValueProcessor, 
HttpStatusCode.BAD_REQUEST);
+    dispatchMethodWithError(HttpMethod.DELETE, valueUri, 
primitiveValueProcessor, HttpStatusCode.BAD_REQUEST);
+    
+    final String primitiveCollectionUri = "FICRTCollString()";
+    PrimitiveCollectionProcessor primitiveCollectionProcessor = 
mock(PrimitiveCollectionProcessor.class);
+    dispatch(HttpMethod.GET, primitiveCollectionUri, 
primitiveCollectionProcessor);
+    verify(primitiveCollectionProcessor).readPrimitiveCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, primitiveCollectionUri, 
primitiveCollectionProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, primitiveCollectionUri, 
primitiveCollectionProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, primitiveCollectionUri, 
primitiveCollectionProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, primitiveCollectionUri, 
primitiveCollectionProcessor);
+
+    final String primitiveCountUri = "FICRTCollString()/$count";
+    final CountPrimitiveCollectionProcessor primitiveCountProcessor = 
mock(CountPrimitiveCollectionProcessor.class);
+    dispatch(HttpMethod.GET, primitiveCountUri, primitiveCountProcessor);
+    verify(primitiveCountProcessor).countPrimitiveCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, primitiveCountUri, 
primitiveCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, primitiveCountUri, 
primitiveCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, primitiveCountUri, 
primitiveCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, primitiveCountUri, 
primitiveCountProcessor);
+
+    ComplexProcessor complexProcessor = mock(ComplexProcessor.class);
+    dispatch(HttpMethod.GET, "FICRTCTTwoPrim()", complexProcessor);
+    verify(complexProcessor).readComplex(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    ComplexCollectionProcessor complexCollectionProcessor = 
mock(ComplexCollectionProcessor.class);
+    dispatch(HttpMethod.GET, "FICRTCollCTTwoPrim()", 
complexCollectionProcessor);
+    verify(complexCollectionProcessor).readComplexCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    final String complexCountUri = "FICRTCollCTTwoPrim()/$count";
+    final CountComplexCollectionProcessor complexCountProcessor = 
mock(CountComplexCollectionProcessor.class);
+    dispatch(HttpMethod.GET, complexCountUri, complexCountProcessor);
+    verify(complexCountProcessor).countComplexCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, complexCountUri, 
complexCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, complexCountUri, 
complexCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, complexCountUri, 
complexCountProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, complexCountUri, 
complexCountProcessor);
+
+    final String mediaUri = "FICRTESMedia(ParameterInt16=1)/$value";
+    final MediaEntityProcessor mediaProcessor = 
mock(MediaEntityProcessor.class);
+    dispatch(HttpMethod.GET, mediaUri, mediaProcessor);
+    verify(mediaProcessor).readMediaEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.POST, mediaUri, mediaProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, mediaUri, mediaProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, mediaUri, mediaProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, mediaUri, mediaProcessor);
+  }
+
+  @Test
+  public void dispatchAction() throws Exception {
+    final ActionPrimitiveProcessor primitiveProcessor = 
mock(ActionPrimitiveProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRT_STRING, 
primitiveProcessor);
+    verify(primitiveProcessor).processActionPrimitive(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.GET, ContainerProvider.AIRT_STRING, 
primitiveProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, ContainerProvider.AIRT_STRING, 
primitiveProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, ContainerProvider.AIRT_STRING, 
primitiveProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, ContainerProvider.AIRT_STRING, 
primitiveProcessor);
+
+    ActionPrimitiveCollectionProcessor primitiveCollectionProcessor = 
mock(ActionPrimitiveCollectionProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_STRING_TWO_PARAM, 
primitiveCollectionProcessor);
+    verify(primitiveCollectionProcessor).processActionPrimitiveCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    ActionComplexProcessor complexProcessor = 
mock(ActionComplexProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRTCT_TWO_PRIM_PARAM, 
complexProcessor);
+    verify(complexProcessor).processActionComplex(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    ActionComplexCollectionProcessor complexCollectionProcessor = 
mock(ActionComplexCollectionProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_CT_TWO_PRIM_PARAM, 
complexCollectionProcessor);
+    verify(complexCollectionProcessor).processActionComplexCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    ActionEntityProcessor entityProcessor = mock(ActionEntityProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRTET_TWO_KEY_TWO_PRIM_PARAM, 
entityProcessor);
+    verify(entityProcessor).processActionEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    ActionEntityCollectionProcessor entityCollectionProcessor = 
mock(ActionEntityCollectionProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_ET_KEY_NAV_PARAM, 
entityCollectionProcessor);
+    verify(entityCollectionProcessor).processActionEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    ActionEntityProcessor entityProcessorEs = 
mock(ActionEntityProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRTES_ALL_PRIM_PARAM, 
entityProcessorEs);
+    verify(entityProcessorEs).processActionEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    ActionEntityCollectionProcessor entityCollectionProcessorEs = 
mock(ActionEntityCollectionProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRT_COLL_ES_ALL_PRIM_PARAM, 
entityCollectionProcessorEs);
+    verify(entityCollectionProcessorEs).processActionEntityCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    final ActionVoidProcessor voidProcessor = mock(ActionVoidProcessor.class);
+    dispatch(HttpMethod.POST, ContainerProvider.AIRT, voidProcessor);
+    verify(voidProcessor).processActionVoid(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+    dispatchMethodNotAllowed(HttpMethod.GET, ContainerProvider.AIRT, 
voidProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, ContainerProvider.AIRT, 
voidProcessor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, ContainerProvider.AIRT, 
voidProcessor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, ContainerProvider.AIRT, 
voidProcessor);
+  }
+
+  @Test
+  public void dispatchEntity() throws Exception {
+    final String uri = "ESAllPrim(0)";
+    final EntityProcessor processor = mock(EntityProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, uri, processor);
+    verify(processor).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor, times(2)).updateEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deleteEntity(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatch(HttpMethod.POST, "ESAllPrim", processor);
+    verify(processor).createEntity(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+  }
+
+  @Test
+  public void dispatchMedia() throws Exception {
+    final String uri = "ESMedia(1)/$value";
+    final MediaEntityProcessor processor = mock(MediaEntityProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readMediaEntity(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatch(HttpMethod.POST, "ESMedia", processor);
+    verify(processor).createMediaEntity(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor).updateMediaEntity(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class), any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deleteMediaEntity(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+  }
+
+  @Test
+  public void dispatchMediaDeleteIndirect() throws Exception {
+    final MediaEntityProcessor processor = mock(MediaEntityProcessor.class);
+    dispatch(HttpMethod.DELETE, "ESMedia(1)", processor);
+
+    verify(processor).deleteEntity(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+  }
+
+  @Test
+  public void dispatchPrimitiveProperty() throws Exception {
+    final String uri = "ESAllPrim(0)/PropertyString";
+    final PrimitiveProcessor processor = mock(PrimitiveProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readPrimitive(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, uri, processor);
+    verify(processor).updatePrimitive(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor, times(2)).updatePrimitive(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deletePrimitive(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+  }
+
+  @Test
+  public void dispatchPrimitivePropertyValue() throws Exception {
+    final String uri = "ESAllPrim(0)/PropertyString/$value";
+    final PrimitiveValueProcessor processor = 
mock(PrimitiveValueProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readPrimitiveValue(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, null, HttpHeader.CONTENT_TYPE, 
ContentType.TEXT_PLAIN.toContentTypeString(),
+        processor);
+    verify(processor).updatePrimitiveValue(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deletePrimitiveValue(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+  }
+
+  @Test
+  public void dispatchPrimitiveCollectionProperty() throws Exception {
+    final String uri = "ESMixPrimCollComp(7)/CollPropertyString";
+    final PrimitiveCollectionProcessor processor = 
mock(PrimitiveCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readPrimitiveCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor).updatePrimitiveCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deletePrimitiveCollection(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+  }
+
+  @Test
+  public void dispatchPrimitiveCollectionPropertyCount() throws Exception {
+    final String uri = "ESMixPrimCollComp(7)/CollPropertyString/$count";
+    final CountPrimitiveCollectionProcessor processor = 
mock(CountPrimitiveCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).countPrimitiveCollection(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+
+  @Test
+  public void dispatchComplexProperty() throws Exception {
+    final String uri = "ESMixPrimCollComp(7)/PropertyComp";
+    final ComplexProcessor processor = mock(ComplexProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readComplex(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, uri, processor);
+    verify(processor).updateComplex(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor, times(2)).updateComplex(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deleteComplex(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+  }
+
+  @Test
+  public void dispatchComplexCollectionProperty() throws Exception {
+    final String uri = "ESMixPrimCollComp(7)/CollPropertyComp";
+    final ComplexCollectionProcessor processor = 
mock(ComplexCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readComplexCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor).updateComplexCollection(
+        any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), 
any(ContentType.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uri, processor);
+    verify(processor).deleteComplexCollection(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+  }
+
+  @Test
+  public void dispatchComplexCollectionPropertyCount() throws Exception {
+    final String uri = "ESMixPrimCollComp(7)/CollPropertyComp/$count";
+    final CountComplexCollectionProcessor processor = 
mock(CountComplexCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).countComplexCollection(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.DELETE, uri, processor);
+  }
+
+  @Test
+  public void dispatchReference() throws Exception {
+    final String uri = "ESAllPrim(0)/NavPropertyETTwoPrimOne/$ref";
+    final String uriMany = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref";
+    final ReferenceProcessor processor = mock(ReferenceProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readReference(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PATCH, uri, processor);
+    verify(processor).updateReference(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.PUT, uri, processor);
+    verify(processor, times(2)).updateReference(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.POST, uri, processor);
+
+    dispatch(HttpMethod.POST, uriMany, processor);
+    verify(processor).createReference(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatch(HttpMethod.DELETE, uriMany, "$id=ESTwoPrim(1)", null, null, 
processor);
+    verify(processor).deleteReference(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class));
+  }
+
+  @Test
+  public void dispatchReferenceCollection() throws Exception {
+    final String uri = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref";
+    final ReferenceCollectionProcessor processor = 
mock(ReferenceCollectionProcessor.class);
+
+    dispatch(HttpMethod.GET, uri, processor);
+    verify(processor).readReferenceCollection(any(ODataRequest.class), 
any(ODataResponse.class), any(UriInfo.class),
+        any(ContentType.class));
+
+    dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor);
+    dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor);
+  }
+
+  @Test
+  public void noRequestContentType() throws Exception {
+    EntityProcessor processor = mock(EntityProcessor.class);
+    final ODataResponse response = dispatch(HttpMethod.POST, "ESAllPrim", null,
+        HttpHeader.CONTENT_TYPE, null, processor);
+    verifyZeroInteractions(processor);
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void illegalRequestContentType() throws Exception {
+    EntityProcessor processor = mock(EntityProcessor.class);
+    final ODataResponse response = dispatch(HttpMethod.POST, "ESAllPrim", null,
+        HttpHeader.CONTENT_TYPE, "*/*", processor);
+    verifyZeroInteractions(processor);
+    assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), 
response.getStatusCode());
+  }
+
+  @Test
+  public void unsupportedRequestContentType() throws Exception {
+    EntityProcessor processor = mock(EntityProcessor.class);
+    ErrorProcessor errorProcessor = mock(ErrorProcessor.class);
+    dispatch(HttpMethod.POST, "ESAllPrim", null, HttpHeader.CONTENT_TYPE, 
"some/unsupported", errorProcessor);
+    verifyZeroInteractions(processor);
+    verify(errorProcessor).processError(any(ODataRequest.class), 
any(ODataResponse.class),
+        any(ODataServerError.class),
+        any(ContentType.class));
+  }
+
+  private ODataResponse dispatch(final HttpMethod method, final String path, 
final String query,
+      final String headerName, final String headerValue, final Processor 
processor) {
+    ODataRequest request = new ODataRequest();
+    request.setMethod(method);
+    request.setRawBaseUri(BASE_URI);
+    if (path.isEmpty()) {
+      request.setRawRequestUri(BASE_URI);
+    }
+    request.setRawODataPath(path);
+    request.setRawQueryPath(query);
+
+    if (headerName != null) {
+      request.addHeader(headerName, Collections.singletonList(headerValue));
+    }
+
+    if (headerName != HttpHeader.CONTENT_TYPE) {
+      request.addHeader(HttpHeader.CONTENT_TYPE, Collections.singletonList(
+          ContentType.JSON.toContentTypeString()));
+    }
+
+    final OData odata = OData.newInstance();
+    final ServiceMetadata metadata = odata.createServiceMetadata(
+        new EdmTechProvider(), Collections.<EdmxReference> emptyList());
+
+    ODataHandlerImpl handler = new ODataHandlerImpl(odata, metadata, new 
ServerCoreDebugger(odata));
+
+    if (processor != null) {
+      handler.register(processor);
+    }
+
+    final ODataResponse response = handler.process(request);
+    assertNotNull(response);
+    return response;
+  }
+
+  private ODataResponse dispatch(final HttpMethod method, final String path, 
final Processor processor) {
+    return dispatch(method, path, null, null, null, processor);
+  }
+
+  private void dispatchMethodNotAllowed(final HttpMethod method, final String 
path, final Processor processor) {
+    final ODataResponse response = dispatch(method, path, processor);
+    assertEquals(HttpStatusCode.METHOD_NOT_ALLOWED.getStatusCode(), 
response.getStatusCode());
+    assertNotNull(response.getContent());
+  }
+  
+  private void dispatchMethodWithError(final HttpMethod method, final String 
path, final Processor processor, 
+      final HttpStatusCode statusCode) {
+    final ODataResponse response = dispatch(method, path, processor);
+    assertEquals(statusCode.getStatusCode(), response.getStatusCode());
+    assertNotNull(response.getContent());
+  }
+}

Reply via email to