blob: 75e3dcc51524b916caab3072633f626f7b1f513b [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.tecsvc.processor;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.processor.ActionComplexCollectionProcessor;
import org.apache.olingo.server.api.processor.ActionComplexProcessor;
import org.apache.olingo.server.api.processor.ActionPrimitiveCollectionProcessor;
import org.apache.olingo.server.api.processor.ActionPrimitiveProcessor;
import org.apache.olingo.server.api.processor.ComplexCollectionProcessor;
import org.apache.olingo.server.api.processor.ComplexProcessor;
import org.apache.olingo.server.api.processor.PrimitiveCollectionProcessor;
import org.apache.olingo.server.api.processor.PrimitiveProcessor;
import org.apache.olingo.server.api.processor.PrimitiveValueProcessor;
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
import org.apache.olingo.server.api.serializer.PrimitiveValueSerializerOptions;
import org.apache.olingo.server.api.serializer.RepresentationType;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.UriHelper;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.UriResourceProperty;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.tecsvc.data.DataProvider;
/**
* Technical Processor which provides functionality related to primitive and complex types and collections thereof.
*/
public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
implements PrimitiveProcessor, PrimitiveValueProcessor, ActionPrimitiveProcessor,
PrimitiveCollectionProcessor, ActionPrimitiveCollectionProcessor,
ComplexProcessor, ActionComplexProcessor,
ComplexCollectionProcessor, ActionComplexCollectionProcessor {
public TechnicalPrimitiveComplexProcessor(final DataProvider dataProvider) {
super(dataProvider);
}
@Override
public void readPrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException {
readProperty(response, uriInfo, contentType, RepresentationType.PRIMITIVE);
}
@Override
public void updatePrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void deletePrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo)
throws ODataApplicationException {
deleteProperty(response, uriInfo);
}
@Override
public void processActionPrimitive(final ODataRequest request, final ODataResponse response,
final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void readPrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException {
readProperty(response, uriInfo, contentType, RepresentationType.COLLECTION_PRIMITIVE);
}
@Override
public void updatePrimitiveCollection(final ODataRequest request, final ODataResponse response,
final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void deletePrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo)
throws ODataApplicationException {
deleteProperty(response, uriInfo);
}
@Override
public void processActionPrimitiveCollection(final ODataRequest request, final ODataResponse response,
final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException,
SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void readComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException {
readProperty(response, uriInfo, contentType, RepresentationType.COMPLEX);
}
@Override
public void updateComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void processActionComplex(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType
requestFormat, ContentType responseFormat) throws ODataApplicationException, DeserializerException,
SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void deleteComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo)
throws ODataApplicationException {
deleteProperty(response, uriInfo);
}
@Override
public void readComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException {
readProperty(response, uriInfo, contentType, RepresentationType.COLLECTION_COMPLEX);
}
@Override
public void updateComplexCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void processActionComplexCollection(ODataRequest request, ODataResponse response,
UriInfo uriInfo, ContentType requestFormat,
ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
public void deleteComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo)
throws ODataApplicationException {
deleteProperty(response, uriInfo);
}
private void readProperty(final ODataResponse response, final UriInfo uriInfo, final ContentType contentType,
final RepresentationType representationType) throws ODataApplicationException, SerializerException {
final UriInfoResource resource = uriInfo.asUriInfoResource();
validateOptions(resource);
validatePath(resource);
final List<UriResource> resourceParts = resource.getUriResourceParts();
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0);
final List<String> path = getPropertyPath(resourceParts);
final Property property = getPropertyData(resourceEntitySet, path);
if (property == null) {
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
} else {
if (property.getValue() == null) {
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
} else {
final EdmEntitySet edmEntitySet = getEdmEntitySet(resource);
final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(path.size())).getProperty();
final ODataFormat format = ODataFormat.fromContentType(contentType);
ODataSerializer serializer = odata.createSerializer(format);
final ExpandOption expand = uriInfo.getExpandOption();
final SelectOption select = uriInfo.getSelectOption();
final UriHelper helper = odata.createUriHelper();
final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? null :
ContextURL.with().entitySet(edmEntitySet)
.keyPath(helper.buildContextURLKeyPredicate(
((UriResourceEntitySet) resourceParts.get(0)).getKeyPredicates()))
.navOrPropertyPath(buildPropertyPath(path))
.selectList(edmProperty.isPrimitive() ? null :
helper.buildContextURLSelectList((EdmStructuredType) edmProperty.getType(), expand, select))
.build();
switch (representationType) {
case PRIMITIVE:
response.setContent(serializer.primitive((EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with().contextURL(contextURL).facetsFrom(edmProperty).build()));
break;
case COMPLEX:
response.setContent(serializer.complex((EdmComplexType) edmProperty.getType(), property,
ComplexSerializerOptions.with().contextURL(contextURL)
.expand(expand).select(select)
.build()));
break;
case COLLECTION_PRIMITIVE:
response.setContent(serializer.primitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
PrimitiveSerializerOptions.with().contextURL(contextURL).facetsFrom(edmProperty).build()));
break;
case COLLECTION_COMPLEX:
response.setContent(serializer.complexCollection((EdmComplexType) edmProperty.getType(), property,
ComplexSerializerOptions.with().contextURL(contextURL)
.expand(expand).select(select)
.build()));
break;
default:
break;
}
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
}
}
}
private void deleteProperty(final ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException {
final UriInfoResource resource = uriInfo.asUriInfoResource();
validatePath(resource);
final List<UriResource> resourceParts = resource.getUriResourceParts();
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0);
final List<String> path = getPropertyPath(resourceParts);
final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(path.size())).getProperty();
final Property property = getPropertyData(resourceEntitySet, path);
if (edmProperty.isNullable() == null || edmProperty.isNullable()) {
property.setValue(property.getValueType(), edmProperty.isCollection() ? Collections.emptyList() : null);
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
} else {
throw new ODataApplicationException("Not nullable.", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
}
}
private Property getPropertyData(final UriResourceEntitySet resourceEntitySet, final List<String> path)
throws ODataApplicationException {
final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), resourceEntitySet.getKeyPredicates());
if (entity == null) {
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
} else {
Property property = entity.getProperty(path.get(0));
for (final String name : path.subList(1, path.size())) {
if (property != null && (property.isLinkedComplex() || property.isComplex())) {
final List<Property> complex = property.isLinkedComplex() ?
property.asLinkedComplex().getValue() : property.asComplex();
property = null;
for (final Property innerProperty : complex) {
if (innerProperty.getName().equals(name)) {
property = innerProperty;
break;
}
}
}
}
return property;
}
}
private List<String> getPropertyPath(final List<UriResource> path) {
List<String> result = new LinkedList<String>();
int index = 1;
while (index < path.size() && path.get(index) instanceof UriResourceProperty) {
result.add(((UriResourceProperty) path.get(index)).getProperty().getName());
index++;
}
return result;
}
private String buildPropertyPath(final List<String> path) {
StringBuilder result = new StringBuilder();
for (final String segment : path) {
result.append(result.length() == 0 ? "" : '/').append(segment);
}
return result.toString();
}
@Override
public void readPrimitiveValue(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException {
final UriInfoResource resource = uriInfo.asUriInfoResource();
validateOptions(resource);
validatePath(resource);
final List<UriResource> resourceParts = resource.getUriResourceParts();
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0);
final List<String> path = getPropertyPath(resourceParts);
final Property property = getPropertyData(resourceEntitySet, path);
if (property == null || property.getValue() == null) {
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
} else {
final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(path.size())).getProperty();
final EdmPrimitiveType type = (EdmPrimitiveType) edmProperty.getType();
final FixedFormatSerializer serializer = odata.createFixedFormatSerializer();
response.setContent(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ?
serializer.binary((byte[]) property.getValue()) :
serializer.primitiveValue(type, property.getValue(),
PrimitiveValueSerializerOptions.with().facetsFrom(edmProperty).build()));
response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
}
}
private void validatePath(final UriInfoResource uriInfo) throws ODataApplicationException {
final List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
for (final UriResource segment : resourcePaths.subList(1, resourcePaths.size())) {
final UriResourceKind kind = segment.getKind();
if (kind != UriResourceKind.primitiveProperty
&& kind != UriResourceKind.complexProperty
&& kind != UriResourceKind.count
&& kind != UriResourceKind.value) {
throw new ODataApplicationException("Invalid resource type.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
}
}
}