[OLINGO-1201] Enhancements to run better with Netty

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

Branch: refs/heads/master
Commit: 03ab69c498d08b09fda466ed46ee2e1c20e96253
Parents: 5e21bb2
Author: ramya vasanth <ramya.vasa...@sap.com>
Authored: Tue Nov 14 09:40:23 2017 +0530
Committer: ramya vasanth <ramya.vasa...@sap.com>
Committed: Tue Nov 14 09:40:23 2017 +0530

----------------------------------------------------------------------
 .../olingo/netty/server/api/ODataNetty.java     |   56 +
 .../netty/server/api/ODataNettyHandler.java     |   47 +
 .../server/core/ODataNettyHandlerImpl.java      |  334 +++++
 .../netty/server/core/ODataNettyImpl.java       |  164 +++
 .../server/core/ODataNettyHandlerImplTest.java  |  160 +++
 .../netty/server/core/ODataNettyImplTest.java   |   59 +
 .../server/core/ODataNettyHandlerImplTest.java  | 1259 ++++++++++++++++++
 7 files changed, 2079 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ab69c4/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNetty.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNetty.java
 
b/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNetty.java
new file mode 100644
index 0000000..a61b160
--- /dev/null
+++ 
b/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNetty.java
@@ -0,0 +1,56 @@
+/*
+ * 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.netty.server.api;
+
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ServiceMetadata;
+
+public abstract class ODataNetty extends OData {
+
+  private static final String IMPLEMENTATION = 
"org.apache.olingo.netty.server.core.ODataNettyImpl";
+
+  /**
+   * Use this method to create a new OData instance. Each thread/request 
should keep its own instance.
+   * @return a new OData instance
+   */
+  public static ODataNetty newInstance() {
+    try {
+      final Class<?> clazz = Class.forName(ODataNetty.IMPLEMENTATION);
+
+      
+       /* We explicitly do not use the singleton pattern to keep the server 
state free
+       * and avoid class loading issues also during hot deployment.*/
+       
+      final Object object = clazz.newInstance();
+
+      return (ODataNetty) object;
+
+    } catch (final Exception e) {
+      throw new ODataRuntimeException(e);
+    }
+  }
+  /**
+   * Creates a new ODataNettyHandler for handling OData requests in an HTTP 
context.
+   *
+   * @param serviceMetadata - metadata object required to handle an OData 
request
+   */
+  public abstract ODataNettyHandler createNettyHandler(ServiceMetadata 
serviceMetadata);
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ab69c4/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNettyHandler.java
----------------------------------------------------------------------
diff --git 
a/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNettyHandler.java
 
b/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNettyHandler.java
new file mode 100644
index 0000000..414ba92
--- /dev/null
+++ 
b/lib/server-api/src/main/java/org/apache/olingo/netty/server/api/ODataNettyHandler.java
@@ -0,0 +1,47 @@
+/*
+ * 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.netty.server.api;
+
+import java.util.Map;
+
+import org.apache.olingo.server.api.processor.Processor;
+
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+
+public interface ODataNettyHandler {
+
+  /**
+   * <p>Processes a NettyRequest 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>
+   * @param request - must be a HTTP OData request
+   * @param response - HTTP OData response
+   */
+  void processNettyRequest(HttpRequest request, HttpResponse response, 
Map<String, String> requestParameters);
+  
+  /**
+   * <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);
+  
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ab69c4/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImpl.java
new file mode 100644
index 0000000..add6409
--- /dev/null
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImpl.java
@@ -0,0 +1,334 @@
+/*
+ * 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.netty.server.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channel;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.netty.server.api.ODataNettyHandler;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataContent;
+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.processor.Processor;
+import org.apache.olingo.server.core.ODataExceptionHelper;
+import org.apache.olingo.server.core.ODataHandlerException;
+import org.apache.olingo.server.core.ODataHandlerImpl;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufInputStream;
+import io.netty.buffer.ByteBufOutputStream;
+import io.netty.handler.codec.http.HttpContent;
+import io.netty.handler.codec.http.HttpMessage;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.codec.http.HttpResponseStatus;
+
+public class ODataNettyHandlerImpl implements ODataNettyHandler {
+
+  public static final int COPY_BUFFER_SIZE = 8192;
+
+  private final ODataHandlerImpl handler;
+  private final ServerCoreDebugger debugger;
+  
+  private static final String CONTEXT_PATH = "contextPath";
+  private static final String SPLIT = "split";
+
+  private int split = 0;
+
+  public ODataNettyHandlerImpl(final OData odata, final ServiceMetadata 
serviceMetadata) {
+    debugger = new ServerCoreDebugger(odata);
+    handler = new ODataHandlerImpl(odata, serviceMetadata, debugger);
+  }
+  
+  private ODataResponse handleException(final ODataRequest odRequest, final 
Exception e) {
+    ODataResponse resp = new ODataResponse();
+    ODataServerError serverError;
+    if (e instanceof ODataHandlerException) {
+      serverError = 
ODataExceptionHelper.createServerErrorObject((ODataHandlerException) e, null);
+    } else if (e instanceof ODataLibraryException) {
+      serverError = 
ODataExceptionHelper.createServerErrorObject((ODataLibraryException) e, null);
+    } else {
+      serverError = ODataExceptionHelper.createServerErrorObject(e);
+    }
+    handler.handleException(odRequest, resp, serverError, e);
+    return resp;
+  }
+  
+  /**
+   * Convert the OData Response to Netty Response
+   * @param response
+   * @param odResponse
+   */
+  static void convertToHttp(final HttpResponse response, final ODataResponse 
odResponse) {
+           
response.setStatus(HttpResponseStatus.valueOf(odResponse.getStatusCode()));
+
+           for (Entry<String, List<String>> entry : 
odResponse.getAllHeaders().entrySet()) {
+             for (String headerValue : entry.getValue()) {
+               ((HttpMessage)response).headers().add(entry.getKey(), 
headerValue);
+             }
+           }
+
+           if (odResponse.getContent() != null) {
+             copyContent(odResponse.getContent(), response);
+           } else if (odResponse.getODataContent() != null) {
+             writeContent(odResponse, response);
+           }
+         }
+  
+  /**
+   * Write the odata content to netty response content
+   * @param odataResponse
+   * @param response
+   */
+  static void writeContent(final ODataResponse odataResponse, final 
HttpResponse response) {
+    ODataContent res = odataResponse.getODataContent();
+    res.write(Channels.newChannel(new 
ByteBufOutputStream(((HttpContent)response).content())));
+  }
+  
+  static void copyContent(final InputStream inputStream, final HttpResponse 
response) {
+           copyContent(Channels.newChannel(inputStream), response);
+         }
+
+  /** 
+   * Copy OData content to netty content
+   * @param input
+   * @param response
+   */
+  static void copyContent(final ReadableByteChannel input, final HttpResponse 
response) {
+    WritableByteChannel output = null;
+    try {
+      ByteBuffer inBuffer = ByteBuffer.allocate(COPY_BUFFER_SIZE);
+      output = Channels.newChannel(new 
ByteBufOutputStream(((HttpContent)response).content()));
+      while (input.read(inBuffer) > 0) {
+        inBuffer.flip();
+        output.write(inBuffer);
+        inBuffer.clear();
+      }
+    } catch (IOException e) {
+      throw new ODataRuntimeException("Error on reading request content", e);
+    } finally {
+      closeStream(input);
+      closeStream(output);
+    }
+  }
+
+  private static void closeStream(final Channel closeable) {
+    if (closeable != null) {
+      try {
+        closeable.close();
+      } catch (IOException e) {
+        // ignore
+      }
+    }
+  }
+  
+  /**
+   * Extract the information part of Netty Request and fill OData Request
+   * @param odRequest
+   * @param httpRequest
+   * @param split
+   * @param contextPath
+   * @return
+   * @throws ODataLibraryException
+   */
+  private ODataRequest fillODataRequest(final ODataRequest odRequest, final 
HttpRequest httpRequest,
+             final int split, final String contextPath) throws 
ODataLibraryException {
+           final int requestHandle = 
debugger.startRuntimeMeasurement("ODataHttpHandlerImpl", "fillODataRequest");
+           try {
+               ByteBuf byteBuf = ((HttpContent)httpRequest).content();
+               ByteBufInputStream inputStream = new 
ByteBufInputStream(byteBuf);
+             odRequest.setBody(inputStream);
+             
+             odRequest.setProtocol(httpRequest.protocolVersion().text());
+             odRequest.setMethod(extractMethod(httpRequest));
+             int innerHandle = 
debugger.startRuntimeMeasurement("ODataNettyHandlerImpl", "copyHeaders");
+             copyHeaders(odRequest, httpRequest);
+             debugger.stopRuntimeMeasurement(innerHandle);
+             innerHandle = 
debugger.startRuntimeMeasurement("ODataNettyHandlerImpl", "fillUriInformation");
+             fillUriInformationFromHttpRequest(odRequest, httpRequest, split, 
contextPath);
+             debugger.stopRuntimeMeasurement(innerHandle);
+
+             return odRequest;
+           } finally {
+             debugger.stopRuntimeMeasurement(requestHandle);
+           }
+         }
+  
+  static HttpMethod extractMethod(final HttpRequest httpRequest) throws 
ODataLibraryException {
+    final HttpMethod httpRequestMethod;
+       try {
+             httpRequestMethod = 
HttpMethod.valueOf(httpRequest.method().name());
+           } catch (IllegalArgumentException e) {
+             throw new ODataHandlerException("HTTP method not allowed" + 
+           httpRequest.method().name(), e,
+                 ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, 
+                 httpRequest.method().name());
+           }
+       try {
+             if (httpRequestMethod == HttpMethod.POST) {
+               String xHttpMethod = httpRequest.headers().
+                               get(HttpHeader.X_HTTP_METHOD);
+               String xHttpMethodOverride = httpRequest.headers().
+                               get(HttpHeader.X_HTTP_METHOD_OVERRIDE);
+
+               if (xHttpMethod == null && xHttpMethodOverride == null) {
+                 return httpRequestMethod;
+               } else if (xHttpMethod == null) {
+                 return HttpMethod.valueOf(xHttpMethodOverride);
+               } else if (xHttpMethodOverride == null) {
+                 return HttpMethod.valueOf(xHttpMethod);
+               } else {
+                 if (!xHttpMethod.equalsIgnoreCase(xHttpMethodOverride)) {
+                   throw new ODataHandlerException("Ambiguous X-HTTP-Methods",
+                       
ODataHandlerException.MessageKeys.AMBIGUOUS_XHTTP_METHOD, xHttpMethod, 
xHttpMethodOverride);
+                 }
+                 return HttpMethod.valueOf(xHttpMethod);
+               }
+             } else {
+               return httpRequestMethod;
+             }
+           } catch (IllegalArgumentException e) {
+             throw new ODataHandlerException("Invalid HTTP method" + 
+           httpRequest.method().name(), e,
+                 ODataHandlerException.MessageKeys.INVALID_HTTP_METHOD, 
+                 httpRequest.method().name());
+           }
+  }
+
+  /**
+   * Fetch the uri information parsing netty request url
+   * @param odRequest
+   * @param httpRequest
+   * @param split
+   * @param contextPath
+   */
+  static void fillUriInformationFromHttpRequest(final ODataRequest odRequest, 
final HttpRequest httpRequest, 
+                 final int split, final String contextPath) {
+           String rawRequestUri = httpRequest.uri();
+           if (rawRequestUri.indexOf("?") != -1) {
+               rawRequestUri = rawRequestUri.substring(0, 
rawRequestUri.indexOf("?"));
+           }
+
+           String rawODataPath;
+           if (!"".equals(contextPath)) {
+             int beginIndex = rawRequestUri.indexOf(contextPath) + 
contextPath.length();
+             rawODataPath = rawRequestUri.substring(beginIndex);
+           } else {
+             rawODataPath = rawRequestUri;
+           }
+
+           String rawServiceResolutionUri = null;
+           if (split > 0) {
+             rawServiceResolutionUri = rawODataPath;
+             for (int i = 0; i < split; i++) {
+               int index = rawODataPath.indexOf('/', 1);
+               if (-1 == index) {
+                 rawODataPath = "";
+                 break;
+               } else {
+                 rawODataPath = rawODataPath.substring(index);
+               }
+             }
+             int end = rawServiceResolutionUri.length() - 
rawODataPath.length();
+             rawServiceResolutionUri = rawServiceResolutionUri.substring(0, 
end);
+           }
+
+           String rawBaseUri = rawRequestUri.substring(0, 
rawRequestUri.length() - rawODataPath.length());
+
+           int index = httpRequest.uri().indexOf('?');
+           String queryString = null;
+        if (index != -1) {
+            queryString = httpRequest.uri().substring(index + 1);
+        }
+           odRequest.setRawQueryPath(queryString);
+           odRequest.setRawRequestUri(rawRequestUri
+                   + (queryString == null ? "" : "?" + queryString));
+           odRequest.setRawODataPath(rawODataPath);
+           odRequest.setRawBaseUri(rawBaseUri);
+           odRequest.setRawServiceResolutionUri(rawServiceResolutionUri);
+         }
+
+  /**
+   * Copy the headers part of Netty Request to OData Request
+   * @param odRequest
+   * @param req
+   */
+  static void copyHeaders(ODataRequest odRequest, final HttpRequest req) {
+         final Set<String> headers = req.headers().names();
+         Iterator<String> headerNames = headers.iterator();
+         while (headerNames.hasNext()) {
+                 final String headerName = headerNames.next();
+                 final List<String> headerValues = 
req.headers().getAll(headerName);
+             odRequest.addHeader(headerName, headerValues);
+         }
+  }
+  
+@SuppressWarnings("unused")
+@Override
+public void processNettyRequest(HttpRequest request, HttpResponse response, 
+               Map<String, String> requestParameters) {
+         ODataRequest odRequest = new ODataRequest();
+    Exception exception = null;
+    ODataResponse odResponse;
+    
+    final int processMethodHandle = 
+               debugger.startRuntimeMeasurement("ODataNettyHandlerImpl", 
"process");
+    try {
+      fillODataRequest(odRequest, request, 
+          requestParameters.get(SPLIT) != null? 
Integer.parseInt(requestParameters.get(SPLIT)) : split, 
+              requestParameters.get(CONTEXT_PATH));
+
+      odResponse = process(odRequest);
+      // ALL future methods after process must not throw exceptions!
+    } catch (Exception e) {
+      exception = e;
+      odResponse = handleException(odRequest, e);
+    }
+    debugger.stopRuntimeMeasurement(processMethodHandle);
+
+    convertToHttp(response, odResponse);
+  }
+
+  public ODataResponse process(ODataRequest request) {
+    return handler.process(request);
+  }
+
+  @Override
+  public void register(Processor processor) {
+    handler.register(processor);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ab69c4/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyImpl.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyImpl.java
 
b/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyImpl.java
new file mode 100644
index 0000000..113eb03
--- /dev/null
+++ 
b/lib/server-core/src/main/java/org/apache/olingo/netty/server/core/ODataNettyImpl.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.netty.server.core;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
+import org.apache.olingo.commons.api.edmx.EdmxReference;
+import org.apache.olingo.commons.api.ex.ODataRuntimeException;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.netty.server.api.ODataNetty;
+import org.apache.olingo.netty.server.api.ODataNettyHandler;
+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;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
+import org.apache.olingo.server.api.etag.ETagHelper;
+import org.apache.olingo.server.api.etag.ServiceMetadataETagSupport;
+import org.apache.olingo.server.api.prefer.Preferences;
+import org.apache.olingo.server.api.serializer.EdmAssistedSerializer;
+import org.apache.olingo.server.api.serializer.EdmDeltaSerializer;
+import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.uri.UriHelper;
+
+public class ODataNettyImpl extends ODataNetty {
+  
+  private static OData odata;
+  private static final String IMPLEMENTATION = 
"org.apache.olingo.server.core.ODataImpl";
+
+  static {
+    try {
+      final Class<?> clazz = Class.forName(IMPLEMENTATION);
+
+      /*
+       * We explicitly do not use the singleton pattern to keep the server 
state free
+       * and avoid class loading issues also during hot deployment.
+       */
+      final Object object = clazz.newInstance();
+      odata = (OData) object;
+    } catch (Exception e) {
+      throw new ODataRuntimeException(e);
+    }
+  }
+  
+  @Override
+  public ODataNettyHandler createNettyHandler(ServiceMetadata serviceMetadata) 
{
+    return new ODataNettyHandlerImpl(this, serviceMetadata);
+  }
+
+  @Override
+  public ODataSerializer createSerializer(ContentType contentType) throws 
SerializerException {
+    return odata.createSerializer(contentType);
+  }
+  
+  @Override
+  public ODataSerializer createSerializer(final ContentType contentType, 
+      final List<String> versions) throws SerializerException {
+    return odata.createSerializer(contentType, versions);
+  }
+
+  @Override
+  public FixedFormatSerializer createFixedFormatSerializer() {
+    return odata.createFixedFormatSerializer();
+  }
+
+  @Override
+  public FixedFormatDeserializer createFixedFormatDeserializer() {
+    return odata.createFixedFormatDeserializer();
+  }
+
+  @Override
+  public ODataHttpHandler createHandler(ServiceMetadata serviceMetadata) {
+    return odata.createHandler(serviceMetadata);
+  }
+
+  @Override
+  public ODataHandler createRawHandler(ServiceMetadata serviceMetadata) {
+    return odata.createRawHandler(serviceMetadata);
+  }
+
+  @Override
+  public ServiceMetadata createServiceMetadata(CsdlEdmProvider edmProvider, 
List<EdmxReference> references) {
+    return odata.createServiceMetadata(edmProvider, references);
+  }
+
+  @Override
+  public ServiceMetadata createServiceMetadata(CsdlEdmProvider edmProvider, 
List<EdmxReference> references,
+      ServiceMetadataETagSupport serviceMetadataETagSupport) {
+    return odata.createServiceMetadata(edmProvider, references, 
serviceMetadataETagSupport);
+  }
+
+  @Override
+  public UriHelper createUriHelper() {
+    return odata.createUriHelper();
+  }
+
+  @Override
+  public ODataDeserializer createDeserializer(ContentType contentType) throws 
DeserializerException {
+    return odata.createDeserializer(contentType);
+  }
+
+  @Override
+  public ODataDeserializer createDeserializer(ContentType contentType, 
ServiceMetadata metadata)
+      throws DeserializerException {
+    return odata.createDeserializer(contentType);
+  }
+
+  @Override
+  public EdmPrimitiveType createPrimitiveTypeInstance(EdmPrimitiveTypeKind 
kind) {
+    return odata.createPrimitiveTypeInstance(kind);
+  }
+
+  @Override
+  public ETagHelper createETagHelper() {
+    return odata.createETagHelper();
+  }
+
+  @Override
+  public Preferences createPreferences(Collection<String> preferHeaders) {
+    return odata.createPreferences(preferHeaders);
+  }
+
+  @Override
+  public DebugResponseHelper createDebugResponseHelper(String debugFormat) {
+    return odata.createDebugResponseHelper(debugFormat);
+  }
+
+  @Override
+  public EdmAssistedSerializer createEdmAssistedSerializer(ContentType 
contentType) throws SerializerException {
+    return odata.createEdmAssistedSerializer(contentType);
+  }
+
+  @Override
+  public EdmDeltaSerializer createEdmDeltaSerializer(ContentType contentType, 
List<String> versions)
+      throws SerializerException {
+    return odata.createEdmDeltaSerializer(contentType, versions);
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ab69c4/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImplTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImplTest.java
 
b/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImplTest.java
new file mode 100644
index 0000000..7a1a01a
--- /dev/null
+++ 
b/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyHandlerImplTest.java
@@ -0,0 +1,160 @@
+/*
+ * 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.netty.server.core;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.ODataLibraryException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.junit.Test;
+
+import io.netty.handler.codec.http.HttpHeaders;
+import io.netty.handler.codec.http.HttpRequest;
+
+public class ODataNettyHandlerImplTest {
+
+  @Test
+  public void extractMethodForNettyRequest() throws Exception {
+    String[][] mm = {
+        { "GET", null, null, "GET" },
+        { "GET", "xxx", "yyy", "GET" },
+        { "PUT", "xxx", "yyy", "PUT" },
+        { "DELETE", "xxx", "yyy", "DELETE" },
+        { "PATCH", "xxx", "yyy", "PATCH" },
+
+        { "POST", null, null, "POST" },
+        { "POST", null, "GET", "GET" },
+        { "POST", null, "PATCH", "PATCH" },
+
+        { "POST", "GET", null, "GET" },
+        { "POST", "PATCH", null, "PATCH" },
+
+        { "POST", "GET", "GET", "GET" },
+        { "HEAD", null, null, "HEAD" }
+    };
+
+    for (String[] m : mm) {
+
+      HttpRequest hr = mock(HttpRequest.class);
+      io.netty.handler.codec.http.HttpMethod hm = 
mock(io.netty.handler.codec.http.HttpMethod.class);
+      when(hr.method()).thenReturn(hm);
+      when(hm.name()).thenReturn(m[0]);
+      HttpHeaders hh = mock(HttpHeaders.class);
+      when(hr.headers()).thenReturn(hh);
+      when(hh.get("X-HTTP-Method")).thenReturn(m[1]);
+      when(hh.get("X-HTTP-Method-Override")).thenReturn(m[2]);
+
+      assertEquals(HttpMethod.valueOf(m[3]), 
ODataNettyHandlerImpl.extractMethod(hr));
+    }
+  }
+  
+  @Test
+  public void extractMethodFailForNettyRequest() throws Exception {
+    String[][] mm = {
+        { "POST", "bla", null },
+        { "POST", "PUT", "PATCH" },
+        { "OPTIONS", null, null }
+    };
+
+    for (String[] m : mm) {
+
+      HttpRequest hr = mock(HttpRequest.class);
+      io.netty.handler.codec.http.HttpMethod hm = 
mock(io.netty.handler.codec.http.HttpMethod.class);
+      when(hr.method()).thenReturn(hm);
+
+      when(hm.name()).thenReturn(m[0]);
+      HttpHeaders hh = mock(HttpHeaders.class);
+      when(hr.headers()).thenReturn(hh);
+      when(hh.get("X-HTTP-Method")).thenReturn(m[1]);
+      when(hh.get("X-HTTP-Method-Override")).thenReturn(m[2]);
+
+      try {
+        ODataNettyHandlerImpl.extractMethod(hr);
+        fail();
+      } catch (ODataLibraryException e) {
+        // expected
+      }
+    }
+  }
+  
+  @Test
+  public void extractUriForNettyRequests() {
+
+    //@formatter:off (Eclipse formatter)
+    //CHECKSTYLE:OFF (Maven checkstyle)
+    String [][] uris = {
+        /* 0: cp         1: sr          2: od       3: qp        4: spl  */
+        {  "",           "",          "",          "",         "0"},
+        {  "",           "",          "/",         "",         "0"},
+        {  "",           "",          "/od",       "",         "0"},
+        {  "",           "",          "/od/",      "",         "0"},
+
+        {  "/cp",        "",          "",          "",         "0"},
+        {  "/cp",        "",          "/",         "",         "0"},
+        {  "/cp",        "",          "/od",       "",         "0"},
+        {  "",           "/sr",       "",          "",         "1"},
+        {  "",           "/sr",       "/",         "",         "1"},
+        {  "",           "/sr",       "/od",       "",         "1"},
+        {  "",           "/sr/sr",    "",          "",         "2"},
+        {  "",           "/sr/sr",    "/",         "",         "2"},
+        {  "",           "/sr/sr",    "/od",       "",         "2"},
+
+        {  "/cp",        "/sr",       "/",         "",         "1"},
+        {  "/cp",        "/sr",       "/od",       "",         "1"},
+        
+        {  "",           "",          "",          "qp",       "0"},
+        {  "",           "",          "/",         "qp",       "0"},
+        {  "/cp",        "/sr",       "/od",       "qp",       "1"},
+
+        {  "/c%20p",     "/s%20r",    "/o%20d",    "p+q",      "1"},
+    };
+    //@formatter:on
+    // CHECKSTYLE:on
+
+    for (String[] p : uris) {
+      HttpRequest hr = mock(HttpRequest.class);
+
+      String requestUrl = p[0] + p[1] + p[2];
+      if (!p[3].equals("") || p[3].length() > 0) {
+         requestUrl += "?$" + p[3];
+      }
+
+      when(hr.uri()).thenReturn(requestUrl);
+      
+      ODataRequest odr = new ODataRequest();
+      ODataNettyHandlerImpl.fillUriInformationFromHttpRequest(odr, hr, 
Integer.parseInt(p[4]), p[0]);
+
+      String rawBaseUri = p[0] + p[1];
+      String rawODataPath = p[2];
+      String rawQueryPath = "".equals(p[3]) ? null : "$" + p[3];
+      String rawRequestUri = p[0] + p[1] + p[2] + ("".equals(p[3]) ? "" : "?$" 
+ p[3]);
+      String rawServiceResolutionUri = "".equals(p[1]) ? null : p[1];
+
+      assertEquals(rawBaseUri, odr.getRawBaseUri());
+      assertEquals(rawODataPath, odr.getRawODataPath());
+      assertEquals(rawQueryPath, odr.getRawQueryPath());
+      assertEquals(rawRequestUri, odr.getRawRequestUri());
+      assertEquals(rawServiceResolutionUri, odr.getRawServiceResolutionUri());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ab69c4/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyImplTest.java
----------------------------------------------------------------------
diff --git 
a/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyImplTest.java
 
b/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyImplTest.java
new file mode 100644
index 0000000..e71ffbd
--- /dev/null
+++ 
b/lib/server-core/src/test/java/org/apache/olingo/netty/server/core/ODataNettyImplTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.netty.server.core;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.netty.server.api.ODataNetty;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.junit.Test;
+
+public class ODataNettyImplTest {
+
+  private final ODataNetty odata = ODataNetty.newInstance();
+
+  @Test
+  public void serializerSupportedFormats() throws SerializerException {
+    assertNotNull(odata.createSerializer(ContentType.JSON_NO_METADATA));
+    assertNotNull(odata.createSerializer(ContentType.JSON));
+    assertNotNull(odata.createSerializer(ContentType.APPLICATION_JSON));
+    assertNotNull(odata.createSerializer(ContentType.JSON_FULL_METADATA));
+    
+  }
+
+  @Test
+  public void deserializerSupportedFormats() throws DeserializerException {
+    assertNotNull(odata.createDeserializer(ContentType.JSON_NO_METADATA));
+    assertNotNull(odata.createDeserializer(ContentType.JSON));
+    assertNotNull(odata.createDeserializer(ContentType.JSON_FULL_METADATA));
+    assertNotNull(odata.createDeserializer(ContentType.APPLICATION_JSON));
+  }
+
+  @Test
+  public void serializerFixedFormat() throws DeserializerException {
+    assertNotNull(odata.createFixedFormatSerializer());
+  }
+  
+  @Test
+  public void deserializerFixedFormat() throws DeserializerException {
+    assertNotNull(odata.createFixedFormatDeserializer());
+  }
+}

Reply via email to