You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2017/04/25 08:23:07 UTC
olingo-odata2 git commit: [OLINGO-1093] Support Binary Content in
Batch
Repository: olingo-odata2
Updated Branches:
refs/heads/master 474d8f3e7 -> 0bce4ab78
[OLINGO-1093] Support Binary Content in Batch
Contributed by Vasanth, Ramya in OLINGO-1093
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/0bce4ab7
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/0bce4ab7
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/0bce4ab7
Branch: refs/heads/master
Commit: 0bce4ab78054d83408782e2855d17b2dfadbc6c9
Parents: 474d8f3
Author: Christian Amend <ch...@sap.com>
Authored: Tue Apr 25 10:14:34 2017 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Tue Apr 25 10:14:34 2017 +0200
----------------------------------------------------------------------
.../api/client/batch/BatchChangeSetPart.java | 12 +-
.../core/batch/BatchChangeSetPartImpl.java | 18 +-
.../olingo/odata2/core/batch/BatchHelper.java | 71 ++++++-
.../odata2/core/batch/BatchResponseWriter.java | 5 +-
.../odata2/core/batch/v2/BatchLineReader.java | 13 +-
.../odata2/core/batch/v2/BatchParserCommon.java | 12 +-
.../batch/v2/BatchRequestTransformator.java | 2 +-
.../odata2/core/batch/BatchRequestTest.java | 48 +++++
.../odata2/core/batch/BatchResponseTest.java | 77 +++++++
.../core/batch/v2/BatchLineReaderTest.java | 53 +++++
.../src/test/resources/Employee_1.png | Bin 0 -> 8429 bytes
.../apache/olingo/odata2/fit/ref/BatchTest.java | 204 +++++++++++++++++++
.../odata-fit/src/test/resources/Employee_1.png | Bin 0 -> 8429 bytes
.../src/test/resources/simpleGet.batch | 8 +
.../src/test/resources/simpleGet1.batch | 8 +
.../ref/processor/ScenarioDataSource.java | 2 +
.../olingo/odata2/ref/processor/Util.java | 26 +++
17 files changed, 536 insertions(+), 23 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
index ecabf9b..93f86d5 100644
--- a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
+++ b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
@@ -30,7 +30,7 @@ public abstract class BatchChangeSetPart {
public abstract Map<String, String> getHeaders();
- public abstract String getBody();
+ public abstract Object getBody();
public abstract byte[] getBodyAsBytes();
@@ -55,6 +55,14 @@ public abstract class BatchChangeSetPart {
public static BatchChangeSetPartBuilder body(final String body) {
return newBuilder().body(body);
}
+
+ /**
+ * @param body a change request body
+ * @return a new builder object
+ */
+ public static BatchChangeSetPartBuilder body(final byte[] body) {
+ return newBuilder().body(body);
+ }
/**
* @param uri should not be null
@@ -100,6 +108,8 @@ public abstract class BatchChangeSetPart {
public abstract BatchChangeSetPartBuilder headers(Map<String, String> headers);
public abstract BatchChangeSetPartBuilder body(String body);
+
+ public abstract BatchChangeSetPartBuilder body(byte[] body);
public abstract BatchChangeSetPartBuilder uri(String uri);
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
index b1d83ab..2b5f44f 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
@@ -28,7 +28,7 @@ import java.util.Map;
public class BatchChangeSetPartImpl extends BatchChangeSetPart {
private String method;
private Map<String, String> headers = new HashMap<String, String>();
- private String body;
+ private Object body;
private String uri;
public String contentId;
private static final String CHANGE_METHODS = "(PUT|POST|DELETE|MERGE|PATCH)";
@@ -40,7 +40,7 @@ public class BatchChangeSetPartImpl extends BatchChangeSetPart {
@Override
public String getBody() {
- return body;
+ return body.toString();
}
@Override
@@ -49,7 +49,11 @@ public class BatchChangeSetPartImpl extends BatchChangeSetPart {
return new byte[0];
}
Charset charset = getCharset();
- return body.getBytes(charset);
+ if (body instanceof byte[]) {
+ return (byte[]) body; //NOSONAR
+ } else {
+ return body.toString().getBytes(charset);
+ }
}
private Charset getCharset() {
@@ -74,7 +78,7 @@ public class BatchChangeSetPartImpl extends BatchChangeSetPart {
public class BatchChangeSetRequestBuilderImpl extends BatchChangeSetPartBuilder {
private String method;
private Map<String, String> headers = new HashMap<String, String>();
- private String body;
+ private Object body;
private String uri;
private String contentId;
@@ -102,6 +106,12 @@ public class BatchChangeSetPartImpl extends BatchChangeSetPart {
this.body = body;
return this;
}
+
+ @Override
+ public BatchChangeSetPartBuilder body(byte[] body) {
+ this.body = body;
+ return this;
+ }
@Override
public BatchChangeSetPartBuilder uri(final String uri) {
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
index 835f47b..4889a42 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
@@ -40,13 +40,15 @@ import java.util.UUID;
public class BatchHelper {
public static final String BINARY_ENCODING = "binary";
- public static final String DEFAULT_ENCODING = "utf-8";
+ public static final String UTF8_ENCODING = "UTF-8";
+ public static final String ISO_ENCODING = "ISO-8859-1";
+ public static String DEFAULT_ENCODING = "UTF-8";
public static final String HTTP_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
public static final String HTTP_CONTENT_ID = "Content-Id";
public static final String MIME_HEADER_CONTENT_ID = "MimeHeader-ContentId";
public static final String REQUEST_HEADER_CONTENT_ID = "RequestHeader-ContentId";
- public static final Charset DEFAULT_CHARSET = Charset.forName(DEFAULT_ENCODING);
+ public static Charset DEFAULT_CHARSET = Charset.forName(DEFAULT_ENCODING);
protected static String generateBoundary(final String value) {
return value + "_" + UUID.randomUUID().toString();
@@ -72,11 +74,21 @@ public class BatchHelper {
return getCharset(contentType);
}
- public static Charset extractCharset(String contentType) {
- if(contentType == null) {
- return DEFAULT_CHARSET;
+ public static Charset extractCharset(ContentType contentType) {
+ if (contentType != null) {
+ final String charsetValue = contentType.getParameters().get(ContentType.PARAMETER_CHARSET);
+ if (charsetValue == null) {
+ if (contentType.isCompatible(ContentType.APPLICATION_JSON) || contentType.getSubtype().contains("xml")) {
+ setDefaultValues(UTF8_ENCODING);
+ return Charset.forName(UTF8_ENCODING);
+ }
+ } else {
+ setDefaultValues(charsetValue);
+ return Charset.forName(charsetValue);
+ }
}
- return getCharset(contentType);
+ setDefaultValues(ISO_ENCODING);
+ return Charset.forName(ISO_ENCODING);
}
private static Charset getCharset(String contentType) {
@@ -84,10 +96,23 @@ public class BatchHelper {
if(ct != null) {
String charsetString = ct.getParameters().get(ContentType.PARAMETER_CHARSET);
if (charsetString != null && Charset.isSupported(charsetString)) {
+ setDefaultValues(charsetString);
return Charset.forName(charsetString);
+ } else {
+ if (ct.isCompatible(ContentType.APPLICATION_JSON) || ct.getSubtype().contains("xml")) {
+ setDefaultValues(UTF8_ENCODING);
+ return Charset.forName(UTF8_ENCODING);
+ }
}
}
- return DEFAULT_CHARSET;
+ setDefaultValues(ISO_ENCODING);
+ return Charset.forName(ISO_ENCODING);
+ }
+
+ private static void setDefaultValues(String contentType) {
+ DEFAULT_CHARSET = Charset.forName(contentType);
+ DEFAULT_ENCODING = contentType;
+
}
/**
@@ -151,6 +176,33 @@ public class BatchHelper {
public String toString() {
return new String(buffer.array(), 0, buffer.position());
}
+
+ /**
+ * Fetch the calibrated length in case of binary data.
+ * Since after applying the charset the content length changes.
+ * If the previously generated length is sent back then the batch response
+ * body is seen truncated
+ * @param batchResponseBody
+ * @return
+ */
+ public int calculateLength(Object batchResponseBody) {
+ if (batchResponseBody != null) {
+ if (batchResponseBody instanceof String) {
+ if (DEFAULT_ENCODING.equalsIgnoreCase(ISO_ENCODING)) {
+ try {
+ return ((String) batchResponseBody).getBytes(UTF8_ENCODING).length;
+ } catch (UnsupportedEncodingException e) {
+ throw new ODataRuntimeException(e);
+ }
+ } else {
+ return getLength();
+ }
+ } else {
+ return getLength();
+ }
+ }
+ return getLength();
+ }
}
/**
@@ -202,6 +254,7 @@ public class BatchHelper {
return EMPTY_BYTES;
} else if(entity instanceof InputStream) {
try {
+ extractCharset(ContentType.parse(response.getHeader("Content-Type")));
ByteArrayOutputStream output = new ByteArrayOutputStream();
ByteBuffer inBuffer = ByteBuffer.allocate(BUFFER_SIZE);
ReadableByteChannel ic = Channels.newChannel((InputStream) entity);
@@ -215,7 +268,11 @@ public class BatchHelper {
} catch (IOException e) {
throw new ODataRuntimeException("Error on reading request content");
}
+ } else if (entity instanceof byte[]) {
+ setDefaultValues(ISO_ENCODING);
+ return (byte[]) entity;
} else if(entity instanceof String) {
+ setDefaultValues(UTF8_ENCODING);
return ((String) entity).getBytes(DEFAULT_CHARSET);
} else {
throw new ODataRuntimeException("Error on reading request content for entity type:" + entity.getClass());
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
index 0ef6f0e..9dc986c 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
@@ -58,14 +58,17 @@ public class BatchResponseWriter {
String boundary = BatchHelper.generateBoundary("batch");
appendResponsePart(batchResponseParts, boundary);
final Object batchResponseBody;
+ int length = 0;
if(writeEntityAsInputStream) {
batchResponseBody = writer.getContentAsStream();
+ length = writer.calculateLength(batchResponseBody);
} else {
batchResponseBody = writer.getContentAsString(BatchHelper.DEFAULT_CHARSET);
+ length = writer.calculateLength(batchResponseBody);
}
return ODataResponse.entity(batchResponseBody).status(HttpStatusCodes.ACCEPTED)
.header(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary)
- .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(writer.getLength()))
+ .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(length))
.build();
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReader.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReader.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReader.java
index 4075764..11cb947 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReader.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReader.java
@@ -33,9 +33,10 @@ public class BatchLineReader {
private static final byte LF = '\n';
private static final int EOF = -1;
private static final int BUFFER_SIZE = 8192;
- private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
- private static final Charset CS_ISO_8859_1 = Charset.forName("iso-8859-1");
+ private static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
+ private static final String UTF8_CHARSET = "UTF-8";
private static final String CONTENT_TYPE = "content-type";
+ private static final String XML_SUBTYPE = "xml";
public static final String BOUNDARY = "boundary";
public static final String DOUBLE_DASH = "--";
public static final String CRLF = "\r\n";
@@ -104,7 +105,11 @@ public class BatchLineReader {
if (charsetString != null) {
currentCharset = Charset.forName(charsetString);
} else {
- currentCharset = DEFAULT_CHARSET;
+ if (ct.isCompatible(ContentType.APPLICATION_JSON) || ct.getSubtype().contains(XML_SUBTYPE)) {
+ currentCharset = Charset.forName(UTF8_CHARSET);
+ } else {
+ currentCharset = DEFAULT_CHARSET;
+ }
}
// boundary
String boundary = ct.getParameters().get(BOUNDARY);
@@ -182,7 +187,7 @@ public class BatchLineReader {
if(readState.isReadBody()) {
currentLine = new String(buffer.array(), 0, buffer.position(), getCurrentCharset());
} else {
- currentLine = new String(buffer.array(), 0, buffer.position(), CS_ISO_8859_1);
+ currentLine = new String(buffer.array(), 0, buffer.position(), DEFAULT_CHARSET);
}
updateCurrentCharset(currentLine);
return currentLine;
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
index 76b44ce..7f5cc12 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchParserCommon.java
@@ -36,6 +36,7 @@ import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.core.batch.AcceptParser;
import org.apache.olingo.odata2.core.batch.BatchHelper;
+import org.apache.olingo.odata2.core.commons.ContentType;
import org.apache.olingo.odata2.core.commons.Decoder;
public class BatchParserCommon {
@@ -97,21 +98,22 @@ public class BatchParserCommon {
* Otherwise the whole content is written into the InputStream.
*
* @param contentType content type value
- * @param body content which is written into the InputStream
+ * @param operation which is written into the InputStream
* @param contentLength if it is a positive value the content is trimmed to according length.
* Otherwise the whole content is written into the InputStream.
* @return Content of BatchQueryOperation as InputStream in according charset and length
* @throws BatchException if something goes wrong
*/
- public static InputStream convertToInputStream(final String contentType, final List<Line> body,
+ public static InputStream convertToInputStream(final String contentType, final BatchQueryOperation operation,
final int contentLength)
throws BatchException {
- Charset charset = BatchHelper.extractCharset(contentType);
+ Charset charset = BatchHelper.extractCharset(ContentType.parse(
+ contentType));
final String message;
if(contentLength <= -1) {
- message = lineListToString(body);
+ message = lineListToString(operation.getBody());
} else {
- message = trimLineListToLength(body, contentLength);
+ message = trimLineListToLength(operation.getBody(), contentLength);
}
return new ByteArrayInputStream(message.getBytes(charset));
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
index bf3cc82..5a2b85b 100644
--- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
+++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/v2/BatchRequestTransformator.java
@@ -128,7 +128,7 @@ public class BatchRequestTransformator implements BatchTransformator {
} else {
int contentLength = BatchTransformatorCommon.getContentLength(headers);
String contentType = headers.getHeader(HttpHeaders.CONTENT_TYPE);
- return BatchParserCommon.convertToInputStream(contentType, operation.getBody(), contentLength);
+ return BatchParserCommon.convertToInputStream(contentType, operation, contentLength);
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
index 77e344e..0908149 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java
@@ -21,6 +21,7 @@ package org.apache.olingo.odata2.core.batch;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
import java.io.IOException;
import java.io.InputStream;
@@ -321,5 +322,52 @@ public class BatchRequestTest {
public void testBatchChangeSetPartWithInvalidMethod() throws BatchException, IOException {
BatchChangeSetPart.method(GET).uri("Employees('2')").build();
+ }
+
+ @Test
+ public void testBatchChangeSetRawBytes() throws IOException, BatchException {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put("content-type", "application/octect-stream");
+ byte[] data = getRawBytes();
+ BatchChangeSetPart request = BatchChangeSetPart.method(PUT)
+ .uri("Employees('2')/$value")
+ .body(data)
+ .headers(headers)
+ .build();
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ changeSet.add(request);
+ batch.add(changeSet);
+
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+ assertNotNull(batchRequest);
+
+ StringHelper.Stream batchRequestStream = StringHelper.toStream(batchRequest);
+ String requestBody = batchRequestStream.asString("ISO-8859-1");
+ checkMimeHeaders(requestBody);
+ checkHeaders(headers, requestBody);
+
+ assertTrue(requestBody.contains("--batch_"));
+ assertTrue(requestBody.contains("--changeset_"));
+ assertTrue(requestBody.contains("PUT Employees('2')/$value HTTP/1.1"));
+
+ String contentType = "multipart/mixed; boundary=" + BOUNDARY;
+ BatchParser parser = new BatchParser(contentType, parseProperties, true);
+ List<BatchRequestPart> parseResult = parser.parseBatchRequest(batchRequestStream.asStream());
+ assertEquals(1, parseResult.size());
+ InputStream in = parseResult.get(0).getRequests().get(0).getBody();
+ StringHelper.Stream parsedReqStream = StringHelper.toStream(in);
+ String parsedReqData = parsedReqStream.asString("ISO-8859-1");
+ assertArrayEquals(data, parsedReqData.getBytes("ISO-8859-1"));
+ }
+
+ private byte[] getRawBytes() {
+ byte[] data = new byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1];
+ // binary content, not a valid UTF-8 representation of a string
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ data[i - Byte.MIN_VALUE] = (byte) i;
+ }
+ return data;
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseTest.java
index 4076a25..91411f0 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseTest.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -32,8 +33,11 @@ import org.apache.olingo.odata2.api.batch.BatchException;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.exception.ODataException;
import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.core.batch.v2.BatchLineReader;
import org.apache.olingo.odata2.core.batch.v2.BatchParser;
+import org.apache.olingo.odata2.core.batch.v2.Line;
import org.apache.olingo.odata2.testutil.helper.StringHelper;
import org.junit.Test;
@@ -142,4 +146,77 @@ public class BatchResponseTest {
assertEquals(2, result.size());
assertEquals("Failing content:\n" + content.asString(), 19, content.linesCount());
}
+
+ @Test
+ public void testBatchResponseRawBytes() throws BatchException, IOException {
+ List<BatchResponsePart> parts = new ArrayList<BatchResponsePart>();
+ byte[] data = getRawBytes();
+ ODataResponse response = ODataResponse.entity(data)
+ .status(HttpStatusCodes.OK)
+ .contentHeader("application/octect-stream;charset=iso-8859-1")
+ .build();
+ List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
+ responses.add(response);
+ parts.add(BatchResponsePart.responses(responses).changeSet(false).build());
+
+ BatchResponseWriter writer = new BatchResponseWriter();
+ ODataResponse batchResponse = writer.writeResponse(parts);
+
+ assertEquals(202, batchResponse.getStatus().getStatusCode());
+ assertNotNull(batchResponse.getEntity());
+ String body = (String) batchResponse.getEntity();
+
+ assertTrue(body.contains("--batch"));
+ assertTrue(body.contains("HTTP/1.1 200 OK"));
+ assertTrue(body.contains("Content-Type: application/http"));
+ assertTrue(body.contains("Content-Transfer-Encoding: binary"));
+
+ String contentHeader = batchResponse.getContentHeader();
+ BatchParser parser = new BatchParser(contentHeader, true);
+ List<BatchSingleResponse> result = parser.parseBatchResponse(new ByteArrayInputStream(body.getBytes("iso-8859-1")));
+ assertEquals(1, result.size());
+ assertArrayEquals(data, result.get(0).getBody().getBytes("ISO-8859-1"));
+ }
+
+ @Test
+ public void testBatchResponseRawBytesAsStream() throws IOException, ODataException {
+ List<BatchResponsePart> parts = new ArrayList<BatchResponsePart>();
+ byte[] data = getRawBytes();
+ ODataResponse response = ODataResponse.entity(data)
+ .status(HttpStatusCodes.OK)
+ .contentHeader("application/octect-stream;charset=iso-8859-1")
+ .build();
+ List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
+ responses.add(response);
+ parts.add(BatchResponsePart.responses(responses).changeSet(false).build());
+
+ BatchResponseWriter writer = new BatchResponseWriter(true);
+ ODataResponse batchResponse = writer.writeResponse(parts);
+
+ assertEquals(202, batchResponse.getStatus().getStatusCode());
+ assertNotNull(batchResponse.getEntity());
+ BatchLineReader reader =
+ new BatchLineReader(batchResponse.getEntityAsStream());
+ List<Line> lines = reader.toLineList();
+ reader.close();
+ StringBuilder builder = new StringBuilder();
+ for (Line line : lines) {
+ builder.append(line);
+ }
+ String contentHeader = batchResponse.getContentHeader();
+ BatchParser parser = new BatchParser(contentHeader, true);
+ List<BatchSingleResponse> result = parser.parseBatchResponse(
+ new ByteArrayInputStream(builder.toString().getBytes("iso-8859-1")));
+ assertEquals(1, result.size());
+ assertArrayEquals(data, result.get(0).getBody().getBytes("ISO-8859-1"));
+ }
+
+ private byte[] getRawBytes() {
+ byte[] data = new byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1];
+ // binary content, not a valid UTF-8 representation of a string
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ data[i - Byte.MIN_VALUE] = (byte) i;
+ }
+ return data;
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReaderTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReaderTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReaderTest.java
index 351c693..f97b013 100644
--- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReaderTest.java
+++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/v2/BatchLineReaderTest.java
@@ -19,10 +19,16 @@
package org.apache.olingo.odata2.core.batch.v2;
import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.util.List;
import org.apache.olingo.odata2.core.batch.v2.BatchLineReader;
@@ -270,4 +276,51 @@ public class BatchLineReaderTest {
throws UnsupportedEncodingException {
return new BatchLineReader(new ByteArrayInputStream(inputString.getBytes("UTF-8")), bufferSize);
}
+
+ @Test
+ public void rawBytes() throws Exception {
+ byte[] content = new byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1];
+ // binary content, not a valid UTF-8 representation of a string
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ content[i - Byte.MIN_VALUE] = (byte) i;
+ }
+ BatchLineReader reader = new BatchLineReader(new ByteArrayInputStream(content));
+ final String contentString = reader.readLine() // initial part up to '\n'
+ + reader.readLine() // second part from '\n' to '\r'
+ + reader.readLine(); // the rest
+ assertArrayEquals(content, contentString.getBytes(Charset.forName("ISO-8859-1")));
+ assertNull(reader.readLine());
+ reader.close();
+ }
+
+ @Test
+ public void imageTest() throws Exception {
+ byte[] data = getImageData("/Employee_1.png");
+ BatchLineReader reader = new BatchLineReader(new ByteArrayInputStream(data));
+ final List<Line> contentString = reader.toLineList();
+ String finalContent = "";
+ for (Line content : contentString) {
+ finalContent += content.toString();
+ }
+
+ assertArrayEquals(data, finalContent.getBytes(Charset.forName("ISO-8859-1")));
+ reader.close();
+ }
+
+ private byte[] getImageData(String imageUrl) throws IOException {
+ byte[] data = null;
+ try {
+ InputStream in = this.getClass().getResourceAsStream(imageUrl);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ int b = 0;
+ while ((b = in.read()) != -1) {
+ stream.write(b);
+ }
+
+ data = stream.toByteArray();
+ } catch (IOException e) {
+ throw e;
+ }
+ return data;
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-core/src/test/resources/Employee_1.png
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-core/src/test/resources/Employee_1.png b/odata2-lib/odata-core/src/test/resources/Employee_1.png
new file mode 100644
index 0000000..f817682
Binary files /dev/null and b/odata2-lib/odata-core/src/test/resources/Employee_1.png differ
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
index 80a2be6..d11e38e 100644
--- a/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
+++ b/odata2-lib/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
@@ -22,10 +22,18 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import junit.framework.Assert;
@@ -33,7 +41,16 @@ import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart;
+import org.apache.olingo.odata2.api.client.batch.BatchPart;
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.core.batch.BatchRequestWriter;
+import org.apache.olingo.odata2.ref.processor.Util;
import org.apache.olingo.odata2.testutil.helper.StringHelper;
import org.apache.olingo.odata2.testutil.server.ServletType;
import org.junit.Test;
@@ -44,6 +61,10 @@ import org.junit.Test;
*/
public class BatchTest extends AbstractRefTest {
+ private static final String PUT = "PUT";
+ private static final String POST = "POST";
+ private static final String BOUNDARY = "batch_123";
+
public BatchTest(final ServletType servletType) {
super(servletType);
}
@@ -181,4 +202,187 @@ public class BatchTest extends AbstractRefTest {
assertEquals(202, response.getStatusLine().getStatusCode());
return response;
}
+
+ /**
+ * @param method
+ * @param data
+ * @param contentType
+ * @return
+ */
+ private InputStream createBatchRequest(String method, byte[] data, String contentType) {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ Map<String, String> headers = new HashMap<String, String>();
+
+ BatchChangeSetPart request = null;
+ if (method.equalsIgnoreCase(PUT)) {
+ headers.put("content-type", contentType);
+ request = BatchChangeSetPart.method(PUT)
+ .uri("Employees('2')/$value")
+ .body(data)
+ .headers(headers)
+ .contentId("1")
+ .build();
+ } else if (method.equalsIgnoreCase(POST)) {
+ headers.put("content-type", contentType);
+ request = BatchChangeSetPart.method(POST)
+ .uri("Employees")
+ .body(data)
+ .headers(headers)
+ .contentId("1")
+ .build();
+ }
+
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ changeSet.add(request);
+ batch.add(changeSet);
+
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+
+ return batchRequest;
+ }
+
+ @Test
+ public void testBatchWithChangesetWithRawBytesInPutOperation() throws Exception {
+ InputStream requestPayload = createBatchRequestWithRawBytes(PUT);
+ final HttpPost put = new HttpPost(URI.create(getEndpoint().toString() + "$batch"));
+ put.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY);
+ HttpEntity entity = new InputStreamEntity(requestPayload, -1);
+ put.setEntity(entity);
+ HttpResponse response = getHttpClient().execute(put);
+ byte[] actualData = Util.getInstance().getBinaryContent();
+ byte[] expectedData = rawBytes();
+ // Comparing data stored in the data source and the data sent in the request
+ assertArrayEquals(actualData, expectedData);
+
+ assertNotNull(response);
+ assertEquals(202, response.getStatusLine().getStatusCode());
+ String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent());
+ assertTrue(responseBody.contains("204 No Content"));
+
+ HttpResponse resp = execute("/simpleGet.batch", BOUNDARY);
+ InputStream in = resp.getEntity().getContent();
+ StringHelper.Stream batchRequestStream = StringHelper.toStream(in);
+ String requestBody = batchRequestStream.asString();
+
+ String contentType = resp.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(
+ new ByteArrayInputStream(requestBody.getBytes("iso-8859-1")), contentType);
+ for (BatchSingleResponse batchResp : responses) {
+ assertEquals("200", batchResp.getStatusCode());
+ assertEquals("OK", batchResp.getStatusInfo());
+ assertArrayEquals(batchResp.getBody().getBytes("iso-8859-1"), actualData);
+ }
+ }
+
+ @Test
+ public void testBatchWithChangesetWithRawBytesInPOSTOperation() throws Exception {
+ InputStream requestPayload = createBatchRequestWithRawBytes(POST);
+ final HttpPost put = new HttpPost(URI.create(getEndpoint().toString() + "$batch"));
+ put.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY);
+ HttpEntity entity = new InputStreamEntity(requestPayload, -1);
+ put.setEntity(entity);
+ HttpResponse response = getHttpClient().execute(put);
+ byte[] actualData = Util.getInstance().getBinaryContent();
+ byte[] expectedData = rawBytes();
+ // Comparing data stored in the data source and the data sent in the request
+ assertArrayEquals(actualData, expectedData);
+
+ assertNotNull(response);
+ assertEquals(202, response.getStatusLine().getStatusCode());
+ String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent());
+ assertTrue(responseBody.contains("201 Created"));
+
+ HttpResponse resp = execute("/simpleGet1.batch", BOUNDARY);
+ InputStream in = resp.getEntity().getContent();
+ StringHelper.Stream batchRequestStream = StringHelper.toStream(in);
+ String requestBody = batchRequestStream.asString();
+
+ String contentType = resp.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(
+ new ByteArrayInputStream(requestBody.getBytes("iso-8859-1")), contentType);
+ for (BatchSingleResponse batchResp : responses) {
+ assertEquals("200", batchResp.getStatusCode());
+ assertEquals("OK", batchResp.getStatusInfo());
+ assertArrayEquals(batchResp.getBody().getBytes("iso-8859-1"), expectedData);
+ }
+ }
+
+ @Test
+ public void testBatchWithChangesetWithImageObjectInPutOperation() throws Exception {
+ InputStream requestPayload = createBatchRequestWithImage("/Employee_1.png", PUT);
+
+ final HttpPost put = new HttpPost(URI.create(getEndpoint().toString() + "$batch"));
+ put.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY);
+ HttpEntity entity = new InputStreamEntity(requestPayload, -1);
+ put.setEntity(entity);
+ HttpResponse response = getHttpClient().execute(put);
+ byte[] actualData = Util.getInstance().getBinaryContent();
+ byte[] expectedData = getImageData("/Employee_1.png");
+ // Comparing data stored in the data source and the data sent in the request
+ assertArrayEquals(actualData, expectedData);
+
+ assertNotNull(response);
+ assertEquals(202, response.getStatusLine().getStatusCode());
+ String responseBody = StringHelper.inputStreamToStringCRLFLineBreaks(response.getEntity().getContent());
+ assertTrue(responseBody.contains("204 No Content"));
+
+ HttpResponse resp = execute("/simpleGet.batch", BOUNDARY);
+ InputStream in = resp.getEntity().getContent();
+ StringHelper.Stream batchRequestStream = StringHelper.toStream(in);
+ String requestBody = batchRequestStream.asString();
+
+ String contentType = resp.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(
+ new ByteArrayInputStream(requestBody.getBytes("iso-8859-1")), contentType);
+ for (BatchSingleResponse batchResp : responses) {
+ assertEquals("200", batchResp.getStatusCode());
+ assertEquals("OK", batchResp.getStatusInfo());
+ assertArrayEquals(batchResp.getBody().getBytes("iso-8859-1"), actualData);
+ }
+ }
+
+ private InputStream createBatchRequestWithImage(String imageUrl, String method) throws IOException {
+ byte[] data = getImageData(imageUrl);
+ return createBatchRequest(method, data, "image/jpeg");
+ }
+
+ private InputStream createBatchRequestWithRawBytes(String method) {
+ byte[] data = rawBytes();
+ return createBatchRequest(method, data, "application/octect-stream");
+ }
+
+ /**
+ * @return
+ */
+ private byte[] rawBytes() {
+ byte[] data = new byte[Byte.MAX_VALUE - Byte.MIN_VALUE + 1];
+ // binary content, not a valid UTF-8 representation of a string
+ for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+ data[i - Byte.MIN_VALUE] = (byte) i;
+ }
+ return data;
+ }
+
+ /**
+ * @param imageUrl
+ * @return
+ * @throws IOException
+ */
+ private byte[] getImageData(String imageUrl) throws IOException {
+ byte[] data = null;
+ try {
+ InputStream in = this.getClass().getResourceAsStream(imageUrl);
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ int b = 0;
+ while ((b = in.read()) != -1) {
+ stream.write(b);
+ }
+
+ data = stream.toByteArray();
+ } catch (IOException e) {
+ throw new IOException(e);
+ }
+ return data;
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-fit/src/test/resources/Employee_1.png
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/resources/Employee_1.png b/odata2-lib/odata-fit/src/test/resources/Employee_1.png
new file mode 100644
index 0000000..f817682
Binary files /dev/null and b/odata2-lib/odata-fit/src/test/resources/Employee_1.png differ
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-fit/src/test/resources/simpleGet.batch
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/resources/simpleGet.batch b/odata2-lib/odata-fit/src/test/resources/simpleGet.batch
new file mode 100644
index 0000000..4ae2fce
--- /dev/null
+++ b/odata2-lib/odata-fit/src/test/resources/simpleGet.batch
@@ -0,0 +1,8 @@
+--batch_123
+Content-Type: application/http
+Content-Transfer-Encoding:binary
+
+GET Employees('2')/$value HTTP/1.1
+
+
+--batch_123--
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-fit/src/test/resources/simpleGet1.batch
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-fit/src/test/resources/simpleGet1.batch b/odata2-lib/odata-fit/src/test/resources/simpleGet1.batch
new file mode 100644
index 0000000..21febba
--- /dev/null
+++ b/odata2-lib/odata-fit/src/test/resources/simpleGet1.batch
@@ -0,0 +1,8 @@
+--batch_123
+Content-Type: application/http
+Content-Transfer-Encoding:binary
+
+GET Employees('7')/$value HTTP/1.1
+
+
+--batch_123--
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
index d2f55aa..ff8813a 100644
--- a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
+++ b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ScenarioDataSource.java
@@ -366,6 +366,8 @@ public class ScenarioDataSource {
final Employee employee = (Employee) mediaLinkEntryData;
employee.setImage(binaryData.getData());
employee.setImageType(binaryData.getMimeType());
+ //Storing the binary data to be used for comparison in the tests
+ Util.getInstance().setBinaryContent(employee.getImage());
} else if (ENTITYSET_2_1.equals(entitySet.getName())) {
final Photo photo = (Photo) mediaLinkEntryData;
photo.setImage(binaryData.getData());
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/0bce4ab7/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/Util.java
----------------------------------------------------------------------
diff --git a/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/Util.java b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/Util.java
new file mode 100644
index 0000000..9bbdb2e
--- /dev/null
+++ b/odata2-lib/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/Util.java
@@ -0,0 +1,26 @@
+package org.apache.olingo.odata2.ref.processor;
+
+
+public class Util {
+
+private static final Util instance = new Util();
+
+ private byte[] binaryContent = null;
+
+ public static Util getInstance() {
+ return instance;
+ }
+ /**
+ * @return the binaryContent
+ */
+ public byte[] getBinaryContent() {
+ return binaryContent;
+ }
+
+ /**
+ * @param binaryContent the binaryContent to set
+ */
+ public void setBinaryContent(byte[] binaryContent) {
+ this.binaryContent = binaryContent;
+ }
+}
\ No newline at end of file