blob: 36cbd183f693cb3cba33c610557e22b64ce1a5db [file] [log] [blame]
/*
* 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.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.olingo.commons.api.ODataRuntimeException;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataHttpHandler;
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.ODataTranslatedException;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.processor.Processor;
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ODataHttpHandlerImpl implements ODataHttpHandler {
private static final Logger LOG = LoggerFactory.getLogger(ODataHttpHandlerImpl.class);
private ODataHandler handler;
private int split = 0;
public ODataHttpHandlerImpl(final OData odata, final ServiceMetadata serviceMetadata) {
handler = new ODataHandler(odata, serviceMetadata);
}
@Override
public void process(final HttpServletRequest request, final HttpServletResponse response) {
ODataRequest odRequest = null;
ODataResponse odResponse;
try {
odRequest = createODataRequest(request, split);
odResponse = handler.process(odRequest);
// ALL future methods after process must not throw exceptions!
} catch (Exception e) {
odResponse = handleException(odRequest, e);
}
convertToHttp(response, odResponse);
}
@Override
public void setSplit(int split) {
this.split = split;
}
private ODataResponse handleException(ODataRequest odRequest, Exception e) {
ODataResponse resp = new ODataResponse();
ODataServerError serverError;
if (e instanceof ODataHandlerException) {
serverError = ODataExceptionHelper.createServerErrorObject((ODataHandlerException) e, null);
} else if (e instanceof ODataTranslatedException) {
serverError = ODataExceptionHelper.createServerErrorObject((ODataTranslatedException) e, null);
} else {
serverError = ODataExceptionHelper.createServerErrorObject(e);
}
handler.handleException(odRequest, resp, serverError);
return resp;
}
static void convertToHttp(final HttpServletResponse response, final ODataResponse odResponse) {
response.setStatus(odResponse.getStatusCode());
for (Entry<String, String> entry : odResponse.getHeaders().entrySet()) {
response.setHeader(entry.getKey(), entry.getValue());
}
InputStream input = odResponse.getContent();
if (input != null) {
OutputStream output = null;
try {
output = response.getOutputStream();
byte[] buffer = new byte[1024];
int n;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
throw new ODataRuntimeException(e);
} finally {
closeStream(output);
closeStream(input);
}
}
}
private static void closeStream(Closeable closeable) {
if(closeable != null) {
try {
closeable.close();
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
}
}
private ODataRequest createODataRequest(final HttpServletRequest httpRequest, final int split)
throws ODataTranslatedException {
try {
ODataRequest odRequest = new ODataRequest();
odRequest.setBody(httpRequest.getInputStream());
extractHeaders(odRequest, httpRequest);
extractMethod(odRequest, httpRequest);
extractUri(odRequest, httpRequest, split);
return odRequest;
} catch (final IOException e) {
throw new SerializerException("An I/O exception occurred.", e,
SerializerException.MessageKeys.IO_EXCEPTION);
}
}
static void extractMethod(final ODataRequest odRequest, final HttpServletRequest httpRequest)
throws ODataTranslatedException {
try {
HttpMethod httpRequestMethod = HttpMethod.valueOf(httpRequest.getMethod());
if (httpRequestMethod == HttpMethod.POST) {
String xHttpMethod = httpRequest.getHeader(HttpHeader.X_HTTP_METHOD);
String xHttpMethodOverride = httpRequest.getHeader(HttpHeader.X_HTTP_METHOD_OVERRIDE);
if (xHttpMethod == null && xHttpMethodOverride == null) {
odRequest.setMethod(httpRequestMethod);
} else if (xHttpMethod == null) {
odRequest.setMethod(HttpMethod.valueOf(xHttpMethodOverride));
} else if (xHttpMethodOverride == null) {
odRequest.setMethod(HttpMethod.valueOf(xHttpMethod));
} else {
if (!xHttpMethod.equalsIgnoreCase(xHttpMethodOverride)) {
throw new ODataHandlerException("Ambiguous X-HTTP-Methods",
ODataHandlerException.MessageKeys.AMBIGUOUS_XHTTP_METHOD, xHttpMethod, xHttpMethodOverride);
}
odRequest.setMethod(HttpMethod.valueOf(xHttpMethod));
}
} else {
odRequest.setMethod(httpRequestMethod);
}
} catch (IllegalArgumentException e) {
throw new ODataHandlerException("Invalid HTTP method" + httpRequest.getMethod(),
ODataHandlerException.MessageKeys.INVALID_HTTP_METHOD, httpRequest.getMethod());
}
}
static void extractUri(final ODataRequest odRequest, final HttpServletRequest httpRequest, final int split) {
String rawRequestUri = httpRequest.getRequestURL().toString();
String rawODataPath;
if (!"".equals(httpRequest.getServletPath())) {
int beginIndex;
beginIndex = rawRequestUri.indexOf(httpRequest.getServletPath());
beginIndex += httpRequest.getServletPath().length();
rawODataPath = rawRequestUri.substring(beginIndex);
} else if (!"".equals(httpRequest.getContextPath())) {
int beginIndex;
beginIndex = rawRequestUri.indexOf(httpRequest.getContextPath());
beginIndex += httpRequest.getContextPath().length();
rawODataPath = rawRequestUri.substring(beginIndex);
} else {
rawODataPath = httpRequest.getRequestURI();
}
String rawServiceResolutionUri;
if (split > 0) {
rawServiceResolutionUri = rawODataPath;
for (int i = 0; i < split; i++) {
int e = rawODataPath.indexOf("/", 1);
if (-1 == e) {
rawODataPath = "";
} else {
rawODataPath = rawODataPath.substring(e);
}
}
int end = rawServiceResolutionUri.length() - rawODataPath.length();
rawServiceResolutionUri = rawServiceResolutionUri.substring(0, end);
} else {
rawServiceResolutionUri = null;
}
String rawBaseUri = rawRequestUri.substring(0, rawRequestUri.length() - rawODataPath.length());
odRequest.setRawQueryPath(httpRequest.getQueryString());
odRequest.setRawRequestUri(rawRequestUri
+ (httpRequest.getQueryString() == null ? "" : "?" + httpRequest.getQueryString()));
odRequest.setRawODataPath(rawODataPath);
odRequest.setRawBaseUri(rawBaseUri);
odRequest.setRawServiceResolutionUri(rawServiceResolutionUri);
}
static void extractHeaders(final ODataRequest odRequest, final HttpServletRequest req) {
for (Enumeration<?> headerNames = req.getHeaderNames(); headerNames.hasMoreElements();) {
String headerName = (String) headerNames.nextElement();
List<String> headerValues = new ArrayList<String>();
for (Enumeration<?> headers = req.getHeaders(headerName); headers.hasMoreElements();) {
String value = (String) headers.nextElement();
headerValues.add(value);
}
odRequest.addHeader(headerName, headerValues);
}
}
@Override
public void register(final Processor processor) {
handler.register(processor);
}
@Override
public void register(final CustomContentTypeSupport customContentTypeSupport) {
handler.register(customContentTypeSupport);
}
}