| /* |
| * 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; |
| } |
| } |