You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2016/02/19 21:57:41 UTC

olingo-odata4 git commit: [OlINGO-832] Clean up and basic IT test

Repository: olingo-odata4
Updated Branches:
  refs/heads/OLINGO-832_StreamSerializerPoC 4aa1277a1 -> 09fd6d9b4


[OlINGO-832] Clean up and basic IT test


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/09fd6d9b
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/09fd6d9b
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/09fd6d9b

Branch: refs/heads/OLINGO-832_StreamSerializerPoC
Commit: 09fd6d9b48dd0b833176dbe0b2864c5065b99ee0
Parents: 4aa1277
Author: Michael Bolz <mi...@sap.com>
Authored: Fri Feb 19 21:57:31 2016 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Fri Feb 19 21:57:31 2016 +0100

----------------------------------------------------------------------
 .../fit/tecsvc/http/BasicStreamITCase.java      |  66 ++++++
 .../server/api/WriteContentErrorCallback.java   |   5 +
 .../server/api/WriteContentErrorContext.java    |   4 +-
 .../server/core/ODataWritableContent.java       | 235 +++++--------------
 .../serializer/SerializerStreamResultImpl.java  |  19 --
 .../core/serializer/xml/ODataXmlSerializer.java |  62 ++++-
 .../processor/TechnicalEntityProcessor.java     |  52 +++-
 7 files changed, 247 insertions(+), 196 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
new file mode 100644
index 0000000..1903d13
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.fit.tecsvc.http;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.commons.api.format.ContentType;
+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.fit.AbstractBaseTestITCase;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.junit.Test;
+
+public class BasicStreamITCase extends AbstractBaseTestITCase {
+
+  private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/";
+
+  @Test
+  public void streamAllPrim() throws Exception {
+    URL url = new URL(SERVICE_URI + "ESAllPrim?$format=json");
+
+    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.name());
+    connection.setRequestProperty("odata.streaming", "true");
+    connection.connect();
+
+    assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode());
+    assertEquals(ContentType.JSON, ContentType.create(connection.getHeaderField(HttpHeader.CONTENT_TYPE)));
+
+    final String content = IOUtils.toString(connection.getInputStream());
+
+    assertTrue(content.contains("\"PropertyString\":\"First Resource - positive values->streamed\""));
+    assertTrue(content.contains("\"PropertyString\":\"Second Resource - negative values->streamed\""));
+    assertTrue(content.contains("\"PropertyString\":\"->streamed\""));
+  }
+
+
+  @Override
+  protected ODataClient getClient() {
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorCallback.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorCallback.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorCallback.java
index abc500a..3132876 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorCallback.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorCallback.java
@@ -18,8 +18,13 @@
  */
 package org.apache.olingo.server.api;
 
+import java.io.OutputStream;
 import java.nio.channels.WritableByteChannel;
 
+/**
+ * The WriteContentErrorCallback is called when during the {@link ODataContent#write(OutputStream)}
+ * or the {@link ODataContent#write(WritableByteChannel)} an error occurs.
+ */
 public interface WriteContentErrorCallback {
   void handleError(WriteContentErrorContext context, WritableByteChannel channel);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorContext.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorContext.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorContext.java
index d773df1..837c184 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorContext.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/WriteContentErrorContext.java
@@ -18,8 +18,10 @@
  */
 package org.apache.olingo.server.api;
 
+/**
+ * The WriteContentErrorErrorContext is the parameter for the WriteContentErrorCallback.
+ */
 public interface WriteContentErrorContext {
   Exception getException();
   ODataLibraryException getODataLibraryException();
-//  Object getParameter(String name);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/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 904a6d0..7a7c142 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
@@ -20,15 +20,9 @@ package org.apache.olingo.server.core;
 
 import java.io.IOException;
 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.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
 
-import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityIterator;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.ex.ODataRuntimeException;
@@ -38,82 +32,60 @@ import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.WriteContentErrorCallback;
 import org.apache.olingo.server.api.WriteContentErrorContext;
 import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.serializer.SerializerStreamResult;
 import org.apache.olingo.server.core.serializer.SerializerStreamResultImpl;
 import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer;
-import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
-
-import com.fasterxml.jackson.core.JsonFactory;
-import com.fasterxml.jackson.core.JsonGenerator;
+import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializer;
 
 public class ODataWritableContent implements ODataContent {
-  private StreamChannel channel;
-
-  private static class StreamChannel implements ReadableByteChannel {
-    private static final Charset DEFAULT = Charset.forName("UTF-8");
-    private ByteBuffer head;
-    private ByteBuffer tail;
-    private ODataJsonSerializer jsonSerializer;
-    private EntityIterator coll;
-    private ServiceMetadata metadata;
-    private EdmEntityType entityType;
-    private EntityCollectionSerializerOptions options;
-
-    public StreamChannel(EntityIterator coll, EdmEntityType entityType, String head,
-                         ODataJsonSerializer jsonSerializer, ServiceMetadata metadata,
-                         EntityCollectionSerializerOptions options, String tail) {
-      this.coll = coll;
+  private StreamContent streamContent;
+
+  private static abstract class StreamContent {
+    protected ODataSerializer serializer;
+    protected EntityIterator iterator;
+    protected ServiceMetadata metadata;
+    protected EdmEntityType entityType;
+    protected EntityCollectionSerializerOptions options;
+
+    public StreamContent(EntityIterator iterator, EdmEntityType entityType,
+                         ODataSerializer serializer, ServiceMetadata metadata,
+                         EntityCollectionSerializerOptions options) {
+      this.iterator = iterator;
       this.entityType = entityType;
-      this.head = head == null ? ByteBuffer.allocate(0) : ByteBuffer.wrap(head.getBytes(DEFAULT));
-      this.jsonSerializer = jsonSerializer;
+      this.serializer = serializer;
       this.metadata = metadata;
       this.options = options;
-      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));
-//          }
-//        }
-//      } else if(tail.hasRemaining()) {
-//        out.write(tail.array());
-//        tail.flip();
-//        return true;
-//      }
-//      return false;
-//    }
+    protected abstract void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException;
 
     public void write(OutputStream out) {
       try {
-        writeEntity(coll, out);
+        writeEntity(iterator, out);
       } catch (SerializerException e) {
         final WriteContentErrorCallback errorCallback = options.getWriteContentErrorCallback();
         if(errorCallback != null) {
-          final ErrorContext errorContext = new ErrorContext(e).setParameter("Sample", "Some exception happened.");
+          final ErrorContext errorContext = new ErrorContext(e);
           errorCallback.handleError(errorContext, Channels.newChannel(out));
         }
       }
     }
+  }
+
+  private static class StreamContentForJson extends StreamContent {
+    private ODataJsonSerializer jsonSerializer;
 
+    public StreamContentForJson(EntityIterator iterator, EdmEntityType entityType,
+        ODataJsonSerializer jsonSerializer, ServiceMetadata metadata,
+        EntityCollectionSerializerOptions options) {
+      super(iterator, entityType, jsonSerializer, metadata, options);
 
-    private void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException {
+      this.jsonSerializer = jsonSerializer;
+    }
+
+    protected void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException {
       try {
         jsonSerializer.entityCollectionIntoStream(metadata, entityType, entity, options, outputStream);
         outputStream.flush();
@@ -121,97 +93,32 @@ public class ODataWritableContent implements ODataContent {
         throw new ODataRuntimeException("Failed entity serialization");
       }
     }
+  }
 
-    @Override
-    public int read(ByteBuffer dest) throws IOException {
-      ByteBuffer buffer = getCurrentBuffer();
-      if (buffer != null && buffer.hasRemaining()) {
-        int r = buffer.remaining();
-        if(r <= dest.remaining()) {
-          dest.put(buffer);
-        } else {
-          r = dest.remaining();
-          byte[] buf = new byte[dest.remaining()];
-          buffer.get(buf);
-          dest.put(buf);
-        }
-        return r;
-      }
-      return -1;
-    }
+  private static class StreamContentForXml extends StreamContent {
+    private ODataXmlSerializer xmlSerializer;
 
-    ByteBuffer currentBuffer;
+    public StreamContentForXml(EntityIterator iterator, EdmEntityType entityType,
+        ODataXmlSerializer xmlSerializer, ServiceMetadata metadata,
+        EntityCollectionSerializerOptions options) {
+      super(iterator, entityType, xmlSerializer, metadata, options);
 
-    private ByteBuffer getCurrentBuffer() {
-      if(currentBuffer == null) {
-        currentBuffer = head;
-      }
-      if(!currentBuffer.hasRemaining()) {
-        if (coll.hasNext()) {
-          try {
-            // FIXME: mibo_160108: Inefficient buffer handling, replace
-            currentBuffer = serEntity(coll.next());
-            if(coll.hasNext()) {
-              ByteBuffer b = ByteBuffer.allocate(currentBuffer.position() + 1);
-              currentBuffer.flip();
-              b.put(currentBuffer).put(",".getBytes(DEFAULT));
-              currentBuffer = b;
-            }
-            currentBuffer.flip();
-          } catch (SerializerException e) {
-            return getCurrentBuffer();
-          }
-        } else if(tail.hasRemaining()) {
-          currentBuffer = tail;
-        } else {
-          return null;
-        }
-      }
-      return currentBuffer;
+      this.xmlSerializer = xmlSerializer;
     }
 
-    private ByteBuffer serEntity(Entity entity) throws SerializerException {
+    protected void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException {
       try {
-        CircleStreamBuffer buffer = new CircleStreamBuffer();
-        OutputStream outputStream = buffer.getOutputStream();
-        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.close();
-        outputStream.close();
-        return buffer.getBuffer();
+        xmlSerializer.entityCollectionIntoStream(metadata, entityType, entity, options, outputStream);
+        outputStream.flush();
       } catch (final IOException e) {
-        return ByteBuffer.wrap(("ERROR" + e.getMessage()).getBytes());
+        throw new ODataRuntimeException("Failed entity serialization");
       }
     }
-
-
-    @Override
-    public boolean isOpen() {
-      return false;
-    }
-
-    @Override
-    public void close() throws IOException {
-
-    }
-  }
-
-  public ReadableByteChannel getChannel() {
-    return this.channel;
-  }
-
-  public boolean isWriteSupported() {
-    return true;
   }
 
   @Override
   public void write(WritableByteChannel writeChannel) {
-    this.channel.write(Channels.newOutputStream(writeChannel));
+    this.streamContent.write(Channels.newOutputStream(writeChannel));
   }
 
   @Override
@@ -219,20 +126,18 @@ public class ODataWritableContent implements ODataContent {
     write(Channels.newChannel(stream));
   }
 
-  private ODataWritableContent(StreamChannel channel) {
-    this.channel = channel;
+  private ODataWritableContent(StreamContent streamContent) {
+    this.streamContent = streamContent;
   }
 
-  public static ODataWritableContentBuilder with(EntityIterator coll, EdmEntityType entityType,
-                                             ODataJsonSerializer jsonSerializer,
-                                             ServiceMetadata metadata, EntityCollectionSerializerOptions options) {
-    return new ODataWritableContentBuilder(coll, entityType, jsonSerializer, metadata, options);
+  public static ODataWritableContentBuilder with(EntityIterator iterator, EdmEntityType entityType,
+                                             ODataSerializer serializer, ServiceMetadata metadata,
+      EntityCollectionSerializerOptions options) {
+    return new ODataWritableContentBuilder(iterator, entityType, serializer, metadata, options);
   }
 
   public static class ErrorContext implements WriteContentErrorContext {
     private ODataLibraryException exception;
-    final private Map<String, Object> parameters = new HashMap<String, Object>();
-
     public ErrorContext(ODataLibraryException exception) {
       this.exception = exception;
     }
@@ -245,50 +150,36 @@ public class ODataWritableContent implements ODataContent {
     public ODataLibraryException getODataLibraryException() {
       return exception;
     }
-
-    public ErrorContext setParameter(String name, Object value) {
-      parameters.put(name, value);
-      return this;
-    }
-
-//    @Override
-    public Object getParameter(String name) {
-      return parameters.get(name);
-    }
   }
 
   public static class ODataWritableContentBuilder {
-    private ODataJsonSerializer jsonSerializer;
+    private ODataSerializer serializer;
     private EntityIterator entities;
     private ServiceMetadata metadata;
     private EdmEntityType entityType;
     private EntityCollectionSerializerOptions options;
-    private String head;
-    private String tail;
 
     public ODataWritableContentBuilder(EntityIterator entities, EdmEntityType entityType,
-                                   ODataJsonSerializer jsonSerializer,
+                                    ODataSerializer serializer,
                                    ServiceMetadata metadata, EntityCollectionSerializerOptions options) {
       this.entities = entities;
       this.entityType = entityType;
-      this.jsonSerializer = jsonSerializer;
+      this.serializer = serializer;
       this.metadata = metadata;
       this.options = options;
     }
 
-    public ODataWritableContentBuilder addHead(String head) {
-      this.head = head;
-      return this;
-    }
-
-    public ODataWritableContentBuilder addTail(String tail) {
-      this.tail = tail;
-      return this;
-    }
-
     public ODataContent buildContent() {
-      StreamChannel input = new StreamChannel(entities, entityType, head, jsonSerializer, metadata, options, tail);
-      return new ODataWritableContent(input);
+      if(serializer instanceof ODataJsonSerializer) {
+        StreamContent input = new StreamContentForJson(entities, entityType,
+            (ODataJsonSerializer) serializer, metadata, options);
+        return new ODataWritableContent(input);
+      } else if(serializer instanceof ODataXmlSerializer) {
+        StreamContentForXml input = new StreamContentForXml(entities, entityType,
+            (ODataXmlSerializer) serializer, metadata, options);
+        return new ODataWritableContent(input);
+      }
+      throw new ODataRuntimeException("No suitable serializer found");
     }
     public SerializerStreamResult build() {
       return SerializerStreamResultImpl.with().content(buildContent()).build();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/SerializerStreamResultImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/SerializerStreamResultImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/SerializerStreamResultImpl.java
index 14fab97..a7c0efc 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/SerializerStreamResultImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/SerializerStreamResultImpl.java
@@ -18,14 +18,10 @@
  */
 package org.apache.olingo.server.core.serializer;
 
-import java.io.InputStream;
-
 import org.apache.olingo.server.api.ODataContent;
-import org.apache.olingo.server.api.serializer.SerializerResult;
 import org.apache.olingo.server.api.serializer.SerializerStreamResult;
 
 public class SerializerStreamResultImpl implements SerializerStreamResult {
-  private InputStream content;
   private ODataContent oDataContent;
 
   @Override
@@ -33,21 +29,6 @@ public class SerializerStreamResultImpl implements SerializerStreamResult {
     return oDataContent;
   }
 
-  //  @Override
-//  public ReadableByteChannel getChannel() {
-//    return Channels.newChannel(getContent());
-//  }
-//
-//  @Override
-//  public void write(WritableByteChannel channel) {
-//    ResultHelper.copy(Channels.newChannel(content), channel);
-//  }
-//
-//  @Override
-//  public boolean isWriteSupported() {
-//    return false;
-//  }
-
   public static SerializerResultBuilder with() {
     return new SerializerResultBuilder();
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
index a42e3df..2fa16ea 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
@@ -70,6 +70,7 @@ import org.apache.olingo.server.api.serializer.SerializerStreamResult;
 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.SelectOption;
+import org.apache.olingo.server.core.ODataWritableContent;
 import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
 import org.apache.olingo.server.core.serializer.SerializerResultImpl;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
@@ -282,10 +283,67 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     }
   }
 
+  public void entityCollectionIntoStream(ServiceMetadata metadata, EdmEntityType entityType, EntityIterator entitySet,
+      EntityCollectionSerializerOptions options, OutputStream outputStream) throws SerializerException {
+
+    final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
+//    if (options != null && options.getWriteOnlyReferences()) {
+//      ReferenceCollectionSerializerOptions rso = ReferenceCollectionSerializerOptions.with()
+//          .contextURL(contextURL).build();
+//      return entityReferenceCollection(entitySet, rso);
+//    }
+
+    SerializerException cachedException = null;
+    try {
+      CircleStreamBuffer buffer = new CircleStreamBuffer();
+      outputStream = buffer.getOutputStream();
+      XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(outputStream, DEFAULT_CHARSET);
+      writer.writeStartDocument(DEFAULT_CHARSET, "1.0");
+      writer.writeStartElement(ATOM, Constants.ATOM_ELEM_FEED, NS_ATOM);
+      writer.writeNamespace(ATOM, NS_ATOM);
+      writer.writeNamespace(METADATA, NS_METADATA);
+      writer.writeNamespace(DATA, NS_DATA);
+
+      writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
+          ContextURLBuilder.create(contextURL).toASCIIString());
+      writeMetadataETag(metadata, writer);
+
+      if (options != null && options.getId() != null) {
+        writer.writeStartElement(ATOM, Constants.ATOM_ELEM_ID, NS_ATOM);
+        writer.writeCharacters(options.getId());
+        writer.writeEndElement();
+      }
+
+      if (options != null && options.getCount() != null && options.getCount().getValue()
+          && entitySet.getCount() != null) {
+        writeCount(entitySet, writer);
+      }
+      if (entitySet.getNext() != null) {
+        writeNextLink(entitySet, writer);
+      }
+
+      if (options == null) {
+        writeEntitySet(metadata, entityType, entitySet, null, null, null, writer);
+      } else {
+        writeEntitySet(metadata, entityType, entitySet,
+            options.getExpand(), options.getSelect(), options.xml10InvalidCharReplacement(), writer);
+      }
+
+      writer.writeEndElement();
+      writer.writeEndDocument();
+
+      writer.flush();
+    } catch (final XMLStreamException e) {
+      cachedException =
+          new SerializerException(IO_EXCEPTION_TEXT, e, SerializerException.MessageKeys.IO_EXCEPTION);
+      throw cachedException;
+    }
+  }
+
   @Override
   public SerializerStreamResult entityCollectionStreamed(ServiceMetadata metadata, EdmEntityType entityType,
       EntityIterator entities, EntityCollectionSerializerOptions options) throws SerializerException {
-    throw new ODataRuntimeException("entityCollectionStreamed for XML not supported (yet)");
+      return ODataWritableContent.with(entities, entityType, this, metadata, options).build();
   }
 
   @Override
@@ -1163,5 +1221,5 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       return value;
     }
     return result.toString();
-  }  
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/09fd6d9b/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 28989d6..850867e 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
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.tecsvc.processor;
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
 
 import org.apache.olingo.commons.api.data.ContextURL;
@@ -27,6 +28,8 @@ 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;
@@ -526,13 +529,19 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
       final SerializerResult serializerResult =
           serializeReferenceCollection(entitySetSerialization, edmEntitySet, requestedContentType, countOption);
       response.setContent(serializerResult.getContent());
-    } else {
+    } else if(isOdataStreaming(request)) {
       final SerializerStreamResult serializerResult =
           serializeEntityCollectionStreamed(request,
               entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
               expand, select, countOption, id);
 
       response.setODataContent(serializerResult.getODataContent());
+    } else {
+      final SerializerResult serializerResult =
+          serializeEntityCollection(request,
+              entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
+              expand, select, countOption, id);
+      response.setContent(serializerResult.getContent());
     }
 
     //
@@ -544,6 +553,29 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     }
   }
 
+  private boolean isOdataStreaming(ODataRequest request) {
+    String odataStreaming = request.getHeader("odata.streaming");
+    return Boolean.parseBoolean(odataStreaming);
+  }
+
+  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());
+  }
+
   // serialise as streamed collection
   private SerializerStreamResult serializeEntityCollectionStreamed(final ODataRequest request,
       final EntityCollection entityCollection, final EdmEntitySet edmEntitySet,
@@ -561,7 +593,23 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
 
       @Override
       public Entity next() {
-        return entityIterator.next();
+        return addToPrimitiveProperty(entityIterator.next(), "PropertyString", "->streamed");
+      }
+
+      private Entity addToPrimitiveProperty(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);
+            final String old = property.getValue().toString();
+            String newValue = (old == null ? "": old) + data.toString();
+            entity.addProperty(new Property(null, name, ValueType.PRIMITIVE, newValue));
+            break;
+          }
+          pos++;
+        }
+        return entity;
       }
     };