[OLINGO-832] ODataJsonSerializer changes for streaming
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/4aa1277a Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/4aa1277a Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/4aa1277a Branch: refs/heads/OLINGO-856_ODataHandlerInAPI Commit: 4aa1277a1284aa7a61c6e86a6685ff1a942d0e3b Parents: 396a39b Author: Michael Bolz <[email protected]> Authored: Fri Feb 19 15:11:40 2016 +0100 Committer: Michael Bolz <[email protected]> Committed: Fri Feb 19 15:11:40 2016 +0100 ---------------------------------------------------------------------- .../api/data/AbstractEntityCollection.java | 3 - .../server/core/ODataWritableContent.java | 84 ++++++------ .../serializer/json/ODataJsonSerializer.java | 40 +++--- .../processor/TechnicalEntityProcessor.java | 131 +------------------ .../json/ODataJsonSerializerTest.java | 8 +- 5 files changed, 67 insertions(+), 199 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4aa1277a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java ---------------------------------------------------------------------- diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java index 9b4f9ff..a3222c7 100644 --- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java @@ -27,7 +27,4 @@ public abstract class AbstractEntityCollection extends AbstractODataObject imple public abstract URI getNext(); public abstract URI getDeltaLink(); -// -// @Override -// Iterator<Entity> iterator(); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4aa1277a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataWritableContent.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataWritableContent.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataWritableContent.java index 1b9cb30..904a6d0 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataWritableContent.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataWritableContent.java @@ -65,51 +65,58 @@ public class ODataWritableContent implements ODataContent { EntityCollectionSerializerOptions options, String tail) { this.coll = coll; this.entityType = entityType; - this.head = ByteBuffer.wrap(head.getBytes(DEFAULT)); + this.head = head == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(head.getBytes(DEFAULT)); this.jsonSerializer = jsonSerializer; this.metadata = metadata; this.options = options; - this.tail = ByteBuffer.wrap(tail.getBytes(DEFAULT)); + this.tail = tail == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(tail.getBytes(DEFAULT)); } - public boolean write(OutputStream out) throws IOException { - if(head.hasRemaining()) { - out.write(head.array()); - head.flip(); - return true; - } - if (coll.hasNext()) { - try { - writeEntity(coll.next(), out); - if(coll.hasNext()) { - out.write(",".getBytes(DEFAULT)); - } - return true; - } catch (SerializerException e) { - final WriteContentErrorCallback errorCallback = options.getWriteContentErrorCallback(); - if(errorCallback != null) { - final ErrorContext errorContext = new ErrorContext(e).setParameter("Sample", "Some exception happened."); - errorCallback.handleError(errorContext, Channels.newChannel(out)); - } +// public boolean write(OutputStream out) throws IOException { +// if(head.hasRemaining()) { +// out.write(head.array()); +// head.flip(); +// return true; +// } +// if (coll.hasNext()) { +// try { +// writeEntity(coll.next(), out); +// if(coll.hasNext()) { +// out.write(",".getBytes(DEFAULT)); +// } +// return true; +// } catch (SerializerException e) { +// final WriteContentErrorCallback errorCallback = options.getWriteContentErrorCallback(); +// if(errorCallback != null) { +// final ErrorContext errorContext = new ErrorContext(e).setParameter("Sample", "Some exception happened."); +// errorCallback.handleError(errorContext, Channels.newChannel(out)); +// } +// } +// } else if(tail.hasRemaining()) { +// out.write(tail.array()); +// tail.flip(); +// return true; +// } +// return false; +// } + + public void write(OutputStream out) { + try { + writeEntity(coll, out); + } catch (SerializerException e) { + final WriteContentErrorCallback errorCallback = options.getWriteContentErrorCallback(); + if(errorCallback != null) { + final ErrorContext errorContext = new ErrorContext(e).setParameter("Sample", "Some exception happened."); + errorCallback.handleError(errorContext, Channels.newChannel(out)); } - } else if(tail.hasRemaining()) { - out.write(tail.array()); - tail.flip(); - return true; } - return false; } - private void writeEntity(Entity entity, OutputStream outputStream) throws SerializerException { + private void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException { try { - JsonGenerator json = new JsonFactory().createGenerator(outputStream); - jsonSerializer.writeEntity(metadata, entityType, entity, null, - options == null ? null : options.getExpand(), - options == null ? null : options.getSelect(), - options != null && options.getWriteOnlyReferences(), - json); - json.flush(); + jsonSerializer.entityCollectionIntoStream(metadata, entityType, entity, options, outputStream); + outputStream.flush(); } catch (final IOException e) { throw new ODataRuntimeException("Failed entity serialization"); } @@ -204,14 +211,7 @@ public class ODataWritableContent implements ODataContent { @Override public void write(WritableByteChannel writeChannel) { - try { - boolean contentAvailable = true; - while(contentAvailable) { - contentAvailable = this.channel.write(Channels.newOutputStream(writeChannel)); - } - } catch (IOException e) { - e.printStackTrace(); - } + this.channel.write(Channels.newOutputStream(writeChannel)); } @Override http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4aa1277a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java ---------------------------------------------------------------------- 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 df2ee84..cb60b4e 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,10 +18,8 @@ */ package org.apache.olingo.server.core.serializer.json; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.nio.charset.Charset; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -184,8 +182,16 @@ public class ODataJsonSerializer extends AbstractODataSerializer { public SerializerStreamResult entityCollectionStreamed(ServiceMetadata metadata, EdmEntityType entityType, EntityIterator entities, EntityCollectionSerializerOptions options) throws SerializerException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - SerializerException cachedException = null; + return ODataWritableContent.with(entities, entityType, this, metadata, options).build(); + } + + + public void entityCollectionIntoStream(final ServiceMetadata metadata, + final EdmEntityType entityType, final EntityIterator entitySet, + final EntityCollectionSerializerOptions options, final OutputStream outputStream) + throws SerializerException { + + SerializerException cachedException; try { JsonGenerator json = new JsonFactory().createGenerator(outputStream); json.writeStartObject(); @@ -196,29 +202,23 @@ public class ODataJsonSerializer extends AbstractODataSerializer { writeMetadataETag(metadata, json); if (options != null && options.getCount() != null && options.getCount().getValue()) { - writeCount(entities, json); + writeCount(entitySet, json); } json.writeFieldName(Constants.VALUE); - json.writeStartArray(); - json.close(); - outputStream.close(); - String temp = new String(outputStream.toByteArray(), Charset.forName("UTF-8")); - String head = temp.substring(0, temp.length()-2); - - outputStream = new ByteArrayOutputStream(); - outputStream.write(']'); - outputStream.write('}'); - outputStream.close(); - String tail = new String(outputStream.toByteArray(), Charset.forName("UTF-8")); + if (options == null) { + writeEntitySet(metadata, entityType, entitySet, null, null, false, json); + } else { + writeEntitySet(metadata, entityType, entitySet, + options.getExpand(), options.getSelect(), options.getWriteOnlyReferences(), json); + } + // next link not supported by default for streaming results +// writeNextLink(entitySet, json); - return ODataWritableContent.with(entities, entityType, this, metadata, options) - .addHead(head).addTail(tail).build(); + json.close(); } catch (final IOException e) { cachedException = new SerializerException(IO_EXCEPTION_TEXT, e, SerializerException.MessageKeys.IO_EXCEPTION); throw cachedException; - } finally { - closeCircleStreamBufferOutput(outputStream, cachedException); } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4aa1277a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java index 1afc288..28989d6 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java @@ -18,16 +18,8 @@ */ package org.apache.olingo.server.tecsvc.processor; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; import java.util.Iterator; -import java.util.List; import java.util.Locale; -import java.util.Random; -import java.util.concurrent.TimeUnit; import org.apache.olingo.commons.api.data.ContextURL; import org.apache.olingo.commons.api.data.ContextURL.Builder; @@ -35,8 +27,6 @@ import org.apache.olingo.commons.api.data.ContextURL.Suffix; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.EntityIterator; -import org.apache.olingo.commons.api.data.Property; -import org.apache.olingo.commons.api.data.ValueType; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.format.ContentType; @@ -44,12 +34,10 @@ import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; -import org.apache.olingo.server.api.ODataContent; import org.apache.olingo.server.api.ODataLibraryException; import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ServiceMetadata; -import org.apache.olingo.server.api.WriteContentErrorCallback; import org.apache.olingo.server.api.deserializer.DeserializerResult; import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.apache.olingo.server.api.prefer.Preferences.Return; @@ -540,7 +528,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor response.setContent(serializerResult.getContent()); } else { final SerializerStreamResult serializerResult = - serializeEntityStreamCollectionFixed(request, + serializeEntityCollectionStreamed(request, entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType, expand, select, countOption, id); @@ -556,8 +544,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } } - // just for demonstration - private SerializerStreamResult serializeEntityStreamCollectionFixed(final ODataRequest request, + // serialise as streamed collection + private SerializerStreamResult serializeEntityCollectionStreamed(final ODataRequest request, final EntityCollection entityCollection, final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ContentType requestedFormat, final ExpandOption expand, final SelectOption select, @@ -573,66 +561,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor @Override public Entity next() { - Entity next = entityIterator.next(); -// replacePrimitiveProperty(next, "PropertyString", generateData(28192)); - replacePrimitiveProperty(next, "PropertyString", generateData(request)); -// next.addProperty(new Property(null, "PropertyString", ValueType.PRIMITIVE, generateData(28192))); - - sleep(request, 2500); - return next; - } - -// @Override -// public List<Entity> getEntities() { -// return entityCollection.getEntities(); -// } - - private void replacePrimitiveProperty(Entity entity, String name, Object data) { - List<Property> properties = entity.getProperties(); - int pos = 0; - for (Property property : properties) { - if(name.equals(property.getName())) { - properties.remove(pos); - entity.addProperty(new Property(null, name, ValueType.PRIMITIVE, data)); - break; - } - pos++; - } + return entityIterator.next(); } - - private void sleep(ODataRequest request, int defaultTimeMs) { - String sleepTimeMs = request.getHeader("StreamSleep"); - if(sleepTimeMs != null) { - try { - defaultTimeMs = Integer.parseInt(sleepTimeMs); - } catch (NumberFormatException e) { } - } - try { - TimeUnit.MILLISECONDS.sleep(defaultTimeMs); - } catch (InterruptedException e) { } - - } - - private String generateData(ODataRequest request) { - String streamHeader = request.getHeader("StreamData"); - if(streamHeader != null) { - try { - return generateData(Integer.parseInt(streamHeader)); - } catch (NumberFormatException e) { } - } - return generateData(28192); - } - - private String generateData(final int len) { - Random random = new Random(); - StringBuilder b = new StringBuilder(len); - for (int j = 0; j < len; j++) { - final char c = (char) ('A' + random.nextInt('Z' - 'A' + 1)); - b.append(c); - } - return b.toString(); - } - }; return odata.createSerializer(requestedFormat).entityCollectionStreamed( @@ -648,59 +578,6 @@ public class TechnicalEntityProcessor extends TechnicalProcessor .build()); } - private SerializerResult serializeEntityStreamCollection(final ODataRequest request, - final EntityCollection entityCollection, final EdmEntitySet edmEntitySet, - final EdmEntityType edmEntityType, - final ContentType requestedFormat, final ExpandOption expand, final SelectOption select, - final CountOption countOption, final String id) throws ODataLibraryException { - - EntityIterator streamCollection = new EntityIterator() { - Iterator<Entity> test = entityCollection.getEntities().iterator(); - @Override - public boolean hasNext() { - return test.hasNext(); - } - - @Override - public Entity next() { - try { - TimeUnit.MILLISECONDS.sleep(1000); - } catch (InterruptedException e) { } - return test.next(); - } - }; - return odata.createSerializer(requestedFormat).entityCollection( - serviceMetadata, - edmEntityType, - streamCollection, - EntityCollectionSerializerOptions.with() - .contextURL(isODataMetadataNone(requestedFormat) ? null : - getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, false, expand, select)) - .count(countOption) - .expand(expand).select(select) - .id(id) - .build()); - } - - - private SerializerResult serializeEntityCollection(final ODataRequest request, final EntityCollection - entityCollection, final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, - final ContentType requestedFormat, final ExpandOption expand, final SelectOption select, - final CountOption countOption, String id) throws ODataLibraryException { - - return odata.createSerializer(requestedFormat).entityCollection( - serviceMetadata, - edmEntityType, - entityCollection, - EntityCollectionSerializerOptions.with() - .contextURL(isODataMetadataNone(requestedFormat) ? null : - getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, false, expand, select)) - .count(countOption) - .expand(expand).select(select) - .id(id) - .build()); - } - private SerializerResult serializeReferenceCollection(final EntityCollection entityCollection, final EdmEntitySet edmEntitySet, final ContentType requestedFormat, final CountOption countOption) throws ODataLibraryException { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/4aa1277a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java ---------------------------------------------------------------------- diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java index 4211819..a7cf057 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java @@ -297,13 +297,7 @@ public class ODataJsonSerializerTest { ByteArrayOutputStream bout = new ByteArrayOutputStream(); result.write(bout); final String resultString = new String(bout.toByteArray(), "UTF-8"); - - Assert.assertThat(resultString, CoreMatchers.startsWith("{" - + "\"@odata.context\":\"$metadata#ESAllPrim\"," - + "\"@odata.metadataEtag\":\"W/\\\"metadataETag\\\"\"," - + "\"value\":")); - Assert.assertThat(resultString, CoreMatchers.endsWith( - "[ERROR: MISSING_PROPERTY")); + Assert.assertEquals(resultString, "ERROR: MISSING_PROPERTY"); }
