diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java index aa119d400..89f2e8996 100755 --- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java +++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/data/PropertyImpl.java @@ -33,8 +33,8 @@ public class PropertyImpl extends AbstractValuable implements Property { this.type = type; } - public PropertyImpl(final String type, final String name, final ValueType valueType, final Object value) { - this(name, type); + public PropertyImpl(String type, String name, ValueType valueType, Object value) { + this(type, name); setValue(valueType, value); } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java index 21304b6f9..2ea5b9ece 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java @@ -18,36 +18,24 @@ */ package org.apache.olingo.server.core.serializer.json; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.util.List; - +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import org.apache.olingo.commons.api.Constants; import org.apache.olingo.commons.api.ODataRuntimeException; -import org.apache.olingo.commons.api.data.ContextURL; -import org.apache.olingo.commons.api.data.Entity; -import org.apache.olingo.commons.api.data.EntitySet; -import org.apache.olingo.commons.api.data.LinkedComplexValue; -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.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.data.*; +import org.apache.olingo.commons.api.edm.*; import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; +import java.util.List; public class ODataJsonSerializer implements ODataSerializer { @@ -147,46 +135,59 @@ public class ODataJsonSerializer implements ODataSerializer { json.writeNull(); } } else { - if (edmProperty.isPrimitive()) { - if (property.isPrimitive()) { - writePrimitiveValue(edmProperty, property.asPrimitive(), json); - } else if (property.isGeospatial()) { - throw new ODataRuntimeException("Property type not yet supported!"); - } else if (property.isEnum()) { - json.writeString(property.asEnum().toString()); - } else { - throw new ODataRuntimeException("Inconsistent property type!"); - } - } else if (edmProperty.isCollection()) { - json.writeStartArray(); - for (Object value : property.asCollection()) { - switch (property.getValueType()) { - case COLLECTION_PRIMITIVE: - writePrimitiveValue(edmProperty, value, json); - break; - case COLLECTION_GEOSPATIAL: - throw new ODataRuntimeException("Property type not yet supported!"); - case COLLECTION_ENUM: - json.writeString(value.toString()); - break; - case COLLECTION_LINKED_COMPLEX: - writeLinkedComplexValue(edmProperty, (LinkedComplexValue) value, json); - break; - default: - throw new ODataRuntimeException("Property type not yet supported!"); - } - } - json.writeEndArray(); + if (edmProperty.isCollection()) { + handleCollection(edmProperty, property, json); + } else if (edmProperty.isPrimitive()) { + handlePrimitive(edmProperty, property, json); + } else if (property.isLinkedComplex()) { + writeComplexValue(edmProperty, property.asLinkedComplex().getValue(), json); + } else if(property.isComplex()) { + writeComplexValue(edmProperty, property.asComplex(), json); } else { - if (property.isLinkedComplex()) { - writeLinkedComplexValue(edmProperty, property.asLinkedComplex(), json); - } else { - throw new ODataRuntimeException("Property type not yet supported!"); - } + throw new ODataRuntimeException("Property type not yet supported!"); } } } + private void handleCollection(EdmProperty edmProperty, Property property, JsonGenerator json) + throws IOException, EdmPrimitiveTypeException { + json.writeStartArray(); + for (Object value : property.asCollection()) { + switch (property.getValueType()) { + case COLLECTION_PRIMITIVE: + writePrimitiveValue(edmProperty, value, json); + break; + case COLLECTION_GEOSPATIAL: + throw new ODataRuntimeException("Property type not yet supported!"); + case COLLECTION_ENUM: + json.writeString(value.toString()); + break; + case COLLECTION_LINKED_COMPLEX: + writeComplexValue(edmProperty, ((LinkedComplexValue) value).getValue(), json); + break; + case COLLECTION_COMPLEX: + writeComplexValue(edmProperty, property.asComplex(), json); + break; + default: + throw new ODataRuntimeException("Property type not yet supported!"); + } + } + json.writeEndArray(); + } + + private void handlePrimitive(EdmProperty edmProperty, Property property, JsonGenerator json) + throws EdmPrimitiveTypeException, IOException { + if (property.isPrimitive()) { + writePrimitiveValue(edmProperty, property.asPrimitive(), json); + } else if (property.isGeospatial()) { + throw new ODataRuntimeException("Property type not yet supported!"); + } else if (property.isEnum()) { + json.writeString(property.asEnum().toString()); + } else { + throw new ODataRuntimeException("Inconsistent property type!"); + } + } + protected void writePrimitiveValue(final EdmProperty edmProperty, final Object primitiveValue, final JsonGenerator json) throws EdmPrimitiveTypeException, IOException { @@ -210,10 +211,9 @@ public class ODataJsonSerializer implements ODataSerializer { } } - private void writeLinkedComplexValue(final EdmProperty edmProperty, final LinkedComplexValue linkedComplexValue, - final JsonGenerator json) throws IOException, EdmPrimitiveTypeException { + private void writeComplexValue(final EdmProperty edmProperty, final List properties, + JsonGenerator json) throws IOException, EdmPrimitiveTypeException { final EdmComplexType type = (EdmComplexType) edmProperty.getType(); - final List properties = linkedComplexValue.getValue(); json.writeStartObject(); for (final String propertyName : type.getPropertyNames()) { final Property property = findProperty(propertyName, properties); diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java index 203ac853e..ec2619bc7 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java @@ -18,71 +18,526 @@ */ package org.apache.olingo.server.core.serializer.json; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.util.Arrays; -import java.util.List; - import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.ValueType; -import org.apache.olingo.commons.api.edm.EdmEntityType; -import org.apache.olingo.commons.api.edm.EdmProperty; +import org.apache.olingo.commons.api.edm.*; +import org.apache.olingo.commons.api.edm.constants.EdmTypeKind; import org.apache.olingo.commons.core.data.EntityImpl; +import org.apache.olingo.commons.core.data.EntitySetImpl; import org.apache.olingo.commons.core.data.PropertyImpl; -import org.apache.olingo.commons.core.edm.primitivetype.EdmString; +import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class ODataJsonSerializerTest { - public static final String PROPERTY_1 = "Property1"; + private static final String ETAllPrim = "ETAllPrim"; + private static final String ETCompAllPrim = "ETCompAllPrim"; + private static final String ETCollAllPrim = "ETCollAllPrim"; + private static final String CTAllPrim = "CTAllPrim"; + private static final String CTAllPrim_Type = "com.sap.odata.test1.CTAllPrim"; - private ContextURL contextUrl; - private EdmEntityType edmEntityType; - private final Logger LOG = LoggerFactory.getLogger(ODataJsonSerializerTest.class); + interface TecSvcProperty { + String getName(); + String getTypeName(); + EdmPrimitiveTypeKind getType(); + boolean isCollection(); + } + + public static class TecSvcComplexProperty implements TecSvcProperty { + + final String typeName; + final String name; + final List properties = new ArrayList(); + boolean collection = false; + + public TecSvcComplexProperty(String typeName, String name) { + this.typeName = typeName; + this.name = name; + } + TecSvcProperty addProperties(List properties) { + this.properties.addAll(properties); + return this; + } + TecSvcProperty asCollection() { + this.collection = true; + return this; + } + @Override + public boolean isCollection() { + return collection; + } + @Override + public String getName() { + return name; + } + @Override + public String getTypeName() { + return typeName; + } + @Override + public EdmPrimitiveTypeKind getType() { + return null; + } + public List getProperties() { + return properties; + } + } + + enum TecSvcSimpleProperty implements TecSvcProperty { + Int16("PropertyInt16", EdmPrimitiveTypeKind.Int16), + String("PropertyString", EdmPrimitiveTypeKind.String), + Boolean("PropertyBoolean", EdmPrimitiveTypeKind.Boolean), + Byte("PropertyByte", EdmPrimitiveTypeKind.Byte), + SByte("PropertySByte", EdmPrimitiveTypeKind.SByte), + Int32("PropertyInt32", EdmPrimitiveTypeKind.Int32), + Int64("PropertyInt64", EdmPrimitiveTypeKind.Int64), + Single("PropertySingle", EdmPrimitiveTypeKind.Single), + Double("PropertyDouble", EdmPrimitiveTypeKind.Double), + Decimal("PropertyDecimal", EdmPrimitiveTypeKind.Decimal), + Binary("PropertyBinary", EdmPrimitiveTypeKind.Binary), + Date("PropertyDate", EdmPrimitiveTypeKind.Date), + DateTimeOffset("PropertyDateTimeOffset", EdmPrimitiveTypeKind.DateTimeOffset), + Duration("PropertyDuration", EdmPrimitiveTypeKind.Duration), + Guid("PropertyGuid", EdmPrimitiveTypeKind.Guid), + TimeOfDay("PropertyTimeOfDay", EdmPrimitiveTypeKind.TimeOfDay), + // +// NavETTwoPrimOne = "NavPropertyETTwoPrimOne", EdmPrimitiveTypeKind.), + // +// NavETTwoPrimMany("NavPropertyETTwoPrimMany", EdmCom.); + Collection_Int16("CollPropertyInt16", EdmPrimitiveTypeKind.Int16, true), + Collection_String("CollPropertyString", EdmPrimitiveTypeKind.String, true), + Collection_Boolean("CollPropertyBoolean", EdmPrimitiveTypeKind.Boolean, true), + Collection_Byte("CollPropertyByte", EdmPrimitiveTypeKind.Byte, true), + Collection_SByte("CollPropertySByte", EdmPrimitiveTypeKind.SByte, true), + Collection_Int32("CollPropertyInt32", EdmPrimitiveTypeKind.Int32, true), + Collection_Int64("CollPropertyInt64", EdmPrimitiveTypeKind.Int64, true), + Collection_Single("CollPropertySingle", EdmPrimitiveTypeKind.Single, true), + Collection_Double("CollPropertyDouble", EdmPrimitiveTypeKind.Double, true), + Collection_Decimal("CollPropertyDecimal", EdmPrimitiveTypeKind.Decimal, true), + Collection_Binary("CollPropertyBinary", EdmPrimitiveTypeKind.Binary, true), + Collection_Date("CollPropertyDate", EdmPrimitiveTypeKind.Date, true), + Collection_DateTimeOffset("CollPropertyDateTimeOffset", EdmPrimitiveTypeKind.DateTimeOffset, true), + Collection_Duration("CollPropertyDuration", EdmPrimitiveTypeKind.Duration, true), + Collection_Guid("CollPropertyGuid", EdmPrimitiveTypeKind.Guid, true), + Collection_TimeOfDay("CollPropertyTimeOfDay", EdmPrimitiveTypeKind.TimeOfDay, true); + + final String name; + final EdmPrimitiveTypeKind type; + final boolean isCollection; + + TecSvcSimpleProperty(String name, EdmPrimitiveTypeKind type) { + this(name, type, false); + } + TecSvcSimpleProperty(String name, EdmPrimitiveTypeKind type, boolean collection) { + this.name = name; + this.type = type; + this.isCollection = collection; + } + @Override + public String getTypeName() { + return type.name(); + } + @Override + public EdmPrimitiveTypeKind getType() { + return type; + } + @Override + public String getName() { + return name; + } + @Override + public boolean isCollection() { + return isCollection; + } + } + + private EdmEntitySet edmESAllPrim; + private EdmEntitySet edmESCompAllPrim; + private EdmEntitySet edmESCollAllPrim; + private EdmEntityType edmETAllPrim; + private EdmEntityType edmETCompAllPrim; + private EdmEntityType edmETCollAllPrim; private ODataJsonSerializer serializer = new ODataJsonSerializer(); @Before public void prepare() throws Exception { - contextUrl = ContextURL.getInstance(new URI("http://localhost:8080/test.svc")); - edmEntityType = Mockito.mock(EdmEntityType.class); - List propertyNames = Arrays.asList(PROPERTY_1); - Mockito.when(edmEntityType.getPropertyNames()).thenReturn(propertyNames); + // entity all primitive + edmETAllPrim = Mockito.mock(EdmEntityType.class); + Mockito.when(edmETAllPrim.getName()).thenReturn(ETAllPrim); + List properties = Arrays.asList( + mockProperty(TecSvcSimpleProperty.Int16, false), + mockProperty(TecSvcSimpleProperty.String), + mockProperty(TecSvcSimpleProperty.Boolean), + mockProperty(TecSvcSimpleProperty.Byte), + mockProperty(TecSvcSimpleProperty.SByte), + mockProperty(TecSvcSimpleProperty.Int32), + mockProperty(TecSvcSimpleProperty.Int64), + mockProperty(TecSvcSimpleProperty.Single), + mockProperty(TecSvcSimpleProperty.Double), + mockProperty(TecSvcSimpleProperty.Decimal), + mockProperty(TecSvcSimpleProperty.Binary), + mockProperty(TecSvcSimpleProperty.Date), + mockProperty(TecSvcSimpleProperty.DateTimeOffset), + mockProperty(TecSvcSimpleProperty.Duration), + mockProperty(TecSvcSimpleProperty.Guid), + mockProperty(TecSvcSimpleProperty.TimeOfDay) +// mockProperty(NavPropertyETTwoPrimOne, false), +// mockProperty(NavPropertyETTwoPrimMany, false) + ); + List propertyNames = new ArrayList(); + for (EdmProperty property : properties) { + propertyNames.add(property.getName()); + Mockito.when(edmETAllPrim.getProperty(property.getName())).thenReturn(property); + } + Mockito.when(edmETAllPrim.getPropertyNames()).thenReturn(propertyNames); + + // Entity Set All Primitive + edmESAllPrim = Mockito.mock(EdmEntitySet.class); + Mockito.when(edmESAllPrim.getName()).thenReturn("ESAllPrim"); + Mockito.when(edmESAllPrim.getEntityType()).thenReturn(edmETAllPrim); + // Entity Set All Primitive + edmESCompAllPrim = Mockito.mock(EdmEntitySet.class); + Mockito.when(edmESCompAllPrim.getName()).thenReturn("ESCompAllPrim"); + Mockito.when(edmESCompAllPrim.getEntityType()).thenReturn(edmETCompAllPrim); + // Entity Set All Primitive + edmESCollAllPrim = Mockito.mock(EdmEntitySet.class); + Mockito.when(edmESCollAllPrim.getName()).thenReturn("ESCollAllPrim"); + Mockito.when(edmESCollAllPrim.getEntityType()).thenReturn(edmETCollAllPrim); + + // Entity Type Complex All Primitive + edmETCompAllPrim = Mockito.mock(EdmEntityType.class); + Mockito.when(edmETCompAllPrim.getName()).thenReturn(ETCompAllPrim); + List capProperties = Arrays.asList( + mockProperty(TecSvcSimpleProperty.Int16, false), + mockProperty(new TecSvcComplexProperty(CTAllPrim_Type, CTAllPrim).addProperties(properties), false) + ); + List capPropertyNames = new ArrayList(); + + for (EdmProperty property : capProperties) { + capPropertyNames.add(property.getName()); + Mockito.when(edmETCompAllPrim.getProperty(property.getName())).thenReturn(property); + } + Mockito.when(edmETCompAllPrim.getPropertyNames()).thenReturn(capPropertyNames); + + // entity type all primitive collections + // + edmETCollAllPrim = Mockito.mock(EdmEntityType.class); + Mockito.when(edmETCollAllPrim.getName()).thenReturn(ETCollAllPrim); + List allCollProperties = Arrays.asList( + mockProperty(TecSvcSimpleProperty.Int16, false), + mockProperty(TecSvcSimpleProperty.Collection_String), + mockProperty(TecSvcSimpleProperty.Collection_Boolean), + mockProperty(TecSvcSimpleProperty.Collection_Byte), + mockProperty(TecSvcSimpleProperty.Collection_SByte), + mockProperty(TecSvcSimpleProperty.Collection_Int32), + mockProperty(TecSvcSimpleProperty.Collection_Int64), + mockProperty(TecSvcSimpleProperty.Collection_Single), + mockProperty(TecSvcSimpleProperty.Collection_Double), + mockProperty(TecSvcSimpleProperty.Collection_Decimal), + mockProperty(TecSvcSimpleProperty.Collection_Binary), + mockProperty(TecSvcSimpleProperty.Collection_Date), + mockProperty(TecSvcSimpleProperty.Collection_DateTimeOffset), + mockProperty(TecSvcSimpleProperty.Collection_Duration), + mockProperty(TecSvcSimpleProperty.Collection_Guid), + mockProperty(TecSvcSimpleProperty.Collection_TimeOfDay) + ); + List etCollAllPrimPropertyNames = new ArrayList(); + + for (EdmProperty property : allCollProperties) { + etCollAllPrimPropertyNames.add(property.getName()); + Mockito.when(edmETCollAllPrim.getProperty(property.getName())).thenReturn(property); + } + Mockito.when(edmETCollAllPrim.getPropertyNames()).thenReturn(etCollAllPrimPropertyNames); + + // Entity Set all primitive collection + } + + private EdmProperty mockProperty(TecSvcProperty name) { + return mockProperty(name, true); + } + + private EdmProperty mockProperty(TecSvcProperty tecProperty, boolean nullable) { EdmProperty edmElement = Mockito.mock(EdmProperty.class); - Mockito.when(edmElement.getName()).thenReturn(PROPERTY_1); - Mockito.when(edmElement.isPrimitive()).thenReturn(true); - Mockito.when(edmElement.getMaxLength()).thenReturn(20); - Mockito.when(edmElement.getType()).thenReturn(EdmString.getInstance()); - Mockito.when(edmEntityType.getProperty(PROPERTY_1)).thenReturn(edmElement); + Mockito.when(edmElement.getName()).thenReturn(tecProperty.getName()); + if (tecProperty instanceof TecSvcComplexProperty) { + TecSvcComplexProperty complexProperty = (TecSvcComplexProperty) tecProperty; + Mockito.when(edmElement.isPrimitive()).thenReturn(false); + EdmComplexType type = Mockito.mock(EdmComplexType.class); + Mockito.when(type.getKind()).thenReturn(EdmTypeKind.COMPLEX); + Mockito.when(type.getName()).thenReturn(tecProperty.getTypeName()); + Mockito.when(edmElement.getType()).thenReturn(type); + List propertyNames = new ArrayList(); + List properties = complexProperty.getProperties(); + for (EdmProperty property : properties) { + propertyNames.add(property.getName()); + Mockito.when(type.getProperty(property.getName())).thenReturn(property); + } + Mockito.when(type.getPropertyNames()).thenReturn(propertyNames); + } else { + Mockito.when(edmElement.isPrimitive()).thenReturn(true); + // TODO: set default values + Mockito.when(edmElement.getMaxLength()).thenReturn(40); + Mockito.when(edmElement.getPrecision()).thenReturn(10); + Mockito.when(edmElement.getScale()).thenReturn(10); + Mockito.when(edmElement.getType()).thenReturn(EdmPrimitiveTypeFactory.getInstance(tecProperty.getType())); + } + Mockito.when(edmElement.isCollection()).thenReturn(tecProperty.isCollection()); + Mockito.when(edmElement.isNullable()).thenReturn(nullable); + return edmElement; + } + + private PropertyImpl createProperty(TecSvcProperty property, ValueType vType, Object value) { + return new PropertyImpl(property.getTypeName(), property.getName(), vType, value); + } + + private PropertyImpl createProperty(String type, TecSvcSimpleProperty property, ValueType vType, Object ... value) { + final Object propValue; + if(value == null || value.length ==0) { + propValue = null; + } else if(property.isCollection()) { + propValue = Arrays.asList(value); + } else { + propValue = value[0]; + } + return new PropertyImpl(type, property.name, vType, propValue); } @Test public void entitySimple() throws Exception { + Entity entity = createETAllPrim(); -// Entity entity = new EntityImpl(); -// entity.addProperty(new PropertyImpl("Edm.String", PROPERTY_1, ValueType.PRIMITIVE, "Value_1")); - Entity entity = new EntityImpl(); - PropertyImpl property = new PropertyImpl("Edm.String", PROPERTY_1); - property.setValue(ValueType.PRIMITIVE, "Value_1"); - entity.addProperty(property); - - InputStream result = serializer.entity(edmEntityType, entity, contextUrl); + InputStream result = serializer.entity(edmETAllPrim, entity, createContextURL(edmESAllPrim, true)); String resultString = streamToString(result); -// System.out.println(resultString); - Assert.assertEquals("{\"@odata.context\":\"http://localhost:8080/test.svc\",\"Property1\":\"Value_1\"}", - resultString); + String expectedResult = "{" + + "\"@odata.context\":\"$metadata#ESAllPrim/$entity\"," + + "\"PropertyInt16\":4711," + + "\"PropertyString\":\"StringValue\"," + + "\"PropertyBoolean\":true," + + "\"PropertyByte\":19," + + "\"PropertySByte\":1," + + "\"PropertyInt32\":2147483647," + + "\"PropertyInt64\":9223372036854775807," + + "\"PropertySingle\":47.11," + + "\"PropertyDouble\":4.711," + + "\"PropertyDecimal\":4711.1174," + + "\"PropertyBinary\":\"BAcBAQ==\"," + + "\"PropertyDate\":\"2014-03-19\"," + + "\"PropertyDateTimeOffset\":\"2014-03-19T10:12:00Z\"," + + "\"PropertyDuration\":\"P16148425DT0S\"," + + "\"PropertyGuid\":\"0000aaaa-00bb-00cc-00dd-000000ffffff\"," + + "\"PropertyTimeOfDay\":\"10:12:00\"" + + "}"; + Assert.assertEquals(expectedResult, resultString); } - private String streamToString(final InputStream result) throws IOException { + @Test + public void entitySetETAllPrim() throws Exception { + EdmEntitySet edmEntitySet = edmESAllPrim; + EntitySetImpl entitySet = new EntitySetImpl(); + for (int i = 0; i < 100; i++) { + entitySet.getEntities().add(createETAllPrim(i)); + } + entitySet.setCount(entitySet.getEntities().size()); + ContextURL contextUrl = createContextURL(edmESAllPrim, false); + entitySet.setNext(URI.create(contextUrl.getURI().toASCIIString() + "/next")); + + InputStream result = serializer.entitySet(edmEntitySet, entitySet, contextUrl); + String resultString = streamToString(result); + + Assert.assertTrue(resultString.matches("\\{" + + "\"@odata\\.context\":\"\\$metadata#ESAllPrim\"," + + "\"@odata\\.count\":100," + + "\"value\":\\[.*\\]," + + "\"@odata\\.nextLink\":\"\\$metadata#ESAllPrim/next\"" + + "\\}")); + + Matcher matcher = Pattern.compile("(\\{[a-z0-9:\\=\"\\-,\\.\\+]*\\})", + Pattern.CASE_INSENSITIVE).matcher(resultString); + int count = 0; + while(matcher.find()) { + Assert.assertTrue(matcher.group().contains("PropertyInt16\":" + count++)); + } + Assert.assertEquals(100, count); + } + + @Test + public void entityCollAllPrim() throws Exception { + Entity entity = createETCollAllPrim(4711); + + ContextURL contextUrl = createContextURL(edmESCollAllPrim, true); + InputStream result = serializer.entity(edmETCollAllPrim, entity, contextUrl); + String resultString = streamToString(result); + String expectedResult = "{" + + "\"@odata.context\":\"$metadata#ESCollAllPrim/$entity\"," + + "\"PropertyInt16\":4711," + + "\"CollPropertyString\":[\"StringValue_1\",\"StringValue_2\"]," + + "\"CollPropertyBoolean\":[true,false]," + + "\"CollPropertyByte\":[19,42]," + + "\"CollPropertySByte\":[1,2]," + + "\"CollPropertyInt32\":[2147483647,-2147483648]," + + "\"CollPropertyInt64\":[9223372036854775807,-9223372036854775808]," + + "\"CollPropertySingle\":[47.11,11.47]," + + "\"CollPropertyDouble\":[4.711,711.4]," + + "\"CollPropertyDecimal\":[4711.1174,1174.4711]," + + "\"CollPropertyBinary\":[\"BAcBAQ==\",\"dGVzdA==\"]," + + "\"CollPropertyDate\":[\"2014-03-19\",\"2014-07-02\"]," + + "\"CollPropertyDateTimeOffset\":[\"2014-03-19T10:12:00Z\",\"2014-07-02T13:30:00Z\"]," + + "\"CollPropertyDuration\":[\"P16148425DT0S\",\"P16253562DT12H0S\"]," + + "\"CollPropertyGuid\":[\"0000aaaa-00bb-00cc-00dd-000000ffffff\",\"0000ffff-00dd-00cc-00bb-000000aaaaaa\"]," + + "\"CollPropertyTimeOfDay\":[\"10:12:00\",\"13:30:00\"]" + + "}"; + Assert.assertEquals(expectedResult, resultString); + } + + @Test + public void entityETCompAllPrim() throws Exception { + Entity complexCtAllPrim = createETAllPrim(); + + Entity entity = new EntityImpl(); + entity.addProperty(new PropertyImpl("Edm.Int16", TecSvcSimpleProperty.Int16.name, ValueType.PRIMITIVE, 4711)); + entity.addProperty(createProperty( + new TecSvcComplexProperty(CTAllPrim_Type, CTAllPrim), + ValueType.COMPLEX, complexCtAllPrim.getProperties())); + + ContextURL contextUrl = createContextURL(edmESCompAllPrim, true); + InputStream result = serializer.entity(edmETCompAllPrim, entity, contextUrl); + String resultString = streamToString(result); + String expectedResult = "{" + + "\"@odata.context\":\"$metadata#ESCompAllPrim/$entity\"," + + "\"PropertyInt16\":4711," + + "\"CTAllPrim\":{" + + "\"PropertyInt16\":4711," + + "\"PropertyString\":\"StringValue\"," + + "\"PropertyBoolean\":true," + + "\"PropertyByte\":19," + + "\"PropertySByte\":1," + + "\"PropertyInt32\":2147483647," + + "\"PropertyInt64\":9223372036854775807," + + "\"PropertySingle\":47.11," + + "\"PropertyDouble\":4.711," + + "\"PropertyDecimal\":4711.1174," + + "\"PropertyBinary\":\"BAcBAQ==\"," + + "\"PropertyDate\":\"2014-03-19\"," + + "\"PropertyDateTimeOffset\":\"2014-03-19T10:12:00Z\"," + + "\"PropertyDuration\":\"P16148425DT0S\"," + + "\"PropertyGuid\":\"0000aaaa-00bb-00cc-00dd-000000ffffff\"," + + "\"PropertyTimeOfDay\":\"10:12:00\"" + + "}}"; + Assert.assertEquals(expectedResult, resultString); + } + + private ContextURL createContextURL(EdmEntitySet entitySet, boolean isEntity) throws URISyntaxException { + StringBuilder sb = new StringBuilder("$metadata#" + entitySet.getName()); + if(isEntity) { + sb.append("/$entity"); + } + return ContextURL.getInstance(new URI(sb.toString())); + } + + private Entity createETAllPrim() { + return createETAllPrim(4711); + } + + private Entity createETCollAllPrim(int id) { + Entity entity = new EntityImpl(); + Calendar date = createCalendarInstance(); + date.set(2014, Calendar.MARCH, 19, 10, 12, 0); + date.set(Calendar.MILLISECOND, 0); + Calendar date2 = createCalendarInstance(); + date2.set(2014, Calendar.JULY, 2, 13, 30, 0); + date2.set(Calendar.MILLISECOND, 0); + // + entity.addProperty(createProperty("Edm.Int16", TecSvcSimpleProperty.Int16, ValueType.PRIMITIVE, id)); + // + entity.addProperty(createProperty("Collection(Edm.Int16)", TecSvcSimpleProperty.Collection_Int16, + ValueType.COLLECTION_PRIMITIVE, id)); + entity.addProperty(createProperty("Collection(Edm.String)", TecSvcSimpleProperty.Collection_String, + ValueType.COLLECTION_PRIMITIVE, "StringValue_1", "StringValue_2")); + entity.addProperty(createProperty("Collection(Edm.Boolean)", TecSvcSimpleProperty.Collection_Boolean, + ValueType.COLLECTION_PRIMITIVE, Boolean.TRUE, Boolean.FALSE)); + entity.addProperty(createProperty("Collection(Edm.Byte)", TecSvcSimpleProperty.Collection_Byte, + ValueType.COLLECTION_PRIMITIVE, Byte.valueOf("19"), Byte.valueOf("42"))); + entity.addProperty(createProperty("Collection(Edm.SByte)", TecSvcSimpleProperty.Collection_SByte, + ValueType.COLLECTION_PRIMITIVE, Short.valueOf("1"), Short.valueOf("2"))); + entity.addProperty(createProperty("Collection(Edm.Int32)", TecSvcSimpleProperty.Collection_Int32, + ValueType.COLLECTION_PRIMITIVE, Integer.MAX_VALUE, Integer.MIN_VALUE)); + entity.addProperty(createProperty("Collection(Edm.Int64)", TecSvcSimpleProperty.Collection_Int64, + ValueType.COLLECTION_PRIMITIVE, Long.MAX_VALUE, Long.MIN_VALUE)); + entity.addProperty(createProperty("Collection(Edm.Single)", TecSvcSimpleProperty.Collection_Single, + ValueType.COLLECTION_PRIMITIVE, 47.11, 11.47)); + entity.addProperty(createProperty("Collection(Edm.Double)", TecSvcSimpleProperty.Collection_Double, + ValueType.COLLECTION_PRIMITIVE, 4.711, 711.4)); + entity.addProperty(createProperty("Collection(Edm.Decimal)", TecSvcSimpleProperty.Collection_Decimal, + ValueType.COLLECTION_PRIMITIVE, 4711.1174, 1174.4711)); + entity.addProperty(createProperty("Collection(Edm.Binary)", TecSvcSimpleProperty.Collection_Binary, + ValueType.COLLECTION_PRIMITIVE, new byte[]{0x04, 0x07, 0x01, 0x01}, "test".getBytes())); + entity.addProperty(createProperty("Collection(Edm.Date)", TecSvcSimpleProperty.Collection_Date, + ValueType.COLLECTION_PRIMITIVE, date, date2)); + entity.addProperty(createProperty("Collection(Edm.DateTimeOffset)", TecSvcSimpleProperty.Collection_DateTimeOffset, + ValueType.COLLECTION_PRIMITIVE, date, date2)); + entity.addProperty(createProperty("Collection(Edm.Duration)", TecSvcSimpleProperty.Collection_Duration, + ValueType.COLLECTION_PRIMITIVE, date.getTimeInMillis(), date2.getTimeInMillis())); + entity.addProperty(createProperty("Collection(Edm.Guid)", TecSvcSimpleProperty.Collection_Guid, + ValueType.COLLECTION_PRIMITIVE, + UUID.fromString("AAAA-BB-CC-DD-FFFFFF"), + UUID.fromString("FFFF-DD-CC-BB-AAAAAA"))); + entity.addProperty(createProperty("Collection(Edm.TimeOfDay)", TecSvcSimpleProperty.Collection_TimeOfDay, + ValueType.COLLECTION_PRIMITIVE, date, date2)); + return entity; + } + + private Entity createETAllPrim(int id) { + Entity entity = new EntityImpl(); + Calendar date = createCalendarInstance(); + date.set(2014, Calendar.MARCH, 19, 10, 12, 0); + date.set(Calendar.MILLISECOND, 0); + entity.addProperty(createProperty("Edm.Int16", TecSvcSimpleProperty.Int16, ValueType.PRIMITIVE, id)); + entity.addProperty(createProperty("Edm.String", TecSvcSimpleProperty.String, ValueType.PRIMITIVE, "StringValue")); + entity.addProperty(createProperty("Edm.Boolean", TecSvcSimpleProperty.Boolean, ValueType.PRIMITIVE, Boolean.TRUE)); + entity.addProperty(createProperty("Edm.Byte", TecSvcSimpleProperty.Byte, ValueType.PRIMITIVE, Byte.valueOf("19"))); + entity.addProperty(createProperty("Edm.SByte", + TecSvcSimpleProperty.SByte, ValueType.PRIMITIVE, Short.valueOf("1"))); + entity.addProperty(createProperty("Edm.Int32", + TecSvcSimpleProperty.Int32, ValueType.PRIMITIVE, Integer.MAX_VALUE)); + entity.addProperty(createProperty("Edm.Int64", TecSvcSimpleProperty.Int64, ValueType.PRIMITIVE, Long.MAX_VALUE)); + entity.addProperty(createProperty("Edm.Single", TecSvcSimpleProperty.Single, ValueType.PRIMITIVE, 47.11)); + entity.addProperty(createProperty("Edm.Double", TecSvcSimpleProperty.Double, ValueType.PRIMITIVE, 4.711)); + entity.addProperty(createProperty("Edm.Decimal", TecSvcSimpleProperty.Decimal, ValueType.PRIMITIVE, 4711.1174)); + entity.addProperty(createProperty("Edm.Binary", TecSvcSimpleProperty.Binary, ValueType.PRIMITIVE, + new byte[]{0x04, 0x07, 0x01, 0x01})); + entity.addProperty(createProperty("Edm.Date", TecSvcSimpleProperty.Date, ValueType.PRIMITIVE, date)); + entity.addProperty(createProperty("Edm.DateTimeOffset", TecSvcSimpleProperty.DateTimeOffset, ValueType.PRIMITIVE, + date)); + entity.addProperty(createProperty("Edm.Duration", TecSvcSimpleProperty.Duration, ValueType.PRIMITIVE, + date.getTimeInMillis())); + entity.addProperty(createProperty("Edm.Guid", TecSvcSimpleProperty.Guid, ValueType.PRIMITIVE, + UUID.fromString("AAAA-BB-CC-DD-FFFFFF"))); + entity.addProperty(createProperty("Edm.TimeOfDay", TecSvcSimpleProperty.TimeOfDay, ValueType.PRIMITIVE, date)); + return entity; + } + + private Calendar createCalendarInstance() { + Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.ENGLISH); + cal.set(Calendar.ZONE_OFFSET, 0); + return cal; + } + + private String streamToString(InputStream result) throws IOException { byte[] buffer = new byte[8192]; StringBuilder sb = new StringBuilder(); diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java index b3dc02de1..ffb8d7f72 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/SampleJsonProcessor.java @@ -6,9 +6,9 @@ * 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 @@ -19,7 +19,7 @@ package org.apache.olingo.server.tecsvc.processor; import java.net.URI; -import java.util.UUID; +import java.util.*; import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.Entity; @@ -27,6 +27,8 @@ 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.edm.Edm; +import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ODataFormat; @@ -42,6 +44,7 @@ import org.apache.olingo.server.api.processor.CollectionProcessor; import org.apache.olingo.server.api.processor.EntityProcessor; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.uri.UriInfo; +import org.apache.olingo.server.api.uri.UriResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,26 +55,22 @@ public class SampleJsonProcessor implements CollectionProcessor, EntityProcessor private Edm edm; @Override - public void init(final OData odata, final Edm edm) { + public void init(OData odata, Edm edm) { this.odata = odata; this.edm = edm; } @Override - public void readCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, - final ContentType requestedContentType) { + public void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) { long time = System.nanoTime(); - EntitySet entitySet = createEntitySet(); - LOG.info((System.nanoTime() - time) / 1000 + " microseconds"); time = System.nanoTime(); ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON); - response.setContent(serializer.entitySet( - edm.getEntityContainer(new FullQualifiedName("com.sap.odata.test1", "Container")) - .getEntitySet("ESAllPrim"), - entitySet, - ContextURL.getInstance(URI.create("dummyContextURL")))); + EdmEntitySet edmEntitySet = getEntitySet(uriInfo); + ContextURL contextUrl = getContextUrl(request, edmEntitySet.getEntityType()); + EntitySet entitySet = createEntitySet(edmEntitySet.getEntityType(), contextUrl.getURI().toASCIIString()); + response.setContent(serializer.entitySet(edmEntitySet, entitySet, contextUrl)); LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds"); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); @@ -79,26 +78,50 @@ public class SampleJsonProcessor implements CollectionProcessor, EntityProcessor } @Override - public void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, - final ContentType requestedContentType) { + public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, String format) { long time = System.nanoTime(); - Entity entity = createEntity(); LOG.info((System.nanoTime() - time) / 1000 + " microseconds"); time = System.nanoTime(); ODataSerializer serializer = odata.createSerializer(ODataFormat.JSON); - response.setContent(serializer.entity( - edm.getEntityContainer(new FullQualifiedName("com.sap.odata.test1", "Container")) - .getEntitySet("ESAllPrim").getEntityType(), - entity, - ContextURL.getInstance(URI.create("dummyContextURL")))); + EdmEntityType entityType = getEntityType(uriInfo); + Entity entity = createEntity(entityType); + + response.setContent(serializer.entity(entityType, entity, + getContextUrl(request, entityType))); LOG.info("Finished in " + (System.nanoTime() - time) / 1000 + " microseconds"); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString()); } - protected Entity createEntity() { + private ContextURL getContextUrl(ODataRequest request, EdmEntityType entityType) { + return ContextURL.getInstance(URI.create(request.getRawBaseUri() + "/" + entityType.getName())); + } + + public EdmEntityType getEntityType(UriInfo uriInfo) { + return getEntitySet(uriInfo).getEntityType(); + } + + public EdmEntitySet getEntitySet(UriInfo uriInfo) { + List resourcePaths = uriInfo.getUriResourceParts(); + if(resourcePaths.isEmpty()) { + throw new RuntimeException("Invalid resource path."); + } + String entitySetName = resourcePaths.get(resourcePaths.size()-1).toString(); + return edm.getEntityContainer(new FullQualifiedName("com.sap.odata.test1", "Container")) + .getEntitySet(entitySetName); + } + + protected Entity createEntity(EdmEntityType entityType) { + boolean complex = (entityType.getName().contains("Comp")); + if(entityType.getName().contains("Coll")) { + return createEntityWithCollection(complex); + } + return createEntity(complex); + } + + protected Entity createEntity(boolean complex) { Entity entity = new EntityImpl(); Property property = new PropertyImpl(); property.setName("PropertyString"); @@ -112,15 +135,95 @@ public class SampleJsonProcessor implements CollectionProcessor, EntityProcessor propertyGuid.setName("PropertyGuid"); propertyGuid.setValue(ValueType.PRIMITIVE, UUID.randomUUID()); entity.getProperties().add(propertyGuid); + + if(complex) { + entity.addProperty(createComplexProperty()); + } + return entity; } - protected EntitySet createEntitySet() { + protected Entity createEntityWithCollection(boolean complex) { + Entity entity = new EntityImpl(); + Property propertyInt = new PropertyImpl(); + propertyInt.setName("PropertyInt16"); + propertyInt.setValue(ValueType.PRIMITIVE, 42); + Property property = new PropertyImpl(); + property.setName("CollPropertyString"); + property.setValue(ValueType.COLLECTION_PRIMITIVE, Arrays.asList("dummyValue", "dummyValue_2")); + entity.getProperties().add(property); + entity.getProperties().add(propertyInt); + Property propertyGuid = new PropertyImpl(); + propertyGuid.setName("CollPropertyGuid"); + propertyGuid.setValue(ValueType.COLLECTION_PRIMITIVE, Arrays.asList(UUID.randomUUID(), UUID.randomUUID())); + entity.getProperties().add(propertyGuid); + + if(complex) { + entity.addProperty(createCollectionOfComplexProperty()); + } + + return entity; + } + + protected Property createComplexProperty() { + List properties = new ArrayList(); + Property property = new PropertyImpl(); + property.setName("PropertyString"); + property.setValue(ValueType.PRIMITIVE, "dummyValue"); + properties.add(property); + Property propertyInt = new PropertyImpl(); + propertyInt.setName("PropertyInt16"); + propertyInt.setValue(ValueType.PRIMITIVE, 42); + properties.add(propertyInt); + Property propertyGuid = new PropertyImpl(); + propertyGuid.setName("PropertyGuid"); + propertyGuid.setValue(ValueType.PRIMITIVE, UUID.randomUUID()); + properties.add(propertyGuid); + + return new PropertyImpl("com.sap.odata.test1.ETCompAllPrim", "PropertyComplex", ValueType.COMPLEX, + properties); + } + + protected Property createCollectionOfComplexProperty() { + List properties = new ArrayList(); + Property property = new PropertyImpl(); + property.setName("PropertyString"); + property.setValue(ValueType.PRIMITIVE, "dummyValue"); + properties.add(property); + Property propertyInt = new PropertyImpl(); + propertyInt.setName("PropertyInt16"); + propertyInt.setValue(ValueType.PRIMITIVE, 42); + properties.add(propertyInt); + Property propertyGuid = new PropertyImpl(); + propertyGuid.setName("PropertyGuid"); + propertyGuid.setValue(ValueType.PRIMITIVE, UUID.randomUUID()); + properties.add(propertyGuid); + + List properties2 = new ArrayList(); + Property property2 = new PropertyImpl(); + property2.setName("PropertyString"); + property2.setValue(ValueType.PRIMITIVE, "dummyValue2"); + properties2.add(property2); + Property property2Int = new PropertyImpl(); + property2Int.setName("PropertyInt16"); + property2Int.setValue(ValueType.PRIMITIVE, 44); + properties2.add(property2Int); + Property property2Guid = new PropertyImpl(); + property2Guid.setName("PropertyGuid"); + property2Guid.setValue(ValueType.PRIMITIVE, UUID.randomUUID()); + properties2.add(property2Guid); + + return new PropertyImpl("com.sap.odata.test1.ETCompAllPrim", "PropertyComplex", ValueType.COMPLEX, + Arrays.asList(properties, properties2)); + } + + protected EntitySet createEntitySet(EdmEntityType edmEntityType, String baseUri) { EntitySet entitySet = new EntitySetImpl(); - entitySet.setCount(4242); - entitySet.setNext(URI.create("nextLinkURI")); - for (int i = 0; i < 1000; i++) { - entitySet.getEntities().add(createEntity()); + int count = (int) ((Math.random() * 50) + 1); + entitySet.setCount(count); + entitySet.setNext(URI.create(baseUri + "nextLink")); + for (int i = 0; i < count; i++) { + entitySet.getEntities().add(createEntity(edmEntityType)); } return entitySet; }