[OLINGO-832] Merge branch 'OLINGO-832_StreamSerializerPoC'
This commit is contained in:
commit
47bc730a89
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -525,7 +525,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
|
|||
|
||||
common(writer, entitySet);
|
||||
|
||||
for (Entity entity : entitySet.getEntities()) {
|
||||
for (Entity entity : entitySet) {
|
||||
if (entity.getType() == null && entity.getProperties().isEmpty()) {
|
||||
entityRef(writer, entity);
|
||||
} else {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.commons.api.data;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
|
||||
public abstract class AbstractEntityCollection extends AbstractODataObject implements Iterable<Entity> {
|
||||
public abstract Integer getCount();
|
||||
|
||||
public abstract URI getNext();
|
||||
|
||||
public abstract URI getDeltaLink();
|
||||
}
|
|
@ -20,12 +20,13 @@ package org.apache.olingo.commons.api.data;
|
|||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data representation for a collection of single entities.
|
||||
*/
|
||||
public class EntityCollection extends AbstractODataObject {
|
||||
public class EntityCollection extends AbstractEntityCollection {
|
||||
|
||||
private final List<Entity> entities = new ArrayList<Entity>();
|
||||
private Integer count;
|
||||
|
@ -46,6 +47,7 @@ public class EntityCollection extends AbstractODataObject {
|
|||
*
|
||||
* @return number of entries into the entity set.
|
||||
*/
|
||||
@Override
|
||||
public Integer getCount() {
|
||||
return count;
|
||||
}
|
||||
|
@ -73,6 +75,7 @@ public class EntityCollection extends AbstractODataObject {
|
|||
*
|
||||
* @return next link if exists; null otherwise.
|
||||
*/
|
||||
@Override
|
||||
public URI getNext() {
|
||||
return next;
|
||||
}
|
||||
|
@ -82,6 +85,7 @@ public class EntityCollection extends AbstractODataObject {
|
|||
*
|
||||
* @return delta link if exists; null otherwise.
|
||||
*/
|
||||
@Override
|
||||
public URI getDeltaLink() {
|
||||
return deltaLink;
|
||||
}
|
||||
|
@ -95,6 +99,11 @@ public class EntityCollection extends AbstractODataObject {
|
|||
this.deltaLink = deltaLink;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entity> iterator() {
|
||||
return this.entities.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!super.equals(o)) {
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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.commons.api.data;
|
||||
|
||||
import org.apache.olingo.commons.api.ex.ODataNotSupportedException;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Data representation for a collection of single entities.
|
||||
*/
|
||||
public abstract class EntityIterator extends AbstractEntityCollection implements Iterator<Entity> {
|
||||
|
||||
public abstract boolean hasNext();
|
||||
public abstract Entity next();
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
//"Remove is not supported for iteration over Entities."
|
||||
throw new ODataNotSupportedException("Entity Iterator does not support remove()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entity> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getCount() {
|
||||
throw new ODataNotSupportedException("Entity Iterator does not support getCount()");
|
||||
}
|
||||
|
||||
public URI getNext() {
|
||||
throw new ODataNotSupportedException("Entity Iterator does not support getNext()");
|
||||
}
|
||||
|
||||
public URI getDeltaLink() {
|
||||
throw new ODataNotSupportedException("Entity Iterator does not support getDeltaLink()");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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.commons.api.ex;
|
||||
|
||||
/**
|
||||
* Core runtime exception for OData.
|
||||
*/
|
||||
public class ODataNotSupportedException extends ODataRuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 42L;
|
||||
|
||||
/**
|
||||
* Create with <code>message</code>.
|
||||
*
|
||||
* @param msg message text for exception
|
||||
*/
|
||||
public ODataNotSupportedException(final String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with <code>message</code> for and <code>cause</code> of exception.
|
||||
*
|
||||
* @param msg message text for exception
|
||||
* @param cause cause of exception
|
||||
*/
|
||||
public ODataNotSupportedException(final String msg, final Exception cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create with <code>cause</code> of exception.
|
||||
*
|
||||
* @param cause cause of exception
|
||||
*/
|
||||
public ODataNotSupportedException(final Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.api;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
public interface ODataContent {
|
||||
void write(WritableByteChannel channel);
|
||||
|
||||
void write(OutputStream stream);
|
||||
}
|
|
@ -18,12 +18,12 @@
|
|||
*/
|
||||
package org.apache.olingo.server.api;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
|
||||
/**
|
||||
* Response object to carry OData-relevant HTTP information (status code, response headers, and content).
|
||||
*/
|
||||
|
@ -131,4 +131,13 @@ public class ODataResponse {
|
|||
return content;
|
||||
}
|
||||
|
||||
private ODataContent odataContent;
|
||||
|
||||
public void setODataContent(ODataContent result) {
|
||||
odataContent = result;
|
||||
}
|
||||
|
||||
public ODataContent getODataContent() {
|
||||
return odataContent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.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);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.api;
|
||||
|
||||
/**
|
||||
* The WriteContentErrorErrorContext is the parameter for the WriteContentErrorCallback.
|
||||
*/
|
||||
public interface WriteContentErrorContext {
|
||||
Exception getException();
|
||||
ODataLibraryException getODataLibraryException();
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.olingo.server.api.serializer;
|
||||
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.server.api.WriteContentErrorCallback;
|
||||
import org.apache.olingo.server.api.uri.queryoption.CountOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
|
@ -32,6 +33,7 @@ public class EntityCollectionSerializerOptions {
|
|||
private SelectOption select;
|
||||
private boolean writeOnlyReferences;
|
||||
private String id;
|
||||
private WriteContentErrorCallback writeContentErrorCallback;
|
||||
private String xml10InvalidCharReplacement;
|
||||
|
||||
/** Gets the {@link ContextURL}. */
|
||||
|
@ -64,6 +66,17 @@ public class EntityCollectionSerializerOptions {
|
|||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the callback which is used in case of an exception during
|
||||
* write of the content (in case the content will be written/streamed
|
||||
* in the future)
|
||||
* @return callback which is used in case of an exception during
|
||||
* write of the content
|
||||
*
|
||||
*/
|
||||
public WriteContentErrorCallback getWriteContentErrorCallback() {
|
||||
return writeContentErrorCallback;
|
||||
}
|
||||
/** Gets the replacement string for unicode characters, that is not allowed in XML 1.0 */
|
||||
public String xml10InvalidCharReplacement() {
|
||||
return xml10InvalidCharReplacement;
|
||||
|
@ -118,7 +131,19 @@ public class EntityCollectionSerializerOptions {
|
|||
options.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the callback which is used in case of an exception during
|
||||
* write of the content.
|
||||
*
|
||||
* @param writeContentErrorCallback the callback
|
||||
* @return the builder
|
||||
*/
|
||||
public Builder writeContentErrorCallback(WriteContentErrorCallback writeContentErrorCallback) {
|
||||
options.writeContentErrorCallback = writeContentErrorCallback;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** set the replacement String for xml 1.0 unicode controlled characters that are not allowed */
|
||||
public Builder xml10InvalidCharReplacement(final String replacement) {
|
||||
options.xml10InvalidCharReplacement = replacement;
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
package org.apache.olingo.server.api.serializer;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.EntityIterator;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
|
@ -61,7 +62,17 @@ public interface ODataSerializer {
|
|||
* @param options options for the serializer
|
||||
*/
|
||||
SerializerResult entityCollection(ServiceMetadata metadata, EdmEntityType entityType,
|
||||
EntityCollection entitySet, EntityCollectionSerializerOptions options) throws SerializerException;
|
||||
AbstractEntityCollection entitySet, EntityCollectionSerializerOptions options) throws SerializerException;
|
||||
|
||||
/**
|
||||
* Writes entity-collection data into an InputStream.
|
||||
* @param metadata metadata for the service
|
||||
* @param entityType the {@link EdmEntityType}
|
||||
* @param entities the data of the entity set
|
||||
* @param options options for the serializer
|
||||
*/
|
||||
SerializerStreamResult entityCollectionStreamed(ServiceMetadata metadata, EdmEntityType entityType,
|
||||
EntityIterator entities, EntityCollectionSerializerOptions options) throws SerializerException;
|
||||
|
||||
/**
|
||||
* Writes entity data into an InputStream.
|
||||
|
@ -128,8 +139,9 @@ public interface ODataSerializer {
|
|||
* @param metadata metadata for the service
|
||||
* @param edmEntitySet {@link EdmEntitySet}
|
||||
* @param entityCollection data of the entity collection
|
||||
* @param ReferenceCollectionSerializerOptions {@link ReferenceCollectionSerializerOptions}
|
||||
* @param options {@link ReferenceCollectionSerializerOptions}
|
||||
*/
|
||||
SerializerResult referenceCollection(ServiceMetadata metadata, EdmEntitySet edmEntitySet,
|
||||
EntityCollection entityCollection, ReferenceCollectionSerializerOptions options) throws SerializerException;
|
||||
AbstractEntityCollection entityCollection, ReferenceCollectionSerializerOptions options)
|
||||
throws SerializerException;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.api.serializer;
|
||||
|
||||
import org.apache.olingo.server.api.ODataContent;
|
||||
|
||||
/**
|
||||
* Result type for {@link ODataSerializer} methods
|
||||
* which supports stream/write in the future
|
||||
*/
|
||||
public interface SerializerStreamResult {
|
||||
/**
|
||||
* Returns the content as ODataContent
|
||||
* @return content
|
||||
*/
|
||||
ODataContent getODataContent();
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
package org.apache.olingo.server.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.Channels;
|
||||
|
@ -38,6 +39,7 @@ import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
|||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataContent;
|
||||
import org.apache.olingo.server.api.ODataHttpHandler;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
|
@ -149,22 +151,35 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
|
|||
}
|
||||
}
|
||||
|
||||
if (odResponse.getContent() != null) {
|
||||
copyContent(odResponse, response);
|
||||
if (odResponse.getContent() != null ) {
|
||||
copyContent(odResponse.getContent(), response);
|
||||
} else if(odResponse.getODataContent() != null) {
|
||||
writeContent(odResponse, response);
|
||||
}
|
||||
}
|
||||
|
||||
static void copyContent(final ODataResponse odataResponse, final HttpServletResponse servletResponse) {
|
||||
ReadableByteChannel input = null;
|
||||
static void writeContent(final ODataResponse odataResponse, final HttpServletResponse servletResponse) {
|
||||
try {
|
||||
ODataContent res = odataResponse.getODataContent();
|
||||
res.write(Channels.newChannel(servletResponse.getOutputStream()));
|
||||
} catch (IOException e) {
|
||||
throw new ODataRuntimeException("Error on reading request content", e);
|
||||
}
|
||||
}
|
||||
|
||||
static void copyContent(final InputStream inputStream, final HttpServletResponse servletResponse) {
|
||||
copyContent(Channels.newChannel(inputStream), servletResponse);
|
||||
}
|
||||
|
||||
static void copyContent(final ReadableByteChannel input, final HttpServletResponse servletResponse) {
|
||||
WritableByteChannel output = null;
|
||||
try {
|
||||
ByteBuffer inBuffer = ByteBuffer.allocate(COPY_BUFFER_SIZE);
|
||||
output = Channels.newChannel(servletResponse.getOutputStream());
|
||||
input = Channels.newChannel(odataResponse.getContent());
|
||||
while (input.read(inBuffer) > 0) {
|
||||
inBuffer.flip();
|
||||
output.write(inBuffer);
|
||||
inBuffer.rewind();
|
||||
inBuffer.clear();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ODataRuntimeException("Error on reading request content", e);
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
import org.apache.olingo.commons.api.data.EntityIterator;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.server.api.ODataContent;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
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.xml.ODataXmlSerializer;
|
||||
|
||||
public class ODataWritableContent implements ODataContent {
|
||||
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.serializer = serializer;
|
||||
this.metadata = metadata;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
protected abstract void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException;
|
||||
|
||||
public void write(OutputStream out) {
|
||||
try {
|
||||
writeEntity(iterator, out);
|
||||
} catch (SerializerException e) {
|
||||
final WriteContentErrorCallback errorCallback = options.getWriteContentErrorCallback();
|
||||
if(errorCallback != null) {
|
||||
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);
|
||||
|
||||
this.jsonSerializer = jsonSerializer;
|
||||
}
|
||||
|
||||
protected void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException {
|
||||
try {
|
||||
jsonSerializer.entityCollectionIntoStream(metadata, entityType, entity, options, outputStream);
|
||||
outputStream.flush();
|
||||
} catch (final IOException e) {
|
||||
throw new ODataRuntimeException("Failed entity serialization");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class StreamContentForXml extends StreamContent {
|
||||
private ODataXmlSerializer xmlSerializer;
|
||||
|
||||
public StreamContentForXml(EntityIterator iterator, EdmEntityType entityType,
|
||||
ODataXmlSerializer xmlSerializer, ServiceMetadata metadata,
|
||||
EntityCollectionSerializerOptions options) {
|
||||
super(iterator, entityType, xmlSerializer, metadata, options);
|
||||
|
||||
this.xmlSerializer = xmlSerializer;
|
||||
}
|
||||
|
||||
protected void writeEntity(EntityIterator entity, OutputStream outputStream) throws SerializerException {
|
||||
try {
|
||||
xmlSerializer.entityCollectionIntoStream(metadata, entityType, entity, options, outputStream);
|
||||
outputStream.flush();
|
||||
} catch (final IOException e) {
|
||||
throw new ODataRuntimeException("Failed entity serialization");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(WritableByteChannel writeChannel) {
|
||||
this.streamContent.write(Channels.newOutputStream(writeChannel));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(OutputStream stream) {
|
||||
write(Channels.newChannel(stream));
|
||||
}
|
||||
|
||||
private ODataWritableContent(StreamContent streamContent) {
|
||||
this.streamContent = streamContent;
|
||||
}
|
||||
|
||||
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;
|
||||
public ErrorContext(ODataLibraryException exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
@Override
|
||||
public ODataLibraryException getODataLibraryException() {
|
||||
return exception;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ODataWritableContentBuilder {
|
||||
private ODataSerializer serializer;
|
||||
private EntityIterator entities;
|
||||
private ServiceMetadata metadata;
|
||||
private EdmEntityType entityType;
|
||||
private EntityCollectionSerializerOptions options;
|
||||
|
||||
public ODataWritableContentBuilder(EntityIterator entities, EdmEntityType entityType,
|
||||
ODataSerializer serializer,
|
||||
ServiceMetadata metadata, EntityCollectionSerializerOptions options) {
|
||||
this.entities = entities;
|
||||
this.entityType = entityType;
|
||||
this.serializer = serializer;
|
||||
this.metadata = metadata;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public ODataContent buildContent() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ 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;
|
||||
|
||||
public class SerializerResultImpl implements SerializerResult {
|
||||
|
@ -30,23 +31,34 @@ public class SerializerResultImpl implements SerializerResult {
|
|||
return content;
|
||||
}
|
||||
|
||||
// @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();
|
||||
}
|
||||
|
||||
public static class SerializerResultBuilder {
|
||||
private InputStream content;
|
||||
private SerializerResultImpl result = new SerializerResultImpl();
|
||||
|
||||
public SerializerResultBuilder content(final InputStream input) {
|
||||
content = input;
|
||||
|
||||
result.content = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerializerResult build() {
|
||||
SerializerResultImpl result = new SerializerResultImpl();
|
||||
result.content = content;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core.serializer;
|
||||
|
||||
import org.apache.olingo.server.api.ODataContent;
|
||||
import org.apache.olingo.server.api.serializer.SerializerStreamResult;
|
||||
|
||||
public class SerializerStreamResultImpl implements SerializerStreamResult {
|
||||
private ODataContent oDataContent;
|
||||
|
||||
@Override
|
||||
public ODataContent getODataContent() {
|
||||
return oDataContent;
|
||||
}
|
||||
|
||||
public static SerializerResultBuilder with() {
|
||||
return new SerializerResultBuilder();
|
||||
}
|
||||
|
||||
public static class SerializerResultBuilder {
|
||||
private SerializerStreamResultImpl result = new SerializerStreamResultImpl();
|
||||
|
||||
public SerializerResultBuilder content(final ODataContent content) {
|
||||
result.oDataContent = content;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerializerStreamResult build() {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,7 +29,8 @@ import org.apache.olingo.commons.api.Constants;
|
|||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.EntityIterator;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Linked;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
|
@ -57,11 +58,13 @@ import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOpti
|
|||
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
import org.apache.olingo.server.api.serializer.SerializerStreamResult;
|
||||
import org.apache.olingo.server.api.uri.UriHelper;
|
||||
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.serializer.AbstractODataSerializer;
|
||||
import org.apache.olingo.server.core.ODataWritableContent;
|
||||
import org.apache.olingo.server.core.serializer.SerializerResultImpl;
|
||||
import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
|
||||
import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
|
||||
|
@ -136,7 +139,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
|
||||
@Override
|
||||
public SerializerResult entityCollection(final ServiceMetadata metadata,
|
||||
final EdmEntityType entityType, final EntityCollection entitySet,
|
||||
final EdmEntityType entityType, final AbstractEntityCollection entitySet,
|
||||
final EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
|
@ -175,6 +178,50 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializerStreamResult entityCollectionStreamed(ServiceMetadata metadata, EdmEntityType entityType,
|
||||
EntityIterator entities, EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
|
||||
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();
|
||||
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
writeContextURL(contextURL, json);
|
||||
|
||||
writeMetadataETag(metadata, json);
|
||||
|
||||
if (options != null && options.getCount() != null && options.getCount().getValue()) {
|
||||
writeCount(entitySet, json);
|
||||
}
|
||||
json.writeFieldName(Constants.VALUE);
|
||||
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);
|
||||
|
||||
json.close();
|
||||
} catch (final IOException e) {
|
||||
cachedException =
|
||||
new SerializerException(IO_EXCEPTION_TEXT, e, SerializerException.MessageKeys.IO_EXCEPTION);
|
||||
throw cachedException;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializerResult entity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final EntitySerializerOptions options) throws SerializerException {
|
||||
|
@ -203,7 +250,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
private ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException {
|
||||
ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException {
|
||||
if (isODataMetadataNone) {
|
||||
return null;
|
||||
} else if (contextURL == null) {
|
||||
|
@ -213,11 +260,11 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final boolean onlyReference, final JsonGenerator json) throws IOException,
|
||||
SerializerException {
|
||||
json.writeStartArray();
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
for (final Entity entity : entitySet) {
|
||||
if (onlyReference) {
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.JSON_ID, entity.getId().toASCIIString());
|
||||
|
@ -229,9 +276,9 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
json.writeEndArray();
|
||||
}
|
||||
|
||||
protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final ContextURL contextURL, final ExpandOption expand,
|
||||
final SelectOption select, final boolean onlyReference, final JsonGenerator json)
|
||||
public void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType, final Entity entity,
|
||||
final ContextURL contextURL, final ExpandOption expand, final SelectOption select, final boolean onlyReference,
|
||||
final JsonGenerator json)
|
||||
throws IOException, SerializerException {
|
||||
json.writeStartObject();
|
||||
if (!isODataMetadataNone) {
|
||||
|
@ -736,7 +783,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
|
||||
@Override
|
||||
public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
|
||||
final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions options)
|
||||
final AbstractEntityCollection entityCollection, final ReferenceCollectionSerializerOptions options)
|
||||
throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
|
@ -755,7 +802,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
|
||||
json.writeArrayFieldStart(Constants.VALUE);
|
||||
for (final Entity entity : entityCollection.getEntities()) {
|
||||
for (final Entity entity : entityCollection) {
|
||||
json.writeStartObject();
|
||||
json.writeStringField(Constants.JSON_ID, uriHelper.buildCanonicalURL(edmEntitySet, entity));
|
||||
json.writeEndObject();
|
||||
|
@ -779,13 +826,13 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
|
||||
}
|
||||
|
||||
private void writeContextURL(final ContextURL contextURL, final JsonGenerator json) throws IOException {
|
||||
void writeContextURL(final ContextURL contextURL, final JsonGenerator json) throws IOException {
|
||||
if (!isODataMetadataNone && contextURL != null) {
|
||||
json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeMetadataETag(final ServiceMetadata metadata, final JsonGenerator json) throws IOException {
|
||||
void writeMetadataETag(final ServiceMetadata metadata, final JsonGenerator json) throws IOException {
|
||||
if (!isODataMetadataNone
|
||||
&& metadata != null
|
||||
&& metadata.getServiceMetadataETagSupport() != null
|
||||
|
@ -795,7 +842,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
private void writeCount(final EntityCollection entityCollection, final JsonGenerator json) throws IOException {
|
||||
void writeCount(final AbstractEntityCollection entityCollection, final JsonGenerator json) throws IOException {
|
||||
if (entityCollection.getCount() != null) {
|
||||
if (isIEEE754Compatible) {
|
||||
json.writeStringField(Constants.JSON_COUNT, entityCollection.getCount().toString());
|
||||
|
@ -805,7 +852,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
private void writeNextLink(final EntityCollection entitySet, final JsonGenerator json) throws IOException {
|
||||
void writeNextLink(final AbstractEntityCollection entitySet, final JsonGenerator json) throws IOException {
|
||||
if (entitySet.getNext() != null) {
|
||||
json.writeStringField(Constants.JSON_NEXT_LINK, entitySet.getNext().toASCIIString());
|
||||
}
|
||||
|
|
|
@ -193,6 +193,25 @@ public class CircleStreamBuffer {
|
|||
return readBuffer.get();
|
||||
}
|
||||
|
||||
public ByteBuffer getBuffer() throws IOException {
|
||||
if (readClosed) {
|
||||
throw new IOException("Tried to read from closed stream.");
|
||||
}
|
||||
writeMode = false;
|
||||
|
||||
// FIXME: mibo_160108: This is not efficient and only for test/poc reasons
|
||||
int reqSize = 0;
|
||||
for (ByteBuffer byteBuffer : bufferQueue) {
|
||||
reqSize += byteBuffer.position();
|
||||
}
|
||||
ByteBuffer tmp = ByteBuffer.allocateDirect(reqSize);
|
||||
for (ByteBuffer byteBuffer : bufferQueue) {
|
||||
byteBuffer.flip();
|
||||
tmp.put(byteBuffer);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// #############################################
|
||||
// #
|
||||
// # Writing parts
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.core.serializer.utils;
|
||||
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.Channel;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
|
||||
public class ResultHelper {
|
||||
|
||||
public static final int COPY_BUFFER_SIZE = 8192;
|
||||
|
||||
public static void copy(InputStream input, OutputStream output) {
|
||||
copy(Channels.newChannel(input), Channels.newChannel(output));
|
||||
}
|
||||
|
||||
public static void copy(ReadableByteChannel input, WritableByteChannel output) {
|
||||
try {
|
||||
ByteBuffer inBuffer = ByteBuffer.allocate(COPY_BUFFER_SIZE);
|
||||
while (input.read(inBuffer) > 0) {
|
||||
inBuffer.flip();
|
||||
output.write(inBuffer);
|
||||
inBuffer.clear();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ODataRuntimeException("Error on reading request content", e);
|
||||
} finally {
|
||||
closeStream(input);
|
||||
closeStream(output);
|
||||
}
|
||||
}
|
||||
|
||||
private static void closeStream(final Channel closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,6 +35,8 @@ import org.apache.olingo.commons.api.data.ComplexValue;
|
|||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntityCollection;
|
||||
import org.apache.olingo.commons.api.data.AbstractEntityCollection;
|
||||
import org.apache.olingo.commons.api.data.EntityIterator;
|
||||
import org.apache.olingo.commons.api.data.Link;
|
||||
import org.apache.olingo.commons.api.data.Linked;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
|
@ -51,6 +53,7 @@ import org.apache.olingo.commons.api.edm.EdmType;
|
|||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
import org.apache.olingo.commons.api.ex.ODataErrorDetail;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
|
||||
import org.apache.olingo.server.api.ODataServerError;
|
||||
|
@ -63,9 +66,11 @@ import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOpti
|
|||
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
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;
|
||||
|
@ -210,7 +215,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
|
||||
@Override
|
||||
public SerializerResult entityCollection(final ServiceMetadata metadata,
|
||||
final EdmEntityType entityType, final EntityCollection entitySet,
|
||||
final EdmEntityType entityType, final AbstractEntityCollection entitySet,
|
||||
final EntityCollectionSerializerOptions options) throws SerializerException {
|
||||
|
||||
final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
|
||||
|
@ -278,6 +283,69 @@ 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 {
|
||||
return ODataWritableContent.with(entities, entityType, this, metadata, options).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SerializerResult entity(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final Entity entity, final EntitySerializerOptions options) throws SerializerException {
|
||||
|
@ -338,10 +406,10 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
|
||||
protected void writeEntitySet(final ServiceMetadata metadata, final EdmEntityType entityType,
|
||||
final EntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final AbstractEntityCollection entitySet, final ExpandOption expand, final SelectOption select,
|
||||
final String xml10InvalidCharReplacement,final XMLStreamWriter writer)
|
||||
throws XMLStreamException, SerializerException {
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
for (final Entity entity : entitySet) {
|
||||
writeEntity(metadata, entityType, entity, null, expand, select, xml10InvalidCharReplacement, writer, false);
|
||||
}
|
||||
}
|
||||
|
@ -1063,12 +1131,12 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
|
||||
@Override
|
||||
public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
|
||||
final EntityCollection entityCollection, final ReferenceCollectionSerializerOptions options)
|
||||
final AbstractEntityCollection entityCollection, final ReferenceCollectionSerializerOptions options)
|
||||
throws SerializerException {
|
||||
return entityReferenceCollection(entityCollection, options);
|
||||
}
|
||||
|
||||
protected SerializerResult entityReferenceCollection(final EntityCollection entitySet,
|
||||
protected SerializerResult entityReferenceCollection(final AbstractEntityCollection entitySet,
|
||||
final ReferenceCollectionSerializerOptions options) throws SerializerException {
|
||||
OutputStream outputStream = null;
|
||||
SerializerException cachedException = null;
|
||||
|
@ -1091,7 +1159,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
if (entitySet.getNext() != null) {
|
||||
writeNextLink(entitySet, writer);
|
||||
}
|
||||
for (final Entity entity : entitySet.getEntities()) {
|
||||
for (final Entity entity : entitySet) {
|
||||
writeReference(entity, options == null ? null : options.getContextURL(), writer, false);
|
||||
}
|
||||
writer.writeEndElement();
|
||||
|
@ -1114,14 +1182,14 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
}
|
||||
}
|
||||
|
||||
private void writeCount(final EntityCollection entitySet, final XMLStreamWriter writer)
|
||||
private void writeCount(final AbstractEntityCollection entitySet, final XMLStreamWriter writer)
|
||||
throws XMLStreamException {
|
||||
writer.writeStartElement(METADATA, Constants.ATOM_ELEM_COUNT, NS_METADATA);
|
||||
writer.writeCharacters(String.valueOf(entitySet.getCount()));
|
||||
writer.writeEndElement();
|
||||
}
|
||||
|
||||
private void writeNextLink(final EntityCollection entitySet, final XMLStreamWriter writer)
|
||||
private void writeNextLink(final AbstractEntityCollection entitySet, final XMLStreamWriter writer)
|
||||
throws XMLStreamException {
|
||||
writer.writeStartElement(ATOM, Constants.ATOM_ELEM_LINK, NS_ATOM);
|
||||
writer.writeAttribute(Constants.ATTR_REL, Constants.NEXT_LINK_REL);
|
||||
|
@ -1153,5 +1221,5 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
|
|||
return value;
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,13 @@
|
|||
*/
|
||||
package org.apache.olingo.server.core.uri.parser.search;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token.AND;
|
||||
import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token.CLOSE;
|
||||
import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token.NOT;
|
||||
|
@ -26,13 +33,6 @@ import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.T
|
|||
import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token.PHRASE;
|
||||
import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token.WORD;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SearchTokenizerTest {
|
||||
|
||||
@Test
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
*/
|
||||
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;
|
||||
|
@ -25,6 +27,9 @@ import org.apache.olingo.commons.api.data.ContextURL.Builder;
|
|||
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;
|
||||
|
@ -51,6 +56,7 @@ import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
|
|||
import org.apache.olingo.server.api.serializer.ReferenceCollectionSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.ReferenceSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.SerializerResult;
|
||||
import org.apache.olingo.server.api.serializer.SerializerStreamResult;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceNavigation;
|
||||
|
@ -519,12 +525,26 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
id = request.getRawBaseUri() + edmEntitySet.getName();
|
||||
}
|
||||
|
||||
// Serialize
|
||||
final SerializerResult serializerResult = (isReference) ?
|
||||
serializeReferenceCollection(entitySetSerialization, edmEntitySet, requestedContentType, countOption) :
|
||||
serializeEntityCollection(request, entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
|
||||
expand, select, countOption, id);
|
||||
response.setContent(serializerResult.getContent());
|
||||
if(isReference) {
|
||||
final SerializerResult serializerResult =
|
||||
serializeReferenceCollection(entitySetSerialization, edmEntitySet, requestedContentType, countOption);
|
||||
response.setContent(serializerResult.getContent());
|
||||
} 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());
|
||||
}
|
||||
|
||||
//
|
||||
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
|
||||
response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
|
||||
if (pageSize != null) {
|
||||
|
@ -533,6 +553,11 @@ 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,
|
||||
|
@ -551,6 +576,56 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
.build());
|
||||
}
|
||||
|
||||
// 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,
|
||||
final CountOption countOption, final String id) throws ODataLibraryException {
|
||||
|
||||
EntityIterator streamCollection = new EntityIterator() {
|
||||
Iterator<Entity> entityIterator = entityCollection.iterator();
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return entityIterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity 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;
|
||||
}
|
||||
};
|
||||
|
||||
return odata.createSerializer(requestedFormat).entityCollectionStreamed(
|
||||
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 serializeReferenceCollection(final EntityCollection entityCollection,
|
||||
final EdmEntitySet edmEntitySet, final ContentType requestedFormat, final CountOption countOption)
|
||||
throws ODataLibraryException {
|
||||
|
|
|
@ -18,18 +18,25 @@
|
|||
*/
|
||||
package org.apache.olingo.server.core.serializer.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.WritableByteChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.output.ByteArrayOutputStream;
|
||||
import org.apache.olingo.commons.api.data.ComplexValue;
|
||||
import org.apache.olingo.commons.api.data.ContextURL;
|
||||
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.EdmComplexType;
|
||||
|
@ -40,7 +47,10 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
|||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataContent;
|
||||
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.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
|
||||
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
|
||||
|
@ -85,12 +95,12 @@ public class ODataJsonSerializerTest {
|
|||
public void setup() {
|
||||
TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
TimeZone.setDefault(TimeZone.getDefault());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void entitySimple() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
|
@ -207,6 +217,90 @@ public class ODataJsonSerializerTest {
|
|||
Assert.assertEquals(8, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entityCollectionStreamed() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
final EntityIterator entityIterator = new EntityIterator() {
|
||||
Iterator<Entity> innerIterator = data.readAll(edmEntitySet).iterator();
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return innerIterator.hasNext();
|
||||
}
|
||||
@Override
|
||||
public Entity next() {
|
||||
return innerIterator.next();
|
||||
}
|
||||
};
|
||||
CountOption countOption = Mockito.mock(CountOption.class);
|
||||
Mockito.when(countOption.getValue()).thenReturn(true);
|
||||
|
||||
ODataContent result = serializer.entityCollectionStreamed(
|
||||
metadata, edmEntitySet.getEntityType(), entityIterator,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getODataContent();
|
||||
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\":[{\"PropertyInt16\":32767,\"PropertyString\""));
|
||||
Assert.assertThat(resultString, CoreMatchers.endsWith(
|
||||
"\"PropertyTimeOfDay\":\"00:01:01\"}]}"));
|
||||
|
||||
int count = 0;
|
||||
int index = -1;
|
||||
while ((index = resultString.indexOf("PropertyInt16\":", ++index)) > 0) {
|
||||
count++;
|
||||
}
|
||||
Assert.assertEquals(3, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void entityCollectionStreamedWithError() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
|
||||
final EntityIterator entityIterator = new EntityIterator() {
|
||||
Iterator<Entity> innerIterator = data.readAll(edmEntitySet).iterator();
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return innerIterator.hasNext();
|
||||
}
|
||||
@Override
|
||||
public Entity next() {
|
||||
return new Entity();
|
||||
}
|
||||
};
|
||||
CountOption countOption = Mockito.mock(CountOption.class);
|
||||
Mockito.when(countOption.getValue()).thenReturn(true);
|
||||
|
||||
WriteContentErrorCallback errorCallback = new WriteContentErrorCallback() {
|
||||
@Override
|
||||
public void handleError(WriteContentErrorContext context, WritableByteChannel channel) {
|
||||
try {
|
||||
String msgKey = context.getODataLibraryException().getMessageKey().getKey();
|
||||
String toChannel = "ERROR: " + msgKey;
|
||||
channel.write(ByteBuffer.wrap(toChannel.getBytes("UTF-8")));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error in error.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ODataContent result = serializer.entityCollectionStreamed(
|
||||
metadata, edmEntitySet.getEntityType(), entityIterator,
|
||||
EntityCollectionSerializerOptions.with()
|
||||
.writeContentErrorCallback(errorCallback)
|
||||
.contextURL(ContextURL.with().entitySet(edmEntitySet).build())
|
||||
.build()).getODataContent();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
result.write(bout);
|
||||
final String resultString = new String(bout.toByteArray(), "UTF-8");
|
||||
Assert.assertEquals(resultString, "ERROR: MISSING_PROPERTY");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void entityCollAllPrim() throws Exception {
|
||||
final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
|
||||
|
|
Loading…
Reference in New Issue