You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2015/06/21 16:58:27 UTC
olingo-odata2 git commit: [OLINGO-709] Support injection of
ODataServiceFactory instance
Repository: olingo-odata2
Updated Branches:
refs/heads/OLINGO-709-InjectODataServiceFactory [created] f1ca1a204
[OLINGO-709] Support injection of ODataServiceFactory instance
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/f1ca1a20
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/f1ca1a20
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/f1ca1a20
Branch: refs/heads/OLINGO-709-InjectODataServiceFactory
Commit: f1ca1a20492c4a6d2e74bda0c1a21d0996a24c32
Parents: 5fc3ed2
Author: mibo <mi...@mirb.de>
Authored: Sun Jun 21 16:26:55 2015 +0200
Committer: mibo <mi...@mirb.de>
Committed: Sun Jun 21 16:57:24 2015 +0200
----------------------------------------------------------------------
.../olingo/odata2/api/ODataServiceFactory.java | 5 +
.../core/servlet/AbstractODataServlet.java | 350 +++++++++++++++++++
.../odata2/core/servlet/ODataServlet.java | 287 +--------------
.../olingo/odata2/core/servlet/RestUtil.java | 5 +-
.../core/servlet/AbstractODataServletTest.java | 280 +++++++++++++++
.../odata2/core/servlet/ODataServletTest.java | 58 +--
6 files changed, 682 insertions(+), 303 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f1ca1a20/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ODataServiceFactory.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ODataServiceFactory.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ODataServiceFactory.java
index 7b6f7a3..4b408c5 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ODataServiceFactory.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/ODataServiceFactory.java
@@ -42,6 +42,11 @@ public abstract class ODataServiceFactory {
public static final String FACTORY_CLASSLOADER_LABEL = "org.apache.olingo.odata2.service.factory.classloader";
/**
+ * Label used in web.xml to assign servlet init parameter to factory class instance.
+ */
+ public static final String FACTORY_INSTANCE_LABEL = "org.apache.olingo.odata2.service.factory.instance";
+
+ /**
* Label used in web.xml to assign servlet init parameter for a path split (service resolution).
*/
public static final String PATH_SPLIT_LABEL = "org.apache.olingo.odata2.path.split";
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f1ca1a20/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/AbstractODataServlet.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/AbstractODataServlet.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/AbstractODataServlet.java
new file mode 100644
index 0000000..2fc6972
--- /dev/null
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/AbstractODataServlet.java
@@ -0,0 +1,350 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.servlet;
+
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.ODataServiceFactory;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
+import org.apache.olingo.odata2.api.exception.MessageReference;
+import org.apache.olingo.odata2.api.exception.ODataBadRequestException;
+import org.apache.olingo.odata2.api.exception.ODataHttpException;
+import org.apache.olingo.odata2.api.exception.ODataInternalServerErrorException;
+import org.apache.olingo.odata2.api.exception.ODataMethodNotAllowedException;
+import org.apache.olingo.odata2.api.exception.ODataNotAcceptableException;
+import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.core.ODataContextImpl;
+import org.apache.olingo.odata2.core.ODataRequestHandler;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.InputStream;
+
+public abstract class AbstractODataServlet extends HttpServlet {
+
+ private static final String HTTP_METHOD_OPTIONS = "OPTIONS";
+ private static final String HTTP_METHOD_HEAD = "HEAD";
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Get the service factory instance which is used for creation of the
+ * <code>ODataService</code> which handles the processing of the request.
+ *
+ * @param request the http request which is processed as an OData request
+ * @return an instance of an ODataServiceFactory
+ */
+ protected abstract ODataServiceFactory getServiceFactory(HttpServletRequest request);
+
+ @Override
+ protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
+ // We have to create the Service Factory here because otherwise we do not have access to the error callback
+ ODataServiceFactory serviceFactory = getServiceFactory(req);
+ if(serviceFactory == null) {
+ throw new ODataRuntimeException("Unable to get Service Factory. Check either '" +
+ ODataServiceFactory.FACTORY_LABEL + "' or '" + ODataServiceFactory.FACTORY_INSTANCE_LABEL + "' config.");
+ }
+
+ String xHttpMethod = req.getHeader("X-HTTP-Method");
+ String xHttpMethodOverride = req.getHeader("X-HTTP-Method-Override");
+ if (xHttpMethod != null && xHttpMethodOverride != null) {
+ if (!xHttpMethod.equalsIgnoreCase(xHttpMethodOverride)) {
+ ODataExceptionWrapper wrapper = new ODataExceptionWrapper(req, serviceFactory);
+ createResponse(resp, wrapper.wrapInExceptionResponse(
+ new ODataBadRequestException(ODataBadRequestException.AMBIGUOUS_XMETHOD)));
+ }
+ }
+
+ if (req.getPathInfo() != null) {
+ handle(req, resp, xHttpMethod, xHttpMethodOverride, serviceFactory);
+ } else {
+ handleRedirect(req, resp, serviceFactory);
+ }
+ }
+
+
+ protected void handle(final HttpServletRequest req, final HttpServletResponse resp, final String xHttpMethod,
+ final String xHttpMethodOverride, ODataServiceFactory serviceFactory) throws IOException {
+ String method = req.getMethod();
+ if (ODataHttpMethod.GET.name().equals(method)) {
+ handleRequest(req, ODataHttpMethod.GET, resp, serviceFactory);
+ } else if (ODataHttpMethod.POST.name().equals(method)) {
+ if (xHttpMethod == null && xHttpMethodOverride == null) {
+ handleRequest(req, ODataHttpMethod.POST, resp, serviceFactory);
+ } else if (xHttpMethod == null) {
+ /* tunneling */
+ boolean methodHandled = handleHttpTunneling(req, resp, xHttpMethodOverride, serviceFactory);
+ if (!methodHandled) {
+ createMethodNotAllowedResponse(req, ODataHttpException.COMMON, resp, serviceFactory);
+ }
+ } else {
+ /* tunneling */
+ boolean methodHandled = handleHttpTunneling(req, resp, xHttpMethod, serviceFactory);
+ if (!methodHandled) {
+ createNotImplementedResponse(req, ODataNotImplementedException.TUNNELING, resp, serviceFactory);
+ }
+ }
+
+ } else if (ODataHttpMethod.PUT.name().equals(method)) {
+ handleRequest(req, ODataHttpMethod.PUT, resp, serviceFactory);
+ } else if (ODataHttpMethod.DELETE.name().equals(method)) {
+ handleRequest(req, ODataHttpMethod.DELETE, resp, serviceFactory);
+ } else if (ODataHttpMethod.PATCH.name().equals(method)) {
+ handleRequest(req, ODataHttpMethod.PATCH, resp, serviceFactory);
+ } else if (ODataHttpMethod.MERGE.name().equals(method)) {
+ handleRequest(req, ODataHttpMethod.MERGE, resp, serviceFactory);
+ } else if (HTTP_METHOD_HEAD.equals(method) || HTTP_METHOD_OPTIONS.equals(method)) {
+ createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp, serviceFactory);
+ } else {
+ createNotImplementedResponse(req, ODataHttpException.COMMON, resp, serviceFactory);
+ }
+ }
+
+ private boolean handleHttpTunneling(final HttpServletRequest req, final HttpServletResponse resp,
+ final String xHttpMethod, ODataServiceFactory serviceFactory) throws IOException {
+ if (ODataHttpMethod.MERGE.name().equals(xHttpMethod)) {
+ handleRequest(req, ODataHttpMethod.MERGE, resp, serviceFactory);
+ } else if (ODataHttpMethod.PATCH.name().equals(xHttpMethod)) {
+ handleRequest(req, ODataHttpMethod.PATCH, resp, serviceFactory);
+ } else if (ODataHttpMethod.DELETE.name().equals(xHttpMethod)) {
+ handleRequest(req, ODataHttpMethod.DELETE, resp, serviceFactory);
+ } else if (ODataHttpMethod.PUT.name().equals(xHttpMethod)) {
+ handleRequest(req, ODataHttpMethod.PUT, resp, serviceFactory);
+ } else if (ODataHttpMethod.GET.name().equals(xHttpMethod)) {
+ handleRequest(req, ODataHttpMethod.GET, resp, serviceFactory);
+ } else if (ODataHttpMethod.POST.name().equals(xHttpMethod)) {
+ handleRequest(req, ODataHttpMethod.POST, resp, serviceFactory);
+ } else if (HTTP_METHOD_HEAD.equals(xHttpMethod) || HTTP_METHOD_OPTIONS.equals(xHttpMethod)) {
+ createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp, serviceFactory);
+ } else {
+ createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp, serviceFactory);
+ }
+ return true;
+ }
+
+ private void
+ handleRequest(final HttpServletRequest req, final ODataHttpMethod method, final HttpServletResponse resp,
+ ODataServiceFactory serviceFactory)
+ throws IOException {
+ try {
+ final String pathSplitAsString = getInitParameter(ODataServiceFactory.PATH_SPLIT_LABEL);
+ int pathSplit = 0;
+ if (pathSplitAsString != null) {
+ pathSplit = Integer.parseInt(pathSplitAsString);
+ }
+ if (req.getHeader(HttpHeaders.ACCEPT) != null && req.getHeader(HttpHeaders.ACCEPT).isEmpty()) {
+ createNotAcceptableResponse(req, ODataNotAcceptableException.COMMON, resp, serviceFactory);
+ }
+ ODataRequest odataRequest = ODataRequest.method(method)
+ .contentType(RestUtil.extractRequestContentType(req.getContentType()).toContentTypeString())
+ .acceptHeaders(RestUtil.extractAcceptHeaders(req.getHeader(HttpHeaders.ACCEPT)))
+ .acceptableLanguages(RestUtil.extractAcceptableLanguage(req.getHeader(HttpHeaders.ACCEPT_LANGUAGE)))
+ .pathInfo(RestUtil.buildODataPathInfo(req, pathSplit))
+ .allQueryParameters(RestUtil.extractAllQueryParameters(req.getQueryString()))
+ .requestHeaders(RestUtil.extractHeaders(req))
+ .body(req.getInputStream())
+ .build();
+
+ ODataContextImpl context = new ODataContextImpl(odataRequest, serviceFactory);
+ context.setParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT, req);
+
+ ODataService service = serviceFactory.createService(context);
+ if (service == null) {
+ createServiceUnavailableResponse(req, ODataInternalServerErrorException.NOSERVICE, resp, serviceFactory);
+ } else {
+ context.setService(service);
+ service.getProcessor().setContext(context);
+
+ ODataRequestHandler requestHandler = new ODataRequestHandler(serviceFactory, service, context);
+ final ODataResponse odataResponse = requestHandler.handle(odataRequest);
+ createResponse(resp, odataResponse);
+ }
+ } catch (Exception e) {
+ ODataExceptionWrapper wrapper = new ODataExceptionWrapper(req, serviceFactory);
+ createResponse(resp, wrapper.wrapInExceptionResponse(e));
+ }
+ }
+
+ protected void handleRedirect(final HttpServletRequest req, final HttpServletResponse resp,
+ ODataServiceFactory serviceFactory) throws IOException {
+ String method = req.getMethod();
+ if (ODataHttpMethod.GET.name().equals(method) ||
+ ODataHttpMethod.POST.name().equals(method) ||
+ ODataHttpMethod.PUT.name().equals(method) ||
+ ODataHttpMethod.DELETE.name().equals(method) ||
+ ODataHttpMethod.PATCH.name().equals(method) ||
+ ODataHttpMethod.MERGE.name().equals(method) ||
+ HTTP_METHOD_HEAD.equals(method) ||
+ HTTP_METHOD_OPTIONS.equals(method)) {
+ ODataResponse odataResponse = ODataResponse.status(HttpStatusCodes.TEMPORARY_REDIRECT)
+ .header(HttpHeaders.LOCATION, createLocation(req))
+ .build();
+ createResponse(resp, odataResponse);
+ } else {
+ createNotImplementedResponse(req, ODataHttpException.COMMON, resp, serviceFactory);
+ }
+
+ }
+
+ private String createLocation(final HttpServletRequest req) {
+ StringBuilder location = new StringBuilder();
+ String contextPath = req.getContextPath();
+ if (contextPath != null) {
+ location.append(contextPath);
+ }
+ String servletPath = req.getServletPath();
+ if (servletPath != null) {
+ location.append(servletPath);
+ }
+ location.append("/");
+ return location.toString();
+ }
+
+ protected void createResponse(final HttpServletResponse resp, final ODataResponse response) throws IOException {
+ resp.setStatus(response.getStatus().getStatusCode());
+ resp.setContentType(response.getContentHeader());
+ for (String headerName : response.getHeaderNames()) {
+ resp.setHeader(headerName, response.getHeader(headerName));
+ }
+
+ Object entity = response.getEntity();
+ if (entity != null) {
+ ServletOutputStream out = resp.getOutputStream();
+ int curByte;
+ int contentLength = 0;
+
+ if (entity instanceof InputStream) {
+ while ((curByte = ((InputStream) entity).read()) != -1) {
+ contentLength++;
+ out.write((char) curByte);
+ }
+ ((InputStream) entity).close();
+ } else if (entity instanceof String) {
+ String body = (String) entity;
+ final byte[] entityBytes = body.getBytes("utf-8");
+ out.write(entityBytes);
+ contentLength = entityBytes.length;
+ }
+
+ if (response.getHeader(HttpHeaders.CONTENT_LENGTH) != null) {
+ // Override content length
+ try {
+ contentLength = Integer.parseInt(response.getHeader(HttpHeaders.CONTENT_LENGTH));
+ } catch (NumberFormatException e) {
+ // Ignore
+ }
+ }
+
+ resp.setContentLength(contentLength);
+ out.flush();
+ out.close();
+ }
+ }
+
+ private void createNotImplementedResponse(final HttpServletRequest req, final MessageReference messageReference,
+ final HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
+ // RFC 2616, 5.1.1: "An origin server SHOULD return the status code [...]
+ // 501 (Not Implemented) if the method is unrecognized [...] by the origin server."
+ ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
+ ODataResponse response =
+ exceptionWrapper.wrapInExceptionResponse(new ODataNotImplementedException(messageReference));
+// resp.setStatus(HttpStatusCodes.NOT_IMPLEMENTED.getStatusCode());
+ createResponse(resp, response);
+ }
+
+ private void createMethodNotAllowedResponse(final HttpServletRequest req, final MessageReference messageReference,
+ final HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
+ ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
+ ODataResponse response =
+ exceptionWrapper.wrapInExceptionResponse(new ODataMethodNotAllowedException(messageReference));
+ createResponse(resp, response);
+ }
+
+ private void createNotAcceptableResponse(final HttpServletRequest req, final MessageReference messageReference,
+ final HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
+ ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
+ ODataResponse response =
+ exceptionWrapper.wrapInExceptionResponse(new ODataNotAcceptableException(messageReference));
+ createResponse(resp, response);
+ }
+
+ private void createServiceUnavailableResponse(HttpServletRequest req, MessageReference messageReference,
+ HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
+ ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
+ ODataResponse response =
+ exceptionWrapper.wrapInExceptionResponse(new ODataInternalServerErrorException(messageReference));
+ createResponse(resp, response);
+ }
+
+ /**
+ * Create an instance of a ODataServiceFactory via factory class
+ * from servlet init parameter ODataServiceFactory.FACTORY_LABEL
+ * and ODataServiceFactory.FACTORY_CLASSLOADER_LABEL (if set).
+ *
+ * @see ODataServiceFactory#FACTORY_LABEL
+ * @see ODataServiceFactory#FACTORY_CLASSLOADER_LABEL
+ *
+ * @param req http servlet request
+ * @return instance of a ODataServiceFactory
+ */
+ protected ODataServiceFactory createODataServiceFactory(HttpServletRequest req)
+ throws InstantiationException, IllegalAccessException, ClassNotFoundException {
+ final String factoryClassName = getInitParameter(ODataServiceFactory.FACTORY_LABEL);
+ if(factoryClassName == null) {
+ return null;
+ }
+
+ ClassLoader cl = (ClassLoader) req.getAttribute(ODataServiceFactory.FACTORY_CLASSLOADER_LABEL);
+ if (cl == null) {
+ return (ODataServiceFactory) Class.forName(factoryClassName).newInstance();
+ } else {
+ return (ODataServiceFactory) Class.forName(factoryClassName, true, cl).newInstance();
+ }
+ }
+
+ /**
+ * Get an instance of a ODataServiceFactory from request attribute
+ * ODataServiceFactory.FACTORY_INSTANCE_LABEL
+ *
+ * @see ODataServiceFactory#FACTORY_INSTANCE_LABEL
+ *
+ * @param req http servlet request
+ * @return instance of a ODataServiceFactory
+ */
+ protected ODataServiceFactory getServiceFactoryInstance(HttpServletRequest req) {
+ Object factory = req.getAttribute(ODataServiceFactory.FACTORY_INSTANCE_LABEL);
+ if(factory == null) {
+ return null;
+ } else if(factory instanceof ODataServiceFactory) {
+ return (ODataServiceFactory) factory;
+ }
+ throw new ODataRuntimeException("Invalid service factory instance of type " + factory.getClass());
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f1ca1a20/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
index 5607025..d3e95e8 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java
@@ -18,295 +18,28 @@
******************************************************************************/
package org.apache.olingo.odata2.core.servlet;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.ODataServiceFactory;
-import org.apache.olingo.odata2.api.commons.HttpHeaders;
-import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
-import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
-import org.apache.olingo.odata2.api.exception.MessageReference;
-import org.apache.olingo.odata2.api.exception.ODataBadRequestException;
-import org.apache.olingo.odata2.api.exception.ODataHttpException;
-import org.apache.olingo.odata2.api.exception.ODataInternalServerErrorException;
-import org.apache.olingo.odata2.api.exception.ODataMethodNotAllowedException;
-import org.apache.olingo.odata2.api.exception.ODataNotAcceptableException;
-import org.apache.olingo.odata2.api.exception.ODataNotImplementedException;
-import org.apache.olingo.odata2.api.processor.ODataContext;
-import org.apache.olingo.odata2.api.processor.ODataRequest;
-import org.apache.olingo.odata2.api.processor.ODataResponse;
-import org.apache.olingo.odata2.core.ODataContextImpl;
-import org.apache.olingo.odata2.core.ODataRequestHandler;
import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
-public class ODataServlet extends HttpServlet {
+import javax.servlet.http.HttpServletRequest;
- private static final String HTTP_METHOD_OPTIONS = "OPTIONS";
- private static final String HTTP_METHOD_HEAD = "HEAD";
+public final class ODataServlet extends AbstractODataServlet {
- /**
- *
- */
private static final long serialVersionUID = 1L;
- @Override
- protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws IOException {
- final String factoryClassName = getInitParameter(ODataServiceFactory.FACTORY_LABEL);
- if (factoryClassName == null) {
- throw new ODataRuntimeException("config missing: " + ODataServiceFactory.FACTORY_LABEL);
- }
-
- // We have to create the Service Factory here because otherwise we do not have access to the error callback
- ODataServiceFactory serviceFactory = createServiceFactory(req);
-
- String xHttpMethod = req.getHeader("X-HTTP-Method");
- String xHttpMethodOverride = req.getHeader("X-HTTP-Method-Override");
- if (xHttpMethod != null && xHttpMethodOverride != null) {
- if (!xHttpMethod.equalsIgnoreCase(xHttpMethodOverride)) {
- ODataExceptionWrapper wrapper = new ODataExceptionWrapper(req, serviceFactory);
- createResponse(resp, wrapper.wrapInExceptionResponse(
- new ODataBadRequestException(ODataBadRequestException.AMBIGUOUS_XMETHOD)));
- }
- }
-
- if (req.getPathInfo() != null) {
- handle(req, resp, xHttpMethod, xHttpMethodOverride, serviceFactory);
- } else {
- handleRedirect(req, resp, serviceFactory);
- }
- }
-
- private void handle(final HttpServletRequest req, final HttpServletResponse resp, final String xHttpMethod,
- final String xHttpMethodOverride, ODataServiceFactory serviceFactory) throws IOException {
- String method = req.getMethod();
- if (ODataHttpMethod.GET.name().equals(method)) {
- handleRequest(req, ODataHttpMethod.GET, resp, serviceFactory);
- } else if (ODataHttpMethod.POST.name().equals(method)) {
- if (xHttpMethod == null && xHttpMethodOverride == null) {
- handleRequest(req, ODataHttpMethod.POST, resp, serviceFactory);
- } else if (xHttpMethod == null) {
- /* tunneling */
- boolean methodHandled = handleHttpTunneling(req, resp, xHttpMethodOverride, serviceFactory);
- if (!methodHandled) {
- createMethodNotAllowedResponse(req, ODataHttpException.COMMON, resp, serviceFactory);
- }
- } else {
- /* tunneling */
- boolean methodHandled = handleHttpTunneling(req, resp, xHttpMethod, serviceFactory);
- if (!methodHandled) {
- createNotImplementedResponse(req, ODataNotImplementedException.TUNNELING, resp, serviceFactory);
- }
- }
-
- } else if (ODataHttpMethod.PUT.name().equals(method)) {
- handleRequest(req, ODataHttpMethod.PUT, resp, serviceFactory);
- } else if (ODataHttpMethod.DELETE.name().equals(method)) {
- handleRequest(req, ODataHttpMethod.DELETE, resp, serviceFactory);
- } else if (ODataHttpMethod.PATCH.name().equals(method)) {
- handleRequest(req, ODataHttpMethod.PATCH, resp, serviceFactory);
- } else if (ODataHttpMethod.MERGE.name().equals(method)) {
- handleRequest(req, ODataHttpMethod.MERGE, resp, serviceFactory);
- } else if (HTTP_METHOD_HEAD.equals(method) || HTTP_METHOD_OPTIONS.equals(method)) {
- createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp, serviceFactory);
- } else {
- createNotImplementedResponse(req, ODataHttpException.COMMON, resp, serviceFactory);
- }
- }
-
- private boolean handleHttpTunneling(final HttpServletRequest req, final HttpServletResponse resp,
- final String xHttpMethod, ODataServiceFactory serviceFactory) throws IOException {
- if (ODataHttpMethod.MERGE.name().equals(xHttpMethod)) {
- handleRequest(req, ODataHttpMethod.MERGE, resp, serviceFactory);
- } else if (ODataHttpMethod.PATCH.name().equals(xHttpMethod)) {
- handleRequest(req, ODataHttpMethod.PATCH, resp, serviceFactory);
- } else if (ODataHttpMethod.DELETE.name().equals(xHttpMethod)) {
- handleRequest(req, ODataHttpMethod.DELETE, resp, serviceFactory);
- } else if (ODataHttpMethod.PUT.name().equals(xHttpMethod)) {
- handleRequest(req, ODataHttpMethod.PUT, resp, serviceFactory);
- } else if (ODataHttpMethod.GET.name().equals(xHttpMethod)) {
- handleRequest(req, ODataHttpMethod.GET, resp, serviceFactory);
- } else if (ODataHttpMethod.POST.name().equals(xHttpMethod)) {
- handleRequest(req, ODataHttpMethod.POST, resp, serviceFactory);
- } else if (HTTP_METHOD_HEAD.equals(xHttpMethod) || HTTP_METHOD_OPTIONS.equals(xHttpMethod)) {
- createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp, serviceFactory);
- } else {
- createNotImplementedResponse(req, ODataNotImplementedException.COMMON, resp, serviceFactory);
- }
- return true;
- }
-
- private void
- handleRequest(final HttpServletRequest req, final ODataHttpMethod method, final HttpServletResponse resp,
- ODataServiceFactory serviceFactory)
- throws IOException {
+ /**
+ * @{inherit}
+ */
+ protected ODataServiceFactory getServiceFactory(HttpServletRequest request) {
try {
- final String pathSplitAsString = getInitParameter(ODataServiceFactory.PATH_SPLIT_LABEL);
- int pathSplit = 0;
- if (pathSplitAsString != null) {
- pathSplit = Integer.parseInt(pathSplitAsString);
- }
- if (req.getHeader(HttpHeaders.ACCEPT) != null && req.getHeader(HttpHeaders.ACCEPT).isEmpty()) {
- createNotAcceptableResponse(req, ODataNotAcceptableException.COMMON, resp, serviceFactory);
+ ODataServiceFactory factoryInstance = getServiceFactoryInstance(request);
+ if(factoryInstance == null) {
+ return createODataServiceFactory(request);
}
- ODataRequest odataRequest = ODataRequest.method(method)
- .contentType(RestUtil.extractRequestContentType(req.getContentType()).toContentTypeString())
- .acceptHeaders(RestUtil.extractAcceptHeaders(req.getHeader(HttpHeaders.ACCEPT)))
- .acceptableLanguages(RestUtil.extractAcceptableLanguage(req.getHeader(HttpHeaders.ACCEPT_LANGUAGE)))
- .pathInfo(RestUtil.buildODataPathInfo(req, pathSplit))
- .allQueryParameters(RestUtil.extractAllQueryParameters(req.getQueryString()))
- .requestHeaders(RestUtil.extractHeaders(req))
- .body(req.getInputStream())
- .build();
-
- ODataContextImpl context = new ODataContextImpl(odataRequest, serviceFactory);
- context.setParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT, req);
-
- ODataService service = serviceFactory.createService(context);
- if (service == null) {
- createServiceUnavailableResponse(req, ODataInternalServerErrorException.NOSERVICE, resp, serviceFactory);
- } else {
- context.setService(service);
- service.getProcessor().setContext(context);
-
- ODataRequestHandler requestHandler = new ODataRequestHandler(serviceFactory, service, context);
- final ODataResponse odataResponse = requestHandler.handle(odataRequest);
- createResponse(resp, odataResponse);
- }
- } catch (Exception e) {
- ODataExceptionWrapper wrapper = new ODataExceptionWrapper(req, serviceFactory);
- createResponse(resp, wrapper.wrapInExceptionResponse(e));
- }
- }
+ return factoryInstance;
- private ODataServiceFactory createServiceFactory(HttpServletRequest req) {
- try {
- final String factoryClassName = getInitParameter(ODataServiceFactory.FACTORY_LABEL);
- ClassLoader cl = (ClassLoader) req.getAttribute(ODataServiceFactory.FACTORY_CLASSLOADER_LABEL);
- if (cl == null) {
- return (ODataServiceFactory) Class.forName(factoryClassName).newInstance();
- } else {
- return (ODataServiceFactory) Class.forName(factoryClassName, true, cl).newInstance();
- }
} catch (Exception e) {
throw new ODataRuntimeException(e);
}
}
-
- private void handleRedirect(final HttpServletRequest req, final HttpServletResponse resp,
- ODataServiceFactory serviceFactory) throws IOException {
- String method = req.getMethod();
- if (ODataHttpMethod.GET.name().equals(method) ||
- ODataHttpMethod.POST.name().equals(method) ||
- ODataHttpMethod.PUT.name().equals(method) ||
- ODataHttpMethod.DELETE.name().equals(method) ||
- ODataHttpMethod.PATCH.name().equals(method) ||
- ODataHttpMethod.MERGE.name().equals(method) ||
- HTTP_METHOD_HEAD.equals(method) ||
- HTTP_METHOD_OPTIONS.equals(method)) {
- ODataResponse odataResponse = ODataResponse.status(HttpStatusCodes.TEMPORARY_REDIRECT)
- .header(HttpHeaders.LOCATION, createLocation(req))
- .build();
- createResponse(resp, odataResponse);
- } else {
- createNotImplementedResponse(req, ODataHttpException.COMMON, resp, serviceFactory);
- }
-
- }
-
- private String createLocation(final HttpServletRequest req) {
- StringBuilder location = new StringBuilder();
- String contextPath = req.getContextPath();
- if (contextPath != null) {
- location.append(contextPath);
- }
- String servletPath = req.getServletPath();
- if (servletPath != null) {
- location.append(servletPath);
- }
- location.append("/");
- return location.toString();
- }
-
- private void createResponse(final HttpServletResponse resp, final ODataResponse response) throws IOException {
- resp.setStatus(response.getStatus().getStatusCode());
- resp.setContentType(response.getContentHeader());
- for (String headerName : response.getHeaderNames()) {
- resp.setHeader(headerName, response.getHeader(headerName));
- }
-
- Object entity = response.getEntity();
- if (entity != null) {
- ServletOutputStream out = resp.getOutputStream();
- int curByte;
- int contentLength = 0;
-
- if (entity instanceof InputStream) {
- while ((curByte = ((InputStream) entity).read()) != -1) {
- contentLength++;
- out.write((char) curByte);
- }
- ((InputStream) entity).close();
- } else if (entity instanceof String) {
- String body = (String) entity;
- final byte[] entityBytes = body.getBytes("utf-8");
- out.write(entityBytes);
- contentLength = entityBytes.length;
- }
-
- if (response.getHeader(HttpHeaders.CONTENT_LENGTH) != null) {
- // Override content length
- try {
- contentLength = Integer.parseInt(response.getHeader(HttpHeaders.CONTENT_LENGTH));
- } catch (NumberFormatException e) {
- // Ignore
- }
- }
-
- resp.setContentLength(contentLength);
- out.flush();
- out.close();
- }
- }
-
- private void createNotImplementedResponse(final HttpServletRequest req, final MessageReference messageReference,
- final HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
- // RFC 2616, 5.1.1: "An origin server SHOULD return the status code [...]
- // 501 (Not Implemented) if the method is unrecognized [...] by the origin server."
- ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
- ODataResponse response =
- exceptionWrapper.wrapInExceptionResponse(new ODataNotImplementedException(messageReference));
-// resp.setStatus(HttpStatusCodes.NOT_IMPLEMENTED.getStatusCode());
- createResponse(resp, response);
- }
-
- private void createMethodNotAllowedResponse(final HttpServletRequest req, final MessageReference messageReference,
- final HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
- ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
- ODataResponse response =
- exceptionWrapper.wrapInExceptionResponse(new ODataMethodNotAllowedException(messageReference));
- createResponse(resp, response);
- }
-
- private void createNotAcceptableResponse(final HttpServletRequest req, final MessageReference messageReference,
- final HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
- ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
- ODataResponse response =
- exceptionWrapper.wrapInExceptionResponse(new ODataNotAcceptableException(messageReference));
- createResponse(resp, response);
- }
-
- private void createServiceUnavailableResponse(HttpServletRequest req, MessageReference messageReference,
- HttpServletResponse resp, ODataServiceFactory serviceFactory) throws IOException {
- ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req, serviceFactory);
- ODataResponse response =
- exceptionWrapper.wrapInExceptionResponse(new ODataInternalServerErrorException(messageReference));
- createResponse(resp, response);
- }
-
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f1ca1a20/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
index 65aaf06..da7b05b 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/RestUtil.java
@@ -366,9 +366,10 @@ public class RestUtil {
pathInfoString = pathInfoString.substring(servletRequest.getContextPath().length());
}
- int indexServletPath = requestUri.indexOf(servletRequest.getServletPath());
+ int indexServletPath = pathInfoString.indexOf(servletRequest.getServletPath());
if (indexServletPath >= 0) {
- pathInfoString = pathInfoString.substring(servletRequest.getServletPath().length());
+ int substringFromPos = indexServletPath + servletRequest.getServletPath().length();
+ pathInfoString = pathInfoString.substring(substringFromPos);
}
return pathInfoString;
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f1ca1a20/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/AbstractODataServletTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/AbstractODataServletTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/AbstractODataServletTest.java
new file mode 100644
index 0000000..de21917
--- /dev/null
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/AbstractODataServletTest.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.servlet;
+
+import junit.framework.Assert;
+import org.apache.olingo.odata2.api.ODataService;
+import org.apache.olingo.odata2.api.ODataServiceFactory;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataProcessor;
+import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.api.servicedocument.Collection;
+import org.apache.olingo.odata2.core.ODataResponseImpl;
+import org.apache.olingo.odata2.core.rest.ODataServiceFactoryImpl;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import javax.servlet.GenericServlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collections;
+
+/**
+ *
+ */
+public class AbstractODataServletTest {
+
+ private HttpServletRequest reqMock;
+ private HttpServletResponse respMock;
+ private ServletConfig configMock;
+
+ public AbstractODataServletTest() {
+ reqMock = Mockito.mock(HttpServletRequest.class);
+ respMock = Mockito.mock(HttpServletResponse.class);
+ configMock = Mockito.mock(ServletConfig.class);
+ }
+
+ private static class MyTestODataServlet extends AbstractODataServlet {
+ enum ServiceFactorySource {INSTANCE, CLASSLOADER, MOCK};
+
+ ODataServiceFactory viaInstance;
+ ODataServiceFactory viaClassLoader;
+ ODataServiceFactory viaMock;
+ final ServiceFactorySource source;
+
+ public MyTestODataServlet() {
+ this(ServiceFactorySource.MOCK);
+ }
+
+ public MyTestODataServlet(ServiceFactorySource source) {
+ this.source = source;
+ }
+
+ @Override
+ protected ODataServiceFactory getServiceFactory(HttpServletRequest request) {
+ viaInstance = getServiceFactoryInstance(request);
+ try {
+ viaClassLoader = createODataServiceFactory(request);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ viaMock = Mockito.mock(ODataServiceFactory.class);
+
+ switch (source) {
+ case INSTANCE: return viaInstance;
+ case CLASSLOADER: return viaClassLoader;
+ case MOCK: return viaMock;
+ }
+ return null;
+ }
+ }
+
+ @Test
+ public void handleRedirect() throws Exception {
+ AbstractODataServlet servlet = new MyTestODataServlet();
+ prepareServlet(servlet);
+ prepareRequest(reqMock);
+ servlet.service(reqMock, respMock);
+
+ Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
+ Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/context-path/servlet-path/");
+ }
+
+ @Test
+ public void handleRedirectWoServletPath() throws Exception {
+ AbstractODataServlet servlet = new MyTestODataServlet();
+ prepareServlet(servlet);
+ prepareRequest(reqMock, "/context-path", null);
+ servlet.service(reqMock, respMock);
+
+ Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
+ Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/context-path/");
+ }
+
+ @Test
+ public void handleRedirectWoContextPath() throws Exception {
+ AbstractODataServlet servlet = new MyTestODataServlet();
+ prepareServlet(servlet);
+ prepareRequest(reqMock, null, "/servlet-path");
+ servlet.service(reqMock, respMock);
+
+ Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
+ Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/servlet-path/");
+ }
+
+ @Test
+ public void handleRedirectWoPath() throws Exception {
+ AbstractODataServlet servlet = new MyTestODataServlet();
+ prepareServlet(servlet);
+ prepareRequest(reqMock, null, null);
+ servlet.service(reqMock, respMock);
+
+ Mockito.verify(respMock).setStatus(HttpStatusCodes.TEMPORARY_REDIRECT.getStatusCode());
+ Mockito.verify(respMock).setHeader(HttpHeaders.LOCATION, "/");
+ }
+
+ @Test
+ public void contentLengthCalculatedString() throws Exception {
+ final Method createResponse =
+ AbstractODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
+ createResponse.setAccessible(true);
+
+ final AbstractODataServlet servlet = new MyTestODataServlet();
+ final String content = "Test\r\n";
+ final ODataResponse response = ODataResponseImpl.status(HttpStatusCodes.OK).entity(content).build();
+ prepareResponseMockToWrite(respMock);
+ prepareServlet(servlet);
+
+ createResponse.invoke(servlet, respMock, response);
+ Mockito.verify(respMock).setContentLength(content.getBytes("utf-8").length);
+ }
+
+ @Test
+ public void contentLengthCalculatedStream() throws Exception {
+ final Method createResponse =
+ AbstractODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
+ createResponse.setAccessible(true);
+
+ final AbstractODataServlet servlet = new MyTestODataServlet();
+ final String content = "Test\r\n";
+
+ final ODataResponse response =
+ ODataResponseImpl.status(HttpStatusCodes.OK).entity(new ByteArrayInputStream(content.getBytes("utf-8")))
+ .build();
+ prepareResponseMockToWrite(respMock);
+ prepareServlet(servlet);
+
+ createResponse.invoke(servlet, respMock, response);
+ Mockito.verify(respMock).setContentLength(content.getBytes("utf-8").length);
+ }
+
+ @Test
+ public void contentLengthHeader() throws Exception {
+ final Method createResponse =
+ AbstractODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
+ createResponse.setAccessible(true);
+ final AbstractODataServlet servlet = new MyTestODataServlet();
+ final ODataResponse response =
+ ODataResponseImpl.status(HttpStatusCodes.OK).header(HttpHeaders.CONTENT_LENGTH, "15").entity("").build();
+ prepareResponseMockToWrite(respMock);
+ prepareServlet(servlet);
+
+ createResponse.invoke(servlet, respMock, response);
+
+ Mockito.verify(respMock).setHeader(HttpHeaders.CONTENT_LENGTH, "15");
+ Mockito.verify(respMock).setContentLength(15);
+ }
+
+ @Test
+ public void contentLengthHeaderInvalid() throws Exception {
+ final Method createResponse =
+ AbstractODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
+ createResponse.setAccessible(true);
+ final AbstractODataServlet servlet = new MyTestODataServlet();
+ final ODataResponse response =
+ ODataResponseImpl.status(HttpStatusCodes.OK).header(HttpHeaders.CONTENT_LENGTH, "ab").entity("Test").build();
+ prepareResponseMockToWrite(respMock);
+ prepareServlet(servlet);
+
+ createResponse.invoke(servlet, respMock, response);
+
+ Mockito.verify(respMock).setHeader(HttpHeaders.CONTENT_LENGTH, "ab");
+ Mockito.verify(respMock).setContentLength(4); // ||"Test"|| = 4
+ }
+
+ @Test
+ public void serviceInstance() throws Exception {
+ MyTestODataServlet servlet = new MyTestODataServlet(MyTestODataServlet.ServiceFactorySource.INSTANCE);
+ prepareServlet(servlet, false);
+ prepareRequest(reqMock, "", "/servlet-path");
+ Mockito.when(reqMock.getPathInfo()).thenReturn("/request-path-info");
+ Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path/request-path-info");
+ ODataServiceFactory factory = Mockito.mock(ODataServiceFactory.class);
+ ODataService service = Mockito.mock(ODataService.class);
+ Mockito.when(factory.createService(Mockito.any(ODataContext.class))).thenReturn(service);
+ ODataProcessor processor = Mockito.mock(ODataProcessor.class);
+ Mockito.when(service.getProcessor()).thenReturn(processor);
+ Mockito.when(reqMock.getAttribute(ODataServiceFactory.FACTORY_INSTANCE_LABEL)).thenReturn(factory);
+ Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
+
+ servlet.service(reqMock, respMock);
+
+ Mockito.verify(factory).createService(Mockito.any(ODataContext.class));
+ Assert.assertNotNull(servlet.viaInstance);
+ Assert.assertNull(servlet.viaClassLoader);
+ }
+
+ @Test
+ public void serviceClassloader() throws Exception {
+ MyTestODataServlet servlet = new MyTestODataServlet(MyTestODataServlet.ServiceFactorySource.CLASSLOADER);
+ prepareServlet(servlet);
+ prepareRequest(reqMock, "", "/servlet-path");
+ Mockito.when(reqMock.getPathInfo()).thenReturn("/request-path-info");
+ Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path/request-path-info");
+ Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
+
+ servlet.service(reqMock, respMock);
+
+ Assert.assertNull(servlet.viaInstance);
+ Assert.assertNotNull(servlet.viaClassLoader);
+ }
+
+ private void prepareResponseMockToWrite(final HttpServletResponse response) throws IOException {
+ Mockito.when(response.getOutputStream()).thenReturn(new ServletOutputStream() {
+ @Override
+ public void write(int b) throws IOException {}
+ });
+ }
+
+ private void prepareRequest(final HttpServletRequest req, final String contextPath, final String servletPath) {
+ Mockito.when(req.getMethod()).thenReturn("GET");
+ Mockito.when(req.getContextPath()).thenReturn(contextPath);
+ Mockito.when(req.getServletPath()).thenReturn(servletPath);
+ Mockito.when(req.getHeaderNames()).thenReturn(Collections.emptyEnumeration());
+ }
+
+ private void prepareRequest(final HttpServletRequest req) {
+ prepareRequest(req, "/context-path", "/servlet-path");
+ }
+
+ private void prepareServlet(final GenericServlet servlet) throws Exception {
+ prepareServlet(servlet, true);
+ }
+
+ private void prepareServlet(final GenericServlet servlet, boolean withFactoryLabel) throws Exception {
+ // private transient ServletConfig config;
+ Field configField = GenericServlet.class.getDeclaredField("config");
+ configField.setAccessible(true);
+ configField.set(servlet, configMock);
+
+ if(withFactoryLabel) {
+ String factoryClassName = ODataServiceFactoryImpl.class.getName();
+ Mockito.when(configMock.getInitParameter(ODataServiceFactory.FACTORY_LABEL)).thenReturn(factoryClassName);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f1ca1a20/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/ODataServletTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/ODataServletTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/ODataServletTest.java
index 883ab96..e1ad5dc 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/ODataServletTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/servlet/ODataServletTest.java
@@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.Collections;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
@@ -29,9 +30,13 @@ import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import junit.framework.Assert;
+import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.ODataServiceFactory;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.processor.ODataContext;
+import org.apache.olingo.odata2.api.processor.ODataProcessor;
import org.apache.olingo.odata2.api.processor.ODataResponse;
import org.apache.olingo.odata2.core.ODataResponseImpl;
import org.apache.olingo.odata2.core.rest.ODataServiceFactoryImpl;
@@ -100,7 +105,7 @@ public class ODataServletTest {
@Test
public void contentLengthCalculatedString() throws Exception {
final Method createResponse =
- ODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
+ AbstractODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
createResponse.setAccessible(true);
final ODataServlet servlet = new ODataServlet();
@@ -116,7 +121,7 @@ public class ODataServletTest {
@Test
public void contentLengthCalculatedStream() throws Exception {
final Method createResponse =
- ODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
+ AbstractODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
createResponse.setAccessible(true);
final ODataServlet servlet = new ODataServlet();
@@ -133,39 +138,43 @@ public class ODataServletTest {
}
@Test
- public void contentLengthHeader() throws Exception {
- final Method createResponse =
- ODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
- createResponse.setAccessible(true);
- final ODataServlet servlet = new ODataServlet();
- final ODataResponse response =
- ODataResponseImpl.status(HttpStatusCodes.OK).header(HttpHeaders.CONTENT_LENGTH, "15").entity("").build();
- prepareResponseMockToWrite(respMock);
+ public void serviceInstance() throws Exception {
+ ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
+ prepareRequest(reqMock, "", "/servlet-path");
+ Mockito.when(reqMock.getPathInfo()).thenReturn("/request-path-info");
+ Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path/request-path-info");
+ ODataServiceFactory factory = Mockito.mock(ODataServiceFactory.class);
+ ODataService service = Mockito.mock(ODataService.class);
+ Mockito.when(factory.createService(Mockito.any(ODataContext.class))).thenReturn(service);
+ ODataProcessor processor = Mockito.mock(ODataProcessor.class);
+ Mockito.when(service.getProcessor()).thenReturn(processor);
+ Mockito.when(reqMock.getAttribute(ODataServiceFactory.FACTORY_INSTANCE_LABEL)).thenReturn(factory);
+ Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
- createResponse.invoke(servlet, respMock, response);
+ servlet.service(reqMock, respMock);
- Mockito.verify(respMock).setHeader(HttpHeaders.CONTENT_LENGTH, "15");
- Mockito.verify(respMock).setContentLength(15);
+ Mockito.verify(factory).createService(Mockito.any(ODataContext.class));
}
@Test
- public void contentLengthHeaderInvalid() throws Exception {
- final Method createResponse =
- ODataServlet.class.getDeclaredMethod("createResponse", HttpServletResponse.class, ODataResponse.class);
- createResponse.setAccessible(true);
- final ODataServlet servlet = new ODataServlet();
- final ODataResponse response =
- ODataResponseImpl.status(HttpStatusCodes.OK).header(HttpHeaders.CONTENT_LENGTH, "ab").entity("Test").build();
- prepareResponseMockToWrite(respMock);
+ public void serviceClassloader() throws Exception {
+ ODataServlet servlet = new ODataServlet();
prepareServlet(servlet);
+ prepareRequest(reqMock, "", "/servlet-path");
+ Mockito.when(reqMock.getPathInfo()).thenReturn("/request-path-info");
+ Mockito.when(reqMock.getRequestURI()).thenReturn("http://localhost:8080/servlet-path/request-path-info");
+ Mockito.when(respMock.getOutputStream()).thenReturn(Mockito.mock(ServletOutputStream.class));
- createResponse.invoke(servlet, respMock, response);
+ servlet.service(reqMock, respMock);
- Mockito.verify(respMock).setHeader(HttpHeaders.CONTENT_LENGTH, "ab");
- Mockito.verify(respMock).setContentLength(4); // ||"Test"|| = 4
+ Mockito.verify(configMock).getInitParameter(ODataServiceFactory.FACTORY_LABEL);
+ Mockito.verify(reqMock).getAttribute(ODataServiceFactory.FACTORY_CLASSLOADER_LABEL);
+
+ Assert.assertEquals(ODataServiceFactoryImpl.class, servlet.createODataServiceFactory(reqMock).getClass());
}
+
private void prepareResponseMockToWrite(final HttpServletResponse response) throws IOException {
Mockito.when(response.getOutputStream()).thenReturn(new ServletOutputStream() {
@Override
@@ -177,6 +186,7 @@ public class ODataServletTest {
Mockito.when(req.getMethod()).thenReturn("GET");
Mockito.when(req.getContextPath()).thenReturn(contextPath);
Mockito.when(req.getServletPath()).thenReturn(servletPath);
+ Mockito.when(req.getHeaderNames()).thenReturn(Collections.emptyEnumeration());
}
private void prepareRequest(final HttpServletRequest req) {