blob: 29c71345ec67fab90e8c3a77c12f7a3223ef147e [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.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.edm.EdmAnnotation;
import org.apache.olingo.commons.api.edm.EdmSchema;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.annotation.EdmConstantExpression;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.core.requests.DataRequest;
import org.apache.olingo.server.core.uri.parser.Parser;
import org.apache.olingo.server.core.uri.parser.UriParserException;
import org.apache.olingo.server.core.uri.validator.UriValidationException;
public abstract class ServiceRequest {
protected OData odata;
protected UriInfo uriInfo;
protected ServiceMetadata serviceMetadata;
protected CustomContentTypeSupport customContentType;
protected ODataRequest request;
public ServiceRequest(OData odata, ServiceMetadata serviceMetadata) {
this.odata = odata;
this.serviceMetadata = serviceMetadata;
}
public OData getOdata() {
return odata;
}
public ServiceMetadata getServiceMetaData() {
return this.serviceMetadata;
}
public UriInfo getUriInfo() {
return uriInfo;
}
protected void setUriInfo(UriInfo uriInfo) {
this.uriInfo = uriInfo;
}
public static boolean assertHttpMethod(HttpMethod issued, HttpMethod[] allowedMethods,
ODataResponse response) throws ODataHandlerException {
boolean allowed = false;
for (HttpMethod method :allowedMethods) {
if (issued.equals(method)) {
allowed = true;
}
}
if (!allowed) {
return methodNotAllowed(response, issued, null, allowedMethods);
}
return true;
}
public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
boolean allowed = false;
HttpMethod issued = this.request.getMethod();
for (HttpMethod method :allowedMethods()) {
if (issued.equals(method)) {
allowed = true;
}
}
if (!allowed) {
return methodNotAllowed(response, issued, null, allowedMethods());
}
return true;
}
public HttpMethod[] allowedMethods() {
return new HttpMethod[] {HttpMethod.GET};
}
public CustomContentTypeSupport getCustomContentTypeSupport() {
return this.customContentType;
}
public void setCustomContentTypeSupport(CustomContentTypeSupport support) {
this.customContentType = support;
}
public ODataRequest getODataRequest() {
return this.request;
}
protected void setODataRequest(ODataRequest request) {
this.request = request;
}
public ContentType getRequestContentType() {
if (this.request.getHeader(HttpHeader.CONTENT_TYPE) != null) {
return ContentType.parse(this.request.getHeader(HttpHeader.CONTENT_TYPE));
}
return ContentType.APPLICATION_OCTET_STREAM;
}
public abstract void execute(ServiceHandler handler, ODataResponse response)
throws ODataLibraryException, ODataApplicationException;
public abstract ContentType getResponseContentType() throws ContentNegotiatorException;
public static boolean methodNotAllowed(ODataResponse response, HttpMethod issued, String reason,
HttpMethod... allowed) throws ODataHandlerException {
StringBuilder sb = new StringBuilder();
for (HttpMethod method:allowed) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(method.name());
}
response.setHeader("Allow", sb.toString());
if (reason == null) {
reason = "HTTP method " + issued + " is not allowed.";
}
throw new ODataHandlerException(reason,
ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_ALLOWED, issued.name());
}
public void notImplemented() throws ODataHandlerException {
throw new ODataHandlerException("not implemented", //$NON-NLS-1$
ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
}
protected boolean isGET() {
return this.request.getMethod() == HttpMethod.GET;
}
protected boolean isPUT() {
return this.request.getMethod() == HttpMethod.PUT;
}
protected boolean isDELETE() {
return this.request.getMethod() == HttpMethod.DELETE;
}
protected boolean isPATCH() {
return this.request.getMethod() == HttpMethod.PATCH;
}
protected boolean isPOST() {
return this.request.getMethod() == HttpMethod.POST;
}
protected HttpMethod httpMethod() {
return this.request.getMethod();
}
private static FullQualifiedName XML10_CHAR_REPLACE_FQN = new FullQualifiedName(
"org.apache.olingo.v1.xml10-incompatible-char-replacement");
/**
* Replacement character for the XML10 characters that are not supported.
* @return
*/
protected String xml10IncompatibleCharReplacement() {
for (EdmSchema schema : getServiceMetaData().getEdm().getSchemas()) {
if (schema.getEntityContainer() != null) {
for (EdmAnnotation annotation:schema.getAnnotations()) {
if (annotation.getTerm() != null
&& annotation.getTerm().getFullQualifiedName().equals(XML10_CHAR_REPLACE_FQN)) {
EdmConstantExpression expr = annotation.getExpression().asConstant();
return expr.getValueAsString();
}
}
}
}
return null;
}
@SuppressWarnings("unchecked")
public <T> T getSerializerOptions(Class<T> serilizerOptions,
ContextURL contextUrl, boolean references) throws ContentNegotiatorException {
String xmlReplacement = null;
if (getResponseContentType().isCompatible(ContentType.APPLICATION_XML)
|| getResponseContentType().isCompatible(ContentType.APPLICATION_ATOM_XML)) {
xmlReplacement = xml10IncompatibleCharReplacement();
}
if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) {
return (T) EntitySerializerOptions.with()
.contextURL(contextUrl)
.expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
.writeOnlyReferences(references)
.xml10InvalidCharReplacement(xmlReplacement)
.build();
} else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) {
return (T) EntityCollectionSerializerOptions.with()
.contextURL(contextUrl)
.count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
.select(uriInfo.getSelectOption()).writeOnlyReferences(references)
.id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath())
.xml10InvalidCharReplacement(xmlReplacement)
.build();
} else if (serilizerOptions.isAssignableFrom(ComplexSerializerOptions.class)) {
return (T) ComplexSerializerOptions.with().contextURL(contextUrl)
.expand(this.uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
.xml10InvalidCharReplacement(xmlReplacement)
.build();
} else if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
.xml10InvalidCharReplacement(xmlReplacement)
.build();
}
return null;
}
public ReturnRepresentation getReturnRepresentation() {
String prefer = this.request.getHeader(HttpHeader.PREFER);
if (prefer != null) {
if (prefer.contains("return=minimal")) { //$NON-NLS-1$
return ReturnRepresentation.MINIMAL;
} else if (prefer.contains("return=representation")) {
return ReturnRepresentation.REPRESENTATION;
}
}
return ReturnRepresentation.NONE;
}
public String getHeader(String key) {
return this.request.getHeader(key);
}
public String getETag() {
String etag = getHeader(HttpHeader.IF_MATCH);
if (etag == null) {
etag = getHeader(HttpHeader.IF_NONE_MATCH);
}
return ((etag == null) ? "*" : etag); //$NON-NLS-1$
}
public ODataSerializer getSerializer() throws ContentNegotiatorException,
SerializerException {
return this.odata.createSerializer(getResponseContentType());
}
public ODataSerializer getSerializer(ContentType type) throws ContentNegotiatorException,
SerializerException {
return this.odata.createSerializer(type);
}
public Map<String, String> getPreferences(){
HashMap<String, String> map = new HashMap<String, String>();
List<String> headers = request.getHeaders(HttpHeader.PREFER);
if (headers != null) {
for (String header:headers) {
int idx = header.indexOf('=');
if (idx != -1) {
String key = header.substring(0, idx);
String value = header.substring(idx+1);
if (value.startsWith("\"")) {
value = value.substring(1);
}
if (value.endsWith("\"")) {
value = value.substring(0, value.length()-1);
}
map.put(key, value);
} else {
map.put(header, "true");
}
}
}
return map;
}
public String getPreference(String key) {
return getPreferences().get(key);
}
public String getQueryParameter(String param) {
String queryPath = getODataRequest().getRawQueryPath();
if (queryPath != null) {
StringTokenizer st = new StringTokenizer(queryPath, ",");
while (st.hasMoreTokens()) {
String token = st.nextToken();
int index = token.indexOf('=');
if (index != -1) {
String key = token.substring(0, index);
String value = token.substring(index+1);
if (key.equals(param)) {
return value;
}
}
}
}
return null;
}
public DataRequest parseLink(URI uri) throws UriParserException, UriValidationException {
String path = "/";
URI servicePath = URI.create(getODataRequest().getRawBaseUri());
path = servicePath.getPath();
String rawPath = uri.getPath();
int e = rawPath.indexOf(path);
if (-1 == e) {
rawPath = uri.getPath();
} else {
rawPath = rawPath.substring(e+path.length());
}
UriInfo uriInfo = new Parser(serviceMetadata.getEdm(), odata).parseUri(rawPath, uri.getQuery(), null);
ServiceDispatcher dispatcher = new ServiceDispatcher(odata, serviceMetadata, null, customContentType);
dispatcher.visit(uriInfo);
dispatcher.request.setUriInfo(uriInfo);
return (DataRequest)dispatcher.request;
}
}