From 925a86d963332a98b0fd891acad5933ea9b26f09 Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Tue, 7 Jul 2015 22:43:18 +0200 Subject: [PATCH 1/7] [OLINGO-729] Better support of RFC1341 Multipart for --- .../core/deserializer/batch/BatchParser.java | 3 +- .../BufferedReaderIncludingLineEndings.java | 102 +++++---- .../serializer/BatchResponseSerializer.java | 153 ++++++++++---- .../batchhandler/MockedBatchHandlerTest.java | 9 +- ...ufferedReaderIncludingLineEndingsTest.java | 194 ++++-------------- .../BatchResponseSerializerTest.java | 123 ++++++++++- 6 files changed, 339 insertions(+), 245 deletions(-) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java index 5d251eca3..731437ab9 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java @@ -20,7 +20,6 @@ package org.apache.olingo.server.core.deserializer.batch; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.util.LinkedList; import java.util.List; @@ -74,7 +73,7 @@ public class BatchParser { private List> splitBodyParts(final InputStream in, final String boundary) throws IOException, BatchDeserializerException { - final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(new InputStreamReader(in)); + final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(in); final List message = reader.toLineList(); reader.close(); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java index 2268a1d9a..a36b86bdf 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java @@ -18,37 +18,41 @@ */ package org.apache.olingo.server.core.deserializer.batch; +import org.apache.olingo.commons.api.format.ContentType; + import java.io.IOException; -import java.io.Reader; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -public class BufferedReaderIncludingLineEndings extends Reader { - private static final char CR = '\r'; - private static final char LF = '\n'; +public class BufferedReaderIncludingLineEndings { + private static final byte CR = '\r'; + private static final byte LF = '\n'; private static final int EOF = -1; private static final int BUFFER_SIZE = 8192; - private Reader reader; - private char[] buffer; + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + private InputStream reader; + private byte[] buffer; private int offset = 0; private int limit = 0; - public BufferedReaderIncludingLineEndings(final Reader reader) { + public BufferedReaderIncludingLineEndings(final InputStream reader) { this(reader, BUFFER_SIZE); } - public BufferedReaderIncludingLineEndings(final Reader reader, final int bufferSize) { + public BufferedReaderIncludingLineEndings(final InputStream reader, final int bufferSize) { if (bufferSize <= 0) { throw new IllegalArgumentException("Buffer size must be greater than zero."); } this.reader = reader; - buffer = new char[bufferSize]; + buffer = new byte[bufferSize]; } - @Override - public int read(final char[] charBuffer, final int bufferOffset, final int length) throws IOException { - if ((bufferOffset + length) > charBuffer.length) { + public int read(final byte[] byteBuffer, final int bufferOffset, final int length) throws IOException { + if ((bufferOffset + length) > byteBuffer.length) { throw new IndexOutOfBoundsException("Buffer is too small"); } @@ -86,7 +90,7 @@ public class BufferedReaderIncludingLineEndings extends Reader { bytesToRead -= readByte; for (int i = 0; i < readByte; i++) { - charBuffer[currentOutputOffset++] = buffer[offset++]; + byteBuffer[currentOutputOffset++] = buffer[offset++]; } } } @@ -105,6 +109,27 @@ public class BufferedReaderIncludingLineEndings extends Reader { return result; } + private Charset currentCharset = DEFAULT_CHARSET; + + private void updateCurrentCharset(String currentLine) { + if(currentLine != null) { + if(currentLine.startsWith("Content-Type:") && currentLine.contains(ContentType.PARAMETER_CHARSET)) { + currentLine = currentLine.substring(13, currentLine.length()-2).trim(); + ContentType t = ContentType.parse(currentLine); + if(t != null) { + String charsetString = t.getParameter(ContentType.PARAMETER_CHARSET); + currentCharset = Charset.forName(charsetString); + } + } else if(isEndBoundary(currentLine)) { + currentCharset = Charset.forName("us-ascii"); + } + } + } + + private boolean isEndBoundary(String currentLine) { + return false; + } + public List toLineList() throws IOException { final List result = new ArrayList(); String currentLine; @@ -122,7 +147,7 @@ public class BufferedReaderIncludingLineEndings extends Reader { return null; } - final StringBuilder stringBuffer = new StringBuilder(); + ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); boolean foundLineEnd = false; // EOF will be considered as line ending while (!foundLineEnd) { @@ -134,8 +159,14 @@ public class BufferedReaderIncludingLineEndings extends Reader { } if (!foundLineEnd) { - char currentChar = buffer[offset++]; - stringBuffer.append(currentChar); + byte currentChar = this.buffer[offset++]; + if(!buffer.hasRemaining()) { + buffer.flip(); + ByteBuffer tmp = ByteBuffer.allocate(buffer.limit() *2); + tmp.put(buffer); + buffer = tmp; + } + buffer.put(currentChar); if (currentChar == LF) { foundLineEnd = true; @@ -149,44 +180,27 @@ public class BufferedReaderIncludingLineEndings extends Reader { } // Check if there is at least one character - if (limit != EOF && buffer[offset] == LF) { - stringBuffer.append(LF); + if (limit != EOF && this.buffer[offset] == LF) { + buffer.put(LF); offset++; } } } } - return (stringBuffer.length() == 0) ? null : stringBuffer.toString(); + if(buffer.position() == 0) { + return null; + } else { + String currentLine = new String(buffer.array(), 0, buffer.position(), getCurrentCharset()); + updateCurrentCharset(currentLine); + return currentLine; + } } - @Override public void close() throws IOException { reader.close(); } - @Override - public boolean ready() throws IOException { - // Not EOF and buffer refill is not required - return !isEOF() && !(limit == offset); - } - - @Override - public void reset() throws IOException { - throw new IOException("Reset is not supported"); - } - - @Override - public void mark(final int readAheadLimit) throws IOException { - throw new IOException("Mark is not supported"); - } - - @Override - public boolean markSupported() { - return false; - } - - @Override public long skip(final long n) throws IOException { if (n == 0) { return 0; @@ -230,4 +244,8 @@ public class BufferedReaderIncludingLineEndings extends Reader { return limit; } + + private Charset getCurrentCharset() { + return currentCharset; + } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java index 577f08385..e277b595b 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java @@ -22,11 +22,14 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.olingo.commons.api.ODataRuntimeException; +import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpContentType; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; @@ -45,14 +48,14 @@ public class BatchResponseSerializer { public InputStream serialize(final List responses, final String boundary) throws BatchSerializerException { - StringBuilder builder = createBody(responses, boundary); + BodyBuilder builder = createBody(responses, boundary); - return new ByteArrayInputStream(builder.toString().getBytes()); + return new ByteArrayInputStream(builder.getContent()); } - private StringBuilder createBody(final List batchResponses, final String boundary) + private BodyBuilder createBody(final List batchResponses, final String boundary) throws BatchSerializerException { - final StringBuilder builder = new StringBuilder(); + final BodyBuilder builder = new BodyBuilder(); for (final ODataResponsePart part : batchResponses) { builder.append(getDashBoundary(boundary)); @@ -68,7 +71,7 @@ public class BatchResponseSerializer { return builder; } - private void appendChangeSet(final ODataResponsePart part, final StringBuilder builder) + private void appendChangeSet(final ODataResponsePart part, final BodyBuilder builder) throws BatchSerializerException { final String changeSetBoundary = generateBoundary("changeset"); @@ -83,50 +86,27 @@ public class BatchResponseSerializer { builder.append(getCloseDelimiter(changeSetBoundary)); } - private void appendBodyPart(final ODataResponse response, final StringBuilder builder, final boolean isChangeSet) + private void appendBodyPart(final ODataResponse response, final BodyBuilder builder, final boolean isChangeSet) throws BatchSerializerException { - byte[] body = getBody(response); appendBodyPartHeader(response, builder, isChangeSet); builder.append(CRLF); appendStatusLine(response, builder); - appendResponseHeader(response, body.length, builder); + Body body = new Body(response); + appendResponseHeader(response, body.getLength(), builder); builder.append(CRLF); - builder.append(new String(body)); + builder.append(body); builder.append(CRLF); } - private byte[] getBody(final ODataResponse response) { - final InputStream content = response.getContent(); - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - - if (content != null) { - byte[] buffer = new byte[BUFFER_SIZE]; - int n; - - try { - while ((n = content.read(buffer, 0, buffer.length)) != -1) { - out.write(buffer, 0, n); - } - out.flush(); - } catch (IOException e) { - throw new ODataRuntimeException(e); - } - - return out.toByteArray(); - } else { - return new byte[0]; - } - } - - private void appendChangeSetHeader(final StringBuilder builder, final String changeSetBoundary) { + private void appendChangeSetHeader(final BodyBuilder builder, final String changeSetBoundary) { appendHeader(HttpHeader.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + "; boundary=" + changeSetBoundary, builder); } - private void appendHeader(final String name, final String value, final StringBuilder builder) { + private void appendHeader(final String name, final String value, final BodyBuilder builder) { builder.append(name) .append(COLON) .append(SP) @@ -134,7 +114,7 @@ public class BatchResponseSerializer { .append(CRLF); } - private void appendStatusLine(final ODataResponse response, final StringBuilder builder) { + private void appendStatusLine(final ODataResponse response, final BodyBuilder builder) { builder.append("HTTP/1.1") .append(SP) .append(response.getStatusCode()) @@ -144,7 +124,7 @@ public class BatchResponseSerializer { } private void appendResponseHeader(final ODataResponse response, final int contentLength, - final StringBuilder builder) { + final BodyBuilder builder) { final Map header = response.getHeaders(); for (final String key : header.keySet()) { @@ -157,7 +137,7 @@ public class BatchResponseSerializer { appendHeader(HttpHeader.CONTENT_LENGTH, "" + contentLength, builder); } - private void appendBodyPartHeader(final ODataResponse response, final StringBuilder builder, + private void appendBodyPartHeader(final ODataResponse response, final BodyBuilder builder, final boolean isChangeSet) throws BatchSerializerException { appendHeader(HttpHeader.CONTENT_TYPE, HttpContentType.APPLICATION_HTTP, builder); appendHeader(BatchParserCommon.CONTENT_TRANSFER_ENCODING, BatchParserCommon.BINARY_ENCODING, builder); @@ -182,4 +162,103 @@ public class BatchResponseSerializer { private String generateBoundary(final String value) { return value + "_" + UUID.randomUUID().toString(); } + + private class BodyBuilder { + private final Charset CHARSET_UTF_8 = Charset.forName("utf-8"); + private ByteBuffer buffer = ByteBuffer.allocate(8192); + private boolean isClosed = false; + + public byte[] getContent() { + isClosed = true; + byte[] tmp = new byte[buffer.position()]; + buffer.flip(); + buffer.get(tmp, 0, buffer.limit()); + return tmp; + } + + public BodyBuilder append(String string) { + byte [] b = string.getBytes(CHARSET_UTF_8); + put(b); + return this; + } + + private void put(byte[] b) { + if(isClosed) { + throw new RuntimeException("BodyBuilder is closed."); + } + if(buffer.remaining() < b.length) { + buffer.flip(); + ByteBuffer tmp = ByteBuffer.allocate(buffer.limit() *2); + tmp.put(buffer); + buffer = tmp; + } + buffer.put(b); + } + + public BodyBuilder append(int statusCode) { + return append(String.valueOf(statusCode)); + } + + public BodyBuilder append(Body body) { + put(body.getContent()); + return this; + } + + public String toString() { +// byte[] tmp = new byte[buffer.position()]; +// buffer.get(tmp, 0, buffer.position()); + return new String(buffer.array(), 0, buffer.position()); + } + } + + private class Body { + private final Charset CHARSET_DEFAULT = Charset.forName("utf-8"); + private final byte[] content; + private Charset charset = CHARSET_DEFAULT; + + public Body(ODataResponse response) { + this.content = getBody(response); + String contentType = response.getHeaders().get(HttpHeader.CONTENT_TYPE); + if(contentType != null) { + ContentType ct = ContentType.create(contentType); + if(ct != null) { + String usedCharset = ct.getParameter(ContentType.PARAMETER_CHARSET); + if(usedCharset != null) { + this.charset = Charset.forName(usedCharset); + } + } + } + } + + public int getLength() { + return content.length; + } + + private byte[] getBody(final ODataResponse response) { + final InputStream content = response.getContent(); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + + if (content != null) { + byte[] buffer = new byte[BUFFER_SIZE]; + int n; + + try { + while ((n = content.read(buffer, 0, buffer.length)) != -1) { + out.write(buffer, 0, n); + } + out.flush(); + } catch (IOException e) { + throw new ODataRuntimeException(e); + } + + return out.toByteArray(); + } else { + return new byte[0]; + } + } + + public byte[] getContent() { + return content; + } + } } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java index 47f7b866f..3e4e610d2 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java @@ -26,7 +26,6 @@ import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -150,7 +149,7 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent())); + new BufferedReaderIncludingLineEndings(response.getContent()); final List responseContent = reader.toList(); reader.close(); @@ -221,7 +220,7 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent())); + new BufferedReaderIncludingLineEndings(response.getContent()); final List responseContent = reader.toList(); int line = 0; @@ -300,7 +299,7 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent())); + new BufferedReaderIncludingLineEndings(response.getContent()); final List responseContent = reader.toList(); reader.close(); @@ -418,7 +417,7 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent())); + new BufferedReaderIncludingLineEndings(response.getContent()); final List responseContent = reader.toList(); reader.close(); diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java index 4a41dc6bd..d0d2fa88f 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; -import java.io.InputStreamReader; import java.util.List; import org.junit.Test; @@ -71,7 +70,7 @@ public class BufferedReaderIncludingLineEndingsTest { @Test public void testNoBytes() throws Exception { BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(new ByteArrayInputStream(new byte[0]))); + new BufferedReaderIncludingLineEndings(new ByteArrayInputStream(new byte[0])); assertNull(reader.readLine()); assertNull(reader.readLine()); @@ -246,7 +245,7 @@ public class BufferedReaderIncludingLineEndingsTest { @Test public void testReadMoreBufferCapacityThanCharacterAvailable() throws Exception { final String TEXT = "Foo"; - char[] buffer = new char[20]; + byte[] buffer = new byte[20]; BufferedReaderIncludingLineEndings reader = create(TEXT); assertEquals(3, reader.read(buffer, 0, 20)); @@ -274,109 +273,15 @@ public class BufferedReaderIncludingLineEndingsTest { reader.close(); } - @Test - public void testSkipToMuch() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL); - - assertEquals(8, reader.skip(10)); // Test\r - assertEquals(null, reader.readLine()); - reader.close(); - } - - @Test - public void testReadBufferOne() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL, 1); - - assertEquals('T', reader.read()); - assertEquals('e', reader.read()); - assertEquals('s', reader.read()); - assertEquals('t', reader.read()); - assertEquals('\r', reader.read()); - assertEquals('1', reader.read()); - assertEquals('2', reader.read()); - assertEquals('3', reader.read()); - assertEquals(-1, reader.read()); - assertEquals(-1, reader.read()); - } - - @Test - public void testReadZeroBytes() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL, 1); - - char[] buffer = new char[3]; - assertEquals(0, reader.read(buffer, 0, 0)); - assertEquals('T', reader.read()); - assertEquals(0, reader.read(buffer, 0, 0)); - assertEquals("est\r", reader.readLine()); - assertEquals("123", reader.readLine()); - - reader.close(); - } - - @Test - public void testRead() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL); - - assertEquals('T', reader.read()); - assertEquals('e', reader.read()); - assertEquals('s', reader.read()); - assertEquals('t', reader.read()); - assertEquals('\r', reader.read()); - assertEquals('1', reader.read()); - assertEquals('2', reader.read()); - assertEquals('3', reader.read()); - assertEquals(-1, reader.read()); - assertEquals(-1, reader.read()); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testFailReadBufferAndOffsetBiggerThanBuffer() throws Exception { - BufferedReaderIncludingLineEndings reader = create(""); - - final char[] buffer = new char[3]; - reader.read(buffer, 1, 3); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testFailLengthNegative() throws Exception { - final char[] buffer = new char[3]; - BufferedReaderIncludingLineEndings reader = create("123"); - - reader.read(buffer, 1, -2); - reader.close(); - } - - @Test(expected = IndexOutOfBoundsException.class) - public void testFailOffsetNegative() throws Exception { - final char[] buffer = new char[3]; - BufferedReaderIncludingLineEndings reader = create("123"); - - reader.read(buffer, -1, 2); - reader.close(); - } - - @Test - public void testReadAndReadLine() throws Exception { - final String TEXT = "Test\r" + - "bar\n" + - "123\r\n" + - "foo"; - - BufferedReaderIncludingLineEndings reader = create(TEXT); - - assertEquals('T', reader.read()); - assertEquals('e', reader.read()); - assertEquals('s', reader.read()); - assertEquals('t', reader.read()); - assertEquals("\r", reader.readLine()); - assertEquals("bar\n", reader.readLine()); - assertEquals('1', reader.read()); - assertEquals('2', reader.read()); - assertEquals("3\r\n", reader.readLine()); - assertEquals("foo", reader.readLine()); - assertEquals(null, reader.readLine()); - assertEquals(-1, reader.read()); - } +// @Test +// public void testSkipToMuch() throws Exception { +// BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL); +// +// assertEquals(8, reader.skip(10)); // Test\r +// assertEquals(null, reader.readLine()); +// reader.close(); +// } +// @Test public void testLineEqualsAndHashCode() { @@ -389,11 +294,11 @@ public class BufferedReaderIncludingLineEndingsTest { assertTrue(l1.hashCode() != l3.hashCode()); } - @Test(expected = IllegalArgumentException.class) - public void testSkipNegative() throws Exception { - BufferedReaderIncludingLineEndings reader = create("123"); - reader.skip(-1); - } +// @Test(expected = IllegalArgumentException.class) +// public void testSkipNegative() throws Exception { +// BufferedReaderIncludingLineEndings reader = create("123"); +// reader.skip(-1); +// } @Test(expected = IllegalArgumentException.class) public void testFailBufferSizeZero() throws Exception { @@ -401,52 +306,33 @@ public class BufferedReaderIncludingLineEndingsTest { reader.close(); } - @Test(expected = NullPointerException.class) - public void testInputStreamIsNull() throws Exception { - // Same behaviour like BufferedReader - BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(null); - reader.close(); - } - @Test(expected = IllegalArgumentException.class) public void testFailBufferSizeNegative() throws Exception { BufferedReaderIncludingLineEndings reader = create(TEXT_EMPTY, -1); reader.close(); } - @Test - public void testMarkSupoorted() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_EMPTY); +// @Test +// public void testMarkSupoorted() throws Exception { +// BufferedReaderIncludingLineEndings reader = create(TEXT_EMPTY); +// +// assertEquals(false, reader.markSupported()); +// reader.close(); +// } - assertEquals(false, reader.markSupported()); - reader.close(); - } - - @Test(expected = Exception.class) - public void testFailMark() throws Exception { - BufferedReaderIncludingLineEndings reader = create("123"); - - reader.mark(1); - } - - @Test(expected = Exception.class) - public void testFailReset() throws Exception { - BufferedReaderIncludingLineEndings reader = create("123"); - - reader.reset(); - } - - @Test - public void testReady() throws Exception { - BufferedReaderIncludingLineEndings reader = create("123\r123"); - assertEquals(false, reader.ready()); - assertEquals("123\r", reader.readLine()); - assertEquals(true, reader.ready()); - assertEquals("123", reader.readLine()); - assertEquals(false, reader.ready()); - - reader.close(); - } +// @Test(expected = Exception.class) +// public void testFailMark() throws Exception { +// BufferedReaderIncludingLineEndings reader = create("123"); +// +// reader.mark(1); +// } +// +// @Test(expected = Exception.class) +// public void testFailReset() throws Exception { +// BufferedReaderIncludingLineEndings reader = create("123"); +// +// reader.reset(); +// } @Test public void testToList() throws Exception { @@ -469,13 +355,13 @@ public class BufferedReaderIncludingLineEndingsTest { } private BufferedReaderIncludingLineEndings create(final String inputString) throws Exception { - return new BufferedReaderIncludingLineEndings(new InputStreamReader(new ByteArrayInputStream(inputString - .getBytes("UTF-8")))); + return new BufferedReaderIncludingLineEndings(new ByteArrayInputStream(inputString + .getBytes("UTF-8"))); } private BufferedReaderIncludingLineEndings create(final String inputString, final int bufferSize) throws Exception { - return new BufferedReaderIncludingLineEndings(new InputStreamReader(new ByteArrayInputStream(inputString - .getBytes("UTF-8"))), bufferSize); + return new BufferedReaderIncludingLineEndings(new ByteArrayInputStream(inputString + .getBytes("UTF-8")), bufferSize); } } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java index c5d06530d..29d0329aa 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -64,7 +64,7 @@ public class BatchResponseSerializerTest { final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(content)); + new BufferedReaderIncludingLineEndings(content); final List body = reader.toList(); reader.close(); @@ -96,6 +96,119 @@ public class BatchResponseSerializerTest { assertTrue(body.get(line++).contains("--batch_")); } + @Test + public void testBatchResponseUmlauteUtf8() throws Exception { + final List parts = new ArrayList(); + ODataResponse response = new ODataResponse(); + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + response.setHeader(HttpHeader.CONTENT_TYPE, + ContentType.APPLICATION_JSON.toContentTypeString() + "; charset=UTF-8"); + response.setContent(IOUtils.toInputStream("Wälter Winter" + CRLF)); + + List responses = new ArrayList(1); + responses.add(response); + parts.add(new ODataResponsePart(responses, false)); + + ODataResponse changeSetResponse = new ODataResponse(); + changeSetResponse.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); + changeSetResponse.setHeader(HttpHeader.CONTENT_ID, "1"); + responses = new ArrayList(1); + responses.add(changeSetResponse); + parts.add(new ODataResponsePart(responses, true)); + + BatchResponseSerializer serializer = new BatchResponseSerializer(); + final InputStream content = serializer.serialize(parts, BOUNDARY); + assertNotNull(content); + final BufferedReaderIncludingLineEndings reader = + new BufferedReaderIncludingLineEndings(content); + final List body = reader.toList(); + reader.close(); + + int line = 0; + assertEquals(24, body.size()); + assertTrue(body.get(line++).contains("--batch_")); + assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("HTTP/1.1 200 OK" + CRLF, body.get(line++)); + assertEquals("Content-Type: application/json; charset=UTF-8" + CRLF, body.get(line++)); + assertEquals("Content-Length: 16" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("Wälter Winter" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--batch_")); + assertTrue(body.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_")); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--changeset_")); + assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); + assertEquals("Content-ID: 1" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("HTTP/1.1 204 No Content" + CRLF, body.get(line++)); + assertEquals("Content-Length: 0" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--changeset_")); + assertTrue(body.get(line++).contains("--batch_")); + } + + @Test + public void testBatchResponseUmlauteIso() throws Exception { + final List parts = new ArrayList(); + ODataResponse response = new ODataResponse(); + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + response.setHeader(HttpHeader.CONTENT_TYPE, + ContentType.APPLICATION_JSON.toContentTypeString() + "; charset=iso-8859-1"); + byte[] payload = ("Wälter Winter" + CRLF).getBytes("iso-8859-1"); + response.setContent(new ByteArrayInputStream(payload)); + + List responses = new ArrayList(1); + responses.add(response); + parts.add(new ODataResponsePart(responses, false)); + + ODataResponse changeSetResponse = new ODataResponse(); + changeSetResponse.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); + changeSetResponse.setHeader(HttpHeader.CONTENT_ID, "1"); + responses = new ArrayList(1); + responses.add(changeSetResponse); + parts.add(new ODataResponsePart(responses, true)); + + BatchResponseSerializer serializer = new BatchResponseSerializer(); + final InputStream content = serializer.serialize(parts, BOUNDARY); + assertNotNull(content); + final BufferedReaderIncludingLineEndings reader = + new BufferedReaderIncludingLineEndings(content); + final List body = reader.toList(); + reader.close(); + + int line = 0; + assertEquals(24, body.size()); + assertTrue(body.get(line++).contains("--batch_")); + assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("HTTP/1.1 200 OK" + CRLF, body.get(line++)); + assertEquals("Content-Type: application/json; charset=iso-8859-1" + CRLF, body.get(line++)); + assertEquals("Content-Length: 15" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("Wälter Winter" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--batch_")); + assertTrue(body.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_")); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--changeset_")); + assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); + assertEquals("Content-ID: 1" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("HTTP/1.1 204 No Content" + CRLF, body.get(line++)); + assertEquals("Content-Length: 0" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--changeset_")); + assertTrue(body.get(line++).contains("--batch_")); + } + @Test public void testBatchResponseWithEndingCRLF() throws Exception { final List parts = new ArrayList(); @@ -119,7 +232,7 @@ public class BatchResponseSerializerTest { final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(content)); + new BufferedReaderIncludingLineEndings(content); final List body = reader.toList(); reader.close(); @@ -167,7 +280,7 @@ public class BatchResponseSerializerTest { assertNotNull(content); final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(content)); + new BufferedReaderIncludingLineEndings(content); final List body = reader.toList(); reader.close(); @@ -202,7 +315,7 @@ public class BatchResponseSerializerTest { assertNotNull(content); final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new InputStreamReader(content)); + new BufferedReaderIncludingLineEndings(content); final List body = reader.toList(); reader.close(); From 575f369ac7def6f771c7ec67b290b149dff6cfd2 Mon Sep 17 00:00:00 2001 From: mibo Date: Wed, 8 Jul 2015 15:47:40 +0200 Subject: [PATCH 2/7] [OLINGO-729] Added separate encoding for header and body --- ...gLineEndings.java => BatchLineReader.java} | 177 ++++++++++-------- .../core/deserializer/batch/BatchParser.java | 2 +- .../serializer/BatchResponseSerializer.java | 18 +- .../batchhandler/MockedBatchHandlerTest.java | 18 +- ...ingsTest.java => BatchLineReaderTest.java} | 129 +++---------- .../BatchResponseSerializerTest.java | 131 +++++++++++-- 6 files changed, 253 insertions(+), 222 deletions(-) rename lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/{BufferedReaderIncludingLineEndings.java => BatchLineReader.java} (65%) rename lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/{BufferedReaderIncludingLineEndingsTest.java => BatchLineReaderTest.java} (65%) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java similarity index 65% rename from lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java rename to lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java index a36b86bdf..c4cee5afe 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndings.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java @@ -27,22 +27,27 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -public class BufferedReaderIncludingLineEndings { +public class BatchLineReader { private static final byte CR = '\r'; private static final byte LF = '\n'; private static final int EOF = -1; private static final int BUFFER_SIZE = 8192; - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + private static final Charset CS_ISO_8859_1 = Charset.forName("iso-8859-1"); + private Charset currentCharset = DEFAULT_CHARSET; + private String currentBoundary = null; +// private boolean readBody = false; + private ReadState readState = new ReadState(); private InputStream reader; private byte[] buffer; private int offset = 0; private int limit = 0; - public BufferedReaderIncludingLineEndings(final InputStream reader) { + public BatchLineReader(final InputStream reader) { this(reader, BUFFER_SIZE); } - public BufferedReaderIncludingLineEndings(final InputStream reader, final int bufferSize) { + public BatchLineReader(final InputStream reader, final int bufferSize) { if (bufferSize <= 0) { throw new IllegalArgumentException("Buffer size must be greater than zero."); } @@ -51,7 +56,41 @@ public class BufferedReaderIncludingLineEndings { buffer = new byte[bufferSize]; } - public int read(final byte[] byteBuffer, final int bufferOffset, final int length) throws IOException { + public void close() throws IOException { + reader.close(); + } + + public List toList() throws IOException { + final List result = new ArrayList(); + String currentLine = readLine(); + if(currentLine != null) { + currentBoundary = currentLine.trim(); + result.add(currentLine); + + while ((currentLine = readLine()) != null) { + result.add(currentLine); + } + } + return result; + } + + public List toLineList() throws IOException { + final List result = new ArrayList(); + String currentLine = readLine(); + if(currentLine != null) { + currentBoundary = currentLine.trim(); + int counter = 1; + result.add(new Line(currentLine, counter++)); + + while ((currentLine = readLine()) != null) { + result.add(new Line(currentLine, counter++)); + } + } + + return result; + } + + int read(final byte[] byteBuffer, final int bufferOffset, final int length) throws IOException { if ((bufferOffset + length) > byteBuffer.length) { throw new IndexOutOfBoundsException("Buffer is too small"); } @@ -98,51 +137,69 @@ public class BufferedReaderIncludingLineEndings { return bytesRead; } - public List toList() throws IOException { - final List result = new ArrayList(); - String currentLine; - - while ((currentLine = readLine()) != null) { - result.add(currentLine); - } - - return result; - } - - private Charset currentCharset = DEFAULT_CHARSET; - private void updateCurrentCharset(String currentLine) { + // TODO: mibo: Improve this method if(currentLine != null) { - if(currentLine.startsWith("Content-Type:") && currentLine.contains(ContentType.PARAMETER_CHARSET)) { - currentLine = currentLine.substring(13, currentLine.length()-2).trim(); + if(currentLine.startsWith("Content-Type:")) { +// if(currentLine.contains(ContentType.PARAMETER_CHARSET)) { + currentLine = currentLine.substring(13, currentLine.length() - 2).trim(); ContentType t = ContentType.parse(currentLine); - if(t != null) { + if (t != null) { String charsetString = t.getParameter(ContentType.PARAMETER_CHARSET); - currentCharset = Charset.forName(charsetString); + if (charsetString != null) { + currentCharset = Charset.forName(charsetString); + } else { + currentCharset = DEFAULT_CHARSET; + } + // boundary + String boundary = t.getParameter("boundary"); + if (boundary != null) { + currentBoundary = "--" + boundary; + } } - } else if(isEndBoundary(currentLine)) { - currentCharset = Charset.forName("us-ascii"); + } else if("\r\n".equals(currentLine)) { + readState.foundLinebreak(); + } else if(isBoundary(currentLine)) { + readState.foundBoundary(); +// if(readState.isReadBody()) { +// currentCharset = CS_ISO_8859_1; +// } } } } - private boolean isEndBoundary(String currentLine) { + private class ReadState { + private int state = 0; + + public void foundLinebreak() { + state++; + } + public void foundBoundary() { + state = 0; + } + public boolean isReadBody() { + return state >= 2; + } + public boolean isReadHeader() { + return state < 2; + } + + @Override + public String toString() { + return String.valueOf(state); + } + } + + private boolean isBoundary(String currentLine) { + if((currentBoundary + "\r\n").equals(currentLine)) { + return true; + } else if((currentBoundary + "--\r\n").equals(currentLine)) { + return true; + } return false; } - public List toLineList() throws IOException { - final List result = new ArrayList(); - String currentLine; - int counter = 1; - - while ((currentLine = readLine()) != null) { - result.add(new Line(currentLine, counter++)); - } - - return result; - } - - public String readLine() throws IOException { + String readLine() throws IOException { if (limit == EOF) { return null; } @@ -191,49 +248,17 @@ public class BufferedReaderIncludingLineEndings { if(buffer.position() == 0) { return null; } else { - String currentLine = new String(buffer.array(), 0, buffer.position(), getCurrentCharset()); + String currentLine; + 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); + } updateCurrentCharset(currentLine); return currentLine; } } - public void close() throws IOException { - reader.close(); - } - - public long skip(final long n) throws IOException { - if (n == 0) { - return 0; - } else if (n < 0) { - throw new IllegalArgumentException("skip value is negative"); - } else { - long charactersToSkip = n; - long charactersSkiped = 0; - - while (charactersToSkip != 0) { - // Is buffer refill required? - if (limit == offset) { - fillBuffer(); - - if (isEOF()) { - charactersToSkip = 0; - } - } - - // Check if more characters are available - if (!isEOF()) { - int skipChars = (int) Math.min(limit - offset, charactersToSkip); - - charactersSkiped += skipChars; - charactersToSkip -= skipChars; - offset += skipChars; - } - } - - return charactersSkiped; - } - } - private boolean isEOF() { return limit == EOF; } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java index 731437ab9..3aeb1b564 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchParser.java @@ -73,7 +73,7 @@ public class BatchParser { private List> splitBodyParts(final InputStream in, final String boundary) throws IOException, BatchDeserializerException { - final BufferedReaderIncludingLineEndings reader = new BufferedReaderIncludingLineEndings(in); + final BatchLineReader reader = new BatchLineReader(in); final List message = reader.toLineList(); reader.close(); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java index e277b595b..28d7c73f3 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java @@ -29,7 +29,6 @@ import java.util.Map; import java.util.UUID; import org.apache.olingo.commons.api.ODataRuntimeException; -import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpContentType; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; @@ -165,6 +164,7 @@ public class BatchResponseSerializer { private class BodyBuilder { private final Charset CHARSET_UTF_8 = Charset.forName("utf-8"); + private final Charset CHARSET_ISO_8859_1 = Charset.forName("iso-8859-1"); private ByteBuffer buffer = ByteBuffer.allocate(8192); private boolean isClosed = false; @@ -177,7 +177,9 @@ public class BatchResponseSerializer { } public BodyBuilder append(String string) { - byte [] b = string.getBytes(CHARSET_UTF_8); + // TODO: mibo: check used charset +// byte [] b = string.getBytes(CHARSET_UTF_8); + byte [] b = string.getBytes(CHARSET_ISO_8859_1); put(b); return this; } @@ -212,22 +214,10 @@ public class BatchResponseSerializer { } private class Body { - private final Charset CHARSET_DEFAULT = Charset.forName("utf-8"); private final byte[] content; - private Charset charset = CHARSET_DEFAULT; public Body(ODataResponse response) { this.content = getBody(response); - String contentType = response.getHeaders().get(HttpHeader.CONTENT_TYPE); - if(contentType != null) { - ContentType ct = ContentType.create(contentType); - if(ct != null) { - String usedCharset = ct.getParameter(ContentType.PARAMETER_CHARSET); - if(usedCharset != null) { - this.charset = Charset.forName(usedCharset); - } - } - } } public int getLength() { diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java index 3e4e610d2..7d13d8a1f 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/batchhandler/MockedBatchHandlerTest.java @@ -53,7 +53,7 @@ import org.apache.olingo.server.api.processor.BatchProcessor; import org.apache.olingo.server.api.serializer.BatchSerializerException; import org.apache.olingo.server.core.ODataHandler; import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon; -import org.apache.olingo.server.core.deserializer.batch.BufferedReaderIncludingLineEndings; +import org.apache.olingo.server.core.deserializer.batch.BatchLineReader; import org.junit.Before; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; @@ -148,8 +148,8 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); - BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(response.getContent()); + BatchLineReader reader = + new BatchLineReader(response.getContent()); final List responseContent = reader.toList(); reader.close(); @@ -219,8 +219,8 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); - BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(response.getContent()); + BatchLineReader reader = + new BatchLineReader(response.getContent()); final List responseContent = reader.toList(); int line = 0; @@ -298,8 +298,8 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); - BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(response.getContent()); + BatchLineReader reader = + new BatchLineReader(response.getContent()); final List responseContent = reader.toList(); reader.close(); @@ -416,8 +416,8 @@ public class MockedBatchHandlerTest { batchHandler.process(request, response, true); - BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(response.getContent()); + BatchLineReader reader = + new BatchLineReader(response.getContent()); final List responseContent = reader.toList(); reader.close(); diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java similarity index 65% rename from lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java rename to lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java index d0d2fa88f..3d2507ca5 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BufferedReaderIncludingLineEndingsTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java @@ -28,7 +28,7 @@ import java.util.List; import org.junit.Test; -public class BufferedReaderIncludingLineEndingsTest { +public class BatchLineReaderTest { private static final String TEXT_COMBINED = "Test\r" + "Test2\r\n" + @@ -42,14 +42,12 @@ public class BufferedReaderIncludingLineEndingsTest { "Test7\n" + "\n"; - private static final String TEXT_SMALL = "Test\r" + - "123"; private static final String TEXT_EMPTY = ""; @Test public void testSimpleText() throws Exception { final String TEXT = "Test"; - BufferedReaderIncludingLineEndings reader = create(TEXT); + BatchLineReader reader = create(TEXT); assertEquals(TEXT, reader.readLine()); assertNull(reader.readLine()); @@ -60,7 +58,7 @@ public class BufferedReaderIncludingLineEndingsTest { @Test public void testNoText() throws Exception { final String TEXT = ""; - BufferedReaderIncludingLineEndings reader = create(TEXT); + BatchLineReader reader = create(TEXT); assertNull(reader.readLine()); assertNull(reader.readLine()); @@ -69,8 +67,8 @@ public class BufferedReaderIncludingLineEndingsTest { @Test public void testNoBytes() throws Exception { - BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(new ByteArrayInputStream(new byte[0])); + BatchLineReader reader = + new BatchLineReader(new ByteArrayInputStream(new byte[0])); assertNull(reader.readLine()); assertNull(reader.readLine()); @@ -82,7 +80,7 @@ public class BufferedReaderIncludingLineEndingsTest { final String TEXT = "Test\r\n" + "Test2"; - BufferedReaderIncludingLineEndings reader = create(TEXT); + BatchLineReader reader = create(TEXT); assertEquals("Test\r\n", reader.readLine()); assertEquals("Test2", reader.readLine()); @@ -96,7 +94,7 @@ public class BufferedReaderIncludingLineEndingsTest { final String TEXT = "Test\n" + "Test2"; - BufferedReaderIncludingLineEndings reader = create(TEXT); + BatchLineReader reader = create(TEXT); assertEquals("Test\n", reader.readLine()); assertEquals("Test2", reader.readLine()); @@ -110,7 +108,7 @@ public class BufferedReaderIncludingLineEndingsTest { final String TEXT = "Test\r" + "Test2"; - BufferedReaderIncludingLineEndings reader = create(TEXT); + BatchLineReader reader = create(TEXT); assertEquals("Test\r", reader.readLine()); assertEquals("Test2", reader.readLine()); @@ -121,7 +119,7 @@ public class BufferedReaderIncludingLineEndingsTest { @Test public void testCombined() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_COMBINED); + BatchLineReader reader = create(TEXT_COMBINED); assertEquals("Test\r", reader.readLine()); assertEquals("Test2\r\n", reader.readLine()); @@ -141,7 +139,7 @@ public class BufferedReaderIncludingLineEndingsTest { @Test public void testCombinedBufferSizeTwo() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_COMBINED, 2); + BatchLineReader reader = create(TEXT_COMBINED, 2); assertEquals("Test\r", reader.readLine()); assertEquals("Test2\r\n", reader.readLine()); @@ -173,7 +171,7 @@ public class BufferedReaderIncludingLineEndingsTest { "Test7\n" + "\r\n"; - BufferedReaderIncludingLineEndings reader = create(TEXT, 1); + BatchLineReader reader = create(TEXT, 1); assertEquals("Test\r", reader.readLine()); assertEquals("Test2\r\n", reader.readLine()); @@ -197,92 +195,29 @@ public class BufferedReaderIncludingLineEndingsTest { final String TEXT = "Test\r" + "\r"; - BufferedReaderIncludingLineEndings reader = create(TEXT, 1); + BatchLineReader reader = create(TEXT, 1); assertEquals("Test\r", reader.readLine()); assertEquals("\r", reader.readLine()); reader.close(); } - @Test - public void testSkipSimple() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL); - - assertEquals(5, reader.skip(5)); // Test\r - assertEquals("123", reader.readLine()); - assertNull(reader.readLine()); - assertNull(reader.readLine()); - reader.close(); - } - - @Test - public void testSkipBufferOne() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL, 1); - - assertEquals(5, reader.skip(5)); // Test\r - assertEquals("123", reader.readLine()); - assertNull(reader.readLine()); - assertNull(reader.readLine()); - reader.close(); - } - - @Test - public void testReadThanSkip() throws Exception { - final String TEXT = "Test\r" + - "\r" + - "123"; - - BufferedReaderIncludingLineEndings reader = create(TEXT); - - assertEquals("Test\r", reader.readLine()); - assertEquals(1, reader.skip(1)); // Test\r - assertEquals("123", reader.readLine()); - assertNull(reader.readLine()); - assertNull(reader.readLine()); - reader.close(); - } - @Test public void testReadMoreBufferCapacityThanCharacterAvailable() throws Exception { final String TEXT = "Foo"; byte[] buffer = new byte[20]; - BufferedReaderIncludingLineEndings reader = create(TEXT); + BatchLineReader reader = create(TEXT); assertEquals(3, reader.read(buffer, 0, 20)); assertEquals(-1, reader.read(buffer, 0, 20)); reader.close(); - BufferedReaderIncludingLineEndings readerBufferOne = create(TEXT, 1); + BatchLineReader readerBufferOne = create(TEXT, 1); assertEquals(3, readerBufferOne.read(buffer, 0, 20)); assertEquals(-1, readerBufferOne.read(buffer, 0, 20)); readerBufferOne.close(); } - @Test - public void testSkipZero() throws Exception { - final String TEXT = "Test\r" + - "123\r\n"; - - BufferedReaderIncludingLineEndings reader = create(TEXT); - - assertEquals(0, reader.skip(0)); // Test\r - assertEquals("Test\r", reader.readLine()); - assertEquals("123\r\n", reader.readLine()); - assertNull(reader.readLine()); - assertNull(reader.readLine()); - reader.close(); - } - -// @Test -// public void testSkipToMuch() throws Exception { -// BufferedReaderIncludingLineEndings reader = create(TEXT_SMALL); -// -// assertEquals(8, reader.skip(10)); // Test\r -// assertEquals(null, reader.readLine()); -// reader.close(); -// } -// - @Test public void testLineEqualsAndHashCode() { Line l1 = new Line("The first line", 1); @@ -302,41 +237,19 @@ public class BufferedReaderIncludingLineEndingsTest { @Test(expected = IllegalArgumentException.class) public void testFailBufferSizeZero() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_EMPTY, 0); + BatchLineReader reader = create(TEXT_EMPTY, 0); reader.close(); } @Test(expected = IllegalArgumentException.class) public void testFailBufferSizeNegative() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_EMPTY, -1); + BatchLineReader reader = create(TEXT_EMPTY, -1); reader.close(); } -// @Test -// public void testMarkSupoorted() throws Exception { -// BufferedReaderIncludingLineEndings reader = create(TEXT_EMPTY); -// -// assertEquals(false, reader.markSupported()); -// reader.close(); -// } - -// @Test(expected = Exception.class) -// public void testFailMark() throws Exception { -// BufferedReaderIncludingLineEndings reader = create("123"); -// -// reader.mark(1); -// } -// -// @Test(expected = Exception.class) -// public void testFailReset() throws Exception { -// BufferedReaderIncludingLineEndings reader = create("123"); -// -// reader.reset(); -// } - @Test public void testToList() throws Exception { - BufferedReaderIncludingLineEndings reader = create(TEXT_COMBINED); + BatchLineReader reader = create(TEXT_COMBINED); List stringList = reader.toLineList(); assertEquals(11, stringList.size()); @@ -354,13 +267,13 @@ public class BufferedReaderIncludingLineEndingsTest { reader.close(); } - private BufferedReaderIncludingLineEndings create(final String inputString) throws Exception { - return new BufferedReaderIncludingLineEndings(new ByteArrayInputStream(inputString + private BatchLineReader create(final String inputString) throws Exception { + return new BatchLineReader(new ByteArrayInputStream(inputString .getBytes("UTF-8"))); } - private BufferedReaderIncludingLineEndings create(final String inputString, final int bufferSize) throws Exception { - return new BufferedReaderIncludingLineEndings(new ByteArrayInputStream(inputString + private BatchLineReader create(final String inputString, final int bufferSize) throws Exception { + return new BatchLineReader(new ByteArrayInputStream(inputString .getBytes("UTF-8")), bufferSize); } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java index 29d0329aa..9d3ebeea6 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -34,13 +35,16 @@ import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart; -import org.apache.olingo.server.core.deserializer.batch.BufferedReaderIncludingLineEndings; +import org.apache.olingo.server.core.deserializer.batch.BatchLineReader; import org.junit.Test; public class BatchResponseSerializerTest { private static final String CRLF = "\r\n"; private static final String BOUNDARY = "batch_" + UUID.randomUUID().toString(); + private static final Charset CS_ISO_8859_1 = Charset.forName("iso-8859-1"); + private static final Charset CS_UTF_8 = Charset.forName("utf-8"); + @Test public void testBatchResponse() throws Exception { final List parts = new ArrayList(); @@ -63,8 +67,8 @@ public class BatchResponseSerializerTest { BatchResponseSerializer serializer = new BatchResponseSerializer(); final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); - final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(content); + final BatchLineReader reader = + new BatchLineReader(content); final List body = reader.toList(); reader.close(); @@ -97,7 +101,7 @@ public class BatchResponseSerializerTest { } @Test - public void testBatchResponseUmlauteUtf8() throws Exception { + public void testBatchResponseUmlautsUtf8() throws Exception { final List parts = new ArrayList(); ODataResponse response = new ODataResponse(); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); @@ -119,8 +123,8 @@ public class BatchResponseSerializerTest { BatchResponseSerializer serializer = new BatchResponseSerializer(); final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); - final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(content); + final BatchLineReader reader = + new BatchLineReader(content); final List body = reader.toList(); reader.close(); @@ -152,6 +156,105 @@ public class BatchResponseSerializerTest { assertTrue(body.get(line++).contains("--batch_")); } + @Test + public void testBatchResponseUmlautsUtf8BodyIsoHeader() throws Exception { + final List parts = new ArrayList(); + ODataResponse response = new ODataResponse(); + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + response.setHeader(HttpHeader.CONTENT_TYPE, + ContentType.APPLICATION_JSON.toContentTypeString() + "; charset=UTF-8"); + response.setContent(IOUtils.toInputStream("Wälter Winter" + CRLF)); + + List responses = new ArrayList(1); + responses.add(response); + parts.add(new ODataResponsePart(responses, false)); + + ODataResponse changeSetResponse = new ODataResponse(); + changeSetResponse.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); + changeSetResponse.setHeader(HttpHeader.CONTENT_ID, "1"); + + byte[] umlauts = "äüö".getBytes(CS_ISO_8859_1); + changeSetResponse.setHeader("Custom-Header", new String(umlauts, CS_ISO_8859_1)); + responses = new ArrayList(1); + responses.add(changeSetResponse); + parts.add(new ODataResponsePart(responses, true)); + + BatchResponseSerializer serializer = new BatchResponseSerializer(); + final InputStream content = serializer.serialize(parts, BOUNDARY); + assertNotNull(content); + final BatchLineReader reader = + new BatchLineReader(content); + final List body = reader.toList(); + reader.close(); + + int line = 0; + assertEquals(25, body.size()); + assertTrue(body.get(line++).contains("--batch_")); + assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("HTTP/1.1 200 OK" + CRLF, body.get(line++)); + assertEquals("Content-Type: application/json; charset=UTF-8" + CRLF, body.get(line++)); + assertEquals("Content-Length: 16" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("Wälter Winter" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--batch_")); + assertTrue(body.get(line++).contains("Content-Type: multipart/mixed; boundary=changeset_")); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--changeset_")); + assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); + assertEquals("Content-ID: 1" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals("HTTP/1.1 204 No Content" + CRLF, body.get(line++)); + assertEquals("Custom-Header: äüö" + CRLF, body.get(line++)); + assertEquals("Content-Length: 0" + CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertEquals(CRLF, body.get(line++)); + assertTrue(body.get(line++).contains("--changeset_")); + assertTrue(body.get(line++).contains("--batch_")); + } + + @Test + public void testBatchResponseUmlautsUtf8BodyAndHeader() throws Exception { + final List parts = new ArrayList(); + ODataResponse response = new ODataResponse(); + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + response.setHeader(HttpHeader.CONTENT_TYPE, + ContentType.APPLICATION_JSON.toContentTypeString() + "; charset=UTF-8"); + response.setContent(IOUtils.toInputStream("Wälter Winter" + CRLF)); + + List responses = new ArrayList(1); + responses.add(response); + parts.add(new ODataResponsePart(responses, false)); + + ODataResponse changeSetResponse = new ODataResponse(); + changeSetResponse.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); + changeSetResponse.setHeader(HttpHeader.CONTENT_ID, "1"); + +// byte[] umlauts = "äüö".getBytes(CS_UTF_8); +// changeSetResponse.setHeader("Custom-Header", new String(umlauts, CS_UTF_8)); + changeSetResponse.setHeader("Custom-Header", "äüö"); + responses = new ArrayList(1); + responses.add(changeSetResponse); + parts.add(new ODataResponsePart(responses, true)); + + BatchResponseSerializer serializer = new BatchResponseSerializer(); + final InputStream content = serializer.serialize(parts, BOUNDARY); + assertNotNull(content); + final BatchLineReader reader = + new BatchLineReader(content); + final List body = reader.toList(); + reader.close(); + + assertEquals(25, body.size()); + // TODO: check: with latest change in BatchResponseSerializer is not possible + // to set header values with UTF-8 (only iso-8859-1) +// assertEquals("Custom-Header: äüö" + CRLF, body.get(19)); + assertEquals("Custom-Header: äüö" + CRLF, body.get(19)); + } + @Test public void testBatchResponseUmlauteIso() throws Exception { final List parts = new ArrayList(); @@ -176,8 +279,8 @@ public class BatchResponseSerializerTest { BatchResponseSerializer serializer = new BatchResponseSerializer(); final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); - final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(content); + final BatchLineReader reader = + new BatchLineReader(content); final List body = reader.toList(); reader.close(); @@ -231,8 +334,8 @@ public class BatchResponseSerializerTest { BatchResponseSerializer serializer = new BatchResponseSerializer(); final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); - final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(content); + final BatchLineReader reader = + new BatchLineReader(content); final List body = reader.toList(); reader.close(); @@ -279,8 +382,8 @@ public class BatchResponseSerializerTest { final InputStream content = serializer.serialize(parts, BOUNDARY); assertNotNull(content); - final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(content); + final BatchLineReader reader = + new BatchLineReader(content); final List body = reader.toList(); reader.close(); @@ -314,8 +417,8 @@ public class BatchResponseSerializerTest { assertNotNull(content); - final BufferedReaderIncludingLineEndings reader = - new BufferedReaderIncludingLineEndings(content); + final BatchLineReader reader = + new BatchLineReader(content); final List body = reader.toList(); reader.close(); From 8960fdb5d16dd53b98a96ea58cd75211eda93441 Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Thu, 9 Jul 2015 08:33:58 +0200 Subject: [PATCH 3/7] [OLINGO-713] Code clean up and format --- .../myservice/mynamespace/data/Storage.java | 92 ++++++-------- .../mynamespace/service/DemoEdmProvider.java | 43 +++---- .../DemoEntityCollectionProcessor.java | 47 +++---- .../service/DemoEntityProcessor.java | 64 ++++------ .../service/DemoPrimitiveProcessor.java | 42 +++--- .../java/myservice/mynamespace/util/Util.java | 120 +++++++++--------- .../mynamespace/web/DemoServlet.java | 17 ++- 7 files changed, 199 insertions(+), 226 deletions(-) diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/data/Storage.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/data/Storage.java index 9db188c8f..2034fe6fd 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/data/Storage.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/data/Storage.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -39,7 +39,6 @@ public class Storage { private List productList; private List categoryList; - public Storage() { productList = new ArrayList(); @@ -55,142 +54,135 @@ public class Storage { public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet) { EntityCollection entitySet = null; - if(edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)){ + if (edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)) { entitySet = getProducts(); - }else if(edmEntitySet.getName().equals(DemoEdmProvider.ES_CATEGORIES_NAME)){ + } else if (edmEntitySet.getName().equals(DemoEdmProvider.ES_CATEGORIES_NAME)) { entitySet = getCategories(); } return entitySet; } - public Entity readEntityData(EdmEntitySet edmEntitySet, List keyParams) { Entity entity = null; EdmEntityType edmEntityType = edmEntitySet.getEntityType(); - if(edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)){ + if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) { entity = getProduct(edmEntityType, keyParams); - }else if(edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)){ + } else if (edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)) { entity = getCategory(edmEntityType, keyParams); } return entity; } - - // Navigation + // Navigation public Entity getRelatedEntity(Entity entity, EdmEntityType relatedEntityType) { EntityCollection collection = getRelatedEntityCollection(entity, relatedEntityType); - if(collection.getEntities().isEmpty()) { + if (collection.getEntities().isEmpty()) { return null; } return collection.getEntities().get(0); } - public Entity getRelatedEntity(Entity entity, EdmEntityType relatedEntityType, List keyPredicates) { EntityCollection relatedEntities = getRelatedEntityCollection(entity, relatedEntityType); return Util.findEntity(relatedEntityType, relatedEntities, keyPredicates); } - public EntityCollection getRelatedEntityCollection(Entity sourceEntity, EdmEntityType targetEntityType) { EntityCollection navigationTargetEntityCollection = new EntityCollection(); FullQualifiedName relatedEntityFqn = targetEntityType.getFullQualifiedName(); String sourceEntityFqn = sourceEntity.getType(); - if(sourceEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()) - && relatedEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN)){ + if (sourceEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()) + && relatedEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN)) { // relation Products->Category (result all categories) int productID = (Integer) sourceEntity.getProperty("ID").getValue(); - if(productID == 1 || productID == 2) { + if (productID == 1 || productID == 2) { navigationTargetEntityCollection.getEntities().add(categoryList.get(0)); - } else if(productID == 3 || productID == 4) { + } else if (productID == 3 || productID == 4) { navigationTargetEntityCollection.getEntities().add(categoryList.get(1)); - } else if(productID == 5 || productID == 6) { + } else if (productID == 5 || productID == 6) { navigationTargetEntityCollection.getEntities().add(categoryList.get(2)); } - }else if(sourceEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString()) - && relatedEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN)){ + } else if (sourceEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString()) + && relatedEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN)) { // relation Category->Products (result all products) int categoryID = (Integer) sourceEntity.getProperty("ID").getValue(); - if(categoryID == 1){ - navigationTargetEntityCollection.getEntities().addAll(productList.subList(0, 2));// the first 2 products are notebooks - }else if(categoryID == 2){ - navigationTargetEntityCollection.getEntities().addAll(productList.subList(2, 4));// the next 2 products are organizers - }else if(categoryID == 3){ - navigationTargetEntityCollection.getEntities().addAll(productList.subList(4, 6));// the first 2 products are monitors + if (categoryID == 1) { + // the first 2 products are notebooks + navigationTargetEntityCollection.getEntities().addAll(productList.subList(0, 2)); + } else if (categoryID == 2) { + // the next 2 products are organizers + navigationTargetEntityCollection.getEntities().addAll(productList.subList(2, 4)); + } else if (categoryID == 3) { + // the first 2 products are monitors + navigationTargetEntityCollection.getEntities().addAll(productList.subList(4, 6)); } } - if(navigationTargetEntityCollection.getEntities().isEmpty()){ + if (navigationTargetEntityCollection.getEntities().isEmpty()) { return null; } return navigationTargetEntityCollection; } + /* INTERNAL */ - /* INTERNAL */ - - private EntityCollection getProducts(){ + private EntityCollection getProducts() { EntityCollection retEntitySet = new EntityCollection(); - for(Entity productEntity : this.productList){ - retEntitySet.getEntities().add(productEntity); + for (Entity productEntity : this.productList) { + retEntitySet.getEntities().add(productEntity); } return retEntitySet; } - private Entity getProduct(EdmEntityType edmEntityType, List keyParams) { // the list of entities at runtime EntityCollection entityCollection = getProducts(); - /* generic approach to find the requested entity */ + /* generic approach to find the requested entity */ return Util.findEntity(edmEntityType, entityCollection, keyParams); } - - private EntityCollection getCategories(){ + private EntityCollection getCategories() { EntityCollection entitySet = new EntityCollection(); - for(Entity categoryEntity : this.categoryList){ - entitySet.getEntities().add(categoryEntity); + for (Entity categoryEntity : this.categoryList) { + entitySet.getEntities().add(categoryEntity); } return entitySet; } - private Entity getCategory(EdmEntityType edmEntityType, List keyParams) { // the list of entities at runtime EntityCollection entitySet = getCategories(); - /* generic approach to find the requested entity */ + /* generic approach to find the requested entity */ return Util.findEntity(edmEntityType, entitySet, keyParams); } - - /* HELPER */ - private void initProductSampleData(){ + private void initProductSampleData() { Entity entity = new Entity(); entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1)); entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15")); entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, - "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")); + "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")); entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()); productList.add(entity); @@ -198,7 +190,7 @@ public class Storage { entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2)); entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Professional 17")); entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, - "Notebook Professional, 2.8GHz - 15 XGA - 8GB DDR3 RAM - 500GB")); + "Notebook Professional, 2.8GHz - 15 XGA - 8GB DDR3 RAM - 500GB")); entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()); productList.add(entity); @@ -206,7 +198,7 @@ public class Storage { entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3)); entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA")); entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, - "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")); + "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")); entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()); productList.add(entity); @@ -214,7 +206,7 @@ public class Storage { entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 4)); entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Comfort Easy")); entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, - "32 GB Digital Assitant with high-resolution color screen")); + "32 GB Digital Assitant with high-resolution color screen")); entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()); productList.add(entity); @@ -222,7 +214,7 @@ public class Storage { entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 5)); entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen")); entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, - "19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")); + "19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")); entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()); productList.add(entity); @@ -230,12 +222,12 @@ public class Storage { entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 6)); entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Flat Basic")); entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, - "Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm")); + "Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm")); entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString()); productList.add(entity); } - private void initCategorySampleData(){ + private void initCategorySampleData() { Entity entity = new Entity(); diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java index 86dd9fba3..7b1fef806 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -38,12 +38,9 @@ import org.apache.olingo.commons.api.edm.provider.CsdlSchema; public class DemoEdmProvider extends CsdlAbstractEdmProvider { - // Service Namespace public static final String NAMESPACE = "OData.Demo"; - // OData.Demo - // EDM Container public static final String CONTAINER_NAME = "Container"; public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME); @@ -59,22 +56,20 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { public static final String ES_PRODUCTS_NAME = "Products"; public static final String ES_CATEGORIES_NAME = "Categories"; - - @Override public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException { // this method is called for each EntityType that are configured in the Schema CsdlEntityType entityType = null; - if(entityTypeName.equals(ET_PRODUCT_FQN)){ - //create EntityType properties + if (entityTypeName.equals(ET_PRODUCT_FQN)) { + // create EntityType properties CsdlProperty id = new CsdlProperty().setName("ID") - .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); + .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); CsdlProperty name = new CsdlProperty().setName("Name") - .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()); - CsdlProperty description = new CsdlProperty().setName("Description") - .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()); + .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()); + CsdlProperty description = new CsdlProperty().setName("Description") + .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()); // create PropertyRef for Key element CsdlPropertyRef propertyRef = new CsdlPropertyRef(); @@ -82,23 +77,23 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { // navigation property: many-to-one, null not allowed (product must have a category) CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Category") - .setType(ET_CATEGORY_FQN).setNullable(false).setPartner("Products"); + .setType(ET_CATEGORY_FQN).setNullable(false).setPartner("Products"); List navPropList = new ArrayList(); navPropList.add(navProp); // configure EntityType entityType = new CsdlEntityType(); entityType.setName(ET_PRODUCT_NAME); - entityType.setProperties(Arrays.asList(id, name , description)); + entityType.setProperties(Arrays.asList(id, name, description)); entityType.setKey(Arrays.asList(propertyRef)); entityType.setNavigationProperties(navPropList); - }else if (entityTypeName.equals(ET_CATEGORY_FQN)){ - //create EntityType properties + } else if (entityTypeName.equals(ET_CATEGORY_FQN)) { + // create EntityType properties CsdlProperty id = new CsdlProperty().setName("ID") - .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); + .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName()); CsdlProperty name = new CsdlProperty().setName("Name") - .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()); + .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName()); // create PropertyRef for Key element CsdlPropertyRef propertyRef = new CsdlPropertyRef(); @@ -106,7 +101,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { // navigation property: one-to-many CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Products") - .setType(ET_PRODUCT_FQN).setCollection(true).setPartner("Category"); + .setType(ET_PRODUCT_FQN).setCollection(true).setPartner("Category"); List navPropList = new ArrayList(); navPropList.add(navProp); @@ -127,9 +122,9 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { CsdlEntitySet entitySet = null; - if(entityContainer.equals(CONTAINER)){ + if (entityContainer.equals(CONTAINER)) { - if(entitySetName.equals(ES_PRODUCTS_NAME)){ + if (entitySetName.equals(ES_PRODUCTS_NAME)) { entitySet = new CsdlEntitySet(); entitySet.setName(ES_PRODUCTS_NAME); @@ -143,7 +138,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { navPropBindingList.add(navPropBinding); entitySet.setNavigationPropertyBindings(navPropBindingList); - }else if(entitySetName.equals(ES_CATEGORIES_NAME)){ + } else if (entitySetName.equals(ES_CATEGORIES_NAME)) { entitySet = new CsdlEntitySet(); entitySet.setName(ES_CATEGORIES_NAME); @@ -167,7 +162,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider { // This method is invoked when displaying the service document at // e.g. http://localhost:8080/DemoService/DemoService.svc - if(entityContainerName == null || entityContainerName.equals(CONTAINER)){ + if (entityContainerName == null || entityContainerName.equals(CONTAINER)) { CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo(); entityContainerInfo.setContainerName(CONTAINER); return entityContainerInfo; diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java index 932691e6d..9f281bbf5 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -52,14 +52,11 @@ import org.apache.olingo.server.api.uri.UriResourceNavigation; public class DemoEntityCollectionProcessor implements EntityCollectionProcessor { - private OData odata; private ServiceMetadata srvMetadata; // our database-mock private Storage storage; - - public DemoEntityCollectionProcessor(Storage storage) { this.storage = storage; } @@ -69,21 +66,19 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor this.srvMetadata = serviceMetadata; } - /* * This method is invoked when a collection of entities has to be read. * In our example, this can be either a "normal" read operation, or a navigation: - * + * * Example for "normal" read entity set operation: * http://localhost:8080/DemoService/DemoService.svc/Categories - * + * * Example for navigation * http://localhost:8080/DemoService/DemoService.svc/Categories(3)/Products - * - * */ + */ public void readEntityCollection(ODataRequest request, ODataResponse response, - UriInfo uriInfo, ContentType responseFormat) - throws ODataApplicationException, SerializerException { + UriInfo uriInfo, ContentType responseFormat) + throws ODataApplicationException, SerializerException { EdmEntitySet responseEdmEntitySet = null; // we'll need this to build the ContextURL EntityCollection responseEntityCollection = null; // we'll need this to set the response body @@ -93,27 +88,27 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor int segmentCount = resourceParts.size(); UriResource uriResource = resourceParts.get(0); // in our example, the first segment is the EntitySet - if (! (uriResource instanceof UriResourceEntitySet)) { + if (!(uriResource instanceof UriResourceEntitySet)) { throw new ODataApplicationException("Only EntitySet is supported", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),Locale.ROOT); + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) uriResource; EdmEntitySet startEdmEntitySet = uriResourceEntitySet.getEntitySet(); - if(segmentCount == 1){ // this is the case for: DemoService/DemoService.svc/Categories - responseEdmEntitySet = startEdmEntitySet; //the response body is built from the first (and only) entitySet + if (segmentCount == 1) { // this is the case for: DemoService/DemoService.svc/Categories + responseEdmEntitySet = startEdmEntitySet; // the response body is built from the first (and only) entitySet // 2nd: fetch the data from backend for this requested EntitySetName and deliver as EntitySet responseEntityCollection = storage.readEntitySetData(startEdmEntitySet); - }else if (segmentCount == 2){ // in case of navigation: DemoService.svc/Categories(3)/Products + } else if (segmentCount == 2) { // in case of navigation: DemoService.svc/Categories(3)/Products UriResource lastSegment = resourceParts.get(1); // in our example we don't support more complex URIs - if(lastSegment instanceof UriResourceNavigation){ - UriResourceNavigation uriResourceNavigation = (UriResourceNavigation)lastSegment; + if (lastSegment instanceof UriResourceNavigation) { + UriResourceNavigation uriResourceNavigation = (UriResourceNavigation) lastSegment; EdmNavigationProperty edmNavigationProperty = uriResourceNavigation.getProperty(); EdmEntityType targetEntityType = edmNavigationProperty.getType(); - //from Categories(1) to Products + // from Categories(1) to Products responseEdmEntitySet = Util.getNavigationTargetEntitySet(startEdmEntitySet, edmNavigationProperty); // 2nd: fetch the data from backend @@ -121,19 +116,19 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor List keyPredicates = uriResourceEntitySet.getKeyPredicates(); // e.g. for Categories(3)/Products we have to find the single entity: Category with ID 3 Entity sourceEntity = storage.readEntityData(startEdmEntitySet, keyPredicates); - // error handling for e.g. DemoService.svc/Categories(99)/Products - if(sourceEntity == null) { + // error handling for e.g. DemoService.svc/Categories(99)/Products + if (sourceEntity == null) { throw new ODataApplicationException("Entity not found.", - HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } // then fetch the entity collection where the entity navigates to // note: we don't need to check uriResourceNavigation.isCollection(), // because we are the EntityCollectionProcessor responseEntityCollection = storage.getRelatedEntityCollection(sourceEntity, targetEntityType); } - }else{ // this would be the case for e.g. Products(1)/Category/Products + } else { // this would be the case for e.g. Products(1)/Category/Products throw new ODataApplicationException("Not supported", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),Locale.ROOT); + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } // 3rd: create and configure a serializer @@ -143,7 +138,7 @@ public class DemoEntityCollectionProcessor implements EntityCollectionProcessor ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(responseFormat)); SerializerResult serializerResult = serializer.entityCollection(this.srvMetadata, edmEntityType, - responseEntityCollection, opts); + responseEntityCollection, opts); // 4th: configure the response object: set the body, headers and status code response.setContent(serializerResult.getContent()); diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java index 1d05e1237..a2cf344b1 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -53,37 +53,31 @@ import org.apache.olingo.server.api.uri.UriResourceNavigation; public class DemoEntityProcessor implements EntityProcessor { - private OData odata; private ServiceMetadata srvMetadata; private Storage storage; - - public DemoEntityProcessor(Storage storage) { this.storage = storage; } - public void init(OData odata, ServiceMetadata serviceMetadata) { this.odata = odata; this.srvMetadata = serviceMetadata; } - /* + /** * This method is invoked when a single entity has to be read. * In our example, this can be either a "normal" read operation, or a navigation: - * + * * Example for "normal" read operation: * http://localhost:8080/DemoService/DemoService.svc/Products(1) - * + * * Example for navigation * http://localhost:8080/DemoService/DemoService.svc/Products(1)/Category - * - * */ + */ public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat) - throws ODataApplicationException, SerializerException { - + throws ODataApplicationException, SerializerException { EdmEntityType responseEdmEntityType = null; // we'll need this to build the ContextURL Entity responseEntity = null; // required for serialization of the response body @@ -94,33 +88,33 @@ public class DemoEntityProcessor implements EntityProcessor { int segmentCount = resourceParts.size(); UriResource uriResource = resourceParts.get(0); // in our example, the first segment is the EntitySet - if (! (uriResource instanceof UriResourceEntitySet)) { + if (!(uriResource instanceof UriResourceEntitySet)) { throw new ODataApplicationException("Only EntitySet is supported", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),Locale.ENGLISH); + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ENGLISH); } UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) uriResource; EdmEntitySet startEdmEntitySet = uriResourceEntitySet.getEntitySet(); // Analyze the URI segments - if(segmentCount == 1){ // no navigation + if (segmentCount == 1) { // no navigation responseEdmEntityType = startEdmEntitySet.getEntityType(); responseEdmEntitySet = startEdmEntitySet; // since we have only one segment // 2. step: retrieve the data from backend List keyPredicates = uriResourceEntitySet.getKeyPredicates(); responseEntity = storage.readEntityData(startEdmEntitySet, keyPredicates); - } else if (segmentCount == 2){ //navigation + } else if (segmentCount == 2) { // navigation UriResource navSegment = resourceParts.get(1); // in our example we don't support more complex URIs - if(navSegment instanceof UriResourceNavigation){ - UriResourceNavigation uriResourceNavigation = (UriResourceNavigation)navSegment; + if (navSegment instanceof UriResourceNavigation) { + UriResourceNavigation uriResourceNavigation = (UriResourceNavigation) navSegment; EdmNavigationProperty edmNavigationProperty = uriResourceNavigation.getProperty(); responseEdmEntityType = edmNavigationProperty.getType(); // contextURL displays the last segment responseEdmEntitySet = Util.getNavigationTargetEntitySet(startEdmEntitySet, edmNavigationProperty); // 2nd: fetch the data from backend. - // e.g. for the URI: Products(1)/Category we have to find the correct Category entity + // e.g. for the URI: Products(1)/Category we have to find the correct Category entity List keyPredicates = uriResourceEntitySet.getKeyPredicates(); // e.g. for Products(1)/Category we have to find first the Products(1) Entity sourceEntity = storage.readEntityData(startEdmEntitySet, keyPredicates); @@ -131,18 +125,18 @@ public class DemoEntityProcessor implements EntityProcessor { // the key for nav is used in this case: Categories(3)/Products(5) List navKeyPredicates = uriResourceNavigation.getKeyPredicates(); - if(navKeyPredicates.isEmpty()){ // e.g. DemoService.svc/Products(1)/Category + if (navKeyPredicates.isEmpty()) { // e.g. DemoService.svc/Products(1)/Category responseEntity = storage.getRelatedEntity(sourceEntity, responseEdmEntityType); - }else{ // e.g. DemoService.svc/Categories(3)/Products(5) + } else { // e.g. DemoService.svc/Categories(3)/Products(5) responseEntity = storage.getRelatedEntity(sourceEntity, responseEdmEntityType, navKeyPredicates); } } - }else{ + } else { // this would be the case for e.g. Products(1)/Category/Products(1)/Category - throw new ODataApplicationException("Not supported", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),Locale.ROOT); + throw new ODataApplicationException("Not supported", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - if(responseEntity == null) { + if (responseEntity == null) { // this is the case for e.g. DemoService.svc/Categories(4) or DemoService.svc/Categories(3)/Products(999) throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } @@ -154,36 +148,32 @@ public class DemoEntityProcessor implements EntityProcessor { ODataFormat oDataFormat = ODataFormat.fromContentType(responseFormat); ODataSerializer serializer = this.odata.createSerializer(oDataFormat); SerializerResult serializerResult = serializer.entity(this.srvMetadata, - responseEdmEntityType, responseEntity, opts); + responseEdmEntityType, responseEntity, opts); - //4. configure the response object + // 4. configure the response object response.setContent(serializerResult.getContent()); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); } - - /* * These processor methods are not handled in this tutorial - * */ + */ public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, - ContentType requestFormat, ContentType responseFormat) - throws ODataApplicationException, DeserializerException, SerializerException { + ContentType requestFormat, ContentType responseFormat) + throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, - ContentType requestFormat, ContentType responseFormat) - throws ODataApplicationException, DeserializerException, SerializerException { + ContentType requestFormat, ContentType responseFormat) + throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo) - throws ODataApplicationException { + throws ODataApplicationException { throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } } diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java index 6436ae5bc..c32c5c24a 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -56,30 +56,27 @@ public class DemoPrimitiveProcessor implements PrimitiveProcessor { private OData odata; private Storage storage; - - public DemoPrimitiveProcessor(Storage storage) { this.storage = storage; } - public void init(OData odata, ServiceMetadata serviceMetadata) { this.odata = odata; } - /* * In our example, the URL would be: http://localhost:8080/DemoService/DemoService.svc/Products(1)/Name * and the response: * { - * @odata.context: "$metadata#Products/Name", - * value: "Notebook Basic 15" + * + * @odata.context: "$metadata#Products/Name", + * value: "Notebook Basic 15" * } - * */ + */ public void readPrimitive(ODataRequest request, ODataResponse response, - UriInfo uriInfo, ContentType responseFormat) - throws ODataApplicationException, SerializerException { + UriInfo uriInfo, ContentType responseFormat) + throws ODataApplicationException, SerializerException { // 1. Retrieve info from URI // 1.1. retrieve the info about the requested entity set @@ -92,26 +89,25 @@ public class DemoPrimitiveProcessor implements PrimitiveProcessor { // 1.2. retrieve the requested (Edm) property // the last segment is the Property - UriResourceProperty uriProperty = (UriResourceProperty)resourceParts.get(resourceParts.size() -1); + UriResourceProperty uriProperty = (UriResourceProperty) resourceParts.get(resourceParts.size() - 1); EdmProperty edmProperty = uriProperty.getProperty(); String edmPropertyName = edmProperty.getName(); // in our example, we know we have only primitive types in our model EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType(); - // 2. retrieve data from backend // 2.1. retrieve the entity data, for which the property has to be read Entity entity = storage.readEntityData(edmEntitySet, keyPredicates); if (entity == null) { // Bad request throw new ODataApplicationException("Entity not found", - HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH); + HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH); } // 2.2. retrieve the property data from the entity Property property = entity.getProperty(edmPropertyName); if (property == null) { throw new ODataApplicationException("Property not found", - HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH); + HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH); } // 3. serialize @@ -127,28 +123,28 @@ public class DemoPrimitiveProcessor implements PrimitiveProcessor { SerializerResult serializerResult = serializer.primitive(edmPropertyType, property, options); InputStream propertyStream = serializerResult.getContent(); - //4. configure the response object + // 4. configure the response object response.setContent(propertyStream); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); - }else{ + } else { // in case there's no value for the property, we can skip the serialization response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } } - - /* * These processor methods are not handled in this tutorial - * */ + */ - public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) - throws ODataApplicationException, DeserializerException, SerializerException { + public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, + ContentType responseFormat) + throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo) throws ODataApplicationException { + public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo) + throws ODataApplicationException { throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } } diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/util/Util.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/util/Util.java index 6a9ecb253..3320760dc 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/util/Util.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/util/Util.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -37,15 +37,16 @@ import org.apache.olingo.server.api.uri.UriParameter; public class Util { - - public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet, List keyParams) { + public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet, + List keyParams) { List entityList = entitySet.getEntities(); - // loop over all entities in order to find that one that matches all keys in request e.g. contacts(ContactID=1, CompanyID=1) - for(Entity entity : entityList){ + // loop over all entities in order to find that one that matches + // all keys in request e.g. contacts(ContactID=1, CompanyID=1) + for (Entity entity : entityList) { boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams); - if(foundEntity){ + if (foundEntity) { return entity; } } @@ -53,93 +54,98 @@ public class Util { return null; } + public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity rt_entity, + List keyParams) { - public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity rt_entity, List keyParams) { + // loop over all keys + for (final UriParameter key : keyParams) { + // key + String keyName = key.getName(); + String keyText = key.getText(); - // loop over all keys - for (final UriParameter key : keyParams) { - // key - String keyName = key.getName(); - String keyText = key.getText(); + // note: below line doesn't consider: keyProp can be part of a complexType in V4 + // in such case, it would be required to access it via getKeyPropertyRef() + // but since this isn't the case in our model, we ignore it in our implementation + EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(keyName); + // Edm: we need this info for the comparison below + Boolean isNullable = edmKeyProperty.isNullable(); + Integer maxLength = edmKeyProperty.getMaxLength(); + Integer precision = edmKeyProperty.getPrecision(); + Boolean isUnicode = edmKeyProperty.isUnicode(); + Integer scale = edmKeyProperty.getScale(); + // get the EdmType in order to compare + EdmType edmType = edmKeyProperty.getType(); + // if(EdmType instanceof EdmPrimitiveType) // do we need this? + EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType; - // note: below line doesn't consider: keyProp can be part of a complexType in V4 - // in such case, it would be required to access it via getKeyPropertyRef() - // but since this isn't the case in our model, we ignore it in our implementation - EdmProperty edmKeyProperty = (EdmProperty )edmEntityType.getProperty(keyName); - // Edm: we need this info for the comparison below - Boolean isNullable = edmKeyProperty.isNullable(); - Integer maxLength = edmKeyProperty.getMaxLength(); - Integer precision = edmKeyProperty.getPrecision(); - Boolean isUnicode = edmKeyProperty.isUnicode(); - Integer scale = edmKeyProperty.getScale(); - // get the EdmType in order to compare - EdmType edmType = edmKeyProperty.getType(); - //if(EdmType instanceof EdmPrimitiveType) // do we need this? - EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType)edmType; - - // Runtime data: the value of the current entity - Object valueObject = rt_entity.getProperty(keyName).getValue(); // don't need to check for null, this is done in FWK - // TODO if the property is a complex type + // Runtime data: the value of the current entity + // don't need to check for null, this is done in FWK + Object valueObject = rt_entity.getProperty(keyName).getValue(); + // TODO if the property is a complex type // now need to compare the valueObject with the keyText String // this is done using the type.valueToString String valueAsString = null; try { - valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable, maxLength, precision, scale, isUnicode); + valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable, + maxLength, precision, scale, isUnicode); } catch (EdmPrimitiveTypeException e) { return false; // TODO proper Exception handling } - if (valueAsString == null){ + if (valueAsString == null) { return false; } boolean matches = valueAsString.equals(keyText); - if(matches){ + if (matches) { // if the given key value is found in the current entity, continue with the next key continue; - }else{ + } else { // if any of the key properties is not found in the entity, we don't need to search further return false; } - } - - return true; + } + + return true; } - - - /* + /** * Example: * For the following navigation: DemoService.svc/Categories(1)/Products * we need the EdmEntitySet for the navigation property "Products" * * This is defined as follows in the metadata: - * + * + * * - - - * The "Target" attribute specifies the target EntitySet - * Therefore we need the startEntitySet "Categories" in order to retrieve the target EntitySet "Products" - */ - public static EdmEntitySet getNavigationTargetEntitySet(EdmEntitySet startEntitySet, EdmNavigationProperty edmNavigationProperty) throws ODataApplicationException { + * + * + * + * The "Target" attribute specifies the target EntitySet + * Therefore we need the startEntitySet "Categories" in order to retrieve the target EntitySet "Products" + */ + public static EdmEntitySet getNavigationTargetEntitySet(EdmEntitySet startEntitySet, + EdmNavigationProperty edmNavigationProperty) + throws ODataApplicationException { + EdmEntitySet navigationTargetEntitySet = null; String navPropName = edmNavigationProperty.getName(); EdmBindingTarget edmBindingTarget = startEntitySet.getRelatedBindingTarget(navPropName); - if(edmBindingTarget == null){ - throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + if (edmBindingTarget == null) { + throw new ODataApplicationException("Not supported.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - if(edmBindingTarget instanceof EdmEntitySet){ - navigationTargetEntitySet = (EdmEntitySet)edmBindingTarget; - }else{ - throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + if (edmBindingTarget instanceof EdmEntitySet) { + navigationTargetEntitySet = (EdmEntitySet) edmBindingTarget; + } else { + throw new ODataApplicationException("Not supported.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } return navigationTargetEntitySet; } - -} - +} diff --git a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/web/DemoServlet.java b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/web/DemoServlet.java index dd83c6e9c..5c828e5d3 100755 --- a/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/web/DemoServlet.java +++ b/samples/tutorials/p4_navigation/src/main/java/myservice/mynamespace/web/DemoServlet.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -45,16 +45,15 @@ public class DemoServlet extends HttpServlet { private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class); - @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { try { - HttpSession session = req.getSession(true); - Storage storage = (Storage) session.getAttribute(Storage.class.getName()); - if (storage == null) { - storage = new Storage(); - session.setAttribute(Storage.class.getName(), storage); - } + HttpSession session = req.getSession(true); + Storage storage = (Storage) session.getAttribute(Storage.class.getName()); + if (storage == null) { + storage = new Storage(); + session.setAttribute(Storage.class.getName(), storage); + } // create odata handler and configure it with EdmProvider and Processor OData odata = OData.newInstance(); From c33d0b7019aef3be8e915943e3895d46dfc6c7d3 Mon Sep 17 00:00:00 2001 From: Christian Amend Date: Thu, 9 Jul 2015 13:39:04 +0200 Subject: [PATCH 4/7] [OLINGO-659] Repair eclipse project generation on root pom --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 92d14a28c..1be4cffa6 100644 --- a/pom.xml +++ b/pom.xml @@ -496,6 +496,7 @@ maven-eclipse-plugin 2.9 + false true true 2.0 From 4baaf0d0b94bde0da857ae0fb5ca355f62357962 Mon Sep 17 00:00:00 2001 From: Christian Amend Date: Wed, 8 Jul 2015 15:48:46 +0200 Subject: [PATCH 5/7] [OLINGO-731] Debug interfaces part 1 --- .../apache/olingo/fit/v4/BatchTestITCase.java | 2 - .../org/apache/olingo/server/api/OData.java | 9 ++++ .../olingo/server/api/ODataHttpHandler.java | 7 +++ .../server/api/debug/DebugResponseHelper.java | 38 ++++++++++++++ .../olingo/server/api/debug/DebugSupport.java | 49 +++++++++++++++++ .../server/api/debug/DefaultDebugSupport.java | 52 +++++++++++++++++++ .../server/core/ODataHttpHandlerImpl.java | 33 ++++++++++-- .../apache/olingo/server/core/ODataImpl.java | 9 ++++ .../core/debug/DebugResponseHelperImpl.java | 33 ++++++++++++ .../serializer/json/ODataJsonSerializer.java | 1 - .../server/tecsvc/TechnicalServlet.java | 5 ++ 11 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java create mode 100644 lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java create mode 100644 lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java create mode 100644 lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java index db196c337..793f06f89 100644 --- a/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/v4/BatchTestITCase.java @@ -26,10 +26,8 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.math.BigDecimal; import java.net.URI; -import java.net.URISyntaxException; import java.util.Calendar; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java index 120d6b2f6..6c37ea81f 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java @@ -26,6 +26,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider; import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.server.api.debug.DebugResponseHelper; import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer; import org.apache.olingo.server.api.deserializer.ODataDeserializer; @@ -143,4 +144,12 @@ public abstract class OData { * It can be used in Processor implementations. */ public abstract Preferences createPreferences(Collection preferHeaders); + + /** + * This method creates a DebugResponseHelper for the given debugFormat. If the format is not supported no + * exception is thrown. Instead we give back the implementation for the json format. + * @param debugFormat to be used. + * @return a debug response serializer + */ + public abstract DebugResponseHelper createDebugResponseHelper(String debugFormat); } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java index 20ed77eec..d641581ad 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java @@ -21,6 +21,7 @@ package org.apache.olingo.server.api; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.olingo.server.api.debug.DebugSupport; import org.apache.olingo.server.api.etag.CustomETagSupport; import org.apache.olingo.server.api.processor.Processor; import org.apache.olingo.server.api.serializer.CustomContentTypeSupport; @@ -66,4 +67,10 @@ public interface ODataHttpHandler { */ void register(CustomETagSupport customConcurrencyControlSupport); + /** + * Register the debug support handler + * @param debugSupport + */ + void register(DebugSupport debugSupport); + } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java new file mode 100644 index 000000000..62a2d8a87 --- /dev/null +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java @@ -0,0 +1,38 @@ +/* + * 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.debug; + +import org.apache.olingo.server.api.ODataRequest; +import org.apache.olingo.server.api.ODataResponse; + +/** + * This class supports applications in creating debug responses. + */ +public interface DebugResponseHelper { + + /** + * Creates a debug response based on the given parameters. Will never throw an exception. + * @param request + * @param applicationResponse + * @param exception + * @return the debug response or the raw application response in case an exception occurred. + */ + ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception); + +} diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java new file mode 100644 index 000000000..3ed39a515 --- /dev/null +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java @@ -0,0 +1,49 @@ +/* + * 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.debug; + +import org.apache.olingo.server.api.OData; +import org.apache.olingo.server.api.ODataRequest; +import org.apache.olingo.server.api.ODataResponse; + +/** + * Register this interface to add debug support to your service. + */ +public interface DebugSupport { + + public static final String ODATA_DEBUG_QUERY_PARAMETER = "odata-debug"; + public static final String ODATA_DEBUG_JSON = "json"; + public static final String ODATA_DEBUG_HTML = "html"; + public static final String ODATA_DEBUG_DOWNLOAD = "download"; + + void init(OData odata); + + /** + * This method should create a debug response and deliver it back to the Olingo library. This method MUST NEVER throw + * an exception. + * @param debugFormat which is requested via the odata-debug query parameter + * @param request object which was send to the server + * @param response object which was filled by the application + * @param exception which has been thrown. Might be null in case there was no exception + * @return a new debug response which will be send to the client + */ + ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse response, + Exception exception); + +} diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java new file mode 100644 index 000000000..fb8851de7 --- /dev/null +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java @@ -0,0 +1,52 @@ +/* + * 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.debug; + +import org.apache.olingo.server.api.OData; +import org.apache.olingo.server.api.ODataRequest; +import org.apache.olingo.server.api.ODataResponse; + +/** + * Supports the default debug case. Will always deliver a debug response if requested from the server. + */ +public class DefaultDebugSupport implements DebugSupport { + + private OData odata; + + @Override + public void init(OData odata) { + this.odata = odata; + } + + @Override + public ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse applicationResponse, + Exception exception) { + // Check if debugFormat is supported by the library + if (DebugSupport.ODATA_DEBUG_JSON.equalsIgnoreCase(debugFormat) + || DebugSupport.ODATA_DEBUG_HTML.equalsIgnoreCase(debugFormat) + || DebugSupport.ODATA_DEBUG_DOWNLOAD.equalsIgnoreCase(debugFormat)) { + return odata.createDebugResponseHelper(debugFormat).createDebugResponse(request, applicationResponse, exception); + } else { + // Debug format is not supported by the library by default so in order to avoid an exception we will just give + // back the original response from the application. + return applicationResponse; + } + } + +} diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java index 5563f1b64..566086a19 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -40,6 +40,7 @@ import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataLibraryException; import org.apache.olingo.server.api.ServiceMetadata; +import org.apache.olingo.server.api.debug.DebugSupport; import org.apache.olingo.server.api.etag.CustomETagSupport; import org.apache.olingo.server.api.processor.Processor; import org.apache.olingo.server.api.serializer.CustomContentTypeSupport; @@ -51,7 +52,8 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler { private static final Logger LOG = LoggerFactory.getLogger(ODataHttpHandlerImpl.class); - private ODataHandler handler; + private final ODataHandler handler; + private DebugSupport debugSupport; private int split = 0; public ODataHttpHandlerImpl(final OData odata, final ServiceMetadata serviceMetadata) { @@ -60,6 +62,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler { @Override public void process(final HttpServletRequest request, final HttpServletResponse response) { + Exception exception = null; ODataRequest odRequest = null; ODataResponse odResponse; try { @@ -68,12 +71,27 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler { odResponse = handler.process(odRequest); // ALL future methods after process must not throw exceptions! } catch (Exception e) { + exception = e; odResponse = handleException(odRequest, e); } + if (debugSupport != null) { + String debugFormat = getDebugQueryParameter(request); + if (debugFormat != null) { + // TODO: Should we be more careful here with response assignement in order to not loose the original response? + // TODO: How should we react to exceptions here? + odResponse = debugSupport.createDebugResponse(debugFormat, odRequest, odResponse, exception); + } + } + convertToHttp(response, odResponse); } + private String getDebugQueryParameter(HttpServletRequest request) { + // TODO Auto-generated method stub + return ""; + } + @Override public void setSplit(final int split) { this.split = split; @@ -132,7 +150,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler { private ODataRequest fillODataRequest(final ODataRequest odRequest, final HttpServletRequest httpRequest, final int split) - throws ODataLibraryException { + throws ODataLibraryException { try { odRequest.setBody(httpRequest.getInputStream()); extractHeaders(odRequest, httpRequest); @@ -243,9 +261,14 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler { public void register(final CustomContentTypeSupport customContentTypeSupport) { handler.register(customContentTypeSupport); } - + @Override public void register(final CustomETagSupport customConcurrencyControlSupport) { handler.register(customConcurrencyControlSupport); } + + @Override + public void register(final DebugSupport debugSupport) { + this.debugSupport = debugSupport; + } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java index b4c414b70..dac1642cd 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java @@ -29,6 +29,7 @@ import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; import org.apache.olingo.server.api.ServiceMetadata; +import org.apache.olingo.server.api.debug.DebugResponseHelper; import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer; import org.apache.olingo.server.api.deserializer.ODataDeserializer; @@ -40,6 +41,7 @@ import org.apache.olingo.server.api.serializer.FixedFormatSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.uri.UriHelper; +import org.apache.olingo.server.core.debug.DebugResponseHelperImpl; import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl; import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer; import org.apache.olingo.server.core.etag.ETagHelperImpl; @@ -139,4 +141,11 @@ public class ODataImpl extends OData { return new PreferencesImpl(preferHeaders); } + @Override + public DebugResponseHelper createDebugResponseHelper(String debugFormat) { + //TODO: What should we do with invalid formats? + //TODO: Support more debug formats + return new DebugResponseHelperImpl(); + } + } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java new file mode 100644 index 000000000..ca4d7f388 --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java @@ -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.core.debug; + +import org.apache.olingo.server.api.ODataRequest; +import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.debug.DebugResponseHelper; + +public class DebugResponseHelperImpl implements DebugResponseHelper { + + @Override + public ODataResponse + createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception) { + return applicationResponse; + } + +} diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java index c1292de16..6bd87131c 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java @@ -69,7 +69,6 @@ import org.slf4j.LoggerFactory; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; public class ODataJsonSerializer implements ODataSerializer { diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java index 9c1d50286..8b74a88a3 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java @@ -33,6 +33,7 @@ import javax.servlet.http.HttpSession; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; import org.apache.olingo.server.api.ServiceMetadata; +import org.apache.olingo.server.api.debug.DefaultDebugSupport; import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.edmx.EdmxReferenceInclude; import org.apache.olingo.server.tecsvc.data.DataProvider; @@ -79,11 +80,15 @@ public class TechnicalServlet extends HttpServlet { } ODataHttpHandler handler = odata.createHandler(serviceMetadata); + // Register processors handler.register(new TechnicalEntityProcessor(dataProvider, serviceMetadata)); handler.register(new TechnicalPrimitiveComplexProcessor(dataProvider, serviceMetadata)); handler.register(new TechnicalActionProcessor(dataProvider, serviceMetadata)); handler.register(new TechnicalBatchProcessor(dataProvider)); + // Register Helper handler.register(new ETagSupport()); + handler.register(new DefaultDebugSupport()); + // Process the request handler.process(request, response); } catch (final RuntimeException e) { LOG.error("Server Error", e); From 3c591da1a0cc0ab400803ca5a57fed6566d993e2 Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Thu, 9 Jul 2015 15:29:48 +0200 Subject: [PATCH 6/7] [OLINGO-729] Minor code clean up --- .../deserializer/batch/BatchLineReader.java | 71 +++++++++---------- .../serializer/BatchResponseSerializer.java | 61 ++++++++-------- .../BatchResponseSerializerTest.java | 3 +- 3 files changed, 68 insertions(+), 67 deletions(-) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java index c4cee5afe..d96a5f52d 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java @@ -19,6 +19,7 @@ package org.apache.olingo.server.core.deserializer.batch; import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.http.HttpHeader; import java.io.IOException; import java.io.InputStream; @@ -34,9 +35,11 @@ public class BatchLineReader { 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"); + public static final String BOUNDARY = "boundary"; + public static final String DOUBLE_DASH = "--"; + public static final String CRLF = "\r\n"; private Charset currentCharset = DEFAULT_CHARSET; private String currentBoundary = null; -// private boolean readBody = false; private ReadState readState = new ReadState(); private InputStream reader; private byte[] buffer; @@ -140,60 +143,34 @@ public class BatchLineReader { private void updateCurrentCharset(String currentLine) { // TODO: mibo: Improve this method if(currentLine != null) { - if(currentLine.startsWith("Content-Type:")) { -// if(currentLine.contains(ContentType.PARAMETER_CHARSET)) { + if(currentLine.startsWith(HttpHeader.CONTENT_TYPE)) { currentLine = currentLine.substring(13, currentLine.length() - 2).trim(); - ContentType t = ContentType.parse(currentLine); - if (t != null) { - String charsetString = t.getParameter(ContentType.PARAMETER_CHARSET); + ContentType ct = ContentType.parse(currentLine); + if (ct != null) { + String charsetString = ct.getParameter(ContentType.PARAMETER_CHARSET); if (charsetString != null) { currentCharset = Charset.forName(charsetString); } else { currentCharset = DEFAULT_CHARSET; } // boundary - String boundary = t.getParameter("boundary"); + String boundary = ct.getParameter(BOUNDARY); if (boundary != null) { - currentBoundary = "--" + boundary; + currentBoundary = DOUBLE_DASH + boundary; } } - } else if("\r\n".equals(currentLine)) { + } else if(CRLF.equals(currentLine)) { readState.foundLinebreak(); } else if(isBoundary(currentLine)) { readState.foundBoundary(); -// if(readState.isReadBody()) { -// currentCharset = CS_ISO_8859_1; -// } } } } - private class ReadState { - private int state = 0; - - public void foundLinebreak() { - state++; - } - public void foundBoundary() { - state = 0; - } - public boolean isReadBody() { - return state >= 2; - } - public boolean isReadHeader() { - return state < 2; - } - - @Override - public String toString() { - return String.valueOf(state); - } - } - private boolean isBoundary(String currentLine) { - if((currentBoundary + "\r\n").equals(currentLine)) { + if((currentBoundary + CRLF).equals(currentLine)) { return true; - } else if((currentBoundary + "--\r\n").equals(currentLine)) { + } else if((currentBoundary + DOUBLE_DASH + CRLF).equals(currentLine)) { return true; } return false; @@ -273,4 +250,26 @@ public class BatchLineReader { private Charset getCurrentCharset() { return currentCharset; } + + /** + * Read state indicator (whether currently the body or header part is read). + */ + private class ReadState { + private int state = 0; + + public void foundLinebreak() { + state++; + } + public void foundBoundary() { + state = 0; + } + public boolean isReadBody() { + return state >= 2; + } + + @Override + public String toString() { + return String.valueOf(state); + } + } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java index 28d7c73f3..377c5e1d6 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java @@ -22,7 +22,11 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; import java.nio.charset.Charset; import java.util.List; import java.util.Map; @@ -162,8 +166,10 @@ public class BatchResponseSerializer { return value + "_" + UUID.randomUUID().toString(); } + /** + * Builder class to create the body and the header. + */ private class BodyBuilder { - private final Charset CHARSET_UTF_8 = Charset.forName("utf-8"); private final Charset CHARSET_ISO_8859_1 = Charset.forName("iso-8859-1"); private ByteBuffer buffer = ByteBuffer.allocate(8192); private boolean isClosed = false; @@ -177,8 +183,6 @@ public class BatchResponseSerializer { } public BodyBuilder append(String string) { - // TODO: mibo: check used charset -// byte [] b = string.getBytes(CHARSET_UTF_8); byte [] b = string.getBytes(CHARSET_ISO_8859_1); put(b); return this; @@ -207,12 +211,13 @@ public class BatchResponseSerializer { } public String toString() { -// byte[] tmp = new byte[buffer.position()]; -// buffer.get(tmp, 0, buffer.position()); return new String(buffer.array(), 0, buffer.position()); } } + /** + * Body part which is read and stored as bytes (no charset conversion). + */ private class Body { private final byte[] content; @@ -224,31 +229,29 @@ public class BatchResponseSerializer { return content.length; } - private byte[] getBody(final ODataResponse response) { - final InputStream content = response.getContent(); - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - - if (content != null) { - byte[] buffer = new byte[BUFFER_SIZE]; - int n; - - try { - while ((n = content.read(buffer, 0, buffer.length)) != -1) { - out.write(buffer, 0, n); - } - out.flush(); - } catch (IOException e) { - throw new ODataRuntimeException(e); - } - - return out.toByteArray(); - } else { - return new byte[0]; - } - } - public byte[] getContent() { return content; } + + private byte[] getBody(final ODataResponse response) { + if (response == null || response.getContent() == null) { + return new byte[0]; + } + + try { + ByteArrayOutputStream output = new ByteArrayOutputStream(); + ByteBuffer inBuffer = ByteBuffer.allocate(BUFFER_SIZE); + ReadableByteChannel ic = Channels.newChannel(response.getContent()); + WritableByteChannel oc = Channels.newChannel(output); + while (ic.read(inBuffer) > 0) { + inBuffer.flip(); + oc.write(inBuffer); + inBuffer.rewind(); + } + return output.toByteArray(); + } catch (IOException e) { + throw new ODataRuntimeException("Error on reading request content"); + } + } } -} +} \ No newline at end of file diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java index 9d3ebeea6..f73479b0a 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java @@ -43,7 +43,6 @@ public class BatchResponseSerializerTest { private static final String BOUNDARY = "batch_" + UUID.randomUUID().toString(); private static final Charset CS_ISO_8859_1 = Charset.forName("iso-8859-1"); - private static final Charset CS_UTF_8 = Charset.forName("utf-8"); @Test public void testBatchResponse() throws Exception { @@ -256,7 +255,7 @@ public class BatchResponseSerializerTest { } @Test - public void testBatchResponseUmlauteIso() throws Exception { + public void testBatchResponseUmlautsIso() throws Exception { final List parts = new ArrayList(); ODataResponse response = new ODataResponse(); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); From b484f7f64809fd62a0cfc7cf5cd98eb2f0f1abe6 Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Fri, 10 Jul 2015 09:27:56 +0200 Subject: [PATCH 7/7] [OLINGO-729] More tests and clean up --- .../deserializer/batch/BatchLineReader.java | 100 +++-------------- .../serializer/BatchResponseSerializer.java | 3 +- .../batch/BatchLineReaderTest.java | 103 ++---------------- .../BatchResponseSerializerTest.java | 60 +--------- 4 files changed, 31 insertions(+), 235 deletions(-) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java index 150d31874..bd71d93b8 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReader.java @@ -28,29 +28,19 @@ import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -/** - * Read batch content and split it into lines. - * This class is not thread safe. - */ public class BatchLineReader { - private static final byte CR_BYTE = '\r'; - private static final byte LF_BYTE = '\n'; + private static final byte CR = '\r'; + 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 String BOUNDARY = "boundary"; - private static final String DOUBLE_DASH = "--"; - private static final String CR = "\r"; - private static final String LF = "\n"; - private static final String CRLF = "\r\n"; - // length of the Content-Type Header field including the ':' - // "Content-Type:" => 13 - private static final int CONTENT_TYPE_LENGTH = 13; - - private final ReadState readState = new ReadState(); + public static final String BOUNDARY = "boundary"; + public static final String DOUBLE_DASH = "--"; + public static final String CRLF = "\r\n"; private Charset currentCharset = DEFAULT_CHARSET; private String currentBoundary = null; + private ReadState readState = new ReadState(); private InputStream reader; private byte[] buffer; private int offset = 0; @@ -103,57 +93,11 @@ public class BatchLineReader { return result; } - int read(final byte[] byteBuffer, final int bufferOffset, final int length) throws IOException { - if ((bufferOffset + length) > byteBuffer.length) { - throw new IndexOutOfBoundsException("Buffer is too small"); - } - - if (length < 0 || bufferOffset < 0) { - throw new IndexOutOfBoundsException("Offset and length must be greater than zero"); - } - - // Check if buffer is filled. Return if EOF is reached - // Is buffer refill required - if (limit == offset || isEOF()) { - fillBuffer(); - - if (isEOF()) { - return EOF; - } - } - - int bytesRead = 0; - int bytesToRead = length; - int currentOutputOffset = bufferOffset; - - while (bytesToRead != 0) { - // Is buffer refill required? - if (limit == offset) { - fillBuffer(); - - if (isEOF()) { - bytesToRead = 0; - } - } - - if (bytesToRead > 0) { - int readByte = Math.min(limit - offset, bytesToRead); - bytesRead += readByte; - bytesToRead -= readByte; - - for (int i = 0; i < readByte; i++) { - byteBuffer[currentOutputOffset++] = buffer[offset++]; - } - } - } - - return bytesRead; - } - private void updateCurrentCharset(String currentLine) { if(currentLine != null) { if(currentLine.startsWith(HttpHeader.CONTENT_TYPE)) { - ContentType ct = parseContentType(currentLine); + currentLine = currentLine.substring(13, currentLine.length() - 2).trim(); + ContentType ct = ContentType.parse(currentLine); if (ct != null) { String charsetString = ct.getParameter(ContentType.PARAMETER_CHARSET); if (charsetString != null) { @@ -167,7 +111,7 @@ public class BatchLineReader { currentBoundary = DOUBLE_DASH + boundary; } } - } else if(isLinebreak(currentLine)) { + } else if(CRLF.equals(currentLine)) { readState.foundLinebreak(); } else if(isBoundary(currentLine)) { readState.foundBoundary(); @@ -175,18 +119,6 @@ public class BatchLineReader { } } - private ContentType parseContentType(String currentLine) { - currentLine = currentLine.substring(CONTENT_TYPE_LENGTH, currentLine.length()).trim(); - return ContentType.parse(currentLine); - } - - private boolean isLinebreak(String currentLine) { - if(currentLine.length() > 2) { - return false; - } - return CR.equals(currentLine) || LF.equals(currentLine) || CRLF.equals(currentLine); - } - private boolean isBoundary(String currentLine) { if((currentBoundary + CRLF).equals(currentLine)) { return true; @@ -222,20 +154,20 @@ public class BatchLineReader { } buffer.put(currentChar); - if (currentChar == LF_BYTE) { + if (currentChar == LF) { foundLineEnd = true; - } else if (currentChar == CR_BYTE) { + } else if (currentChar == CR) { foundLineEnd = true; - // Check next char. Consume \n if available + // Check next byte. Consume \n if available // Is buffer refill required? if (limit == offset) { fillBuffer(); } // Check if there is at least one character - if (limit != EOF && this.buffer[offset] == LF_BYTE) { - buffer.put(LF_BYTE); + if (limit != EOF && this.buffer[offset] == LF) { + buffer.put(LF); offset++; } } @@ -256,10 +188,6 @@ public class BatchLineReader { } } - private boolean isEOF() { - return limit == EOF; - } - private int fillBuffer() throws IOException { limit = reader.read(buffer, 0, buffer.length); offset = 0; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java index 21474dd68..377c5e1d6 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java @@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; @@ -193,7 +194,7 @@ public class BatchResponseSerializer { } if(buffer.remaining() < b.length) { buffer.flip(); - ByteBuffer tmp = ByteBuffer.allocate(b.length + BUFFER_SIZE); + ByteBuffer tmp = ByteBuffer.allocate(buffer.limit() *2); tmp.put(buffer); buffer = tmp; } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java index afb51f091..9861b7f0c 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/deserializer/batch/BatchLineReaderTest.java @@ -24,20 +24,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.channels.Channels; -import java.nio.channels.ReadableByteChannel; -import java.nio.channels.WritableByteChannel; -import java.nio.charset.Charset; import java.util.List; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.olingo.commons.api.ODataRuntimeException; -import org.apache.olingo.server.api.ODataResponse; import org.junit.Test; public class BatchLineReaderTest { @@ -55,7 +43,6 @@ public class BatchLineReaderTest { "\n"; private static final String TEXT_EMPTY = ""; - private static final String LF = "\n"; @Test public void testSimpleText() throws Exception { @@ -215,22 +202,6 @@ public class BatchLineReaderTest { reader.close(); } - @Test - public void testReadMoreBufferCapacityThanCharacterAvailable() throws Exception { - final String TEXT = "Foo"; - byte[] buffer = new byte[20]; - - BatchLineReader reader = create(TEXT); - assertEquals(3, reader.read(buffer, 0, 20)); - assertEquals(-1, reader.read(buffer, 0, 20)); - reader.close(); - - BatchLineReader readerBufferOne = create(TEXT, 1); - assertEquals(3, readerBufferOne.read(buffer, 0, 20)); - assertEquals(-1, readerBufferOne.read(buffer, 0, 20)); - readerBufferOne.close(); - } - @Test public void testLineEqualsAndHashCode() { Line l1 = new Line("The first line", 1); @@ -242,28 +213,20 @@ public class BatchLineReaderTest { assertTrue(l1.hashCode() != l3.hashCode()); } - @Test - public void testToList() throws Exception { - BatchLineReader reader = create(TEXT_COMBINED); - List stringList = reader.toList(); + @Test(expected = IllegalArgumentException.class) + public void testFailBufferSizeZero() throws Exception { + BatchLineReader reader = create(TEXT_EMPTY, 0); + reader.close(); + } - assertEquals(11, stringList.size()); - assertEquals("Test\r", stringList.get(0)); - assertEquals("Test2\r\n", stringList.get(1)); - assertEquals("Test3\n", stringList.get(2)); - assertEquals("Test4\r", stringList.get(3)); - assertEquals("\r", stringList.get(4)); - assertEquals("\r\n", stringList.get(5)); - assertEquals("\r\n", stringList.get(6)); - assertEquals("Test5\n", stringList.get(7)); - assertEquals("Test6\r\n", stringList.get(8)); - assertEquals("Test7\n", stringList.get(9)); - assertEquals("\n", stringList.get(10)); + @Test(expected = IllegalArgumentException.class) + public void testFailBufferSizeNegative() throws Exception { + BatchLineReader reader = create(TEXT_EMPTY, -1); reader.close(); } @Test - public void testToLineList() throws Exception { + public void testToList() throws Exception { BatchLineReader reader = create(TEXT_COMBINED); List stringList = reader.toLineList(); @@ -282,53 +245,6 @@ public class BatchLineReaderTest { reader.close(); } - @Test - public void testBatchContent() throws Exception { - String batchContent = getFileContent("/batchLarge.batch", "utf-8"); - BatchLineReader reader = create(batchContent); - - List lines = reader.toList(); - assertEquals(2422, lines.size()); - assertEquals("--batch_8194-cf13-1f56\n", lines.get(0)); - assertEquals(" \n", lines.get(1402)); - assertEquals("\n", lines.get(1903)); - assertEquals("--batch_8194-cf13-1f56--", lines.get(2421)); - } - - private String getFileContent(String fileName, String charset) throws IOException { - byte[] content = getFileContent(fileName); - return new String(content, Charset.forName(charset)); - } - - private byte[] getFileContent(String fileName) throws IOException { - final InputStream input = ClassLoader.class.getResourceAsStream(fileName); - if (input == null) { - throw new IOException("Requested file '" + fileName + "' was not found."); - } - ByteArrayOutputStream output = new ByteArrayOutputStream(); - ByteBuffer inBuffer = ByteBuffer.allocate(8192); - ReadableByteChannel ic = Channels.newChannel(input); - WritableByteChannel oc = Channels.newChannel(output); - while (ic.read(inBuffer) > 0) { - inBuffer.flip(); - oc.write(inBuffer); - inBuffer.rewind(); - } - return output.toByteArray(); - } - - @Test(expected = IllegalArgumentException.class) - public void testFailBufferSizeZero() throws Exception { - BatchLineReader reader = create(TEXT_EMPTY, 0); - reader.close(); - } - - @Test(expected = IllegalArgumentException.class) - public void testFailBufferSizeNegative() throws Exception { - BatchLineReader reader = create(TEXT_EMPTY, -1); - reader.close(); - } - private BatchLineReader create(final String inputString) throws Exception { return new BatchLineReader(new ByteArrayInputStream(inputString .getBytes("UTF-8"))); @@ -338,5 +254,4 @@ public class BatchLineReaderTest { return new BatchLineReader(new ByteArrayInputStream(inputString .getBytes("UTF-8")), bufferSize); } - } diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java index 9570d359a..f73479b0a 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/BatchResponseSerializerTest.java @@ -27,7 +27,6 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; -import java.util.Random; import java.util.UUID; import org.apache.commons.io.IOUtils; @@ -97,7 +96,7 @@ public class BatchResponseSerializerTest { assertEquals(CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertTrue(body.get(line++).contains("--changeset_")); - assertTrue(body.get(line).contains("--batch_")); + assertTrue(body.get(line++).contains("--batch_")); } @Test @@ -153,7 +152,7 @@ public class BatchResponseSerializerTest { assertEquals(CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertTrue(body.get(line++).contains("--changeset_")); - assertTrue(body.get(line).contains("--batch_")); + assertTrue(body.get(line++).contains("--batch_")); } @Test @@ -213,7 +212,7 @@ public class BatchResponseSerializerTest { assertEquals(CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertTrue(body.get(line++).contains("--changeset_")); - assertTrue(body.get(line).contains("--batch_")); + assertTrue(body.get(line++).contains("--batch_")); } @Test @@ -309,7 +308,7 @@ public class BatchResponseSerializerTest { assertEquals(CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertTrue(body.get(line++).contains("--changeset_")); - assertTrue(body.get(line).contains("--batch_")); + assertTrue(body.get(line++).contains("--batch_")); } @Test @@ -363,7 +362,7 @@ public class BatchResponseSerializerTest { assertEquals(CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertTrue(body.get(line++).contains("--changeset_")); - assertTrue(body.get(line).contains("--batch_")); + assertTrue(body.get(line++).contains("--batch_")); } @Test @@ -398,54 +397,7 @@ public class BatchResponseSerializerTest { assertEquals("Content-Length: 13" + CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertEquals("Walter Winter" + CRLF, body.get(line++)); - assertTrue(body.get(line).contains("--batch_")); - } - - @Test - public void testResponseVeryLargeHeader() throws Exception { - List parts = new ArrayList(); - ODataResponse response = new ODataResponse(); - response.setStatusCode(HttpStatusCode.OK.getStatusCode()); - response.setHeader(HttpHeader.CONTENT_TYPE, "application/json"); - final String chValue = generateTestData(20000); - response.setHeader("Custom-Header", chValue); - response.setContent(IOUtils.toInputStream("Walter Winter")); - - List responses = new ArrayList(1); - responses.add(response); - parts.add(new ODataResponsePart(responses, false)); - - final BatchResponseSerializer serializer = new BatchResponseSerializer(); - final InputStream content = serializer.serialize(parts, BOUNDARY); - - assertNotNull(content); - final BatchLineReader reader = - new BatchLineReader(content); - final List body = reader.toList(); - reader.close(); - - int line = 0; - assertEquals(11, body.size()); assertTrue(body.get(line++).contains("--batch_")); - assertEquals("Content-Type: application/http" + CRLF, body.get(line++)); - assertEquals("Content-Transfer-Encoding: binary" + CRLF, body.get(line++)); - assertEquals(CRLF, body.get(line++)); - assertEquals("HTTP/1.1 200 OK" + CRLF, body.get(line++)); - assertEquals("Custom-Header: " + chValue + CRLF, body.get(line++)); - assertEquals("Content-Type: application/json" + CRLF, body.get(line++)); - assertEquals("Content-Length: 13" + CRLF, body.get(line++)); - assertEquals(CRLF, body.get(line++)); - assertEquals("Walter Winter" + CRLF, body.get(line++)); - assertTrue(body.get(line).contains("--batch_")); - } - - private String generateTestData(int amount) { - StringBuilder sb = new StringBuilder(); - Random r = new Random(); - for (int j = 0; j < amount; j++) { - sb.append((char)(65 + r.nextInt(25))); - } - return sb.toString(); } @Test @@ -484,6 +436,6 @@ public class BatchResponseSerializerTest { assertEquals(CRLF, body.get(line++)); assertEquals(CRLF, body.get(line++)); assertTrue(body.get(line++).contains("--changeset_")); - assertTrue(body.get(line).contains("--batch_")); + assertTrue(body.get(line++).contains("--batch_")); } }