blob: 57a8bc8116e47aaab5a293819257f08e37e820d1 [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.odata2.core.rest;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Encoded;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.UriInfo;
import org.apache.olingo.odata2.api.ODataServiceFactory;
import org.apache.olingo.odata2.api.exception.ODataBadRequestException;
import org.apache.olingo.odata2.api.exception.ODataException;
import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
import org.apache.olingo.odata2.core.rest.app.AbstractODataApplication;
/**
* Default OData root locator responsible to handle the whole path and delegate all calls to a sub locator:<p>
* <code>/{odata path} e.g. http://host:port/webapp/odata.svc/$metadata</code><br>
* All path segments defined by a servlet mapping belong to the odata uri.
* </p>
* This behavior can be changed:<p>
* <code>/{custom path}{odata path} e.g. http://host:port/webapp/bmw/odata.svc/$metadata</code><br>
* The first segment defined by a servlet mapping belong to customer context and the following segments are OData
* specific.
* </p>
*
*/
@Path("/")
public class ODataRootLocator {
@Context
private HttpHeaders httpHeaders;
@Context
private UriInfo uriInfo;
@Context
private Request request;
@Context
private ServletConfig servletConfig;
@Context
private HttpServletRequest servletRequest;
@Context
private Application app;
/**
* Default root behavior which will delegate all paths to a ODataLocator.
* @param pathSegments URI path segments - all segments have to be OData
* @param xHttpMethod HTTP Header X-HTTP-Method for tunneling through POST
* @param xHttpMethodOverride HTTP Header X-HTTP-Method-Override for tunneling through POST
* @return a locator handling OData protocol
* @throws ODataException
* @throws ClassNotFoundException
* @throws IllegalAccessException
* @throws InstantiationException
*/
@Path("/{pathSegments: .*}")
public Object handleRequest(
@Encoded @PathParam("pathSegments") final List<PathSegment> pathSegments,
@HeaderParam("X-HTTP-Method") final String xHttpMethod,
@HeaderParam("X-HTTP-Method-Override") final String xHttpMethodOverride)
throws ODataException, ClassNotFoundException, InstantiationException, IllegalAccessException {
if (xHttpMethod != null && xHttpMethodOverride != null) {
/*
* X-HTTP-Method-Override : implemented by CXF
* X-HTTP-Method : implemented in ODataSubLocator:handlePost
*/
if (!xHttpMethod.equalsIgnoreCase(xHttpMethodOverride)) {
throw new ODataBadRequestException(ODataBadRequestException.AMBIGUOUS_XMETHOD);
}
}
if (servletRequest.getPathInfo() == null) {
return handleRedirect();
}
ODataServiceFactory serviceFactory = getServiceFactory();
int pathSplit = getPathSplit();
final SubLocatorParameter param = new SubLocatorParameter();
param.setServiceFactory(serviceFactory);
param.setPathSegments(pathSegments);
param.setHttpHeaders(httpHeaders);
param.setUriInfo(uriInfo);
param.setRequest(request);
param.setServletRequest(servletRequest);
param.setPathSplit(pathSplit);
return ODataSubLocator.create(param);
}
public ODataServiceFactory getServiceFactory() {
return createServiceFactoryFromContext(app, servletRequest, servletConfig);
}
public int getPathSplit() {
int pathSplit = 0;
final String pathSplitAsString = servletConfig.getInitParameter(ODataServiceFactory.PATH_SPLIT_LABEL);
if (pathSplitAsString != null) {
pathSplit = Integer.parseInt(pathSplitAsString);
}
return pathSplit;
}
public static ODataServiceFactory createServiceFactoryFromContext(final Application app,
final HttpServletRequest servletRequest,
final ServletConfig servletConfig) {
try {
Class<?> factoryClass;
if (app instanceof AbstractODataApplication) {
factoryClass = ((AbstractODataApplication) app).getServiceFactoryClass();
} else {
final String factoryClassName = servletConfig.getInitParameter(ODataServiceFactory.FACTORY_LABEL);
if (factoryClassName == null) {
throw new ODataRuntimeException("Servlet config missing: " + ODataServiceFactory.FACTORY_LABEL);
}
ClassLoader cl = (ClassLoader) servletRequest.getAttribute(ODataServiceFactory.FACTORY_CLASSLOADER_LABEL);
if (cl == null) {
factoryClass = Class.forName(factoryClassName);
} else {
factoryClass = Class.forName(factoryClassName, true, cl);
}
}
return (ODataServiceFactory) factoryClass.newInstance();
} catch (Exception e) {
throw new ODataRuntimeException("Exception during ODataServiceFactory creation occured.", e);
}
}
private Object handleRedirect() {
return new ODataRedirectLocator();
}
}