correct context URL for server property responses

Change-Id: Ie262212ab1ec1a0b9067770ff3b13eb14f216e53

Signed-off-by: Michael Bolz <michael.bolz@sap.com>
This commit is contained in:
Klaus Straubinger 2014-10-31 14:11:28 +01:00 committed by Michael Bolz
parent 357e8b654b
commit 3e11738125
9 changed files with 202 additions and 158 deletions

View File

@ -19,7 +19,6 @@
package org.apache.olingo.commons.api.data; package org.apache.olingo.commons.api.data;
import java.net.URI; import java.net.URI;
import java.util.Map;
import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -143,29 +142,8 @@ public class ContextURL {
return this; return this;
} }
public Builder keySegment(String value) { public Builder keyPath(final String value) {
if (value != null) { contextURL.keyPath = value;
contextURL.keyPath = value;
}
return this;
}
public Builder keySegment(Map<String, String> values) {
if (values != null && !values.isEmpty()) {
if (values.size() == 1) {
return keySegment(values.values().iterator().next());
}
StringBuilder sb = new StringBuilder();
for (String key: values.keySet()) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(key).append("=").append(values.get(key));
}
contextURL.keyPath = sb.toString();
}
return this; return this;
} }
@ -174,7 +152,7 @@ public class ContextURL {
return this; return this;
} }
public Builder propertyType(final EdmType type) { public Builder type(final EdmType type) {
contextURL.entitySetOrSingletonOrType = type.getFullQualifiedName().toString(); contextURL.entitySetOrSingletonOrType = type.getFullQualifiedName().toString();
return this; return this;
} }

View File

@ -19,6 +19,7 @@
package org.apache.olingo.server.api.serializer; package org.apache.olingo.server.api.serializer;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet; import org.apache.olingo.commons.api.data.EntitySet;
@ -28,6 +29,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataServerError;
import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption;
@ -93,4 +95,11 @@ public interface ODataSerializer {
*/ */
String buildContextURLSelectList(EdmEntitySet edmEntitySet, ExpandOption expand, SelectOption select) String buildContextURLSelectList(EdmEntitySet edmEntitySet, ExpandOption expand, SelectOption select)
throws SerializerException; throws SerializerException;
/**
* Builds the key-predicate part of a {@link org.apache.olingo.commons.api.data.ContextURL ContextURL}.
* @param keys the keys as a list of {@link UriParameter} instances
* @return a String with the key predicate
*/
String buildContextURLKeyPredicate(List<UriParameter> keys) throws SerializerException;
} }

View File

@ -19,6 +19,7 @@
package org.apache.olingo.server.core.serializer; package org.apache.olingo.server.core.serializer;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
@ -35,6 +36,7 @@ import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.ODataSerializerOptions; import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption;
import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
@ -104,6 +106,13 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
SerializerException.MessageKeys.NOT_IMPLEMENTED); SerializerException.MessageKeys.NOT_IMPLEMENTED);
} }
@Override
public InputStream entityProperty(EdmProperty edmProperty, Property property,
ODataSerializerOptions options) throws SerializerException{
throw new SerializerException("error serialization not implemented for XML format",
SerializerException.MessageKeys.NOT_IMPLEMENTED);
}
@Override @Override
public String buildContextURLSelectList(final EdmEntitySet edmEntitySet, public String buildContextURLSelectList(final EdmEntitySet edmEntitySet,
final ExpandOption expand, final SelectOption select) throws SerializerException { final ExpandOption expand, final SelectOption select) throws SerializerException {
@ -111,9 +120,7 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
} }
@Override @Override
public InputStream entityProperty(EdmProperty edmProperty, Property property, public String buildContextURLKeyPredicate(final List<UriParameter> keys) throws SerializerException {
ODataSerializerOptions options) throws SerializerException{ return ContextURLHelper.buildKeyPredicate(keys);
throw new SerializerException("error serialization not implemented for XML format", }
SerializerException.MessageKeys.NOT_IMPLEMENTED);
}
} }

View File

@ -46,6 +46,7 @@ import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.ODataSerializerOptions; import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption;
@ -176,17 +177,16 @@ public class ODataJsonSerializer implements ODataSerializer {
return buffer.getInputStream(); return buffer.getInputStream();
} }
private ContextURL checkContextURL(final ODataSerializerOptions options) private ContextURL checkContextURL(final ODataSerializerOptions options) throws SerializerException {
throws SerializerException {
ContextURL contextURL = options == null ? null : options.getContextURL();
if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
throw new SerializerException("ContextURL null!",
SerializerException.MessageKeys.NO_CONTEXT_URL);
}
if (format == ODataFormat.JSON_NO_METADATA) { if (format == ODataFormat.JSON_NO_METADATA) {
contextURL = null; return null;
} else {
final ContextURL contextURL = options == null ? null : options.getContextURL();
if (contextURL == null) {
throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL);
}
return contextURL;
} }
return contextURL;
} }
protected void writeEntitySet(final EdmEntityType entityType, final EntitySet entitySet, protected void writeEntitySet(final EdmEntityType entityType, final EntitySet entitySet,
@ -421,28 +421,18 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
@Override @Override
public String buildContextURLSelectList(final EdmEntitySet edmEntitySet, public InputStream entityProperty(final EdmProperty edmProperty, final Property property,
final ExpandOption expand, final SelectOption select) throws SerializerException { final ODataSerializerOptions options) throws SerializerException {
return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
}
@Override
public InputStream entityProperty(EdmProperty edmProperty,
Property property, ODataSerializerOptions options)
throws SerializerException {
final ContextURL contextURL = checkContextURL(options); final ContextURL contextURL = checkContextURL(options);
CircleStreamBuffer buffer = new CircleStreamBuffer(); CircleStreamBuffer buffer = new CircleStreamBuffer();
try { try {
JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream()); JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
json.writeStartObject(); json.writeStartObject();
if (format != ODataFormat.JSON_NO_METADATA) { if (contextURL != null) {
if (contextURL != null) { json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
}
} }
if (property.isPrimitive() && property.isNull()) { if (property.isPrimitive() && property.isNull()) {
throw new SerializerException("Property value can not be null", throw new SerializerException("Property value can not be null.", SerializerException.MessageKeys.NULL_INPUT);
SerializerException.MessageKeys.NULL_INPUT);
} else if (property.isComplex() && !property.isNull()) { } else if (property.isComplex() && !property.isNull()) {
writePropertyValues(edmProperty, property.asComplex(), null, json); writePropertyValues(edmProperty, property.asComplex(), null, json);
} else if (property.isLinkedComplex() && !property.isNull()) { } else if (property.isLinkedComplex() && !property.isNull()) {
@ -459,4 +449,15 @@ public class ODataJsonSerializer implements ODataSerializer {
} }
return buffer.getInputStream(); return buffer.getInputStream();
} }
@Override
public String buildContextURLSelectList(final EdmEntitySet edmEntitySet,
final ExpandOption expand, final SelectOption select) throws SerializerException {
return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
}
@Override
public String buildContextURLKeyPredicate(final List<UriParameter> keys) throws SerializerException {
return ContextURLHelper.buildKeyPredicate(keys);
}
} }

View File

@ -28,6 +28,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.core.Encoder; import org.apache.olingo.commons.core.Encoder;
import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectItem; import org.apache.olingo.server.api.uri.queryoption.SelectItem;
@ -142,4 +143,26 @@ public final class ContextURLHelper {
} }
return result; return result;
} }
/**
* Builds a key predicate for the ContextURL.
* @param keys the keys as a list of {@link UriParameter} instances
* @return a String with the key predicate
*/
public static String buildKeyPredicate(List<UriParameter> keys) throws SerializerException {
if (keys == null || keys.isEmpty()) {
return null;
} else if (keys.size() == 1) {
return Encoder.encode(keys.get(0).getText());
} else {
StringBuilder result = new StringBuilder();
for (final UriParameter key : keys) {
if (result.length() > 0) {
result.append(',');
}
result.append(Encoder.encode(key.getName())).append('=').append(Encoder.encode(key.getText()));
}
return result.toString();
}
}
} }

View File

@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.TreeMap;
import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.ContextURL.Suffix;
@ -106,22 +105,20 @@ public class ContextURLBuilderTest {
} }
@Test @Test
public void buildPropertyValue() { public void buildProperty() {
EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
Mockito.when(entitySet.getName()).thenReturn("Customers"); Mockito.when(entitySet.getName()).thenReturn("Customers");
ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
.entitySet(entitySet) .entitySet(entitySet)
.keySegment(String.valueOf(1)) .keyPath("1")
.navOrPropertyPath("Name") .navOrPropertyPath("Name")
.build(); .build();
assertEquals("http://host/service/$metadata#Customers(1)/Name", assertEquals("http://host/service/$metadata#Customers(1)/Name",
ContextURLBuilder.create(contextURL).toASCIIString()); ContextURLBuilder.create(contextURL).toASCIIString());
TreeMap<String, String> keys = new TreeMap<String, String>();
keys.put("one", String.valueOf(1));
keys.put("two", "'two'");
contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
.entitySet(entitySet) .entitySet(entitySet)
.keySegment(keys) .keyPath("one=1,two='two'")
.navOrPropertyPath("Name") .navOrPropertyPath("Name")
.build(); .build();
assertEquals("http://host/service/$metadata#Customers(one=1,two='two')/Name", assertEquals("http://host/service/$metadata#Customers(one=1,two='two')/Name",
@ -133,13 +130,13 @@ public class ContextURLBuilderTest {
EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
Mockito.when(entitySet.getName()).thenReturn("Customers"); Mockito.when(entitySet.getName()).thenReturn("Customers");
ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
.propertyType(EdmString.getInstance()) .type(EdmString.getInstance())
.build(); .build();
assertEquals("http://host/service/$metadata#Edm.String", assertEquals("http://host/service/$metadata#Edm.String",
ContextURLBuilder.create(contextURL).toASCIIString()); ContextURLBuilder.create(contextURL).toASCIIString());
contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
.propertyType(EdmString.getInstance()).asCollection() .type(EdmString.getInstance()).asCollection()
.build(); .build();
assertEquals("http://host/service/$metadata#Collection(Edm.String)", assertEquals("http://host/service/$metadata#Collection(Edm.String)",
ContextURLBuilder.create(contextURL).toString()); ContextURLBuilder.create(contextURL).toString());
@ -165,7 +162,7 @@ public class ContextURLBuilderTest {
EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class); EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
Mockito.when(entitySet.getName()).thenReturn("Customers"); Mockito.when(entitySet.getName()).thenReturn("Customers");
ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/")) ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
.propertyType(baseType) .type(baseType)
.build(); .build();
assertEquals("http://host/service/$metadata#namespace.BaseTypeName", assertEquals("http://host/service/$metadata#namespace.BaseTypeName",
ContextURLBuilder.create(contextURL).toASCIIString()); ContextURLBuilder.create(contextURL).toASCIIString());

View File

@ -20,16 +20,16 @@ package org.apache.olingo.server.tecsvc.processor;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.LinkedHashMap; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.ContextURL.Suffix;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet; import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.data.Property; 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.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
@ -98,7 +98,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
response.setContent(serializer.entitySet(edmEntitySet, entitySet, response.setContent(serializer.entitySet(edmEntitySet, entitySet,
ODataSerializerOptions.with() ODataSerializerOptions.with()
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null : .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
getContextUrl(serializer, edmEntitySet, false, expand, select, null)) getContextUrl(serializer, edmEntitySet, false, expand, select, null, null))
.count(uriInfo.getCountOption()) .count(uriInfo.getCountOption())
.expand(expand).select(select) .expand(expand).select(select)
.build())); .build()));
@ -124,7 +124,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
response.setContent(serializer.entity(edmEntitySet, entity, response.setContent(serializer.entity(edmEntitySet, entity,
ODataSerializerOptions.with() ODataSerializerOptions.with()
.contextURL(format == ODataFormat.JSON_NO_METADATA ? null : .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
getContextUrl(serializer, edmEntitySet, true, expand, select, null)) getContextUrl(serializer, edmEntitySet, true, expand, select, null, null))
.count(uriInfo.getCountOption()) .count(uriInfo.getCountOption())
.expand(expand).select(select) .expand(expand).select(select)
.build())); .build()));
@ -209,40 +209,47 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
private ContextURL getContextUrl(final ODataSerializer serializer, private ContextURL getContextUrl(final ODataSerializer serializer,
final EdmEntitySet entitySet, final boolean isSingleEntity, final EdmEntitySet entitySet, final boolean isSingleEntity,
final ExpandOption expand, final SelectOption select, final String propertyPath) final ExpandOption expand, final SelectOption select,
throws SerializerException { final List<UriParameter> keys, final String propertyPath) throws SerializerException {
return ContextURL.with().entitySet(entitySet) return ContextURL.with().entitySet(entitySet)
.selectList(serializer.buildContextURLSelectList(entitySet, expand, select)) .selectList(serializer.buildContextURLSelectList(entitySet, expand, select))
.suffix(isSingleEntity && propertyPath == null ? Suffix.ENTITY : null) .suffix(isSingleEntity && propertyPath == null ? Suffix.ENTITY : null)
.keyPath(serializer.buildContextURLKeyPredicate(keys))
.navOrPropertyPath(propertyPath) .navOrPropertyPath(propertyPath)
.build(); .build();
} }
private Map<String, String> mapKeys(List<UriParameter> parameters)
throws ODataApplicationException {
Map<String, String> keys = new LinkedHashMap<String, String>();
for (UriParameter param: parameters) {
keys.put(param.getName(), param.getText());
}
return keys;
}
@Override @Override
public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException { final ContentType contentType) throws ODataApplicationException, SerializerException {
validateOptions(uriInfo.asUriInfoResource()); validateOptions(uriInfo.asUriInfoResource());
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); final List<UriResource> resourceParts = uriInfo.getUriResourceParts();
final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0);
final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet); final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
if (entity == null) { if (entity == null) {
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
} else { } else {
final UriResourceProperty uriProperty = (UriResourceProperty) uriInfo final List<String> path = getPropertyPath(resourceParts);
.getUriResourceParts().get(uriInfo.getUriResourceParts().size() - 1); EdmProperty edmProperty = edmEntitySet.getEntityType().getStructuralProperty(path.get(0));
final EdmProperty edmProperty = uriProperty.getProperty(); Property property = entity.getProperty(path.get(0));
final Property property = entity.getProperty(edmProperty.getName()); for (final String name : path.subList(1, path.size())) {
if (property != null && (property.isLinkedComplex() || property.isComplex())) {
edmProperty = ((EdmComplexType) edmProperty.getType()).getStructuralProperty(name);
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;
}
}
}
}
if (property == null) { if (property == null) {
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
} else { } else {
@ -252,11 +259,10 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
final ODataFormat format = ODataFormat.fromContentType(contentType); final ODataFormat format = ODataFormat.fromContentType(contentType);
ODataSerializer serializer = odata.createSerializer(format); ODataSerializer serializer = odata.createSerializer(format);
response.setContent(serializer.entityProperty(edmProperty, property, response.setContent(serializer.entityProperty(edmProperty, property,
ODataSerializerOptions.with().contextURL(format == ODataFormat.JSON_NO_METADATA ? null : ODataSerializerOptions.with().contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
ContextURL.with().entitySet(edmEntitySet) getContextUrl(serializer, edmEntitySet, true, null, null,
.keySegment(mapKeys(resourceEntitySet.getKeyPredicates())) resourceEntitySet.getKeyPredicates(), buildPropertyPath(path)))
.navOrPropertyPath(edmProperty.getName()) .build()));
.build()).build()));
response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString()); response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
} }
@ -264,6 +270,23 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
} }
} }
private List<String> getPropertyPath(final List<UriResource> path) {
List<String> result = new LinkedList<String>();
int index = path.size();
while (path.get(--index) instanceof UriResourceProperty) {
result.add(0, ((UriResourceProperty) path.get(index)).getProperty().getName());
}
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 @Override
public void readPropertyValue(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, public void readPropertyValue(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException { final ContentType contentType) throws ODataApplicationException, SerializerException {

View File

@ -28,9 +28,9 @@ import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.ContextURL.Suffix;
import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntitySet; import org.apache.olingo.commons.api.data.EntitySet;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType; import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmElement;
import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntityContainer;
import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmProperty;
@ -40,8 +40,8 @@ import org.apache.olingo.commons.core.data.PropertyImpl;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.serializer.ODataSerializerOptions; import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
import org.apache.olingo.server.api.serializer.SerializerException;
import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.CountOption;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
@ -52,7 +52,6 @@ import org.apache.olingo.server.tecsvc.data.DataProvider;
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
import org.hamcrest.CoreMatchers; import org.hamcrest.CoreMatchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mockito; import org.mockito.Mockito;
@ -575,96 +574,70 @@ public class ODataJsonSerializerTest {
} }
@Test @Test
public void individualPrimitiveProperty() throws Exception { public void primitiveProperty() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EntitySet entitySet = data.readAll(edmEntitySet); final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString"); final String resultString = IOUtils.toString(serializer
Entity entity = entitySet.getEntities().get(0); .entityProperty(edmProperty, property,
InputStream result = serializer
.entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyString"),
ODataSerializerOptions.with() ODataSerializerOptions.with()
.contextURL(ContextURL.with().entitySetOrSingletonOrType("Edm.String") .contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
.build()) .build())
.build()); .build()));
final String resultString = IOUtils.toString(result);
Assert.assertEquals("{" Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#Edm.String\"," + "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyString\","
+ "\"value\":\"First Resource - positive values\"}", + "\"value\":\"First Resource - positive values\"}",
resultString); resultString);
} }
@Test(expected = SerializerException.class) @Test(expected = SerializerException.class)
public void individualPrimitivePropertyNull() throws Exception { public void primitivePropertyNull() throws Exception {
PropertyImpl property = new PropertyImpl("Edm.String", "PropertyString", ValueType.PRIMITIVE, null);
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString"); final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
serializer.entityProperty((EdmProperty) edmElement, property, final Property property = new PropertyImpl("Edm.String", edmProperty.getName(), ValueType.PRIMITIVE, null);
ODataSerializerOptions.with() serializer.entityProperty(edmProperty, property,
.contextURL(ContextURL.with().entitySetOrSingletonOrType("Edm.String") ODataSerializerOptions.with()
.build()) .contextURL(ContextURL.with()
.build()); .entitySet(edmEntitySet).keyPath("4242").navOrPropertyPath(edmProperty.getName())
.build())
.build());
} }
@Test @Test
public void individualPrimitivePropertyArray() throws Exception { public void primitiveCollectionProperty() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
final EntitySet entitySet = data.readAll(edmEntitySet); final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("CollPropertyString");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
EdmElement edmElement = edmEntitySet.getEntityType().getProperty("CollPropertyString"); final String resultString = IOUtils.toString(serializer
Entity entity = entitySet.getEntities().get(0); .entityProperty(edmProperty, property,
InputStream result = serializer
.entityProperty((EdmProperty) edmElement, entity.getProperty("CollPropertyString"),
ODataSerializerOptions.with() ODataSerializerOptions.with()
.contextURL(ContextURL.with().entitySetOrSingletonOrType("Collection(Edm.String)") .contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName())
.build()) .build())
.build()); .build()));
final String resultString = IOUtils.toString(result);
Assert.assertEquals("{" Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#Collection%28Edm.String%29\"," + "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyString\","
+ "\"value\":[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]}", + "\"value\":[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]}",
resultString); resultString);
} }
@Test @Test
@Ignore("Serialization of value of primitive property is not done by json serializer") public void complexProperty() throws Exception {
public void individualPrimitivePropertyValue() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
final EntitySet entitySet = data.readAll(edmEntitySet);
EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
Entity entity = entitySet.getEntities().get(0);
InputStream result = serializer
.entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyString"),
ODataSerializerOptions.with()
.contextURL(ContextURL.with().entitySetOrSingletonOrType("ESAllPrim(0)")
.navOrPropertyPath("PropertyString")
.build())
.build());
final String resultString = IOUtils.toString(result);
Assert.assertEquals("\"First Resource - positive values\"", resultString);
}
@Test
public void individualComplexProperty() throws Exception {
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp"); final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
final EntitySet entitySet = data.readAll(edmEntitySet); final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyComp");
final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty("PropertyComp");
EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyComp"); final String resultString = IOUtils.toString(serializer
Entity entity = entitySet.getEntities().get(0); .entityProperty(edmProperty, property,
InputStream result = serializer
.entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyComp"),
ODataSerializerOptions.with() ODataSerializerOptions.with()
.contextURL(ContextURL.with().entitySetOrSingletonOrType("ESMixPrimCollComp.PropertyComp") .contextURL(ContextURL.with()
.entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
.build()) .build())
.build()); .build()));
final String resultString = IOUtils.toString(result);
Assert.assertEquals("{" Assert.assertEquals("{"
+ "\"@odata.context\":\"$metadata#ESMixPrimCollComp.PropertyComp\"," + "\"@odata.context\":\"$metadata#ESMixPrimCollComp(32767)/PropertyComp\","
+ "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}", + "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}",
resultString); resultString);
} }

View File

@ -27,9 +27,11 @@ import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmEntityContainer; import org.apache.olingo.commons.api.edm.EdmEntityContainer;
import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.edmx.EdmxReference;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.queryoption.ExpandItem; import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
import org.apache.olingo.server.api.uri.queryoption.SelectItem; import org.apache.olingo.server.api.uri.queryoption.SelectItem;
@ -179,4 +181,35 @@ public class ContextURLHelperTest {
assertEquals("$metadata#ESTwoPrim(NavPropertyETAllPrimOne(NavPropertyETTwoPrimOne(*)))", assertEquals("$metadata#ESTwoPrim(NavPropertyETAllPrimOne(NavPropertyETTwoPrimOne(*)))",
ContextURLBuilder.create(contextURL).toASCIIString()); ContextURLBuilder.create(contextURL).toASCIIString());
} }
@Test
public void buildSingleKey() throws Exception {
final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
final EdmProperty edmProperty = entitySet.getEntityType().getStructuralProperty("PropertyInt16");
UriParameter key = Mockito.mock(UriParameter.class);
Mockito.when(key.getName()).thenReturn(edmProperty.getName());
Mockito.when(key.getText()).thenReturn("42");
final ContextURL contextURL = ContextURL.with().entitySet(entitySet)
.keyPath(ContextURLHelper.buildKeyPredicate(Arrays.asList(key)))
.navOrPropertyPath(edmProperty.getName()).build();
assertEquals("$metadata#ESTwoPrim(42)/PropertyInt16",
ContextURLBuilder.create(contextURL).toASCIIString());
}
@Test
public void buildCompoundKey() throws Exception {
final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoKeyNav");
final EdmProperty edmProperty = entitySet.getEntityType().getStructuralProperty("PropertyInt16");
UriParameter key1 = Mockito.mock(UriParameter.class);
Mockito.when(key1.getName()).thenReturn(edmProperty.getName());
Mockito.when(key1.getText()).thenReturn("1");
UriParameter key2 = Mockito.mock(UriParameter.class);
Mockito.when(key2.getName()).thenReturn("PropertyString");
Mockito.when(key2.getText()).thenReturn("'2'");
final ContextURL contextURL = ContextURL.with().entitySet(entitySet)
.keyPath(ContextURLHelper.buildKeyPredicate(Arrays.asList(key1, key2)))
.navOrPropertyPath(edmProperty.getName()).build();
assertEquals("$metadata#ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/PropertyInt16",
ContextURLBuilder.create(contextURL).toASCIIString());
}
} }