blob: da5da658db20933586a4f573cb0cd5682a7e4576 [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.data;
import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.olingo.commons.api.data.ComplexValue;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Parameter;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmParameter;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
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.edm.EdmType;
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.UriInfoResource;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.api.uri.queryoption.expression.Literal;
public class DataProvider {
protected static final String MEDIA_PROPERTY_NAME = "$value";
private AtomicInteger KEY_INT_16 = new AtomicInteger(0);
private AtomicInteger KEY_INT_32 = new AtomicInteger(0);
private AtomicLong KEY_INT_64 = new AtomicLong(0);
private AtomicLong KEY_STRING = new AtomicLong(0);
private Map<String, EntityCollection> data;
private final OData odata;
private final Edm edm;
public DataProvider(final OData odata, final Edm edm) {
this.odata = odata;
this.edm = edm;
data = new DataCreator(odata, edm).getData();
}
public EntityCollection readAll(final EdmEntitySet edmEntitySet) throws DataProviderException {
EntityCollection entityCollection = data.get(edmEntitySet.getName());
if (entityCollection == null) {
entityCollection = new EntityCollection();
data.put(edmEntitySet.getName(), entityCollection);
}
return entityCollection;
}
public Entity read(final EdmEntitySet edmEntitySet, final List<UriParameter> keys) throws DataProviderException {
final EntityCollection entitySet = readAll(edmEntitySet);
return entitySet == null ? null : read(edmEntitySet.getEntityType(), entitySet, keys);
}
public Entity read(final EdmEntityType edmEntityType, final EntityCollection entitySet,
final List<UriParameter> keys) throws DataProviderException {
try {
for (final Entity entity : entitySet.getEntities()) {
boolean found = true;
for (final UriParameter key : keys) {
final EdmProperty property = (EdmProperty) edmEntityType.getProperty(key.getName());
final EdmPrimitiveType type = (EdmPrimitiveType) property.getType();
final Object value = entity.getProperty(key.getName()).getValue();
if (key.getExpression() != null && !(key.getExpression() instanceof Literal)) {
throw new DataProviderException("Expression in key value is not supported yet!",
HttpStatusCode.NOT_IMPLEMENTED);
}
final String text = key.getAlias() == null ? key.getText() : ((Literal) key.getExpression()).getText();
final Object keyValue = type.valueOfString(type.fromUriLiteral(text),
property.isNullable(), property.getMaxLength(), property.getPrecision(), property.getScale(),
property.isUnicode(),
Calendar.class.isAssignableFrom(value.getClass()) ? Calendar.class : value.getClass());
if (!value.equals(keyValue)) {
found = false;
break;
}
}
if (found) {
return entity;
}
}
return null;
} catch (final EdmPrimitiveTypeException e) {
throw new DataProviderException("Wrong key!", HttpStatusCode.BAD_REQUEST, e);
}
}
public void delete(final EdmEntitySet edmEntitySet, final Entity entity) throws DataProviderException {
deleteLinksTo(entity);
readAll(edmEntitySet).getEntities().remove(entity);
}
public void deleteLinksTo(final Entity to) throws DataProviderException {
for (final String entitySetName : data.keySet()) {
for (final Entity entity : data.get(entitySetName).getEntities()) {
for (Iterator<Link> linkIterator = entity.getNavigationLinks().iterator(); linkIterator.hasNext();) {
final Link link = linkIterator.next();
if (to.equals(link.getInlineEntity())) {
linkIterator.remove();
} else if (link.getInlineEntitySet() != null) {
for (Iterator<Entity> iterator = link.getInlineEntitySet().getEntities().iterator(); iterator.hasNext();) {
if (to.equals(iterator.next())) {
iterator.remove();
}
}
if (link.getInlineEntitySet().getEntities().isEmpty()) {
linkIterator.remove();
}
}
}
}
}
}
public Entity create(final EdmEntitySet edmEntitySet) throws DataProviderException {
final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
EntityCollection entitySet = readAll(edmEntitySet);
final List<Entity> entities = entitySet.getEntities();
final Map<String, Object> newKey = findFreeComposedKey(entities, edmEntityType);
Entity newEntity = new Entity();
newEntity.setType(edmEntityType.getFullQualifiedName().getFullQualifiedNameAsString());
for (final String keyName : edmEntityType.getKeyPredicateNames()) {
newEntity.addProperty(DataCreator.createPrimitive(keyName, newKey.get(keyName)));
}
createProperties(edmEntityType, newEntity.getProperties());
try {
newEntity.setId(URI.create(odata.createUriHelper().buildCanonicalURL(edmEntitySet, newEntity)));
} catch (final SerializerException e) {
throw new DataProviderException("Unable to set entity ID!", HttpStatusCode.INTERNAL_SERVER_ERROR, e);
}
entities.add(newEntity);
return newEntity;
}
private Map<String, Object> findFreeComposedKey(final List<Entity> entities, final EdmEntityType entityType)
throws DataProviderException {
// Weak key construction
final HashMap<String, Object> keys = new HashMap<String, Object>();
List<String> keyPredicateNames = entityType.getKeyPredicateNames();
for (final String keyName : keyPredicateNames) {
EdmType type = entityType.getProperty(keyName).getType();
FullQualifiedName typeName = type.getFullQualifiedName();
if (type instanceof EdmTypeDefinition) {
typeName = ((EdmTypeDefinition) type).getUnderlyingType().getFullQualifiedName();
}
Object newValue;
if (EdmPrimitiveTypeKind.Int16.getFullQualifiedName().equals(typeName)) {
newValue = (short) KEY_INT_16.incrementAndGet();
while (!isFree(newValue, keyName, entities)) {
newValue = (short) KEY_INT_16.incrementAndGet();
}
} else if (EdmPrimitiveTypeKind.Int32.getFullQualifiedName().equals(typeName)) {
newValue = KEY_INT_32.incrementAndGet();
while (!isFree(newValue, keyName, entities)) {
newValue = KEY_INT_32.incrementAndGet();
}
} else if (EdmPrimitiveTypeKind.Int64.getFullQualifiedName().equals(typeName)) {
// Integer keys
newValue = KEY_INT_64.incrementAndGet();
while (!isFree(newValue, keyName, entities)) {
newValue = KEY_INT_64.incrementAndGet();
}
} else if (EdmPrimitiveTypeKind.String.getFullQualifiedName().equals(typeName)) {
// String keys
newValue = String.valueOf(KEY_STRING.incrementAndGet());
while (!isFree(newValue, keyName, entities)) {
newValue = String.valueOf(KEY_STRING.incrementAndGet());
}
} else if (type instanceof EdmEnumType) {
/* In case of an enum key we only support composite keys. This way we can 0 as a key */
if (keyPredicateNames.size() <= 1) {
throw new DataProviderException("Single Enum as key not supported", HttpStatusCode.NOT_IMPLEMENTED);
}
newValue = new Short((short) 1);
} else {
throw new DataProviderException("Key type not supported", HttpStatusCode.NOT_IMPLEMENTED);
}
keys.put(keyName, newValue);
}
return keys;
}
private boolean isFree(final Object value, final String keyPropertyName, final List<Entity> entities) {
for (final Entity entity : entities) {
if (value != null && value.equals(entity.getProperty(keyPropertyName).getValue())) {
return false;
}
}
return true;
}
private void createProperties(final EdmStructuredType type, final List<Property> properties)
throws DataProviderException {
final List<String> keyNames = type instanceof EdmEntityType ?
((EdmEntityType) type).getKeyPredicateNames() : Collections.<String> emptyList();
for (final String propertyName : type.getPropertyNames()) {
if (!keyNames.contains(propertyName)) {
final EdmProperty edmProperty = type.getStructuralProperty(propertyName);
properties.add(createProperty(edmProperty, propertyName));
}
}
}
private Property createProperty(final EdmProperty edmProperty, final String propertyName)
throws DataProviderException {
final EdmType type = edmProperty.getType();
Property newProperty;
if (edmProperty.isPrimitive()
|| type.getKind() == EdmTypeKind.ENUM || type.getKind() == EdmTypeKind.DEFINITION) {
newProperty = edmProperty.isCollection() ?
DataCreator.createPrimitiveCollection(propertyName) :
DataCreator.createPrimitive(propertyName, null);
} else {
if (edmProperty.isCollection()) {
@SuppressWarnings("unchecked")
Property newProperty2 = DataCreator.createComplexCollection(propertyName,
edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
newProperty = newProperty2;
} else {
newProperty = DataCreator.createComplex(propertyName,
edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
createProperties((EdmComplexType) type, newProperty.asComplex().getValue());
}
}
return newProperty;
}
public void update(final String rawBaseUri, final EdmEntitySet edmEntitySet, Entity entity,
final Entity changedEntity, final boolean patch, final boolean isInsert) throws DataProviderException {
final EdmEntityType entityType = edmEntitySet.getEntityType();
final List<String> keyNames = entityType.getKeyPredicateNames();
// Update Properties
for (final String propertyName : entityType.getPropertyNames()) {
if (!keyNames.contains(propertyName)) {
updateProperty(entityType.getStructuralProperty(propertyName),
entity.getProperty(propertyName),
changedEntity.getProperty(propertyName),
patch);
}
}
// For insert operations collection navigation property bind operations and deep insert operations can be combined.
// In this case, the bind operations MUST appear before the deep insert operations in the payload.
// => Apply bindings first
final boolean navigationBindingsAvailable = !changedEntity.getNavigationBindings().isEmpty();
if (navigationBindingsAvailable) {
applyNavigationBinding(rawBaseUri, edmEntitySet, entity, changedEntity.getNavigationBindings());
}
// Deep insert (only if not an update)
if (isInsert) {
handleDeepInsert(rawBaseUri, edmEntitySet, entity, changedEntity);
} else {
handleDeleteSingleNavigationProperties(edmEntitySet, entity, changedEntity);
}
// Update the ETag if present.
updateETag(entity);
}
public void updateETag(Entity entity) {
if (entity.getETag() != null) {
entity.setETag("W/\"" + UUID.randomUUID() + "\"");
}
}
private void handleDeleteSingleNavigationProperties(final EdmEntitySet edmEntitySet, final Entity entity,
final Entity changedEntity) throws DataProviderException {
final EdmEntityType entityType = edmEntitySet.getEntityType();
final List<String> navigationPropertyNames = entityType.getNavigationPropertyNames();
for (final String navPropertyName : navigationPropertyNames) {
final Link navigationLink = changedEntity.getNavigationLink(navPropertyName);
final EdmNavigationProperty navigationProperty = entityType.getNavigationProperty(navPropertyName);
if (!navigationProperty.isCollection() && navigationLink != null && navigationLink.getInlineEntity() == null) {
// Check if partner is available
if (navigationProperty.getPartner() != null && entity.getNavigationLink(navPropertyName) != null) {
Entity partnerEntity = entity.getNavigationLink(navPropertyName).getInlineEntity();
removeLink(navigationProperty.getPartner(), partnerEntity);
}
// Remove link
removeLink(navigationProperty, entity);
}
}
}
private void applyNavigationBinding(final String rawBaseUri, final EdmEntitySet edmEntitySet,
final Entity entity, final List<Link> navigationBindings) throws DataProviderException {
for (final Link link : navigationBindings) {
final EdmNavigationProperty edmNavProperty = edmEntitySet.getEntityType().getNavigationProperty(link.getTitle());
if (edmNavProperty.isCollection()) {
for (final String bindingLink : link.getBindingLinks()) {
final Entity destEntity = getEntityByReference(bindingLink, rawBaseUri);
createLink(edmNavProperty, entity, destEntity);
}
} else {
final String bindingLink = link.getBindingLink();
final Entity destEntity = getEntityByReference(bindingLink, rawBaseUri);
createLink(edmNavProperty, entity, destEntity);
}
}
}
private void handleDeepInsert(final String rawBaseUri, final EdmEntitySet edmEntitySet, final Entity entity,
final Entity changedEntity) throws DataProviderException {
final EdmEntityType entityType = edmEntitySet.getEntityType();
for (final String navPropertyName : entityType.getNavigationPropertyNames()) {
final Link navigationLink = changedEntity.getNavigationLink(navPropertyName);
if (navigationLink != null) {
// Deep inserts are not allowed in update operations, so we can be sure, that we do not override
// a navigation link!
final EdmNavigationProperty navigationProperty = entityType.getNavigationProperty(navPropertyName);
final EdmEntitySet target = (EdmEntitySet) edmEntitySet.getRelatedBindingTarget(navPropertyName);
if (navigationProperty.isCollection()) {
final List<Entity> entities =
createInlineEntities(rawBaseUri, target, navigationLink.getInlineEntitySet());
for (final Entity inlineEntity : entities) {
createLink(navigationProperty, entity, inlineEntity);
}
} else if (!navigationProperty.isCollection() && navigationLink.getInlineEntity() != null) {
final Entity inlineEntity = createInlineEntity(rawBaseUri, target, navigationLink.getInlineEntity());
createLink(navigationProperty, entity, inlineEntity);
}
}
}
}
private void removeLink(final EdmNavigationProperty navigationProperty, final Entity entity) {
final Link link = entity.getNavigationLink(navigationProperty.getName());
if (link != null) {
entity.getNavigationLinks().remove(link);
}
}
private List<Entity> createInlineEntities(final String rawBaseUri, final EdmEntitySet targetEntitySet,
final EntityCollection changedEntitySet) throws DataProviderException {
List<Entity> entities = new ArrayList<Entity>();
for (final Entity newEntity : changedEntitySet.getEntities()) {
entities.add(createInlineEntity(rawBaseUri, targetEntitySet, newEntity));
}
return entities;
}
private Entity createInlineEntity(final String rawBaseUri, final EdmEntitySet targetEntitySet,
final Entity changedEntity) throws DataProviderException {
final Entity inlineEntity = create(targetEntitySet);
update(rawBaseUri, targetEntitySet, inlineEntity, changedEntity, false, true);
return inlineEntity;
}
private void createLink(final EdmNavigationProperty navigationProperty, final Entity srcEntity,
final Entity destEntity) {
setLink(navigationProperty, srcEntity, destEntity);
final EdmNavigationProperty partnerNavigationProperty = navigationProperty.getPartner();
if (partnerNavigationProperty != null) {
setLink(partnerNavigationProperty, destEntity, srcEntity);
}
}
public void setLink(final EdmNavigationProperty navigationProperty, final Entity srcEntity,
final Entity targetEntity) {
if (navigationProperty.isCollection()) {
DataCreator.setLinks(srcEntity, navigationProperty.getName(), targetEntity);
} else {
DataCreator.setLink(srcEntity, navigationProperty.getName(), targetEntity);
}
}
@SuppressWarnings("unchecked")
public void updateProperty(final EdmProperty edmProperty, Property property, final Property newProperty,
final boolean patch) throws DataProviderException {
final EdmType type = edmProperty.getType();
if (edmProperty.isCollection()) {
// Updating collection properties means replacing all entries with the given ones.
property.asCollection().clear();
if (newProperty != null) {
if (type.getKind() == EdmTypeKind.COMPLEX) {
// Create each complex value.
for (final ComplexValue complexValue : (List<ComplexValue>) newProperty.asCollection()) {
((List<ComplexValue>) property.asCollection()).add(createComplexValue(edmProperty, complexValue, patch));
}
} else {
// Primitive type
((List<Object>) property.asCollection()).addAll(newProperty.asCollection());
}
}
} else if (type.getKind() == EdmTypeKind.COMPLEX) {
for (final String propertyName : ((EdmComplexType) type).getPropertyNames()) {
final List<Property> newProperties = newProperty == null || newProperty.asComplex() == null ? null :
newProperty.asComplex().getValue();
updateProperty(((EdmComplexType) type).getStructuralProperty(propertyName),
findProperty(propertyName, property.asComplex().getValue()),
newProperties == null ? null : findProperty(propertyName, newProperties),
patch);
}
} else {
if (newProperty != null || !patch) {
final Object value = newProperty == null ? null : newProperty.getValue();
updatePropertyValue(property, value);
}
}
}
public void updatePropertyValue(Property property, final Object value) {
property.setValue(property.getValueType(), value);
}
private ComplexValue createComplexValue(final EdmProperty edmProperty, final ComplexValue complexValue,
final boolean patch) throws DataProviderException {
final ComplexValue result = new ComplexValue();
final EdmComplexType edmType = (EdmComplexType) edmProperty.getType();
final List<Property> givenProperties = complexValue.getValue();
// Create ALL properties, even if no value is given. Check if null is allowed
for (final String propertyName : edmType.getPropertyNames()) {
final EdmProperty innerEdmProperty = (EdmProperty) edmType.getProperty(propertyName);
final Property currentProperty = findProperty(propertyName, givenProperties);
final Property newProperty = createProperty(innerEdmProperty, propertyName);
result.getValue().add(newProperty);
if (currentProperty != null) {
updateProperty(innerEdmProperty, newProperty, currentProperty, patch);
} else {
if (innerEdmProperty.isNullable()) {
// Check complex properties ... may be null is not allowed
if (edmProperty.getType().getKind() == EdmTypeKind.COMPLEX) {
updateProperty(innerEdmProperty, newProperty, null, patch);
}
}
}
}
return result;
}
private Property findProperty(final String propertyName, final List<Property> properties) {
for (final Property property : properties) {
if (propertyName.equals(property.getName())) {
return property;
}
}
return null;
}
public byte[] readMedia(final Entity entity) {
return (byte[]) entity.getProperty(MEDIA_PROPERTY_NAME).asPrimitive();
}
public void setMedia(final Entity entity, final byte[] media, final String type) {
entity.getProperties().remove(entity.getProperty(MEDIA_PROPERTY_NAME));
entity.addProperty(DataCreator.createPrimitive(MEDIA_PROPERTY_NAME, media));
entity.setMediaContentType(type);
entity.setMediaETag("W/\"" + UUID.randomUUID() + "\"");
}
public EntityCollection readFunctionEntityCollection(final EdmFunction function, final List<UriParameter> parameters,
final UriInfoResource uriInfo) throws DataProviderException {
return FunctionData.entityCollectionFunction(function.getName(),
getFunctionParameters(function, parameters, uriInfo),
data);
}
public Entity readFunctionEntity(final EdmFunction function, final List<UriParameter> parameters,
final UriInfoResource uriInfo) throws DataProviderException {
return FunctionData.entityFunction(function.getName(),
getFunctionParameters(function, parameters, uriInfo),
data);
}
public Property readFunctionPrimitiveComplex(final EdmFunction function, final List<UriParameter> parameters,
final UriInfoResource uriInfo) throws DataProviderException {
return FunctionData.primitiveComplexFunction(function.getName(),
getFunctionParameters(function, parameters, uriInfo),
data);
}
private Map<String, Parameter> getFunctionParameters(final EdmFunction function,
final List<UriParameter> parameters, final UriInfoResource uriInfo) throws DataProviderException {
Map<String, Parameter> values = new HashMap<String, Parameter>();
for (final UriParameter parameter : parameters) {
if (parameter.getExpression() != null && !(parameter.getExpression() instanceof Literal)) {
throw new DataProviderException("Expression in function-parameter value is not supported yet!",
HttpStatusCode.NOT_IMPLEMENTED);
}
final EdmParameter edmParameter = function.getParameter(parameter.getName());
final String text = parameter.getAlias() == null ?
parameter.getText() :
uriInfo.getValueForAlias(parameter.getAlias());
if (text != null) {
try {
values.put(parameter.getName(),
odata.createFixedFormatDeserializer().parameter(text, edmParameter));
} catch (final DeserializerException e) {
throw new DataProviderException("Invalid function parameter.", HttpStatusCode.BAD_REQUEST, e);
}
}
}
return values;
}
public Property processActionPrimitive(final String name, final Map<String, Parameter> actionParameters)
throws DataProviderException {
return ActionData.primitiveAction(name, actionParameters);
}
public Property processActionComplex(final String name, final Map<String, Parameter> actionParameters)
throws DataProviderException {
return ActionData.complexAction(name, actionParameters);
}
public Property processActionComplexCollection(final String name, final Map<String, Parameter> actionParameters)
throws DataProviderException {
return ActionData.complexCollectionAction(name, actionParameters);
}
public Property processActionPrimitiveCollection(final String name, final Map<String, Parameter> actionParameters)
throws DataProviderException {
return ActionData.primitiveCollectionAction(name, actionParameters, odata);
}
public EntityActionResult processActionEntity(final String name, final Map<String, Parameter> actionParameters)
throws DataProviderException {
return ActionData.entityAction(name, actionParameters, data, odata, edm);
}
public EntityCollection processActionEntityCollection(final String name,
final Map<String, Parameter> actionParameters) throws DataProviderException {
return ActionData.entityCollectionAction(name, actionParameters, odata, edm);
}
public void createReference(final Entity entity, final EdmNavigationProperty navigationProperty, final URI entityId,
final String rawServiceRoot) throws DataProviderException {
setLink(navigationProperty, entity, getEntityByReference(entityId.toASCIIString(), rawServiceRoot));
}
public void deleteReference(final Entity entity, final EdmNavigationProperty navigationProperty,
final String entityId, final String rawServiceRoot) throws DataProviderException {
if (navigationProperty.isCollection()) {
final Entity targetEntity = getEntityByReference(entityId, rawServiceRoot);
final Link navigationLink = entity.getNavigationLink(navigationProperty.getName());
if (navigationLink != null && navigationLink.getInlineEntitySet() != null
&& navigationLink.getInlineEntitySet().getEntities().contains(targetEntity)) {
// Remove partner single-valued navigation property
if (navigationProperty.getPartner() != null) {
final EdmNavigationProperty edmPartnerNavigationProperty = navigationProperty.getPartner();
if (!edmPartnerNavigationProperty.isCollection() && !edmPartnerNavigationProperty.isNullable()) {
throw new DataProviderException("Navigation property must not be null", HttpStatusCode.BAD_REQUEST);
} else if (!edmPartnerNavigationProperty.isCollection()) {
removeLink(edmPartnerNavigationProperty, targetEntity);
} else if (edmPartnerNavigationProperty.isCollection()
&& edmPartnerNavigationProperty.getPartner() != null) {
// Bidirectional referential constraint
final Link partnerNavigationLink = targetEntity.getNavigationLink(edmPartnerNavigationProperty.getName());
if (partnerNavigationLink != null && partnerNavigationLink.getInlineEntitySet() != null) {
partnerNavigationLink.getInlineEntitySet().getEntities().remove(entity);
}
}
}
// Remove target entity from collection-valued navigation property
navigationLink.getInlineEntitySet().getEntities().remove(targetEntity);
} else {
throw new DataProviderException("Entity not found", HttpStatusCode.NOT_FOUND);
}
} else {
if (navigationProperty.isNullable()) {
removeLink(navigationProperty, entity);
} else {
throw new DataProviderException("Navigation property must not be null", HttpStatusCode.BAD_REQUEST);
}
}
}
protected Entity getEntityByReference(final String entityId, final String rawServiceRoot)
throws DataProviderException {
try {
final UriResourceEntitySet uriResource = odata.createUriHelper().parseEntityId(edm, entityId, rawServiceRoot);
final Entity targetEntity = read(uriResource.getEntitySet(), uriResource.getKeyPredicates());
if (targetEntity != null) {
return targetEntity;
} else {
throw new DataProviderException("Entity not found", HttpStatusCode.NOT_FOUND);
}
} catch (DeserializerException e) {
throw new DataProviderException("Invalid entity-id", HttpStatusCode.BAD_REQUEST, e);
}
}
public static class DataProviderException extends ODataApplicationException {
private static final long serialVersionUID = 5098059649321796156L;
public DataProviderException(final String message, final HttpStatusCode statusCode) {
super(message, statusCode.getStatusCode(), Locale.ROOT);
}
public DataProviderException(final String message, final HttpStatusCode statusCode, final Throwable throwable) {
super(message, statusCode.getStatusCode(), Locale.ROOT, throwable);
}
}
}