You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by jh...@apache.org on 2013/08/23 16:29:02 UTC
[1/4] Batch Support, Validation in Deserialization
Updated Branches:
refs/heads/master a13366112 -> 45c27419c
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumerTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumerTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumerTest.java
index dd99c52..8672744 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumerTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumerTest.java
@@ -19,6 +19,7 @@
package org.apache.olingo.odata2.core.ep.consumer;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -33,11 +34,7 @@ import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.mockito.Mockito;
-
+import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmException;
@@ -60,6 +57,10 @@ import org.apache.olingo.odata2.api.exception.ODataMessageException;
import org.apache.olingo.odata2.api.uri.ExpandSelectTreeNode;
import org.apache.olingo.odata2.testutil.helper.StringHelper;
import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
/**
*
@@ -232,6 +233,13 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
" </m:properties>" +
"</entry>";
+ public XmlEntityConsumerTest() {
+ // CHECKSTYLE:OFF:Regexp
+ System.setProperty("javax.xml.stream.XMLInputFactory", "com.ctc.wstx.stax.WstxInputFactory"); //NOSONAR
+ System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory"); //NOSONAR
+ // CHECKSTYLE:ON
+ }
+
private static class EmployeeCallback implements OnReadInlineContent {
List<ODataEntry> employees;
@@ -1366,12 +1374,10 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
}
/**
- * Missing _d_ namespace at mandatory property/tag (_Version_) results in an exception.
- *
+ * Missing _d_ namespace at non-nullable property/tag (_Version_) is allowed.
* @throws Exception
*/
- @Test(expected = EntityProviderException.class)
- public void validationOfNamespacesMissingD_NamespaceAtRequiredTag() throws Exception {
+ public void validationOfNamespacesMissingD_NamespaceAtNonNullableTag() throws Exception {
String roomWithValidNamespaces =
"<?xml version='1.0' encoding='UTF-8'?>" +
"<entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:m=\"http://schemas.microsoft.com/ado/2007/08/dataservices/metadata\" xmlns:d=\"http://schemas.microsoft.com/ado/2007/08/dataservices\" xml:base=\"http://localhost:19000/test/\" m:etag=\"W/"1"\">" +
@@ -1387,9 +1393,14 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
" </content>" +
"</entry>";
- EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+ final EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+ final EdmProperty property = (EdmProperty) entitySet.getEntityType().getProperty("Version");
+ EdmFacets facets = property.getFacets();
+ Mockito.when(facets.isNullable()).thenReturn(false);
+
InputStream reqContent = createContentAsStream(roomWithValidNamespaces);
- readAndExpectException(entitySet, reqContent, false, EntityProviderException.MISSING_PROPERTY.addContent("Version"));
+ final ODataEntry result = new XmlEntityConsumer().readEntry(entitySet, reqContent, EntityProviderReadProperties.init().mergeSemantic(false).build());
+ assertNotNull(result);
}
private void readAndExpectException(final EdmEntitySet entitySet, final InputStream reqContent, final MessageReference messageReference) throws ODataMessageException {
@@ -1512,7 +1523,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("Employees('1')/$value", properties.get("ImageUrl"));
}
@@ -1557,7 +1568,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("Employees('1')/$value", properties.get("ImageUrl"));
}
@@ -1591,7 +1602,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -1626,7 +1637,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -1639,7 +1650,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
@SuppressWarnings("unchecked")
public void testReadEntryMissingKeyProperty() throws Exception {
// prepare
- EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees");
+ final EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees");
InputStream contentBody = createContentAsStream(EMPLOYEE_1_XML.replace("<d:EmployeeId>1</d:EmployeeId>", ""));
// execute
@@ -1651,7 +1662,6 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals(8, properties.size());
assertNull(properties.get("EmployeeId"));
- // assertEquals("1", properties.get("EmployeeId"));
assertEquals("Walter Winter", properties.get("EmployeeName"));
assertEquals("1", properties.get("ManagerId"));
assertEquals("1", properties.get("RoomId"));
@@ -1665,41 +1675,28 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
- @Test(expected = EntityProviderException.class)
- public void testReadEntryMissingProperty() throws Exception {
- // prepare
- EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees");
- EdmProperty property = (EdmProperty) entitySet.getEntityType().getProperty("Age");
- EdmFacets facets = Mockito.mock(EdmFacets.class);
- Mockito.when(facets.isNullable()).thenReturn(false);
- Mockito.when(property.getFacets()).thenReturn(facets);
- String content = EMPLOYEE_1_XML.replace("<d:Age>52</d:Age>", "");
+ @Test
+ public void readEntryNullProperty() throws Exception {
+ final EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees");
+ final String content = EMPLOYEE_1_XML.replace("<d:EntryDate>1999-01-01T00:00:00</d:EntryDate>",
+ "<d:EntryDate m:null='true' />");
InputStream contentBody = createContentAsStream(content);
- // execute
- try {
- XmlEntityConsumer xec = new XmlEntityConsumer();
- ODataEntry result = xec.readEntry(entitySet, contentBody, EntityProviderReadProperties.init().mergeSemantic(false).build());
+ final ODataEntry result = new XmlEntityConsumer().readEntry(entitySet, contentBody, EntityProviderReadProperties.init().mergeSemantic(true).build());
- // verify - not necessary because of thrown exception - but kept to prevent eclipse warning about unused variables
- Map<String, Object> properties = result.getProperties();
- assertEquals(9, properties.size());
- } catch (EntityProviderException e) {
- // do some assertions...
- assertEquals(EntityProviderException.MISSING_PROPERTY.getKey(), e.getMessageReference().getKey());
- assertEquals("Age", e.getMessageReference().getContent().get(0));
- // ...and then re-throw
- throw e;
- }
+ final Map<String, Object> properties = result.getProperties();
+ assertEquals(9, properties.size());
+ assertTrue(properties.containsKey("EntryDate"));
+ assertNull(properties.get("EntryDate"));
}
@Test(expected = EntityProviderException.class)
- public void testReadEntryTooManyValues() throws Exception {
+ public void readEntryTooManyValues() throws Exception {
// prepare
EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees");
String content = EMPLOYEE_1_XML.replace("<d:Age>52</d:Age>", "<d:Age>52</d:Age><d:SomeUnknownTag>SomeUnknownValue</d:SomeUnknownTag>");
@@ -1707,12 +1704,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
// execute
try {
- XmlEntityConsumer xec = new XmlEntityConsumer();
- ODataEntry result = xec.readEntry(entitySet, contentBody, EntityProviderReadProperties.init().mergeSemantic(false).build());
-
- // verify - not necessary because of thrown exception - but kept to prevent eclipse warning about unused variables
- Map<String, Object> properties = result.getProperties();
- assertEquals(9, properties.size());
+ new XmlEntityConsumer().readEntry(entitySet, contentBody, EntityProviderReadProperties.init().mergeSemantic(false).build());
} catch (EntityProviderException e) {
// do some assertions...
assertEquals(EntityProviderException.INVALID_PROPERTY.getKey(), e.getMessageReference().getKey());
@@ -1755,7 +1747,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("69124", city.get("PostalCode"));
assertEquals("Heidelberg", city.get("CityName"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -1827,7 +1819,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -1859,7 +1851,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -1891,7 +1883,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -1961,7 +1953,7 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
assertEquals("69124", city.get("PostalCode"));
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Short.valueOf("52"), properties.get("Age"));
- assertEquals(Long.valueOf(915148800000l), properties.get("EntryDate"));
+ assertEquals(Long.valueOf(915148800000L), properties.get("EntryDate"));
assertEquals("/male_1_WinterW.jpg", properties.get("ImageUrl"));
}
@@ -2013,7 +2005,30 @@ public class XmlEntityConsumerTest extends AbstractConsumerTest {
}
@Test
- public void testReadEntryRooms() throws Exception {
+ public void readIncompleteEntry() throws Exception {
+ final EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+ InputStream reqContent = createContentAsStream(ROOM_1_XML);
+ final ODataEntry result = new XmlEntityConsumer().readEntry(entitySet, reqContent, EntityProviderReadProperties.init().build());
+
+ final EntryMetadata entryMetadata = result.getMetadata();
+ assertEquals("http://localhost:19000/test/Rooms('1')", entryMetadata.getId());
+ assertEquals("W/\"1\"", entryMetadata.getEtag());
+ assertNull(entryMetadata.getUri());
+
+ final MediaMetadata mediaMetadata = result.getMediaMetadata();
+ assertEquals(HttpContentType.APPLICATION_XML, mediaMetadata.getContentType());
+ assertNull(mediaMetadata.getSourceLink());
+ assertNull(mediaMetadata.getEditLink());
+ assertNull(mediaMetadata.getEtag());
+
+ final Map<String, Object> properties = result.getProperties();
+ assertEquals(1, properties.size());
+ assertEquals("1", properties.get("Id"));
+ assertFalse(properties.containsKey("Seats"));
+ }
+
+ @Test
+ public void readIncompleteEntryMerge() throws Exception {
XmlEntityConsumer xec = new XmlEntityConsumer();
EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumerTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumerTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumerTest.java
index d0256a1..84d3416 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumerTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlLinkConsumerTest.java
@@ -47,6 +47,13 @@ public class XmlLinkConsumerTest extends AbstractConsumerTest {
private static final String SINGLE_LINK =
"<uri xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">" + SERVICE_ROOT + "Employees('6')</uri>";
+ public XmlLinkConsumerTest() {
+ // CHECKSTYLE:OFF:Regexp
+ System.setProperty("javax.xml.stream.XMLInputFactory", "com.ctc.wstx.stax.WstxInputFactory"); //NOSONAR
+ System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory"); //NOSONAR
+ // CHECKSTYLE:ON
+ }
+
@Test
public void readLink() throws Exception {
XMLStreamReader reader = createReaderForTest(SINGLE_LINK, true);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumerTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumerTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumerTest.java
index 805f29e..ec12dc8 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumerTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumerTest.java
@@ -19,30 +19,27 @@
package org.apache.olingo.odata2.core.ep.consumer;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-import java.util.Arrays;
+import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.xml.stream.XMLStreamReader;
-import junit.framework.Assert;
-
-import org.junit.Test;
-
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmComplexType;
-import org.apache.olingo.odata2.api.edm.EdmException;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
import org.apache.olingo.odata2.api.edm.EdmProperty;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
-import org.apache.olingo.odata2.api.edm.EdmStructuralType;
-import org.apache.olingo.odata2.api.edm.EdmTypeKind;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Test;
/**
*
@@ -50,7 +47,7 @@ import org.apache.olingo.odata2.testutil.mock.MockFacade;
public class XmlPropertyConsumerTest extends AbstractConsumerTest {
@Test
- public void testReadIntegerProperty() throws Exception {
+ public void readIntegerProperty() throws Exception {
String xml = "<Age xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">67</Age>";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
@@ -61,7 +58,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
}
@Test
- public void testReadIntegerPropertyAsLong() throws Exception {
+ public void readIntegerPropertyAsLong() throws Exception {
String xml = "<Age xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">67</Age>";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
@@ -73,7 +70,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
}
@Test
- public void testReadIntegerPropertyWithNullMapping() throws Exception {
+ public void readIntegerPropertyWithNullMapping() throws Exception {
String xml = "<Age xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">67</Age>";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
@@ -85,7 +82,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
}
@Test
- public void testReadIntegerPropertyWithEmptyMapping() throws Exception {
+ public void readIntegerPropertyWithEmptyMapping() throws Exception {
String xml = "<Age xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">67</Age>";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
@@ -97,7 +94,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
}
@Test
- public void testReadStringProperty() throws Exception {
+ public void readStringProperty() throws Exception {
String xml = "<EmployeeName xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">Max Mustermann</EmployeeName>";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("EmployeeName");
@@ -108,29 +105,77 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
}
@Test
- public void testReadStringNullProperty() throws Exception {
- String xml = "<EntryDate xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ public void readStringPropertyEmpty() throws Exception {
+ final String xml = "<EmployeeName xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\" />";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("EmployeeName");
+
+ final Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false);
+
+ assertTrue(resultMap.containsKey("EmployeeName"));
+ assertEquals("", resultMap.get("EmployeeName"));
+ }
+
+ @Test
+ public void readStringPropertyNull() throws Exception {
+ final String xml = "<EntryDate xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ "\" m:null=\"true\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" />";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("EntryDate");
- Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false);
+ final Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false);
+ assertTrue(resultMap.containsKey("EntryDate"));
assertNull(resultMap.get("EntryDate"));
}
+ @Test
+ public void readStringPropertyNullFalse() throws Exception {
+ final String xml = "<EntryDate xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ + "\" m:null=\"false\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\">1970-01-02T00:00:00</EntryDate>";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("EntryDate");
+
+ final Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false);
+
+ assertEquals(86400000L, ((Calendar) resultMap.get("EntryDate")).getTimeInMillis());
+ }
+
@Test(expected = EntityProviderException.class)
public void invalidSimplePropertyName() throws Exception {
- String xml = "<Invalid xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">67</Invalid>";
+ final String xml = "<Invalid xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\">67</Invalid>";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+
+ new XmlPropertyConsumer().readProperty(reader, property, false);
+ }
+
+ @Test(expected = EntityProviderException.class)
+ public void invalidNullAttribute() throws Exception {
+ final String xml = "<Age xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ + "\" m:null=\"wrong\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" />";
XMLStreamReader reader = createReaderForTest(xml, true);
final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
new XmlPropertyConsumer().readProperty(reader, property, false);
}
+ @Test(expected = EntityProviderException.class)
+ public void nullValueNotAllowed() throws Exception {
+ final String xml = "<Age xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ + "\" m:null=\"true\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" />";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+ EdmFacets facets = mock(EdmFacets.class);
+ when(facets.isNullable()).thenReturn(false);
+ when(property.getFacets()).thenReturn(facets);
+
+ new XmlPropertyConsumer().readProperty(reader, property, false);
+ }
+
@Test
@SuppressWarnings("unchecked")
- public void testReadComplexProperty() throws Exception {
+ public void readComplexProperty() throws Exception {
String xml =
"<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\""
+ " xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" m:type=\"RefScenario.c_Location\">" +
@@ -154,7 +199,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
@Test
@SuppressWarnings("unchecked")
- public void testReadComplexPropertyWithLineBreaks() throws Exception {
+ public void readComplexPropertyWithLineBreaks() throws Exception {
String xml =
"<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\""
+ " xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" m:type=\"RefScenario.c_Location\">" +
@@ -180,7 +225,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
}
@Test(expected = EntityProviderException.class)
- public void testReadComplexPropertyInvalidMapping() throws Exception {
+ public void readComplexPropertyInvalidMapping() throws Exception {
String xml =
"<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\""
+ " xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" type=\"RefScenario.c_Location\">" +
@@ -196,19 +241,16 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
try {
Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false,
createTypeMappings("Location", createTypeMappings("City", createTypeMappings("PostalCode", Integer.class))));
-
- // Map<String, Object> resultMap = xpc.readProperty(reader, property, false,
- // createTypeMappings("PostalCode", Integer.class));
- Assert.assertNotNull(resultMap);
+ assertNotNull(resultMap);
} catch (EntityProviderException e) {
- Assert.assertTrue(e.getCause() instanceof EdmSimpleTypeException);
+ assertTrue(e.getCause() instanceof EdmSimpleTypeException);
throw e;
}
}
@Test
@SuppressWarnings("unchecked")
- public void testReadComplexPropertyWithMappings() throws Exception {
+ public void readComplexPropertyWithMappings() throws Exception {
String xml =
"<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\""
+ " xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" m:type=\"RefScenario.c_Location\">" +
@@ -220,30 +262,11 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
"</Location>";
XMLStreamReader reader = createReaderForTest(xml, true);
- final EdmComplexType locationComplexType = mock(EdmComplexType.class);
- when(locationComplexType.getKind()).thenReturn(EdmTypeKind.COMPLEX);
- when(locationComplexType.getName()).thenReturn("c_Location");
- when(locationComplexType.getNamespace()).thenReturn("RefScenario");
- when(locationComplexType.getPropertyNames()).thenReturn(Arrays.asList("City", "Country"));
-
- final EdmProperty locationComplexProperty = mock(EdmProperty.class);
- when(locationComplexProperty.getType()).thenReturn(locationComplexType);
- when(locationComplexProperty.getName()).thenReturn("Location");
- createProperty("Country", EdmSimpleTypeKind.String, locationComplexType);
-
- final EdmComplexType cityComplexType = mock(EdmComplexType.class);
- when(cityComplexType.getKind()).thenReturn(EdmTypeKind.COMPLEX);
- when(cityComplexType.getName()).thenReturn("c_City");
- when(cityComplexType.getNamespace()).thenReturn("RefScenario");
- when(cityComplexType.getPropertyNames()).thenReturn(Arrays.asList("PostalCode", "CityName"));
-
- final EdmProperty cityProperty = mock(EdmProperty.class);
- when(cityProperty.getType()).thenReturn(cityComplexType);
- when(cityProperty.getName()).thenReturn("City");
- when(locationComplexType.getProperty("City")).thenReturn(cityProperty);
-
- createProperty("PostalCode", EdmSimpleTypeKind.Int32, cityComplexType);
- createProperty("CityName", EdmSimpleTypeKind.String, cityComplexType);
+ EdmProperty locationComplexProperty = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Location");
+ EdmProperty cityProperty = (EdmProperty) ((EdmComplexType) locationComplexProperty.getType()).getProperty("City");
+ EdmProperty postalCodeProperty = (EdmProperty) ((EdmComplexType) cityProperty.getType()).getProperty("PostalCode");
+ // Change the type of the PostalCode property to one that allows different Java types.
+ when(postalCodeProperty.getType()).thenReturn(EdmSimpleTypeKind.Int32.getEdmSimpleTypeInstance());
// Execute test
Map<String, Object> typeMappings =
@@ -262,7 +285,7 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
@SuppressWarnings("unchecked")
@Test
- public void testReadComplexPropertyWithNamespace() throws Exception {
+ public void readComplexPropertyWithNamespace() throws Exception {
String xml =
"<d:Location m:type=\"RefScenario.c_Location\" " +
" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\"" +
@@ -378,11 +401,55 @@ public class XmlPropertyConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", cityMap.get("CityName"));
}
- private static EdmProperty createProperty(final String name, final EdmSimpleTypeKind kind, final EdmStructuralType entityType) throws EdmException {
- final EdmProperty property = mock(EdmProperty.class);
- when(property.getType()).thenReturn(kind.getEdmSimpleTypeInstance());
- when(property.getName()).thenReturn(name);
- when(entityType.getProperty(name)).thenReturn(property);
- return property;
+ @Test
+ public void complexPropertyNull() throws Exception {
+ String xml = "<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ + "\" m:null=\"true\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" />";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Location");
+
+ final Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false);
+
+ assertTrue(resultMap.containsKey("Location"));
+ assertNull(resultMap.get("Location"));
+ }
+
+ @Test(expected = EntityProviderException.class)
+ public void complexPropertyNullValueNotAllowed() throws Exception {
+ final String xml = "<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ + "\" m:null=\"true\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\" />";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Location");
+ EdmFacets facets = mock(EdmFacets.class);
+ when(facets.isNullable()).thenReturn(false);
+ when(property.getFacets()).thenReturn(facets);
+
+ new XmlPropertyConsumer().readProperty(reader, property, false);
+ }
+
+ @Test(expected = EntityProviderException.class)
+ public void complexPropertyNullWithContent() throws Exception {
+ String xml = "<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08
+ + "\" m:null=\"true\" xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\">"
+ + "<City><PostalCode/><CityName/></City><Country>Germany</Country>"
+ + "</Location>";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Location");
+
+ new XmlPropertyConsumer().readProperty(reader, property, false);
+ }
+
+ @Test
+ public void complexPropertyEmpty() throws Exception {
+ final String xml = "<Location xmlns=\"" + Edm.NAMESPACE_D_2007_08 + "\" />";
+ XMLStreamReader reader = createReaderForTest(xml, true);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Location");
+
+ final Map<String, Object> resultMap = new XmlPropertyConsumer().readProperty(reader, property, false);
+
+ assertNotNull(resultMap.get("Location"));
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> innerMap = (Map<String, Object>) resultMap.get("Location");
+ assertTrue(innerMap.isEmpty());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorServiceTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorServiceTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorServiceTest.java
index 0bf7e82..17cd8fe 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorServiceTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorServiceTest.java
@@ -175,6 +175,6 @@ public class ODataSingleProcessorServiceTest extends BaseTest {
@Test
public void defaultSupportedContentTypesForBatch() throws Exception {
List<String> types = service.getSupportedContentTypes(BatchProcessor.class);
- assertTrue(types.contains(ContentType.MULTIPART_MIXED.toContentTypeString()));
+ assertTrue(types.contains(ContentType.WILDCARD.toContentTypeString()));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestAbapCompatibility.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestAbapCompatibility.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestAbapCompatibility.java
index 7df85c6..018dfc2 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestAbapCompatibility.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestAbapCompatibility.java
@@ -235,8 +235,7 @@ public class TestAbapCompatibility extends TestBase {
}
@Test
- public void abapTestFilterParser() //copy of ABAP method test_filter_parser
- {
+ public void abapTestFilterParser() { //copy of ABAP method test_filter_parser
//lcl_helper=>veri_expression( iv_expression = 'W/X' iv_expected = '{W/X}' ).
GetPTF("W/X").aSerialized("{W/X}");
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestParserExceptions.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestParserExceptions.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestParserExceptions.java
index edf2550..683861c 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestParserExceptions.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/uri/expression/TestParserExceptions.java
@@ -240,16 +240,14 @@ public class TestParserExceptions extends TestBase {
}
@Test
- public void testPMvalidateBinaryOperator() /*PM = Parsermethod*/
- {
+ public void testPMvalidateBinaryOperator() {/*PM = Parsermethod*/
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter=123 add 'abc'
//-->Operator 'add' incompatible with operand types 'System.Int32' and 'System.String' at position 4.
GetPTF("123 add 'abc'").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.INVALID_TYPES_FOR_BINARY_OPERATOR).aExMsgText("Operator \"add\" incompatible with operand types \"System.Uint7\" and \"Edm.String\" at position 5 in \"123 add 'abc'\".");
}
@Test
- public void testPMvalidateMethodTypes() /*PM = Parsermethod*/
- {
+ public void testPMvalidateMethodTypes() /*PM = Parsermethod*/{
//CASE 1
//http://services.odata.org/Northwind/Northwind.svc/Products/?$filter=year(327686)
//-->No applicable function found for 'year' at position 0 with the specified arguments. The functions considered are: year(System.DateTime).
@@ -258,8 +256,8 @@ public class TestParserExceptions extends TestBase {
}
@Test
- public void testPMparseFilterString() /*PM = Parsermethod*/
- {
+ public void testPMparseFilterString() { /*PM = Parsermethod*/
+
//http://services.odata.org/Northwind/Northwind.svc/Products(1)/Supplier?$filter='123
//-->Unterminated string literal at position 4 in ''123'.
GetPTF("'123").aExType(ExpressionParserException.class).aExKey(ExpressionParserException.TOKEN_UNDETERMINATED_STRING).aExMsgText("Unterminated string literal at position 1 in \"'123\".");
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/resources/batchResponse.batch
----------------------------------------------------------------------
diff --git a/odata-core/src/test/resources/batchResponse.batch b/odata-core/src/test/resources/batchResponse.batch
new file mode 100644
index 0000000..ff65bb1
--- /dev/null
+++ b/odata-core/src/test/resources/batchResponse.batch
@@ -0,0 +1,39 @@
+--batch_123
+Content-Type: multipart/mixed;boundary=changeset_12ks93js84d
+
+--changeset_12ks93js84d
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-Id: 1
+
+HTTP/1.1 204 No Content
+
+
+--changeset_12ks93js84d
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+
+HTTP/1.1 201 Created
+DataServiceVersion: 2.0
+Content-Id: 2
+Location: http://localhost:19000/ClientBatchTest/Employees('7')
+Content-Type: application/json
+Content-Length: 918
+
+{"d":{"__metadata":{"id":"http://localhost:19000/ClientBatchTest/Employees('7')","uri":"http://localhost:19000/ClientBatchTest/Employees('7')","type":"RefScenario.Employee","content_type":"application/octet-stream","media_src":"Employees('7')/$value","edit_media":"http://localhost:19000/ClientBatchTest/Employees('7')/$value"},"EmployeeId":"7","EmployeeName":"Employee 7","ManagerId":null,"RoomId":null,"TeamId":null,"Location":{"__metadata":{"type":"RefScenario.c_Location"},"City":{"__metadata":{"type":"RefScenario.c_City"},"PostalCode":null,"CityName":null},"Country":null},"Age":0,"EntryDate":null,"ImageUrl":null,"ne_Manager":{"__deferred":{"uri":"http://localhost:19000/ClientBatchTest/Employees('7')/ne_Manager"}},"ne_Team":{"__deferred":{"uri":"http://localhost:19000/ClientBatchTest/Employees('7')/ne_Team"}},"ne_Room":{"__deferred":{"uri":"http://localhost:19000/ClientBatchTest/Employees('7')/ne_Room"}}}}
+
+--changeset_12ks93js84d--
+
+--batch_123
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: 2
+
+HTTP/1.1 200 OK
+DataServiceVersion: 2.0
+Content-Type: text/plain;charset=utf-8
+Content-length: 13
+
+Frederic Fall
+
+--batch_123--
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-fit/src/test/java/org/apache/olingo/odata2/fit/basic/BasicBatchTest.java
----------------------------------------------------------------------
diff --git a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/basic/BasicBatchTest.java b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/basic/BasicBatchTest.java
index 8d7b846..3cfcffb 100644
--- a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/basic/BasicBatchTest.java
+++ b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/basic/BasicBatchTest.java
@@ -36,11 +36,9 @@ import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
-import org.junit.Test;
-
import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.batch.BatchHandler;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
import org.apache.olingo.odata2.api.edm.Edm;
@@ -60,6 +58,7 @@ import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
import org.apache.olingo.odata2.core.processor.ODataSingleProcessorService;
import org.apache.olingo.odata2.testutil.helper.StringHelper;
import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Test;
/**
*
@@ -141,8 +140,8 @@ public class BasicBatchTest extends AbstractBasicTest {
pathInfo.setServiceRoot(new URI("http://localhost:19000/odata"));
EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
- List<BatchPart> batchParts = EntityProvider.parseBatchRequest(requestContentType, content, batchProperties);
- for (BatchPart batchPart : batchParts) {
+ List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(requestContentType, content, batchProperties);
+ for (BatchRequestPart batchPart : batchParts) {
batchResponseParts.add(handler.handleBatchPart(batchPart));
}
batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
----------------------------------------------------------------------
diff --git a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
new file mode 100644
index 0000000..61eb4b2
--- /dev/null
+++ b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/client/ClientBatchTest.java
@@ -0,0 +1,235 @@
+/*******************************************************************************
+ * 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.odata2.fit.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart;
+import org.apache.olingo.odata2.api.client.batch.BatchPart;
+import org.apache.olingo.odata2.api.client.batch.BatchQueryPart;
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.api.ep.EntityProvider;
+import org.apache.olingo.odata2.fit.ref.AbstractRefTest;
+import org.apache.olingo.odata2.testutil.helper.StringHelper;
+import org.junit.Test;
+
+public class ClientBatchTest extends AbstractRefTest {
+ private static final String PUT = "PUT";
+ private static final String POST = "POST";
+ private static final String GET = "GET";
+ private static final String BOUNDARY = "batch_123";
+
+ @Test
+ public void testSimpleBatch() throws Exception {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ BatchPart request = BatchQueryPart.method(GET).uri("$metadata").build();
+ batch.add(request);
+
+ InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
+ String batchRequestBody = StringHelper.inputStreamToString(body, true);
+ checkMimeHeaders(batchRequestBody);
+ checkBoundaryDelimiters(batchRequestBody);
+ assertTrue(batchRequestBody.contains("GET $metadata HTTP/1.1"));
+
+ HttpResponse batchResponse = execute(batchRequestBody);
+ InputStream responseBody = batchResponse.getEntity().getContent();
+ String contentType = batchResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(responseBody, contentType);
+ for (BatchSingleResponse response : responses) {
+ assertEquals("200", response.getStatusCode());
+ assertEquals("OK", response.getStatusInfo());
+ assertTrue(response.getBody().contains("<edmx:Edmx Version=\"1.0\""));
+ assertEquals("application/xml;charset=utf-8", response.getHeader(HttpHeaders.CONTENT_TYPE));
+ assertNotNull(response.getHeader(HttpHeaders.CONTENT_LENGTH));
+ }
+ }
+
+ @Test
+ public void testChangeSetBatch() throws Exception {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ Map<String, String> changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/json;odata=verbose");
+
+ BatchChangeSetPart changeRequest = BatchChangeSetPart.method(PUT)
+ .uri("Employees('2')/EmployeeName")
+ .body("{\"EmployeeName\":\"Frederic Fall MODIFIED\"}")
+ .headers(changeSetHeaders)
+ .build();
+ changeSet.add(changeRequest);
+ batch.add(changeSet);
+
+ BatchPart request = BatchQueryPart.method(GET)
+ .uri("Employees('2')/EmployeeName/$value")
+ .build();
+ batch.add(request);
+
+ InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
+ String bodyAsString = StringHelper.inputStreamToString(body, true);
+ checkMimeHeaders(bodyAsString);
+ checkBoundaryDelimiters(bodyAsString);
+
+ assertTrue(bodyAsString.contains("PUT Employees('2')/EmployeeName HTTP/1.1"));
+ assertTrue(bodyAsString.contains("GET Employees('2')/EmployeeName/$value HTTP/1.1"));
+ assertTrue(bodyAsString.contains("content-type: application/json;odata=verbose"));
+
+ HttpResponse batchResponse = execute(bodyAsString);
+ InputStream responseBody = batchResponse.getEntity().getContent();
+ String contentType = batchResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(responseBody, contentType);
+ for (BatchSingleResponse response : responses) {
+ if ("204".equals(response.getStatusCode())) {
+ assertEquals("No Content", response.getStatusInfo());
+ } else if ("200".equals(response.getStatusCode())) {
+ assertEquals("OK", response.getStatusInfo());
+ assertTrue(response.getBody().contains("Frederic Fall MODIFIED"));
+ } else {
+ fail();
+ }
+ }
+
+ }
+
+ @Test
+ public void testContentIdReferencing() throws Exception {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ Map<String, String> changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/octet-stream");
+ changeSetHeaders.put("Accept", "application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1");
+ BatchChangeSetPart changeRequest = BatchChangeSetPart.method(POST)
+ .uri("Employees")
+ .contentId("1")
+ .body("gAAAAgABwESAAMAAAABAAEA")
+ .headers(changeSetHeaders)
+ .build();
+ changeSet.add(changeRequest);
+
+ changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/json;odata=verbose");
+ BatchChangeSetPart changeRequest2 = BatchChangeSetPart.method(PUT)
+ .uri("$1/EmployeeName")
+ .contentId("2")
+ .body("{\"EmployeeName\":\"Frederic Fall MODIFIED\"}")
+ .headers(changeSetHeaders)
+ .build();
+ changeSet.add(changeRequest2);
+ batch.add(changeSet);
+
+ Map<String, String> getRequestHeaders = new HashMap<String, String>();
+ getRequestHeaders.put("content-id", "3");
+ BatchPart request = BatchQueryPart.method(GET)
+ .uri("Employees('7')/EmployeeName")
+ .contentId("3")
+ .headers(getRequestHeaders).build();
+ batch.add(request);
+
+ InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
+ String bodyAsString = StringHelper.inputStreamToString(body, true);
+ checkMimeHeaders(bodyAsString);
+ checkBoundaryDelimiters(bodyAsString);
+ assertTrue(bodyAsString.contains("POST Employees HTTP/1.1"));
+ assertTrue(bodyAsString.contains("PUT $1/EmployeeName"));
+ assertTrue(bodyAsString.contains("GET Employees('7')/EmployeeName HTTP/1.1"));
+
+ HttpResponse batchResponse = execute(bodyAsString);
+ InputStream responseBody = batchResponse.getEntity().getContent();
+ String contentType = batchResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(responseBody, contentType);
+ for (BatchSingleResponse response : responses) {
+ if ("1".equals(response.getContentId())) {
+ assertEquals("201", response.getStatusCode());
+ assertEquals("Created", response.getStatusInfo());
+ } else if ("2".equals(response.getContentId())) {
+ assertEquals("204", response.getStatusCode());
+ assertEquals("No Content", response.getStatusInfo());
+ } else if ("3".equals(response.getContentId())) {
+ assertEquals("200", response.getStatusCode());
+ assertEquals("OK", response.getStatusInfo());
+ } else {
+ fail();
+ }
+ }
+ }
+
+ @Test
+ public void testErrorBatch() throws Exception {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ BatchPart request = BatchQueryPart.method(GET)
+ .uri("nonsense")
+ .build();
+ batch.add(request);
+
+ InputStream body = EntityProvider.writeBatchRequest(batch, BOUNDARY);
+ String bodyAsString = StringHelper.inputStreamToString(body, true);
+ checkMimeHeaders(bodyAsString);
+ checkBoundaryDelimiters(bodyAsString);
+
+ assertTrue(bodyAsString.contains("GET nonsense HTTP/1.1"));
+ HttpResponse batchResponse = execute(bodyAsString);
+ InputStream responseBody = batchResponse.getEntity().getContent();
+ String contentType = batchResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE).getValue();
+ List<BatchSingleResponse> responses = EntityProvider.parseBatchResponse(responseBody, contentType);
+ for (BatchSingleResponse response : responses) {
+ assertEquals("404", response.getStatusCode());
+ assertEquals("Not Found", response.getStatusInfo());
+ }
+ }
+
+ private HttpResponse execute(final String body) throws Exception {
+ final HttpPost post = new HttpPost(URI.create(getEndpoint().toString() + "$batch"));
+
+ post.setHeader("Content-Type", "multipart/mixed;boundary=" + BOUNDARY);
+ HttpEntity entity = new StringEntity(body);
+ post.setEntity(entity);
+ HttpResponse response = getHttpClient().execute(post);
+
+ assertNotNull(response);
+ assertEquals(202, response.getStatusLine().getStatusCode());
+
+ return response;
+ }
+
+ private void checkMimeHeaders(final String requestBody) {
+ assertTrue(requestBody.contains("Content-Type: application/http"));
+ assertTrue(requestBody.contains("Content-Transfer-Encoding: binary"));
+ }
+
+ private void checkBoundaryDelimiters(final String requestBody) {
+ assertTrue(requestBody.contains("--" + BOUNDARY));
+ assertTrue(requestBody.contains("--" + BOUNDARY + "--"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
----------------------------------------------------------------------
diff --git a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
index 1614b5c..845c4e5 100644
--- a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
+++ b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/BatchTest.java
@@ -91,7 +91,7 @@ public class BatchTest extends AbstractRefTest {
assertNotNull(response);
assertEquals(202, response.getStatusLine().getStatusCode());
- String responseBody = StringHelper.inputStreamToString(response.getEntity().getContent());
+ String responseBody = StringHelper.inputStreamToString(response.getEntity().getContent(), true);
return responseBody;
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonChangeTest.java
----------------------------------------------------------------------
diff --git a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonChangeTest.java b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonChangeTest.java
index 770372f..2f9be76 100644
--- a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonChangeTest.java
+++ b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonChangeTest.java
@@ -22,10 +22,10 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import org.apache.http.HttpResponse;
-import org.junit.Test;
-
import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
+import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
+import org.junit.Test;
/**
* Tests employing the reference scenario changing entities in JSON format.
@@ -46,6 +46,14 @@ public class EntryJsonChangeTest extends AbstractRefTest {
}
@Test
+ public void createEntryMinimal() throws Exception {
+ final String requestBody = "{\"Id\":\"99\"}";
+ final HttpResponse response = postUri("Teams()", requestBody, HttpContentType.APPLICATION_JSON, HttpStatusCodes.CREATED);
+ assertFalse(getBody(response).isEmpty());
+ checkUri("Teams('4')?$format=json");
+ }
+
+ @Test
public void createEntryWithNavigation() throws Exception {
final String requestBody = "{\"Id\":\"199\",\"Name\":\"Room 199\"}";
final HttpResponse response = postUri("Buildings('1')/nb_Rooms()", requestBody, HttpContentType.APPLICATION_JSON, HttpStatusCodes.CREATED);
@@ -97,6 +105,7 @@ public class EntryJsonChangeTest extends AbstractRefTest {
final String requestBody = "{\"Id\":\"99\",\"Name\":\"Building 4\",\"Image\":null,"
+ "\"nb_Rooms\":[{\"Id\":\"201\",\"Name\":\"Room 201\",\"Seats\":1,\"Version\":1,"
+ "\"nr_Employees\":[{\"EmployeeId\":\"99\",\"EmployeeName\":\"Ms X\",\"Age\":22,"
+ + "\"Location\":{\"City\":{\"PostalCode\":null,\"CityName\":null},\"Country\":null},"
+ "\"EntryDate\":\"\\/Date(1424242424242)\\/\","
+ "\"ne_Manager\":{\"__deferred\":{\"uri\":\"" + getEndpoint() + "Managers('1')\"}}}]}]}";
final HttpResponse response = postUri("Buildings()", requestBody, HttpContentType.APPLICATION_JSON, HttpStatusCodes.CREATED);
@@ -113,8 +122,22 @@ public class EntryJsonChangeTest extends AbstractRefTest {
+ "\"RoomId\":\"1\",\"TeamId\":\"1\","
+ "\"Location\":{\"City\":{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},"
+ " \"Country\":\"Germany\"},"
- + "\"Age\":52,\"EntryDate\":null,\"ImageUrl\":\"http://some.host:80/image.url\"}";
+ + "\"EntryDate\":null,\"ImageUrl\":\"http://some.host:80/image.url\"}";
putUri("Employees('2')", requestBody, HttpContentType.APPLICATION_JSON, HttpStatusCodes.NO_CONTENT);
assertEquals("Mister X", getBody(callUri("Employees('2')/EmployeeName/$value")));
+ assertEquals("0", getBody(callUri("Employees('2')/Age/$value")));
+ assertEquals("{\"d\":{\"EntryDate\":null}}", getBody(callUri("Employees('2')/EntryDate?$format=json")));
+ }
+
+ @Test
+ public void patchEntry() throws Exception {
+ final String requestBody = "{\"Location\":"
+ + "{\"City\":{\"PostalCode\":\"69124\",\"CityName\":\"" + CITY_1_NAME + "\"},"
+ + " \"Country\":\"Germany\"},\"EntryDate\":null}";
+ callUri(ODataHttpMethod.PATCH, "Employees('2')", null, null, requestBody, HttpContentType.APPLICATION_JSON, HttpStatusCodes.NO_CONTENT);
+ assertEquals(CITY_1_NAME, getBody(callUri("Employees('2')/Location/City/CityName/$value")));
+ assertEquals("{\"d\":{\"EntryDate\":null}}", getBody(callUri("Employees('2')/EntryDate?$format=json")));
+ assertEquals(EMPLOYEE_2_NAME, getBody(callUri("Employees('2')/EmployeeName/$value")));
+ assertEquals(EMPLOYEE_2_AGE, getBody(callUri("Employees('2')/Age/$value")));
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonCreateInlineTest.java
----------------------------------------------------------------------
diff --git a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonCreateInlineTest.java b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonCreateInlineTest.java
index 7609d00..6dea2f0 100644
--- a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonCreateInlineTest.java
+++ b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryJsonCreateInlineTest.java
@@ -288,6 +288,8 @@ public class EntryJsonCreateInlineTest extends AbstractRefJsonTest {
+ "\"RoomId\": \"1\","
+ "\"TeamId\": \"1\","
+ "\"Age\": 52,"
+ + "\"Location\":{\"City\":{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},"
+ + " \"Country\":\"Germany\"},"
+ "\"ImageUrl\": \"" + getEndpoint() + "Employees('1')/$value\"}]},"
+ "\"nr_Building\":{\"__deferred\":{\"uri\":\"" + getEndpoint() + "Rooms('1')/nr_Building\"}}}}";
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlChangeTest.java
----------------------------------------------------------------------
diff --git a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlChangeTest.java b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlChangeTest.java
index d2407ba..752feb2 100644
--- a/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlChangeTest.java
+++ b/odata-fit/src/test/java/org/apache/olingo/odata2/fit/ref/EntryXmlChangeTest.java
@@ -19,12 +19,12 @@
package org.apache.olingo.odata2.fit.ref;
import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo;
+import static org.custommonkey.xmlunit.XMLAssert.assertXpathExists;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import org.apache.http.HttpResponse;
-import org.custommonkey.xmlunit.XMLAssert;
import org.junit.Test;
import org.apache.olingo.odata2.api.commons.HttpContentType;
@@ -89,9 +89,9 @@ public class EntryXmlChangeTest extends AbstractRefXmlTest {
@Test
public void createWithLargeProperty() throws Exception {
- String largeTeamName = StringHelper.generateData(888888);
+ final String largeTeamName = StringHelper.generateData(888888);
// Create an entry for a type that has no media resource.
- String requestBody = getBody(callUri("Teams('1')"))
+ final String requestBody = getBody(callUri("Teams('1')"))
.replace("'1'", "'9'")
.replace("Id>1", "Id>9")
.replace("Team 1", largeTeamName)
@@ -105,6 +105,19 @@ public class EntryXmlChangeTest extends AbstractRefXmlTest {
}
@Test
+ public void createMinimal() throws Exception {
+ final String requestBody = "<entry xmlns=\"" + Edm.NAMESPACE_ATOM_2005 + "\"" + "\n"
+ + " xmlns:d=\"" + Edm.NAMESPACE_D_2007_08 + "\"" + "\n"
+ + " xmlns:m=\"" + Edm.NAMESPACE_M_2007_08 + "\">" + "\n"
+ + " <content><m:properties><d:Id>99</d:Id></m:properties></content>" + "\n"
+ + "</entry>";
+
+ final HttpResponse response = postUri("Teams()", requestBody, HttpContentType.APPLICATION_ATOM_XML_ENTRY, HttpStatusCodes.CREATED);
+ checkMediaType(response, HttpContentType.APPLICATION_ATOM_XML_UTF8 + ";type=entry");
+ assertEquals(getEndpoint() + "Teams('4')", response.getFirstHeader(HttpHeaders.LOCATION).getValue());
+ }
+
+ @Test
public void createInvalidXml() throws Exception {
getBody(callUri("Employees('7')", HttpStatusCodes.NOT_FOUND));
@@ -207,24 +220,30 @@ public class EntryXmlChangeTest extends AbstractRefXmlTest {
@Test
public void update() throws Exception {
- final String requestBody = getBody(callUri("Employees('1')"))
- .replace("'1'", "'9'")
- .replace("EmployeeId>1", "EmployeeId>9")
- .replace(EMPLOYEE_1_NAME, "Mister X")
+ final String requestBody = getBody(callUri("Employees('2')"))
+ .replace("'2'", "'9'")
+ .replace("EmployeeId>2", "EmployeeId>9")
+ .replace(EMPLOYEE_2_NAME, "Mister X")
+ .replace("<d:Age>" + EMPLOYEE_2_AGE + "</d:Age>", "")
+ .replace(">2003-07-01T00:00:00", " m:null='true'>")
.replaceAll("<link.+?/>", "");
- final HttpResponse response = callUri(ODataHttpMethod.PUT, "Employees('2')", null, null, requestBody, HttpContentType.APPLICATION_ATOM_XML_ENTRY, HttpStatusCodes.NO_CONTENT);
+ final HttpResponse response = callUri(ODataHttpMethod.PUT, "Employees('1')", null, null, requestBody, HttpContentType.APPLICATION_ATOM_XML_ENTRY, HttpStatusCodes.NO_CONTENT);
assertFalse(response.containsHeader(HttpHeaders.LOCATION));
- assertXpathEvaluatesTo("Mister X", "/atom:entry/m:properties/d:EmployeeName", getBody(callUri("Employees('2')")));
+ final String body = getBody(callUri("Employees('1')"));
+ assertXpathEvaluatesTo("Mister X", "/atom:entry/m:properties/d:EmployeeName", body);
+ assertXpathEvaluatesTo("0", "/atom:entry/m:properties/d:Age", body);
+ assertXpathEvaluatesTo("true", "/atom:entry/m:properties/d:EntryDate/@m:null", body);
}
@Test
public void updateUnknownProperty() throws Exception {
- final String requestBody = getBody(callUri("Employees('1')"))
- .replace("<d:Age>52</d:Age>", "<d:Age>33</d:Age><d:SomeUnknownTag>SomeUnknownValue</d:SomeUnknownTag>");
+ final String requestBody = getBody(callUri("Employees('2')"))
+ .replace("<d:Age>" + EMPLOYEE_2_AGE + "</d:Age>",
+ "<d:Age>33</d:Age><d:SomeUnknownTag>SomeUnknownValue</d:SomeUnknownTag>");
- putUri("Employees('1')", requestBody, HttpContentType.APPLICATION_ATOM_XML_ENTRY, HttpStatusCodes.BAD_REQUEST);
+ putUri("Employees('2')", requestBody, HttpContentType.APPLICATION_ATOM_XML_ENTRY, HttpStatusCodes.BAD_REQUEST);
// check nothing has changed
- assertXpathEvaluatesTo("52", "/atom:entry/m:properties/d:Age", getBody(callUri("Employees('1')")));
+ assertXpathEvaluatesTo(EMPLOYEE_2_AGE, "/atom:entry/m:properties/d:Age", getBody(callUri("Employees('2')")));
}
@Test
@@ -254,7 +273,9 @@ public class EntryXmlChangeTest extends AbstractRefXmlTest {
+ " </m:properties>" + "\n"
+ "</entry>";
callUri(ODataHttpMethod.PATCH, "Employees('2')", null, null, requestBody, HttpContentType.APPLICATION_ATOM_XML_ENTRY, HttpStatusCodes.NO_CONTENT);
- assertXpathEvaluatesTo(CITY_1_NAME, "/atom:entry/m:properties/d:Location/d:City/d:CityName", getBody(callUri("Employees('2')")));
+ final String body = getBody(callUri("Employees('2')"));
+ assertXpathEvaluatesTo(CITY_1_NAME, "/atom:entry/m:properties/d:Location/d:City/d:CityName", body);
+ assertXpathEvaluatesTo(EMPLOYEE_2_AGE, "/atom:entry/m:properties/d:Age", body);
requestBody = "<entry xmlns=\"" + Edm.NAMESPACE_ATOM_2005 + "\">" + "\n"
+ " <content xmlns:d=\"" + Edm.NAMESPACE_D_2007_08 + "\"" + "\n"
@@ -272,9 +293,9 @@ public class EntryXmlChangeTest extends AbstractRefXmlTest {
public void delete() throws Exception {
final String uri = "Employees('2')";
deleteUriOk(uri);
- final String requestBody = getBody(callUri(uri, HttpStatusCodes.NOT_FOUND));
- XMLAssert.assertXpathExists("/m:error", requestBody);
+ final String requestBody = getBody(callUri(uri, HttpStatusCodes.NOT_FOUND));
+ assertXpathExists("/m:error", requestBody);
assertXpathEvaluatesTo("Requested entity could not be found.", "/m:error/m:message", requestBody);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-ref/src/main/java/org/apache/olingo/odata2/ref/edm/ScenarioEdmProvider.java
----------------------------------------------------------------------
diff --git a/odata-ref/src/main/java/org/apache/olingo/odata2/ref/edm/ScenarioEdmProvider.java b/odata-ref/src/main/java/org/apache/olingo/odata2/ref/edm/ScenarioEdmProvider.java
index 70509d0..650125e 100644
--- a/odata-ref/src/main/java/org/apache/olingo/odata2/ref/edm/ScenarioEdmProvider.java
+++ b/odata-ref/src/main/java/org/apache/olingo/odata2/ref/edm/ScenarioEdmProvider.java
@@ -326,7 +326,7 @@ public class ScenarioEdmProvider extends EdmProvider {
if (NAMESPACE_1.equals(edmFQName.getNamespace())) {
if (COMPLEX_TYPE_1.getName().equals(edmFQName.getName())) {
List<Property> properties = new ArrayList<Property>();
- properties.add(new ComplexProperty().setName("City").setType(COMPLEX_TYPE_2));
+ properties.add(new ComplexProperty().setName("City").setType(COMPLEX_TYPE_2).setFacets(new Facets().setNullable(false)));
properties.add(new SimpleProperty().setName("Country").setType(EdmSimpleTypeKind.String));
return new ComplexType().setName(COMPLEX_TYPE_1.getName()).setProperties(properties);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java
----------------------------------------------------------------------
diff --git a/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java b/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java
index f93b26d..8534381 100644
--- a/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java
+++ b/odata-ref/src/main/java/org/apache/olingo/odata2/ref/processor/ListsProcessor.java
@@ -33,7 +33,7 @@ import java.util.Map;
import org.apache.olingo.odata2.api.ODataCallback;
import org.apache.olingo.odata2.api.batch.BatchHandler;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
@@ -348,12 +348,12 @@ public class ListsProcessor extends ODataSingleProcessor {
} else {
final EntityProviderReadProperties properties = EntityProviderReadProperties.init()
- .mergeSemantic(true)
+ .mergeSemantic(false)
.addTypeMappings(getStructuralTypeTypeMap(data, entityType))
.build();
final ODataEntry entryValues = parseEntry(entitySet, content, requestContentType, properties);
- setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), true);
+ setStructuralTypeValuesFromMap(data, entityType, entryValues.getProperties(), false);
dataSource.createData(entitySet, data);
@@ -1104,7 +1104,7 @@ public class ListsProcessor extends ODataSingleProcessor {
final List<ODataEntry> relatedValueList = feed.getEntries();
for (final ODataEntry relatedValues : relatedValueList) {
Object relatedData = dataSource.newDataObject(relatedEntitySet);
- setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValues.getProperties(), true);
+ setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValues.getProperties(), false);
dataSource.createData(relatedEntitySet, relatedData);
dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData, relatedEntityType));
createInlinedEntities(relatedEntitySet, relatedData, relatedValues);
@@ -1112,7 +1112,7 @@ public class ListsProcessor extends ODataSingleProcessor {
} else if (relatedValue instanceof ODataEntry) {
final ODataEntry relatedValueEntry = (ODataEntry) relatedValue;
Object relatedData = dataSource.newDataObject(relatedEntitySet);
- setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValueEntry.getProperties(), true);
+ setStructuralTypeValuesFromMap(relatedData, relatedEntityType, relatedValueEntry.getProperties(), false);
dataSource.createData(relatedEntitySet, relatedData);
dataSource.writeRelation(entitySet, data, relatedEntitySet, getStructuralTypeValueMap(relatedData, relatedEntityType));
createInlinedEntities(relatedEntitySet, relatedData, relatedValueEntry);
@@ -1539,15 +1539,12 @@ public class ListsProcessor extends ODataSingleProcessor {
if (type instanceof EdmEntityType && ((EdmEntityType) type).getKeyProperties().contains(property)) {
continue;
}
- if (property.isSimple()) {
- final Object value = valueMap.get(propertyName);
- if (value != null || !merge) {
- setPropertyValue(data, property, value);
- }
- } else {
- @SuppressWarnings("unchecked")
- final Map<String, Object> values = (Map<String, Object>) valueMap.get(propertyName);
- if (values != null || !merge) {
+ if (!merge || valueMap.containsKey(propertyName)) {
+ if (property.isSimple()) {
+ setPropertyValue(data, property, valueMap.get(propertyName));
+ } else {
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> values = (Map<String, Object>) valueMap.get(propertyName);
setStructuralTypeValuesFromMap(getPropertyValue(data, property), (EdmStructuralType) property.getType(), values, merge);
}
}
@@ -1658,8 +1655,8 @@ public class ListsProcessor extends ODataSingleProcessor {
List<BatchResponsePart> batchResponseParts = new ArrayList<BatchResponsePart>();
PathInfo pathInfo = getContext().getPathInfo();
EntityProviderBatchProperties batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build();
- List<BatchPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
- for (BatchPart batchPart : batchParts) {
+ List<BatchRequestPart> batchParts = EntityProvider.parseBatchRequest(contentType, content, batchProperties);
+ for (BatchRequestPart batchPart : batchParts) {
batchResponseParts.add(handler.handleBatchPart(batchPart));
}
batchResponse = EntityProvider.writeBatchResponse(batchResponseParts);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/helper/StringHelper.java
----------------------------------------------------------------------
diff --git a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/helper/StringHelper.java b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/helper/StringHelper.java
index cc2d3e0..bf2e24e 100644
--- a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/helper/StringHelper.java
+++ b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/helper/StringHelper.java
@@ -25,6 +25,7 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
+import java.util.Random;
import org.apache.http.HttpEntity;
@@ -100,15 +101,15 @@ public class StringHelper {
}
/**
- * Generate a string with given length containing random upper case characters ([A-Z]).
- *
- * @param len length of to generated string
- * @return random upper case characters ([A-Z]).
+ * Generates a string with given length containing random upper case characters ([A-Z]).
+ * @param len length of the generated string
+ * @return random upper case characters ([A-Z])
*/
public static String generateData(final int len) {
+ Random random = new Random();
StringBuilder b = new StringBuilder(len);
for (int j = 0; j < len; j++) {
- char c = (char) (Math.random() * 26 + 65);
+ final char c = (char) ('A' + random.nextInt('Z' - 'A' + 1));
b.append(c);
}
return b.toString();
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/EdmMock.java
----------------------------------------------------------------------
diff --git a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/EdmMock.java b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/EdmMock.java
index 005bb13..9ffe44a 100644
--- a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/EdmMock.java
+++ b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/EdmMock.java
@@ -148,6 +148,7 @@ class EdmMock {
EdmProperty roomVersion = createProperty("Version", EdmSimpleTypeKind.Int16, roomType);
EdmFacets roomVersionFacets = mock(EdmFacets.class);
when(roomVersionFacets.getConcurrencyMode()).thenReturn(EdmConcurrencyMode.Fixed);
+ when(roomVersionFacets.isNullable()).thenReturn(null);
when(roomVersion.getFacets()).thenReturn(roomVersionFacets);
when(roomType.getNavigationPropertyNames()).thenReturn(Arrays.asList("nr_Employees", "nr_Building"));
createNavigationProperty("nr_Employees", EdmMultiplicity.MANY, roomEntitySet, employeeEntitySet);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TecEdmInfo.java
----------------------------------------------------------------------
diff --git a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TecEdmInfo.java b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TecEdmInfo.java
index acaf2ad..92733af 100644
--- a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TecEdmInfo.java
+++ b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TecEdmInfo.java
@@ -37,7 +37,10 @@ public class TecEdmInfo {
public EdmEntityType getTypeEtAllTypes() {
try {
- return edm.getEntityContainer(TechnicalScenarioEdmProvider.ENTITY_CONTAINER_1).getEntitySet(TechnicalScenarioEdmProvider.ES_ALL_TYPES).getEntityType();
+ return edm
+ .getEntityContainer(TechnicalScenarioEdmProvider.ENTITY_CONTAINER_1)
+ .getEntitySet(TechnicalScenarioEdmProvider.ES_ALL_TYPES)
+ .getEntityType();
} catch (final EdmException e) {
fail("Error in test setup" + e.getLocalizedMessage());
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TechnicalScenarioEdmProvider.java
----------------------------------------------------------------------
diff --git a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TechnicalScenarioEdmProvider.java b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TechnicalScenarioEdmProvider.java
index 8708fd4..703a068 100644
--- a/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TechnicalScenarioEdmProvider.java
+++ b/odata-testutil/src/main/java/org/apache/olingo/odata2/testutil/mock/TechnicalScenarioEdmProvider.java
@@ -80,13 +80,22 @@ public class TechnicalScenarioEdmProvider extends EdmProvider {
final Schema schema = new Schema();
schema.setNamespace(NAMESPACE_1);
- schema.setEntityTypes(Arrays.asList(getEntityType(ET_KEY_IS_STRING), getEntityType(ET_KEY_IS_INTEGER), getEntityType(ET_COMPLEX_KEY), getEntityType(ET_ALL_TYPES)));
+ schema.setEntityTypes(Arrays.asList(
+ getEntityType(ET_KEY_IS_STRING),
+ getEntityType(ET_KEY_IS_INTEGER),
+ getEntityType(ET_COMPLEX_KEY),
+ getEntityType(ET_ALL_TYPES)));
schema.setComplexTypes(Arrays.asList(getComplexType(CT_ALL_TYPES)));
final EntityContainer entityContainer = new EntityContainer();
entityContainer.setName(ENTITY_CONTAINER_1).setDefaultEntityContainer(true);
- entityContainer.setEntitySets(Arrays.asList(getEntitySet(ENTITY_CONTAINER_1, ES_KEY_IS_STRING), getEntitySet(ENTITY_CONTAINER_1, ES_KEY_IS_INTEGER), getEntitySet(ENTITY_CONTAINER_1, ES_COMPLEX_KEY), getEntitySet(ENTITY_CONTAINER_1, ES_ALL_TYPES), getEntitySet(ENTITY_CONTAINER_1, ES_STRING_FACETS)));
+ entityContainer.setEntitySets(Arrays.asList(
+ getEntitySet(ENTITY_CONTAINER_1, ES_KEY_IS_STRING),
+ getEntitySet(ENTITY_CONTAINER_1, ES_KEY_IS_INTEGER),
+ getEntitySet(ENTITY_CONTAINER_1, ES_COMPLEX_KEY),
+ getEntitySet(ENTITY_CONTAINER_1, ES_ALL_TYPES),
+ getEntitySet(ENTITY_CONTAINER_1, ES_STRING_FACETS)));
schema.setEntityContainers(Arrays.asList(entityContainer));
@@ -98,7 +107,9 @@ public class TechnicalScenarioEdmProvider extends EdmProvider {
if (NAMESPACE_1.equals(edmFQName.getNamespace())) {
if (ET_KEY_IS_STRING.getName().equals(edmFQName.getName())) {
final List<Property> properties = new ArrayList<Property>();
- properties.add(new SimpleProperty().setName("KeyString").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setNullable(false)));
+ properties.add(new SimpleProperty().setName("KeyString")
+ .setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setNullable(false)));
final List<NavigationProperty> navigationProperties = new ArrayList<NavigationProperty>();
@@ -107,7 +118,9 @@ public class TechnicalScenarioEdmProvider extends EdmProvider {
return new EntityType().setName(ET_KEY_IS_STRING.getName()).setProperties(properties).setNavigationProperties(navigationProperties).setKey(createKey("KeyString"));
} else if (ET_KEY_IS_INTEGER.getName().equals(edmFQName.getName())) {
final List<Property> properties = new ArrayList<Property>();
- properties.add(new SimpleProperty().setName("KeyInteger").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setNullable(false)));
+ properties.add(new SimpleProperty().setName("KeyInteger")
+ .setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setNullable(false)));
final List<NavigationProperty> navigationProperties = new ArrayList<NavigationProperty>();
navigationProperties.add(new NavigationProperty().setName("navProperty").setFromRole(ROLE_2).setToRole(ROLE_1).setRelationship(ASSOCIATION_ET1_ET2));
@@ -116,8 +129,12 @@ public class TechnicalScenarioEdmProvider extends EdmProvider {
} else if (ET_COMPLEX_KEY.getName().equals(edmFQName.getName())) {
final List<Property> properties = new ArrayList<Property>();
- properties.add(new SimpleProperty().setName("KeyString").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setNullable(false)));
- properties.add(new SimpleProperty().setName("KeyInteger").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setNullable(false)));
+ properties.add(new SimpleProperty().setName("KeyString")
+ .setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setNullable(false)));
+ properties.add(new SimpleProperty().setName("KeyInteger")
+ .setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setNullable(false)));
return new EntityType().setName(ET_COMPLEX_KEY.getName()).setProperties(properties).setKey(createKey("KeyInteger", "KeyString"));
} else if (ET_ALL_TYPES.getName().equals(edmFQName.getName())) {
@@ -142,17 +159,23 @@ public class TechnicalScenarioEdmProvider extends EdmProvider {
} else if (ET_STRING_FACETS.getName().equals(edmFQName.getName())) {
final List<Property> properties = new ArrayList<Property>();
- properties.add(new SimpleProperty().setName("StringDefaultValue").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setDefaultValue("defaultValue")));
+ properties.add(new SimpleProperty().setName("StringDefaultValue").setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setDefaultValue("defaultValue")));
- properties.add(new SimpleProperty().setName("StringFixedLength").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setFixedLength(true)));
+ properties.add(new SimpleProperty().setName("StringFixedLength").setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setFixedLength(true)));
- properties.add(new SimpleProperty().setName("StringMaxLength").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setMaxLength(15)));
+ properties.add(new SimpleProperty().setName("StringMaxLength").setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setMaxLength(15)));
- properties.add(new SimpleProperty().setName("StringLength").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setMaxLength(15).setFixedLength(true)));
+ properties.add(new SimpleProperty().setName("StringLength").setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setMaxLength(15).setFixedLength(true)));
- properties.add(new SimpleProperty().setName("StringNullable").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setNullable(false)));
+ properties.add(new SimpleProperty().setName("StringNullable").setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setNullable(false)));
- properties.add(new SimpleProperty().setName("StringUnicode").setType(EdmSimpleTypeKind.String).setFacets(new Facets().setUnicode(false)));
+ properties.add(new SimpleProperty().setName("StringUnicode").setType(EdmSimpleTypeKind.String)
+ .setFacets(new Facets().setUnicode(false)));
return new EntityType().setName(ET_STRING_FACETS.getName()).setProperties(properties);
}
[2/4] Batch Support, Validation in Deserialization
Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
index cb2f420..b0babf7 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java
@@ -30,11 +30,8 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
import org.apache.olingo.odata2.api.batch.BatchException;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
@@ -42,24 +39,27 @@ import org.apache.olingo.odata2.api.processor.ODataRequest;
import org.apache.olingo.odata2.core.ODataPathSegmentImpl;
import org.apache.olingo.odata2.core.PathInfoImpl;
import org.apache.olingo.odata2.testutil.helper.StringHelper;
+import org.junit.BeforeClass;
+import org.junit.Test;
/**
*
*/
public class BatchRequestParserTest {
+ private static final String LF = "\r\n";
private static final String CONTENT_ID_REFERENCE = "NewEmployee";
private static final String PUT_MIME_HEADER_CONTENT_ID = "BBB_MIMEPART1";
private static final String PUT_REQUEST_HEADER_CONTENT_ID = "BBB_REQUEST1";
private static final String SERVICE_ROOT = "http://localhost/odata/";
private static EntityProviderBatchProperties batchProperties;
private static final String contentType = "multipart/mixed;boundary=batch_8194-cf13-1f56";
- private static final String MIME_HEADERS = "Content-Type: application/http" + "\r\n"
- + "Content-Transfer-Encoding: binary" + "\r\n";
- private static final String GET_REQUEST = MIME_HEADERS + "\n"
- + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
- + "\n";
+ private static final String MIME_HEADERS = "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF;
+ private static final String GET_REQUEST = MIME_HEADERS + LF
+ + "GET Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ + LF;
@BeforeClass
public static void setProperties() throws URISyntaxException {
@@ -78,10 +78,10 @@ public class BatchRequestParserTest {
}
BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
- List<BatchPart> batchParts = parser.parse(in);
- assertNotNull(batchParts);
- assertEquals(false, batchParts.isEmpty());
- for (BatchPart object : batchParts) {
+ List<BatchRequestPart> batchRequestParts = parser.parse(in);
+ assertNotNull(batchRequestParts);
+ assertEquals(false, batchRequestParts.isEmpty());
+ for (BatchRequestPart object : batchRequestParts) {
if (!object.isChangeSet()) {
assertEquals(1, object.getRequests().size());
ODataRequest retrieveRequest = object.getRequests().get(0);
@@ -128,34 +128,34 @@ public class BatchRequestParserTest {
throw new IOException("Requested file '" + fileName + "' was not found.");
}
String content = StringHelper.inputStreamToString(contentInputStream);
- String batch = "\r\n"
- + "--batch_8194-cf13-1f56" + "\r" + "\n"
- + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\r\n"
- + "\r\n"
- + "--changeset_f980-1cb6-94dd" + "\r\n"
- + "content-type: Application/http" + "\r\n"
- + "content-transfer-encoding: Binary" + "\r\n"
- + "Content-ID: 1" + "\r\n"
- + "\r\n"
- + "POST Employees HTTP/1.1" + "\r\n"
- + "Content-length: 100000" + "\r\n"
- + "Content-type: application/octet-stream" + "\r\n"
- + "\r\n"
- + content + "\r\n"
- + "\r\n"
- + "--changeset_f980-1cb6-94dd--" + "\r\n"
- + "\r\n"
- + "--batch_8194-cf13-1f56" + "\r\n"
+ String batch = LF
+ + "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd" + LF
+ + "content-type: Application/http" + LF
+ + "content-transfer-encoding: Binary" + LF
+ + "Content-ID: 1" + LF
+ + LF
+ + "POST Employees HTTP/1.1" + LF
+ + "Content-length: 100000" + LF
+ + "Content-type: application/octet-stream" + LF
+ + LF
+ + content + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd--" + LF
+ + LF
+ + "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\r\n"
- + "GET Employees?$filter=Age%20gt%2040 HTTP/1.1" + "\r\n"
- + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + "\r\n"
- + "MaxDataServiceVersion: 2.0" + "\r\n"
- + "\r\n"
- + "\r\n"
+ + LF
+ + "GET Employees?$filter=Age%20gt%2040 HTTP/1.1" + LF
+ + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + LF
+ + "MaxDataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
- List<BatchPart> batchParts = parse(batch);
- for (BatchPart object : batchParts) {
+ List<BatchRequestPart> BatchRequestParts = parse(batch);
+ for (BatchRequestPart object : BatchRequestParts) {
if (!object.isChangeSet()) {
assertEquals(1, object.getRequests().size());
ODataRequest retrieveRequest = object.getRequests().get(0);
@@ -167,7 +167,7 @@ public class BatchRequestParserTest {
for (ODataRequest request : requests) {
assertEquals(ODataHttpMethod.POST, request.getMethod());
assertEquals("100000", request.getRequestHeaderValue(HttpHeaders.CONTENT_LENGTH.toLowerCase()));
- assertEquals("1", request.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase()));
+ assertEquals("1", request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase()));
assertEquals("application/octet-stream", request.getContentType());
InputStream body = request.getBody();
assertEquals(content, StringHelper.inputStreamToString(body));
@@ -186,23 +186,23 @@ public class BatchRequestParserTest {
throw new IOException("Requested file '" + fileName + "' was not found.");
}
StringHelper.inputStreamToString(contentInputStream);
- String batch = "\r\n"
- + "--batch_8194-cf13-1f56" + "\r" + "\n"
- + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\r\n"
- + "\r\n"
- + "--changeset_f980-1cb6-94dd" + "\r\n"
+ String batch = LF
+ + "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd" + LF
+ MIME_HEADERS
- + "\r\n"
- + "POST Employees('2') HTTP/1.1" + "\r\n"
- + "Content-Length: 100" + "\r\n"
- + "Content-Type: application/octet-stream" + "\r\n"
- + "\r\n"
- + "\r\n"
- + "--changeset_f980-1cb6-94dd--" + "\r\n"
- + "\r\n"
+ + LF
+ + "POST Employees('2') HTTP/1.1" + LF
+ + "Content-Length: 100" + LF
+ + "Content-Type: application/octet-stream" + LF
+ + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd--" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
- List<BatchPart> batchParts = parse(batch);
- for (BatchPart object : batchParts) {
+ List<BatchRequestPart> batchRequestParts = parse(batch);
+ for (BatchRequestPart object : batchRequestParts) {
if (object.isChangeSet()) {
List<ODataRequest> requests = object.getRequests();
for (ODataRequest request : requests) {
@@ -219,21 +219,21 @@ public class BatchRequestParserTest {
public void testBoundaryParameterWithQuotas() throws BatchException {
String contentType = "multipart/mixed; boundary=\"batch_1.2+34:2j)0?\"";
- String batch = "--batch_1.2+34:2j)0?" + "\n"
+ String batch = "--batch_1.2+34:2j)0?" + LF
+ GET_REQUEST
+ "--batch_1.2+34:2j)0?--";
InputStream in = new ByteArrayInputStream(batch.getBytes());
BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
- List<BatchPart> batchParts = parser.parse(in);
- assertNotNull(batchParts);
- assertEquals(false, batchParts.isEmpty());
+ List<BatchRequestPart> batchRequestParts = parser.parse(in);
+ assertNotNull(batchRequestParts);
+ assertEquals(false, batchRequestParts.isEmpty());
}
@Test(expected = BatchException.class)
public void testBatchWithInvalidContentType() throws BatchException {
String invalidContentType = "multipart;boundary=batch_1740-bb84-2f7f";
- String batch = "--batch_1740-bb84-2f7f" + "\n"
+ String batch = "--batch_1740-bb84-2f7f" + LF
+ GET_REQUEST
+ "--batch_1740-bb84-2f7f--";
InputStream in = new ByteArrayInputStream(batch.getBytes());
@@ -244,7 +244,7 @@ public class BatchRequestParserTest {
@Test(expected = BatchException.class)
public void testBatchWithoutBoundaryParameter() throws BatchException {
String invalidContentType = "multipart/mixed";
- String batch = "--batch_1740-bb84-2f7f" + "\n"
+ String batch = "--batch_1740-bb84-2f7f" + LF
+ GET_REQUEST
+ "--batch_1740-bb84-2f7f--";
InputStream in = new ByteArrayInputStream(batch.getBytes());
@@ -255,7 +255,7 @@ public class BatchRequestParserTest {
@Test(expected = BatchException.class)
public void testBoundaryParameterWithoutQuota() throws BatchException {
String invalidContentType = "multipart;boundary=batch_1740-bb:84-2f7f";
- String batch = "--batch_1740-bb:84-2f7f" + "\n"
+ String batch = "--batch_1740-bb:84-2f7f" + LF
+ GET_REQUEST
+ "--batch_1740-bb:84-2f7f--";
InputStream in = new ByteArrayInputStream(batch.getBytes());
@@ -265,7 +265,7 @@ public class BatchRequestParserTest {
@Test(expected = BatchException.class)
public void testWrongBoundaryString() throws BatchException {
- String batch = "--batch_8194-cf13-1f5" + "\n"
+ String batch = "--batch_8194-cf13-1f5" + LF
+ GET_REQUEST
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
@@ -273,9 +273,9 @@ public class BatchRequestParserTest {
@Test(expected = BatchException.class)
public void testBoundaryWithoutHyphen() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ GET_REQUEST
- + "batch_8194-cf13-1f56" + "\n"
+ + "batch_8194-cf13-1f56" + LF
+ GET_REQUEST
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
@@ -283,7 +283,7 @@ public class BatchRequestParserTest {
@Test(expected = BatchException.class)
public void testNoBoundaryString() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ GET_REQUEST
//+ no boundary string
+ GET_REQUEST
@@ -293,161 +293,184 @@ public class BatchRequestParserTest {
@Test(expected = BatchException.class)
public void testBatchBoundaryEqualsChangeSetBoundary() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
- + "Content-Type: multipart/mixed;boundary=batch_8194-cf13-1f56" + "\n"
- + "\n"
- + "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: multipart/mixed;boundary=batch_8194-cf13-1f56" + LF
+ + LF
+ + "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "PUT Employees('2')/EmployeeName HTTP/1.1" + "\n"
- + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "MaxDataServiceVersion: 2.0" + "\n"
- + "\n"
- + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + "\n"
- + "\n"
+ + LF
+ + "PUT Employees('2')/EmployeeName HTTP/1.1" + LF
+ + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "MaxDataServiceVersion: 2.0" + LF
+ + LF
+ + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testNoContentType() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
- + "Content-Transfer-Encoding: binary" + "\n"
- + "\n"
- + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "GET Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testMimeHeaderContentType() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
- + "Content-Type: text/plain" + "\n"
- + "Content-Transfer-Encoding: binary" + "\n"
- + "\n"
- + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: text/plain" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "GET Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testMimeHeaderEncoding() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
- + "Content-Type: application/http" + "\n"
- + "Content-Transfer-Encoding: 8bit" + "\n"
- + "\n"
- + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: 8bit" + LF
+ + LF
+ + "GET Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testMimeHeaderContentId() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "Content-ID: 1" + "\n"
- + "\n"
- + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
+ + "Content-ID: 1" + LF
+ + LF
+ + "GET Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testInvalidMethodForBatch() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "POST Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
+ + LF
+ + "POST Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testNoMethod() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + /*GET*/"Employees('1')/EmployeeName HTTP/1.1" + "\n"
- + "\n"
+ + LF
+ + /*GET*/"Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testInvalidMethodForChangeset() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
- + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\n"
- + "\n"
- + "--changeset_f980-1cb6-94dd" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd" + LF
+ MIME_HEADERS
- + "\n"
- + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "MaxDataServiceVersion: 2.0" + "\n"
- + "\n"
+ + LF
+ + "GET Employees('2')/EmployeeName HTTP/1.1" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "MaxDataServiceVersion: 2.0" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testInvalidChangeSetBoundary() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
- + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + "\n"
- + "\n"
- + "--changeset_f980-1cb6-94d"/*+"d"*/+ "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + LF
+ + LF
+ + "--changeset_f980-1cb6-94d"/*+"d"*/+ LF
+ MIME_HEADERS
- + "\n"
- + "POST Employees('2') HTTP/1.1" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "MaxDataServiceVersion: 2.0" + "\n"
- + "\n"
+ + LF
+ + "POST Employees('2') HTTP/1.1" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "MaxDataServiceVersion: 2.0" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testNoCloseDelimiter() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ GET_REQUEST;
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testNoCloseDelimiter2() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "GET Employees('1')/EmployeeName HTTP/1.1" + "\n"
- /*--batch_8194-cf13-1f56--*/;
+ + LF
+ + "GET Employees('1')/EmployeeName HTTP/1.1" + LF;
+ parseInvalidBatchBody(batch);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidUri() throws BatchException {
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + MIME_HEADERS
+ + LF
+ + "GET http://localhost/aa/odata/Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ + LF
+ + "--batch_8194-cf13-1f56--";
+ parseInvalidBatchBody(batch);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testUriWithAbsolutePath() throws BatchException {
+ String batch = "--batch_8194-cf13-1f56" + LF
+ + MIME_HEADERS
+ + LF
+ + "GET /odata/Employees('1')/EmployeeName HTTP/1.1" + LF
+ + LF
+ + LF
+ + "--batch_8194-cf13-1f56--";
parseInvalidBatchBody(batch);
}
@Test(expected = BatchException.class)
public void testNoCloseDelimiter3() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n" + GET_REQUEST + "--batch_8194-cf13-1f56-"/*no hash*/;
+ String batch = "--batch_8194-cf13-1f56" + LF + GET_REQUEST + "--batch_8194-cf13-1f56-"/*no hash*/;
parseInvalidBatchBody(batch);
}
@Test
public void testAcceptHeaders() throws BatchException, URISyntaxException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
- + "Content-Length: 100000" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "Accept: application/xml;q=0.3, application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.001" + "\n"
- + "\n"
- + "\n"
+ + LF
+ + "GET Employees('2')/EmployeeName HTTP/1.1" + LF
+ + "Content-Length: 100000" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "Accept: application/xml;q=0.3, application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.001" + LF
+ + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
- List<BatchPart> batchParts = parse(batch);
- for (BatchPart multipart : batchParts) {
+ List<BatchRequestPart> batchRequestParts = parse(batch);
+ for (BatchRequestPart multipart : batchRequestParts) {
if (!multipart.isChangeSet()) {
assertEquals(1, multipart.getRequests().size());
ODataRequest retrieveRequest = multipart.getRequests().get(0);
@@ -463,18 +486,18 @@ public class BatchRequestParserTest {
@Test
public void testAcceptHeaders2() throws BatchException, URISyntaxException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
- + "Content-Length: 100000" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "Accept: */*;q=0.5, application/json;odata=verbose;q=1.0,application/atom+xml" + "\n"
- + "\n"
- + "\n"
+ + LF
+ + "GET Employees('2')/EmployeeName HTTP/1.1" + LF
+ + "Content-Length: 100000" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "Accept: */*;q=0.5, application/json;odata=verbose;q=1.0,application/atom+xml" + LF
+ + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
- List<BatchPart> batchParts = parse(batch);
- for (BatchPart multipart : batchParts) {
+ List<BatchRequestPart> batchRequestParts = parse(batch);
+ for (BatchRequestPart multipart : batchRequestParts) {
if (!multipart.isChangeSet()) {
assertEquals(1, multipart.getRequests().size());
ODataRequest retrieveRequest = multipart.getRequests().get(0);
@@ -491,18 +514,18 @@ public class BatchRequestParserTest {
@Test
public void testAcceptHeaders3() throws BatchException, URISyntaxException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "GET Employees('2')/EmployeeName HTTP/1.1" + "\n"
- + "Content-Length: 100000" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + "\n"
- + "\n"
- + "\n"
+ + LF
+ + "GET Employees('2')/EmployeeName HTTP/1.1" + LF
+ + "Content-Length: 100000" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + LF
+ + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
- List<BatchPart> batchParts = parse(batch);
- for (BatchPart multipart : batchParts) {
+ List<BatchRequestPart> batchRequestParts = parse(batch);
+ for (BatchRequestPart multipart : batchRequestParts) {
if (!multipart.isChangeSet()) {
assertEquals(1, multipart.getRequests().size());
ODataRequest retrieveRequest = multipart.getRequests().get(0);
@@ -521,53 +544,53 @@ public class BatchRequestParserTest {
@Test
public void testContentId() throws BatchException {
- String batch = "--batch_8194-cf13-1f56" + "\n"
+ String batch = "--batch_8194-cf13-1f56" + LF
+ MIME_HEADERS
- + "\n"
- + "GET Employees HTTP/1.1" + "\n"
- + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + "\n"
- + "Content-Id: BBB" + "\n"
- + "\n" + "\n"
- + "--batch_8194-cf13-1f56" + "\n"
- + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + "\n"
- + "\n"
- + "--changeset_f980-1cb6-94dd" + "\n"
+ + LF
+ + "GET Employees HTTP/1.1" + LF
+ + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + LF
+ + "Content-Id: BBB" + LF
+ + LF + LF
+ + "--batch_8194-cf13-1f56" + LF
+ + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd" + LF
+ MIME_HEADERS
- + "Content-Id: " + CONTENT_ID_REFERENCE + "\n"
- + "\n"
- + "POST Employees HTTP/1.1" + "\n"
- + "Content-type: application/octet-stream" + "\n"
- + "\n"
- + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + "\n"
- + "\n"
- + "--changeset_f980-1cb6-94dd" + "\n"
+ + "Content-Id: " + CONTENT_ID_REFERENCE + LF
+ + LF
+ + "POST Employees HTTP/1.1" + LF
+ + "Content-type: application/octet-stream" + LF
+ + LF
+ + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + LF
+ + LF
+ + "--changeset_f980-1cb6-94dd" + LF
+ MIME_HEADERS
- + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + "\n"
- + "\n"
- + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + "\n"
- + "Content-Type: application/json;odata=verbose" + "\n"
- + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + "\n"
- + "\n"
- + "{\"EmployeeName\":\"Peter Fall\"}" + "\n"
- + "--changeset_f980-1cb6-94dd--" + "\n"
- + "\n"
+ + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + LF
+ + LF
+ + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + LF
+ + "Content-Type: application/json;odata=verbose" + LF
+ + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + LF
+ + LF
+ + "{\"EmployeeName\":\"Peter Fall\"}" + LF
+ + "--changeset_f980-1cb6-94dd--" + LF
+ + LF
+ "--batch_8194-cf13-1f56--";
InputStream in = new ByteArrayInputStream(batch.getBytes());
BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
- List<BatchPart> batchParts = parser.parse(in);
- assertNotNull(batchParts);
- for (BatchPart multipart : batchParts) {
+ List<BatchRequestPart> batchRequestParts = parser.parse(in);
+ assertNotNull(batchRequestParts);
+ for (BatchRequestPart multipart : batchRequestParts) {
if (!multipart.isChangeSet()) {
assertEquals(1, multipart.getRequests().size());
ODataRequest retrieveRequest = multipart.getRequests().get(0);
- assertEquals("BBB", retrieveRequest.getRequestHeaderValue(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase()));
+ assertEquals("BBB", retrieveRequest.getRequestHeaderValue(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase()));
} else {
for (ODataRequest request : multipart.getRequests()) {
if (ODataHttpMethod.POST.equals(request.getMethod())) {
- assertEquals(CONTENT_ID_REFERENCE, request.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase()));
+ assertEquals(CONTENT_ID_REFERENCE, request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase()));
} else if (ODataHttpMethod.PUT.equals(request.getMethod())) {
- assertEquals(PUT_MIME_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase()));
- assertEquals(PUT_REQUEST_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase()));
+ assertEquals(PUT_MIME_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase()));
+ assertEquals(PUT_REQUEST_HEADER_CONTENT_ID, request.getRequestHeaderValue(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase()));
assertNull(request.getPathInfo().getRequestUri());
assertEquals("$" + CONTENT_ID_REFERENCE, request.getPathInfo().getODataSegments().get(0).getPath());
}
@@ -576,13 +599,13 @@ public class BatchRequestParserTest {
}
}
- private List<BatchPart> parse(final String batch) throws BatchException {
+ private List<BatchRequestPart> parse(final String batch) throws BatchException {
InputStream in = new ByteArrayInputStream(batch.getBytes());
BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties);
- List<BatchPart> batchParts = parser.parse(in);
- assertNotNull(batchParts);
- assertEquals(false, batchParts.isEmpty());
- return batchParts;
+ List<BatchRequestPart> batchRequestParts = parser.parse(in);
+ assertNotNull(batchRequestParts);
+ assertEquals(false, batchRequestParts.isEmpty());
+ return batchRequestParts;
}
private void parseInvalidBatchBody(final String batch) throws BatchException {
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java
new file mode 100644
index 0000000..61e6709
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java
@@ -0,0 +1,236 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart;
+import org.apache.olingo.odata2.api.client.batch.BatchPart;
+import org.apache.olingo.odata2.api.client.batch.BatchQueryPart;
+import org.apache.olingo.odata2.testutil.helper.StringHelper;
+import org.junit.Test;
+
+public class BatchRequestWriterTest {
+
+ private static final String POST = "POST";
+ private static final String GET = "GET";
+ private static final String PUT = "PUT";
+ private static final String BOUNDARY = "batch_123";
+
+ private void checkMimeHeaders(final String requestBody) {
+ assertTrue(requestBody.contains("Content-Type: application/http"));
+ assertTrue(requestBody.contains("Content-Transfer-Encoding: binary"));
+ }
+
+ @Test
+ public void testBatchQueryPart() throws BatchException, IOException {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put("Accept", "application/json");
+ BatchPart request = BatchQueryPart.method(GET).uri("Employees").headers(headers).build();
+ batch.add(request);
+
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+
+ String requestBody = StringHelper.inputStreamToString(batchRequest);
+ assertNotNull(batchRequest);
+ checkMimeHeaders(requestBody);
+
+ assertTrue(requestBody.contains("--batch_"));
+ assertTrue(requestBody.contains("GET Employees HTTP/1.1"));
+ checkHeaders(headers, requestBody);
+ }
+
+ @Test
+ public void testBatchChangeSet() throws IOException, BatchException {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put("content-type", "application/json");
+ BatchChangeSetPart request = BatchChangeSetPart.method(PUT)
+ .uri("Employees('2')")
+ .body("{\"Возраст\":40}")
+ .headers(headers)
+ .contentId("111")
+ .build();
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ changeSet.add(request);
+ batch.add(changeSet);
+
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+
+ String requestBody = StringHelper.inputStreamToString(batchRequest, true);
+ assertNotNull(batchRequest);
+ checkMimeHeaders(requestBody);
+ checkHeaders(headers, requestBody);
+
+ assertTrue(requestBody.contains("--batch_"));
+ assertTrue(requestBody.contains("--changeset_"));
+ assertTrue(requestBody.contains("PUT Employees('2') HTTP/1.1"));
+ assertTrue(requestBody.contains("{\"Возраст\":40}"));
+ }
+
+ @Test
+ public void testBatchWithGetAndPost() throws BatchException, IOException {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+ Map<String, String> headers = new HashMap<String, String>();
+ headers.put("Accept", "application/json");
+ BatchPart request = BatchQueryPart.method(GET).uri("Employees").headers(headers).contentId("000").build();
+ batch.add(request);
+
+ Map<String, String> changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/json");
+ String body = "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEA";
+ BatchChangeSetPart changeRequest = BatchChangeSetPart.method(POST)
+ .uri("Employees")
+ .body(body)
+ .headers(changeSetHeaders)
+ .contentId("111")
+ .build();
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ changeSet.add(changeRequest);
+ batch.add(changeSet);
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+
+ String requestBody = StringHelper.inputStreamToString(batchRequest);
+ assertNotNull(batchRequest);
+ checkMimeHeaders(requestBody);
+
+ checkHeaders(headers, requestBody);
+ checkHeaders(changeSetHeaders, requestBody);
+ assertTrue(requestBody.contains("GET Employees HTTP/1.1"));
+ assertTrue(requestBody.contains("POST Employees HTTP/1.1"));
+ assertTrue(requestBody.contains(body));
+ }
+
+ @Test
+ public void testChangeSetWithContentIdReferencing() throws BatchException, IOException {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+
+ Map<String, String> changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/json");
+ String body = "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEA";
+ BatchChangeSetPart changeRequest = BatchChangeSetPart.method(POST)
+ .uri("Employees('2')")
+ .body(body)
+ .headers(changeSetHeaders)
+ .contentId("1")
+ .build();
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ changeSet.add(changeRequest);
+
+ changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/json;odata=verbose");
+ BatchChangeSetPart changeRequest2 = BatchChangeSetPart.method(PUT)
+ .uri("$/ManagerId")
+ .body("{\"ManagerId\":1}")
+ .headers(changeSetHeaders)
+ .contentId("2")
+ .build();
+ changeSet.add(changeRequest2);
+ batch.add(changeSet);
+
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+
+ String requestBody = StringHelper.inputStreamToString(batchRequest);
+ assertNotNull(batchRequest);
+ checkMimeHeaders(requestBody);
+
+ assertTrue(requestBody.contains("POST Employees('2') HTTP/1.1"));
+ assertTrue(requestBody.contains("PUT $/ManagerId HTTP/1.1"));
+ assertTrue(requestBody.contains(BatchHelper.HTTP_CONTENT_ID + ": 1"));
+ assertTrue(requestBody.contains(BatchHelper.HTTP_CONTENT_ID + ": 2"));
+ assertTrue(requestBody.contains(body));
+
+ }
+
+ @Test
+ public void testBatchWithTwoChangeSets() throws BatchException, IOException {
+ List<BatchPart> batch = new ArrayList<BatchPart>();
+
+ Map<String, String> changeSetHeaders = new HashMap<String, String>();
+ changeSetHeaders.put("content-type", "application/json");
+ changeSetHeaders.put("content-Id", "111");
+ String body = "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEA";
+ BatchChangeSetPart changeRequest = BatchChangeSetPart.method(POST)
+ .uri("Employees")
+ .body(body)
+ .headers(changeSetHeaders)
+ .build();
+ BatchChangeSet changeSet = BatchChangeSet.newBuilder().build();
+ changeSet.add(changeRequest);
+ batch.add(changeSet);
+
+ Map<String, String> changeSetHeaders2 = new HashMap<String, String>();
+ changeSetHeaders2.put("content-type", "application/json;odata=verbose");
+ changeSetHeaders2.put("content-Id", "222");
+ BatchChangeSetPart changeRequest2 = BatchChangeSetPart.method(PUT)
+ .uri("Employees('2')/ManagerId")
+ .body("{\"ManagerId\":1}")
+ .headers(changeSetHeaders2)
+ .build();
+ BatchChangeSet changeSet2 = BatchChangeSet.newBuilder().build();
+ changeSet2.add(changeRequest2);
+ batch.add(changeSet2);
+
+ BatchRequestWriter writer = new BatchRequestWriter();
+ InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY);
+
+ String requestBody = StringHelper.inputStreamToString(batchRequest);
+ assertNotNull(batchRequest);
+ checkMimeHeaders(requestBody);
+
+ assertTrue(requestBody.contains("POST Employees HTTP/1.1"));
+ assertTrue(requestBody.contains("PUT Employees('2')/ManagerId HTTP/1.1"));
+
+ assertTrue(requestBody.contains(body));
+
+ }
+
+ private void checkHeaders(final Map<String, String> headers, final String requestBody) {
+ for (Map.Entry<String, String> header : headers.entrySet()) {
+ assertTrue(requestBody.contains(header.getKey() + ": " + header.getValue()));
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBatchQueryPartWithInvalidMethod() throws BatchException, IOException {
+ BatchQueryPart.method(PUT).uri("Employees").build();
+
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBatchChangeSetPartWithInvalidMethod() throws BatchException, IOException {
+ BatchChangeSetPart.method(GET).uri("Employees('2')").build();
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseParserTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseParserTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseParserTest.java
new file mode 100644
index 0000000..7936051
--- /dev/null
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseParserTest.java
@@ -0,0 +1,280 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.junit.Test;
+
+public class BatchResponseParserTest {
+
+ private static final String LF = "\r\n";
+
+ @Test
+ public void testSimpleBatchResponse() throws BatchException {
+ String getResponse = "--batch_123" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + "Content-ID: 1" + LF
+ + LF
+ + "HTTP/1.1 200 OK" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + "Content-Type: text/plain;charset=utf-8" + LF
+ + "Content-length: 22" + LF
+ + LF
+ + "Frederic Fall MODIFIED" + LF
+ + LF
+ + "--batch_123--";
+
+ InputStream in = new ByteArrayInputStream(getResponse.getBytes());
+ BatchResponseParser parser = new BatchResponseParser("multipart/mixed;boundary=batch_123");
+ List<BatchSingleResponse> responses = parser.parse(in);
+ for (BatchSingleResponse response : responses) {
+ assertEquals("200", response.getStatusCode());
+ assertEquals("OK", response.getStatusInfo());
+ assertEquals("text/plain;charset=utf-8", response.getHeaders().get(HttpHeaders.CONTENT_TYPE));
+ assertEquals("22", response.getHeaders().get("Content-length"));
+ assertEquals("1", response.getContentId());
+ }
+ }
+
+ @Test
+ public void testBatchResponse() throws BatchException, IOException {
+ String fileName = "/batchResponse.batch";
+ InputStream in = ClassLoader.class.getResourceAsStream(fileName);
+ if (in == null) {
+ throw new IOException("Requested file '" + fileName + "' was not found.");
+ }
+ BatchResponseParser parser = new BatchResponseParser("multipart/mixed;boundary=batch_123");
+ List<BatchSingleResponse> responses = parser.parse(in);
+ for (BatchSingleResponse response : responses) {
+ if ("1".equals(response.getContentId())) {
+ assertEquals("204", response.getStatusCode());
+ assertEquals("No Content", response.getStatusInfo());
+ } else if ("3".equals(response.getContentId())) {
+ assertEquals("200", response.getStatusCode());
+ assertEquals("OK", response.getStatusInfo());
+ }
+ }
+ }
+
+ @Test
+ public void testResponseToChangeSet() throws BatchException {
+ String putResponse = "--batch_123" + LF
+ + "Content-Type: " + HttpContentType.MULTIPART_MIXED + ";boundary=changeset_12ks93js84d" + LF
+ + LF
+ + "--changeset_12ks93js84d" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + "Content-ID: 1" + LF
+ + LF
+ + "HTTP/1.1 204 No Content" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ + "--changeset_12ks93js84d--" + LF
+ + LF
+ + "--batch_123--";
+
+ InputStream in = new ByteArrayInputStream(putResponse.getBytes());
+ BatchResponseParser parser = new BatchResponseParser("multipart/mixed;boundary=batch_123");
+ List<BatchSingleResponse> responses = parser.parse(in);
+ for (BatchSingleResponse response : responses) {
+ assertEquals("204", response.getStatusCode());
+ assertEquals("No Content", response.getStatusInfo());
+ assertEquals("1", response.getContentId());
+ }
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidMimeHeader() throws BatchException {
+ String putResponse = "--batch_123" + LF
+ + "Content-Type: " + HttpContentType.MULTIPART_MIXED + ";boundary=changeset_12ks93js84d" + LF
+ + LF
+ + "--changeset_12ks93js84d" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: 7bit" + LF // Content-Transfer-Encoding must be binary
+ + LF
+ + "HTTP/1.1 No Content" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ + "--changeset_12ks93js84d--" + LF
+ + LF
+ + "--batch_123--";
+
+ parseInvalidBatchResponseBody(putResponse);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testMissingMimeHeader() throws BatchException {
+ String putResponse = "--batch_123" + LF
+ + "Content-Type: " + HttpContentType.MULTIPART_MIXED + ";boundary=changeset_12ks93js84d" + LF
+ + LF
+ + "--changeset_12ks93js84d" + LF
+ + LF
+ + "HTTP/1.1 No Content" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ + "--changeset_12ks93js84d--" + LF
+ + LF
+ + "--batch_123--";
+
+ parseInvalidBatchResponseBody(putResponse);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidContentType() throws BatchException {
+ String putResponse = "--batch_123" + LF
+ + "Content-Type: " + HttpContentType.MULTIPART_MIXED + LF //Missing boundary parameter
+ + LF
+ + "--changeset_12ks93js84d" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "HTTP/1.1 No Content" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ + "--changeset_12ks93js84d--" + LF
+ + LF
+ + "--batch_123--";
+
+ parseInvalidBatchResponseBody(putResponse);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidStatusLine() throws BatchException {
+ String putResponse = "--batch_123" + LF
+ + "Content-Type: " + HttpContentType.MULTIPART_MIXED + ";boundary=changeset_12ks93js84d" + LF
+ + LF
+ + "--changeset_12ks93js84d" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "HTTP/1.1 No Content" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ + "--changeset_12ks93js84d--" + LF
+ + LF
+ + "--batch_123--";
+
+ parseInvalidBatchResponseBody(putResponse);
+
+ }
+
+ @Test(expected = BatchException.class)
+ public void testMissingCloseDelimiter() throws BatchException {
+ String putResponse = "--batch_123" + LF
+ + "Content-Type: " + HttpContentType.MULTIPART_MIXED + ";boundary=changeset_12ks93js84d" + LF
+ + LF
+ + "--changeset_12ks93js84d" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "HTTP/1.1 204 No Content" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + LF
+ + LF
+ + "--changeset_12ks93js84d--" + LF
+ + LF;
+
+ parseInvalidBatchResponseBody(putResponse);
+
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidEnteredContentLength() throws BatchException {
+ String getResponse = "--batch_123" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + "Content-ID: 1" + LF
+ + LF
+ + "HTTP/1.1 200 OK" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + "Content-Type: text/plain;charset=utf-8" + LF
+ + "Content-length: 100" + LF
+ + LF
+ + "Frederic Fall" + LF
+ + LF
+ + "--batch_123--";
+
+ parseInvalidBatchResponseBody(getResponse);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidBoundary() throws BatchException {
+ String getResponse = "--batch_321" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + "Content-ID: 1" + LF
+ + LF
+ + "HTTP/1.1 200 OK" + LF
+ + "DataServiceVersion: 2.0" + LF
+ + "Content-Type: text/plain;charset=utf-8" + LF
+ + LF
+ + "Frederic Fall" + LF
+ + LF
+ + "--batch_123--";
+
+ parseInvalidBatchResponseBody(getResponse);
+ }
+
+ @Test(expected = BatchException.class)
+ public void testInvalidBoundary2() throws BatchException {
+ String getResponse = "--batch_123" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "HTTP/1.1 200 OK" + LF
+ + "Content-Type: text/plain;charset=utf-8" + LF
+ + "Content-Length: 13" + LF
+ + LF
+ + "Frederic Fall" + LF
+ + LF
+ + "batch_123" + LF
+ + "Content-Type: application/http" + LF
+ + "Content-Transfer-Encoding: binary" + LF
+ + LF
+ + "HTTP/1.1 200 OK" + LF
+ + "Content-Type: text/plain;charset=utf-8" + LF
+ + LF
+ + "Walter Winter" + LF
+ + LF
+ + "--batch_123--";
+ parseInvalidBatchResponseBody(getResponse);
+ }
+
+ private void parseInvalidBatchResponseBody(final String putResponse) throws BatchException {
+ InputStream in = new ByteArrayInputStream(putResponse.getBytes());
+ BatchResponseParser parser = new BatchResponseParser("multipart/mixed;boundary=batch_123");
+ parser.parse(in);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
index f236226..d63ab83 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchResponseWriterTest.java
@@ -125,8 +125,8 @@ public class BatchResponseWriterTest {
ODataResponse response = ODataResponse.entity("Walter Winter")
.status(HttpStatusCodes.OK)
.contentHeader("application/json")
- .header(BatchConstants.MIME_HEADER_CONTENT_ID, "mimeHeaderContentId123")
- .header(BatchConstants.REQUEST_HEADER_CONTENT_ID, "requestHeaderContentId123")
+ .header(BatchHelper.MIME_HEADER_CONTENT_ID, "mimeHeaderContentId123")
+ .header(BatchHelper.REQUEST_HEADER_CONTENT_ID, "requestHeaderContentId123")
.build();
List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
responses.add(response);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/parser/EdmParserTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/parser/EdmParserTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/parser/EdmParserTest.java
index 9860fef..da91133 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/parser/EdmParserTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/edm/parser/EdmParserTest.java
@@ -30,8 +30,6 @@ import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
-import org.junit.Test;
-
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmAction;
import org.apache.olingo.odata2.api.edm.EdmConcurrencyMode;
@@ -61,10 +59,16 @@ import org.apache.olingo.odata2.api.edm.provider.SimpleProperty;
import org.apache.olingo.odata2.api.ep.EntityProvider;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
import org.apache.olingo.odata2.api.processor.ODataResponse;
+import org.apache.olingo.odata2.core.ep.AbstractXmlProducerTestHelper;
import org.apache.olingo.odata2.testutil.helper.StringHelper;
import org.apache.olingo.odata2.testutil.mock.EdmTestProvider;
+import org.junit.Test;
-public class EdmParserTest {
+public class EdmParserTest extends AbstractXmlProducerTestHelper {
+
+ public EdmParserTest(final StreamWriterImplType type) {
+ super(type);
+ }
private static final String DEFAULT_VALUE = "Photo";
private static final String FC_TARGET_PATH = "Содержание";
@@ -663,6 +667,7 @@ public class EdmParserTest {
}
}
for (EntityType entityType : schema.getEntityTypes()) {
+ assertEquals(1, entityType.getAnnotationAttributes().size());
AnnotationAttribute attr = entityType.getAnnotationAttributes().get(0);
assertEquals("href", attr.getName());
assertEquals("prefix1", attr.getPrefix());
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/AbstractXmlProducerTestHelper.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/AbstractXmlProducerTestHelper.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/AbstractXmlProducerTestHelper.java
index f86b658..56d7118 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/AbstractXmlProducerTestHelper.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/AbstractXmlProducerTestHelper.java
@@ -37,13 +37,16 @@ public abstract class AbstractXmlProducerTestHelper extends BaseTest {
public AbstractXmlProducerTestHelper(final StreamWriterImplType type) {
switch (type) {
case WOODSTOCKIMPL:
+ System.setProperty("javax.xml.stream.XMLInputFactory", "com.ctc.wstx.stax.WstxInputFactory"); //NOSONAR
System.setProperty("javax.xml.stream.XMLOutputFactory", "com.ctc.wstx.stax.WstxOutputFactory"); //NOSONAR
break;
case SUNINTERNALIMPL:
+ System.setProperty("javax.xml.stream.XMLInputFactory", "com.sun.xml.internal.stream.XMLInputFactoryImpl"); //NOSONAR
System.setProperty("javax.xml.stream.XMLOutputFactory", "com.sun.xml.internal.stream.XMLOutputFactoryImpl"); //NOSONAR
break;
default:
System.setProperty("javax.xml.stream.XMLOutputFactory", "com.sun.xml.internal.stream.XMLOutputFactoryImpl"); //NOSONAR
+ System.setProperty("javax.xml.stream.XMLInputFactory", "com.sun.xml.internal.stream.XMLInputFactoryImpl"); //NOSONAR
break;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumerTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumerTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumerTest.java
index 23dcdda..37edd4d 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumerTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumerTest.java
@@ -21,6 +21,7 @@ package org.apache.olingo.odata2.core.ep.consumer;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.InputStream;
@@ -29,13 +30,13 @@ import java.util.List;
import java.util.Map;
import java.util.TimeZone;
-import org.junit.Test;
-
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
+import org.apache.olingo.odata2.api.ep.EntityProviderReadProperties;
import org.apache.olingo.odata2.api.ep.entry.MediaMetadata;
import org.apache.olingo.odata2.api.ep.entry.ODataEntry;
import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Test;
/**
*
@@ -86,7 +87,7 @@ public class JsonEntryConsumerTest extends AbstractConsumerTest {
assertEquals("Heidelberg", city.get("CityName"));
assertEquals(Integer.valueOf(52), properties.get("Age"));
Calendar entryDate = (Calendar) properties.get("EntryDate");
- assertEquals(Long.valueOf(915148800000l), Long.valueOf(entryDate.getTimeInMillis()));
+ assertEquals(915148800000L, entryDate.getTimeInMillis());
assertEquals(TimeZone.getTimeZone("GMT"), entryDate.getTimeZone());
assertEquals("Employees('1')/$value", properties.get("ImageUrl"));
@@ -135,7 +136,7 @@ public class JsonEntryConsumerTest extends AbstractConsumerTest {
assertNotNull(properties);
assertEquals("1", properties.get("Id"));
assertEquals("Building 1", properties.get("Name"));
- assertEquals(null, properties.get("Image"));
+ assertNull(properties.get("Image"));
assertNull(properties.get("nb_Rooms"));
List<String> associationUris = result.getMetadata().getAssociationUris("nb_Rooms");
@@ -153,7 +154,7 @@ public class JsonEntryConsumerTest extends AbstractConsumerTest {
assertNotNull(properties);
assertEquals("1", properties.get("Id"));
assertEquals("Building 1", properties.get("Name"));
- assertEquals(null, properties.get("Image"));
+ assertNull(properties.get("Image"));
assertNull(properties.get("nb_Rooms"));
List<String> associationUris = result.getMetadata().getAssociationUris("nb_Rooms");
@@ -164,6 +165,41 @@ public class JsonEntryConsumerTest extends AbstractConsumerTest {
}
@Test
+ public void readMinimalEntry() throws Exception {
+ final EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Teams");
+ final ODataEntry result = new JsonEntityConsumer().readEntry(entitySet, createContentAsStream("{\"Id\":\"99\"}"), DEFAULT_PROPERTIES);
+
+ final Map<String, Object> properties = result.getProperties();
+ assertNotNull(properties);
+ assertEquals(1, properties.size());
+ assertEquals("99", properties.get("Id"));
+
+ assertTrue(result.getMetadata().getAssociationUris("nt_Employees").isEmpty());
+ checkMediaDataInitial(result.getMediaMetadata());
+ }
+
+ @Test
+ public void readEntryWithNullProperty() throws Exception {
+ final EdmEntitySet entitySet = MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Rooms");
+ final String content = "{\"Id\":\"99\",\"Seats\":null}";
+
+ for (final boolean merge : new boolean[] { false, true }) {
+ final ODataEntry result = new JsonEntityConsumer().readEntry(entitySet, createContentAsStream(content),
+ EntityProviderReadProperties.init().mergeSemantic(merge).build());
+
+ final Map<String, Object> properties = result.getProperties();
+ assertNotNull(properties);
+ assertEquals(2, properties.size());
+ assertEquals("99", properties.get("Id"));
+ assertTrue(properties.containsKey("Seats"));
+ assertNull(properties.get("Seats"));
+
+ assertTrue(result.getMetadata().getAssociationUris("nr_Employees").isEmpty());
+ checkMediaDataInitial(result.getMediaMetadata());
+ }
+ }
+
+ @Test
public void readWithDoublePropertyOnTeam() throws Exception {
//The file contains the name property two times
try {
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumerTest.java
----------------------------------------------------------------------
diff --git a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumerTest.java b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumerTest.java
index 5cedb91..61ef209 100644
--- a/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumerTest.java
+++ b/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumerTest.java
@@ -36,10 +36,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-import org.junit.Test;
-
-import com.google.gson.stream.JsonReader;
-import org.apache.olingo.odata2.api.edm.EdmComplexType;
+import org.apache.olingo.odata2.api.edm.EdmFacets;
import org.apache.olingo.odata2.api.edm.EdmProperty;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeKind;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
@@ -49,6 +46,9 @@ import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
import org.apache.olingo.odata2.core.ep.aggregator.EntityPropertyInfo;
import org.apache.olingo.odata2.testutil.fit.BaseTest;
import org.apache.olingo.odata2.testutil.mock.MockFacade;
+import org.junit.Test;
+
+import com.google.gson.stream.JsonReader;
/**
*
@@ -56,6 +56,18 @@ import org.apache.olingo.odata2.testutil.mock.MockFacade;
public class JsonPropertyConsumerTest extends BaseTest {
@Test
+ public void booleanSimpleProperty() throws Exception {
+ EdmProperty property = mock(EdmProperty.class);
+ when(property.getName()).thenReturn("Boolean");
+ when(property.isSimple()).thenReturn(true);
+ when(property.getType()).thenReturn(EdmSimpleTypeKind.Boolean.getEdmSimpleTypeInstance());
+
+ JsonReader reader = prepareReader("{\"Boolean\":true}");
+ final Map<String, Object> resultMap = execute(property, reader);
+ assertEquals(Boolean.TRUE, resultMap.get("Boolean"));
+ }
+
+ @Test
public void allNumberSimplePropertyKinds() throws Exception {
String simplePropertyJson = "{\"d\":{\"Age\":67}}";
EdmProperty edmProperty = mock(EdmProperty.class);
@@ -143,15 +155,12 @@ public class JsonPropertyConsumerTest extends BaseTest {
resultMap = execute(edmProperty, reader);
assertEquals(UUID.fromString("aabbccdd-aabb-ccdd-eeff-aabbccddeeff"), resultMap.get("Name"));
//Binary
- byte[] binary = new byte[] { (byte) 0xAA, (byte) 0xBB, (byte) 0xCC };
simplePropertyJson = "{\"d\":{\"Name\":\"qrvM\"}}";
reader = prepareReader(simplePropertyJson);
when(edmProperty.getType()).thenReturn(EdmSimpleTypeKind.Binary.getEdmSimpleTypeInstance());
resultMap = execute(edmProperty, reader);
- //TODO: check why byte is comming back insted of Byte object
- //Byte[] expectedArray = new Byte[] { binary[0], binary[1], binary[2] };
- byte[] actualArray = (byte[]) resultMap.get("Name");
- assertTrue(Arrays.equals(binary, actualArray));
+ assertTrue(Arrays.equals(new byte[] { (byte) 0xAA, (byte) 0xBB, (byte) 0xCC },
+ (byte[]) resultMap.get("Name")));
//Time
simplePropertyJson = "{\"d\":{\"Name\":\"PT23H32M3S\"}}";
reader = prepareReader(simplePropertyJson);
@@ -196,6 +205,26 @@ public class JsonPropertyConsumerTest extends BaseTest {
}
@Test
+ public void simplePropertyNull() throws Exception {
+ JsonReader reader = prepareReader("{\"Name\":null}");
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Room").getProperty("Name");
+ final Map<String, Object> resultMap = new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
+ assertTrue(resultMap.containsKey("Name"));
+ assertNull(resultMap.get("Name"));
+ }
+
+ @Test(expected = EntityProviderException.class)
+ public void simplePropertyNullValueNotAllowed() throws Exception {
+ JsonReader reader = prepareReader("{\"Age\":null}");
+ EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getEntityType("RefScenario", "Employee").getProperty("Age");
+ EdmFacets facets = mock(EdmFacets.class);
+ when(facets.isNullable()).thenReturn(false);
+ when(property.getFacets()).thenReturn(facets);
+
+ new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
+ }
+
+ @Test
public void simplePropertyWithNullMappingStandalone() throws Exception {
String simplePropertyJson = "{\"d\":{\"Age\":67}}";
JsonReader reader = prepareReader(simplePropertyJson);
@@ -289,10 +318,9 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void complexPropertyWithStringToStringMappingStandalone() throws Exception {
- String simplePropertyJson = "{\"d\":{\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
- JsonReader reader = prepareReader(simplePropertyJson);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
+ final String complexPropertyJson = "{\"d\":{\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
+ JsonReader reader = prepareReader(complexPropertyJson);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
EntityProviderReadProperties readProperties = mock(EntityProviderReadProperties.class);
Map<String, Object> innerMappings = new HashMap<String, Object>();
@@ -300,7 +328,7 @@ public class JsonPropertyConsumerTest extends BaseTest {
Map<String, Object> typeMappings = new HashMap<String, Object>();
typeMappings.put("City", innerMappings);
when(readProperties.getTypeMappings()).thenReturn(typeMappings);
- Map<String, Object> result = new JsonPropertyConsumer().readPropertyStandalone(reader, edmProperty, readProperties);
+ Map<String, Object> result = new JsonPropertyConsumer().readPropertyStandalone(reader, property, readProperties);
assertEquals(1, result.size());
@SuppressWarnings("unchecked")
@@ -311,8 +339,8 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void deepComplexPropertyWithStringToStringMappingStandalone() throws Exception {
- String simplePropertyJson = "{\"d\":{\"Location\":{\"__metadata\":{\"type\":\"RefScenario.c_Location\"},\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}}}";
- JsonReader reader = prepareReader(simplePropertyJson);
+ final String complexPropertyJson = "{\"d\":{\"Location\":{\"__metadata\":{\"type\":\"RefScenario.c_Location\"},\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}}}";
+ JsonReader reader = prepareReader(complexPropertyJson);
EdmProperty edmProperty = (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location");
EntityProviderReadProperties readProperties = mock(EntityProviderReadProperties.class);
@@ -340,11 +368,10 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void complexPropertyOnOpenReader() throws Exception {
- String simplePropertyJson = "{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
- JsonReader reader = prepareReader(simplePropertyJson);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
- EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(edmProperty);
+ final String complexPropertyJson = "{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
+ JsonReader reader = prepareReader(complexPropertyJson);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+ EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(property);
JsonPropertyConsumer jpc = new JsonPropertyConsumer();
@SuppressWarnings("unchecked")
@@ -357,11 +384,10 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void complexPropertyOnOpenReaderWithNoMetadata() throws Exception {
- String simplePropertyJson = "{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
- JsonReader reader = prepareReader(simplePropertyJson);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
- EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(edmProperty);
+ final String complexPropertyJson = "{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
+ JsonReader reader = prepareReader(complexPropertyJson);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+ EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(property);
JsonPropertyConsumer jpc = new JsonPropertyConsumer();
@SuppressWarnings("unchecked")
@@ -374,8 +400,8 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void deepComplexPropertyOnOpenReader() throws Exception {
- String simplePropertyJson = "{\"__metadata\":{\"type\":\"RefScenario.c_Location\"},\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}";
- JsonReader reader = prepareReader(simplePropertyJson);
+ final String complexPropertyJson = "{\"__metadata\":{\"type\":\"RefScenario.c_Location\"},\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}";
+ JsonReader reader = prepareReader(complexPropertyJson);
EdmProperty edmProperty = (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location");
EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(edmProperty);
@@ -404,12 +430,11 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void complexPropertyStandalone() throws Exception {
- String simplePropertyJson = "{\"d\":{\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
- JsonReader reader = prepareReader(simplePropertyJson);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
+ final String complexPropertyJson = "{\"d\":{\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
+ JsonReader reader = prepareReader(complexPropertyJson);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
- Map<String, Object> result = new JsonPropertyConsumer().readPropertyStandalone(reader, edmProperty, null);
+ final Map<String, Object> result = new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
assertEquals(1, result.size());
@SuppressWarnings("unchecked")
@@ -420,8 +445,8 @@ public class JsonPropertyConsumerTest extends BaseTest {
@Test
public void deepComplexPropertyStandalone() throws Exception {
- String simplePropertyJson = "{\"d\":{\"Location\":{\"__metadata\":{\"type\":\"RefScenario.c_Location\"},\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}}}";
- JsonReader reader = prepareReader(simplePropertyJson);
+ final String complexPropertyJson = "{\"d\":{\"Location\":{\"__metadata\":{\"type\":\"RefScenario.c_Location\"},\"City\":{\"__metadata\":{\"type\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"},\"Country\":\"Germany\"}}}";
+ JsonReader reader = prepareReader(complexPropertyJson);
EdmProperty edmProperty = (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location");
JsonPropertyConsumer jpc = new JsonPropertyConsumer();
@@ -443,44 +468,66 @@ public class JsonPropertyConsumerTest extends BaseTest {
public void complexPropertyWithInvalidChild() throws Exception {
String cityProperty = "{\"d\":{\"City\":{\"Invalid\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
JsonReader reader = prepareReader(cityProperty);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
- new JsonPropertyConsumer().readPropertyStandalone(reader, edmProperty, null);
+ new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
}
@Test(expected = EntityProviderException.class)
public void complexPropertyWithInvalidName() throws Exception {
String cityProperty = "{\"d\":{\"Invalid\":{\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}}}";
JsonReader reader = prepareReader(cityProperty);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
- new JsonPropertyConsumer().readPropertyStandalone(reader, edmProperty, null);
+ new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
+ }
+
+ @Test
+ public void complexPropertyNull() throws Exception {
+ final String locationProperty = "{\"Location\":null}";
+ JsonReader reader = prepareReader(locationProperty);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location");
+
+ final Map<String, Object> propertyData = new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
+ assertNotNull(propertyData);
+ assertEquals(1, propertyData.size());
+ assertTrue(propertyData.containsKey("Location"));
+ assertNull(propertyData.get("Location"));
+ }
+
+ @Test(expected = EntityProviderException.class)
+ public void complexPropertyNullValueNotAllowed() throws Exception {
+ final String locationProperty = "{\"Location\":null}";
+ JsonReader reader = prepareReader(locationProperty);
+ EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location");
+ EdmFacets facets = mock(EdmFacets.class);
+ when(facets.isNullable()).thenReturn(false);
+ when(property.getFacets()).thenReturn(facets);
+
+ new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
}
@Test
public void complexPropertyEmpty() throws Exception {
- String cityProperty = "{\"d\":{\"City\":null}}";
+ final String cityProperty = "{\"d\":{\"City\":{}}}";
JsonReader reader = prepareReader(cityProperty);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
- Map<String, Object> propertyData = new JsonPropertyConsumer().readPropertyStandalone(reader, edmProperty, null);
+ final Map<String, Object> propertyData = new JsonPropertyConsumer().readPropertyStandalone(reader, property, null);
assertNotNull(propertyData);
assertEquals(1, propertyData.size());
+ assertNotNull(propertyData.get("City"));
@SuppressWarnings("unchecked")
- Map<String, Object> innerResult = (Map<String, Object>) propertyData.get("City");
- assertNull(innerResult);
+ final Map<String, Object> innerMap = (Map<String, Object>) propertyData.get("City");
+ assertTrue(innerMap.isEmpty());
}
@Test(expected = EntityProviderException.class)
public void complexPropertyMetadataInvalidTag() throws Exception {
String complexPropertyJson = "{\"__metadata\":{\"invalid\":\"RefScenario.c_City\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
JsonReader reader = prepareReader(complexPropertyJson);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
- EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(edmProperty);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+ EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(property);
new JsonPropertyConsumer().readPropertyValue(reader, entityPropertyInfo, null);
}
@@ -489,9 +536,8 @@ public class JsonPropertyConsumerTest extends BaseTest {
public void complexPropertyMetadataInvalidTypeContent() throws Exception {
String complexPropertyJson = "{\"__metadata\":{\"type\":\"Invalid\"},\"PostalCode\":\"69124\",\"CityName\":\"Heidelberg\"}";
JsonReader reader = prepareReader(complexPropertyJson);
- EdmComplexType complexPropertyType = (EdmComplexType) MockFacade.getMockEdm().getDefaultEntityContainer().getEntitySet("Employees").getEntityType().getProperty("Location").getType();
- EdmProperty edmProperty = (EdmProperty) complexPropertyType.getProperty("City");
- EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(edmProperty);
+ final EdmProperty property = (EdmProperty) MockFacade.getMockEdm().getComplexType("RefScenario", "c_Location").getProperty("City");
+ EntityComplexPropertyInfo entityPropertyInfo = (EntityComplexPropertyInfo) EntityInfoAggregator.create(property);
new JsonPropertyConsumer().readPropertyValue(reader, entityPropertyInfo, null);
}
[4/4] git commit: Batch Support, Validation in Deserialization
Posted by jh...@apache.org.
Batch Support, Validation in Deserialization
Change-Id: Ic263de081d06b71d395804b75a36c6e4b525d386
Project: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/commit/45c27419
Tree: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/tree/45c27419
Diff: http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/diff/45c27419
Branch: refs/heads/master
Commit: 45c27419cfcf1024d8e57100e7408276a932598c
Parents: a133661
Author: Jens Huesken <jh...@apache.org>
Authored: Fri Aug 23 16:27:58 2013 +0200
Committer: Jens Huesken <jh...@apache.org>
Committed: Fri Aug 23 16:27:58 2013 +0200
----------------------------------------------------------------------
.../olingo/odata2/api/batch/BatchException.java | 8 +-
.../olingo/odata2/api/batch/BatchHandler.java | 6 +-
.../olingo/odata2/api/batch/BatchPart.java | 43 --
.../odata2/api/batch/BatchRequestPart.java | 42 ++
.../odata2/api/client/batch/BatchChangeSet.java | 61 +++
.../api/client/batch/BatchChangeSetPart.java | 110 +++++
.../odata2/api/client/batch/BatchPart.java | 27 ++
.../odata2/api/client/batch/BatchQueryPart.java | 97 +++++
.../api/client/batch/BatchSingleResponse.java | 65 +++
.../olingo/odata2/api/ep/EntityProvider.java | 74 +++-
.../api/ep/EntityProviderReadProperties.java | 29 +-
.../olingo/odata2/api/rt/RuntimeDelegate.java | 21 +
.../odata2/core/batch/BatchChangeSetImpl.java | 49 +++
.../core/batch/BatchChangeSetPartImpl.java | 116 +++++
.../odata2/core/batch/BatchConstants.java | 36 --
.../odata2/core/batch/BatchHandlerImpl.java | 20 +-
.../olingo/odata2/core/batch/BatchHelper.java | 51 +++
.../olingo/odata2/core/batch/BatchPartImpl.java | 58 ---
.../odata2/core/batch/BatchQueryPartImpl.java | 102 +++++
.../odata2/core/batch/BatchRequestParser.java | 294 +++++++------
.../odata2/core/batch/BatchRequestPartImpl.java | 58 +++
.../odata2/core/batch/BatchRequestWriter.java | 120 ++++++
.../odata2/core/batch/BatchResponseParser.java | 354 +++++++++++++++
.../odata2/core/batch/BatchResponseWriter.java | 80 ++--
.../core/batch/BatchSingleResponseImpl.java | 90 ++++
.../olingo/odata2/core/commons/Encoder.java | 1 -
.../olingo/odata2/core/edm/EdmBinary.java | 2 +-
.../olingo/odata2/core/edm/EdmDateTime.java | 2 +-
.../apache/olingo/odata2/core/edm/EdmTime.java | 15 +-
.../odata2/core/edm/parser/EdmParser.java | 11 +-
.../odata2/core/ep/JsonEntityProvider.java | 9 +-
.../odata2/core/ep/ProviderFacadeImpl.java | 22 +-
.../core/ep/aggregator/EntityPropertyInfo.java | 20 +-
.../core/ep/consumer/JsonEntityConsumer.java | 4 +-
.../core/ep/consumer/JsonEntryConsumer.java | 4 +-
.../core/ep/consumer/JsonPropertyConsumer.java | 3 +
.../core/ep/consumer/XmlEntityConsumer.java | 6 +-
.../core/ep/consumer/XmlEntryConsumer.java | 35 +-
.../core/ep/consumer/XmlPropertyConsumer.java | 65 ++-
.../processor/ODataSingleProcessorService.java | 3 +-
.../odata2/core/rt/RuntimeDelegateImpl.java | 25 ++
odata-core/src/main/resources/i18n.properties | 4 +-
.../core/batch/BatchRequestParserTest.java | 427 ++++++++++---------
.../core/batch/BatchRequestWriterTest.java | 236 ++++++++++
.../core/batch/BatchResponseParserTest.java | 280 ++++++++++++
.../core/batch/BatchResponseWriterTest.java | 4 +-
.../odata2/core/edm/parser/EdmParserTest.java | 11 +-
.../core/ep/AbstractXmlProducerTestHelper.java | 3 +
.../core/ep/consumer/JsonEntryConsumerTest.java | 46 +-
.../ep/consumer/JsonPropertyConsumerTest.java | 152 ++++---
.../core/ep/consumer/XmlEntityConsumerTest.java | 123 +++---
.../core/ep/consumer/XmlLinkConsumerTest.java | 7 +
.../ep/consumer/XmlPropertyConsumerTest.java | 181 +++++---
.../ODataSingleProcessorServiceTest.java | 2 +-
.../uri/expression/TestAbapCompatibility.java | 3 +-
.../uri/expression/TestParserExceptions.java | 10 +-
.../src/test/resources/batchResponse.batch | 39 ++
.../olingo/odata2/fit/basic/BasicBatchTest.java | 9 +-
.../odata2/fit/client/ClientBatchTest.java | 235 ++++++++++
.../apache/olingo/odata2/fit/ref/BatchTest.java | 2 +-
.../odata2/fit/ref/EntryJsonChangeTest.java | 29 +-
.../fit/ref/EntryJsonCreateInlineTest.java | 2 +
.../odata2/fit/ref/EntryXmlChangeTest.java | 53 ++-
.../odata2/ref/edm/ScenarioEdmProvider.java | 2 +-
.../odata2/ref/processor/ListsProcessor.java | 29 +-
.../odata2/testutil/helper/StringHelper.java | 11 +-
.../olingo/odata2/testutil/mock/EdmMock.java | 1 +
.../olingo/odata2/testutil/mock/TecEdmInfo.java | 5 +-
.../mock/TechnicalScenarioEdmProvider.java | 47 +-
69 files changed, 3295 insertions(+), 896 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
index bbed22b..f5582d6 100644
--- a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchException.java
@@ -49,7 +49,7 @@ public class BatchException extends ODataMessageException {
/** INVALID_QUERY_PARAMETER requires no content value */
public static final MessageReference INVALID_QUERY_PARAMETER = createMessageReference(BatchException.class, "INVALID_QUERY_PARAMETER");
- /** INVALID_URI requires no content value */
+ /** INVALID_URI requires 1 content value('line number') */
public static final MessageReference INVALID_URI = createMessageReference(BatchException.class, "INVALID_URI");
/** INVALID_BOUNDARY requires 1 content value('line number') */
@@ -91,9 +91,15 @@ public class BatchException extends ODataMessageException {
/** INVALID_REQUEST_LINE requires 2 content value ('request line', 'line number') */
public static final MessageReference INVALID_REQUEST_LINE = createMessageReference(BatchException.class, "INVALID_REQUEST_LINE");
+ /** INVALID_STATUS_LINE requires 2 content value ('status line', 'line number') */
+ public static final MessageReference INVALID_STATUS_LINE = createMessageReference(BatchException.class, "INVALID_STATUS_LINE");
+
/** TRUNCETED_BODY requires 1 content value ('line number') */
public static final MessageReference TRUNCATED_BODY = createMessageReference(BatchException.class, "TRUNCATED_BODY");
+ /** UNSUPPORTED_ABSOLUTE_PATH requires 1 content value ('line number') */
+ public static final MessageReference UNSUPPORTED_ABSOLUTE_PATH = createMessageReference(BatchException.class, "UNSUPPORTED_ABSOLUTE_PATH");
+
public BatchException(final MessageReference messageReference) {
super(messageReference);
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchHandler.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchHandler.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchHandler.java
index 23584f3..1748e3e 100644
--- a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchHandler.java
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchHandler.java
@@ -27,12 +27,12 @@ import org.apache.olingo.odata2.api.processor.ODataResponse;
*/
public interface BatchHandler {
/**
- * <p>Handles the {@link BatchPart} in a way that it results in a corresponding {@link BatchResponsePart}.</p>
- * @param batchPart the incoming batchPart
+ * <p>Handles the {@link BatchRequestPart} in a way that it results in a corresponding {@link BatchResponsePart}.</p>
+ * @param batchRequestPart the incoming MIME part
* @return the corresponding result
* @throws ODataException
*/
- public BatchResponsePart handleBatchPart(BatchPart batchPart) throws ODataException;
+ public BatchResponsePart handleBatchPart(BatchRequestPart batchRequestPart) throws ODataException;
/**
* <p>Delegates a handling of the request {@link ODataRequest} to the request handler and provides ODataResponse {@link ODataResponse}.</p>
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchPart.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchPart.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchPart.java
deleted file mode 100644
index b7d8539..0000000
--- a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchPart.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*******************************************************************************
- * 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.odata2.api.batch;
-
-import java.util.List;
-
-import org.apache.olingo.odata2.api.processor.ODataRequest;
-
-/**
- * A BatchPart
- * <p> BatchPart represents a distinct MIME part of a Batch Request body. It can be ChangeSet or Query Operation
- *
- */
-public interface BatchPart {
-
- /**
- * Get the info if a BatchPart is a ChangeSet
- * @return true or false
- */
- public boolean isChangeSet();
-
- /**
- * Get requests. If a BatchPart is a Query Operation, the list contains one request.
- * @return a list of {@link ODataRequest}
- */
- public List<ODataRequest> getRequests();
-}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java
new file mode 100644
index 0000000..a12f774
--- /dev/null
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/batch/BatchRequestPart.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * 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.odata2.api.batch;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+
+/**
+ * A BatchPart
+ * <p> BatchPart represents a distinct MIME part of a Batch Request body. It can be ChangeSet or Query Operation
+ */
+public interface BatchRequestPart {
+
+ /**
+ * Get the info if a BatchPart is a ChangeSet
+ * @return true or false
+ */
+ public boolean isChangeSet();
+
+ /**
+ * Get requests. If a BatchPart is a Query Operation, the list contains one request.
+ * @return a list of {@link ODataRequest}
+ */
+ public List<ODataRequest> getRequests();
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSet.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSet.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSet.java
new file mode 100644
index 0000000..13f7df0
--- /dev/null
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSet.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * 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.odata2.api.client.batch;
+
+import java.util.List;
+
+import org.apache.olingo.odata2.api.rt.RuntimeDelegate;
+
+/**
+ * A BatchChangeSet
+ * <p> BatchChangeSet represents a Change Set, that consists of change requests
+ */
+public abstract class BatchChangeSet implements BatchPart {
+
+ /**
+ * Add a new change request to the ChangeSet
+ * @param BatchChangeSetPart {@link BatchChangeSetPart}
+ */
+ public abstract void add(BatchChangeSetPart request);
+
+ /**
+ * Get change requests
+ * @return a list of {@link BatchChangeSetPart}
+ */
+ public abstract List<BatchChangeSetPart> getChangeSetParts();
+
+ /**
+ * Get new builder instance
+ * @return {@link BatchChangeSetBuilder}
+ */
+ public static BatchChangeSetBuilder newBuilder() {
+ return BatchChangeSetBuilder.newInstance();
+ }
+
+ public static abstract class BatchChangeSetBuilder {
+
+ protected BatchChangeSetBuilder() {}
+
+ private static BatchChangeSetBuilder newInstance() {
+ return RuntimeDelegate.createBatchChangeSetBuilder();
+ }
+
+ public abstract BatchChangeSet build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
new file mode 100644
index 0000000..ba59edc
--- /dev/null
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchChangeSetPart.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * 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.odata2.api.client.batch;
+
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.rt.RuntimeDelegate;
+
+/**
+ * A BatchChangeSetPart
+ * <p> BatchChangeSetPart represents a change request within a Change Set
+ */
+public abstract class BatchChangeSetPart {
+
+ public abstract Map<String, String> getHeaders();
+
+ public abstract String getBody();
+
+ public abstract String getUri();
+
+ public abstract String getMethod();
+
+ public abstract String getContentId();
+
+ /**
+ * @param headers
+ * @return a new builder object
+ */
+ public static BatchChangeSetPartBuilder headers(final Map<String, String> headers) {
+ return newBuilder().headers(headers);
+ }
+
+ /**
+ * @param body a change request body
+ * @return a new builder object
+ */
+ public static BatchChangeSetPartBuilder body(final String body) {
+ return newBuilder().body(body);
+ }
+
+ /**
+ * @param uri should not be null
+ * @return a new builder object
+ */
+ public static BatchChangeSetPartBuilder uri(final String uri) {
+ return newBuilder().uri(uri);
+ }
+
+ /**
+ * @param method MUST be the PUT, POST, MERGE, DELETE or PATCH method
+ * @return a new builder object
+ */
+ public static BatchChangeSetPartBuilder method(final String method) {
+ return newBuilder().method(method);
+ }
+
+ /**
+ * @param contentId can be used to identify the different request within a the batch
+ * @return a new builder object
+ */
+ public static BatchChangeSetPartBuilder contentId(final String contentId) {
+ return newBuilder().contentId(contentId);
+ }
+
+ /**
+ * @return returns a new builder object
+ */
+ public static BatchChangeSetPartBuilder newBuilder() {
+ return BatchChangeSetPartBuilder.newInstance();
+ }
+
+ public static abstract class BatchChangeSetPartBuilder {
+
+ protected BatchChangeSetPartBuilder() {}
+
+ private static BatchChangeSetPartBuilder newInstance() {
+ return RuntimeDelegate.createBatchChangeSetPartBuilder();
+ }
+
+ public abstract BatchChangeSetPart build();
+
+ public abstract BatchChangeSetPartBuilder headers(Map<String, String> headers);
+
+ public abstract BatchChangeSetPartBuilder body(String body);
+
+ public abstract BatchChangeSetPartBuilder uri(String uri);
+
+ public abstract BatchChangeSetPartBuilder method(String method);
+
+ public abstract BatchChangeSetPartBuilder contentId(String contentId);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchPart.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchPart.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchPart.java
new file mode 100644
index 0000000..6c6c7f0
--- /dev/null
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchPart.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.api.client.batch;
+
+/**
+ * A BatchPartRequest
+ * <p> BatchPartRequest represents a distinct part of a Batch Request body. It can be a ChangeSet or Query Operation.
+ */
+public interface BatchPart {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchQueryPart.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchQueryPart.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchQueryPart.java
new file mode 100644
index 0000000..42bd28d
--- /dev/null
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchQueryPart.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * 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.odata2.api.client.batch;
+
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.rt.RuntimeDelegate;
+
+/**
+ * A BatchQueryPart
+ * <p>BatchQueryPart represents a single retrieve request
+ */
+public abstract class BatchQueryPart implements BatchPart {
+
+ public abstract Map<String, String> getHeaders();
+
+ public abstract String getUri();
+
+ public abstract String getMethod();
+
+ public abstract String getContentId();
+
+ /**
+ * @param headers
+ * @return a new builder object
+ */
+ public static BatchQueryPartBuilder headers(final Map<String, String> headers) {
+ return newBuilder().headers(headers);
+ }
+
+ /**
+ * @param uri should not be null
+ * @return a new builder object
+ */
+ public static BatchQueryPartBuilder uri(final String uri) {
+ return newBuilder().uri(uri);
+ }
+
+ /**
+ * @param method MUST be the HTTP GET method
+ * @return a new builder object
+ */
+ public static BatchQueryPartBuilder method(final String method) {
+ return newBuilder().method(method);
+ }
+
+ /**
+ * @param contentId can be used to identify the different request within a the batch
+ * @return a new builder object
+ */
+ public static BatchQueryPartBuilder contentId(final String contentId) {
+ return newBuilder().contentId(contentId);
+ }
+
+ /**
+ * @return returns a new builder object
+ */
+ public static BatchQueryPartBuilder newBuilder() {
+ return BatchQueryPartBuilder.newInstance();
+ }
+
+ public static abstract class BatchQueryPartBuilder {
+
+ protected BatchQueryPartBuilder() {}
+
+ private static BatchQueryPartBuilder newInstance() {
+ return RuntimeDelegate.createBatchQueryPartBuilder();
+ }
+
+ public abstract BatchQueryPart build();
+
+ public abstract BatchQueryPartBuilder headers(Map<String, String> headers);
+
+ public abstract BatchQueryPartBuilder uri(String uri);
+
+ public abstract BatchQueryPartBuilder method(String method);
+
+ public abstract BatchQueryPartBuilder contentId(String contentId);
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java
new file mode 100644
index 0000000..4d99c7d
--- /dev/null
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/client/batch/BatchSingleResponse.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.api.client.batch;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+* A BatchSingleResponse
+* <p> BatchSingleResponse represents a single response of a Batch Response body. It can be a response to a change request of ChangeSet or a response to a retrieve request
+*/
+public interface BatchSingleResponse {
+ /**
+ * @return a result code of the attempt to understand and satisfy the request
+ */
+ public String getStatusCode();
+
+ /**
+ * @return a short textual description of the status code
+ */
+ public String getStatusInfo();
+
+ /**
+ * @return a value of the Content-Id header
+ */
+ public String getContentId();
+
+ /**
+ * @return a body part of a response message
+ */
+ public String getBody();
+
+ /**
+ * @return all available headers
+ */
+ public Map<String, String> getHeaders();
+
+ /**
+ * @param name HTTP response header name
+ * @return a header value or null if not set
+ */
+ public String getHeader(final String name);
+
+ /**
+ * @return a set of all available header names
+ */
+ public Set<String> getHeaderNames();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
index 97cc26a..cb876aa 100644
--- a/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProvider.java
@@ -23,8 +23,10 @@ import java.util.List;
import java.util.Map;
import org.apache.olingo.odata2.api.batch.BatchException;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.client.batch.BatchPart;
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
@@ -220,13 +222,18 @@ public final class EntityProvider {
ODataFeed readFeed(String contentType, EdmEntitySet entitySet, InputStream content, EntityProviderReadProperties properties) throws EntityProviderException;
/**
- * Read (de-serialize) data from <code>content</code> (as {@link InputStream}) in specified format (given as <code>contentType</code>)
- * based on <code>entity data model</code> (given as {@link EdmEntitySet}) and provide this data as {@link ODataEntry}.
- *
- * @param contentType format of content in the given input stream.
- * @param entitySet entity data model for entity set to be read
- * @param content data in form of an {@link InputStream} which contains the data in specified format
- * @param properties additional properties necessary for reading content from {@link InputStream} into {@link Map}.
+ * Reads (de-serializes) data from <code>content</code> (as {@link InputStream})
+ * in specified format (given as <code>contentType</code>) based on
+ * <code>entity data model</code> (given as {@link EdmEntitySet})
+ * and provides this data as {@link ODataEntry}.
+ * Does not return complete entry data but only data present in the
+ * de-serialized content.
+ * @param contentType format of content in the given input stream
+ * @param entitySet entity data model for entity set to be read
+ * @param content data in form of an {@link InputStream} which
+ * contains the data in specified format
+ * @param properties additional properties necessary for reading
+ * content from {@link InputStream} into {@link Map}.
* @return entry as {@link ODataEntry}
* @throws EntityProviderException if reading of data (de-serialization) fails
*/
@@ -331,7 +338,7 @@ public final class EntityProvider {
* @return list of {@link BatchPart}
* @throws BatchException if parsing fails
*/
- List<BatchPart> parseBatchRequest(String contentType, InputStream content, EntityProviderBatchProperties properties) throws BatchException;
+ List<BatchRequestPart> parseBatchRequest(String contentType, InputStream content, EntityProviderBatchProperties properties) throws BatchException;
/**
* Write responses of Batch Response Parts in Batch Response as {@link ODataResponse}.
@@ -342,6 +349,26 @@ public final class EntityProvider {
* @throws BatchException
*/
ODataResponse writeBatchResponse(List<BatchResponsePart> batchResponseParts) throws BatchException;
+
+ /**
+ * Create Batch Request body as InputStream.
+ *
+ * @param batchParts a list of BatchPartRequests {@link BatchPart}
+ * @param boundary
+ * @return Batch Request as InputStream
+ */
+ InputStream writeBatchRequest(List<BatchPart> batchParts, String boundary);
+
+ /**
+ * Parse Batch Response body (as {@link InputStream}) and provide a list of single responses as {@link BatchSingleResponse}
+ *
+ * @param content response body
+ * @param contentType format of content in the given input stream (incl. boundary parameter)
+ * @return list of {@link BatchSingleResponse}
+ * @throws BatchException
+ */
+ List<BatchSingleResponse> parseBatchResponse(String contentType, InputStream content) throws BatchException;
+
}
/**
@@ -671,15 +698,15 @@ public final class EntityProvider {
}
/**
- * Parse Batch Request body <code>inputStream</code> (as {@link InputStream}) and provide a list of Batch Parts as {@link BatchPart}
+ * Parse Batch Request body <code>inputStream</code> (as {@link InputStream}) and provide a list of Batch Request parts as {@link BatchRequestPart}
*
* @param contentType format of content in the given input stream
* @param content request body
* @param properties additional properties necessary for parsing. Must not be null.
- * @return list of {@link BatchPart}
+ * @return list of {@link BatchRequestPart}
* @throws BatchException if parsing fails
*/
- public static List<BatchPart> parseBatchRequest(final String contentType, final InputStream content, final EntityProviderBatchProperties properties) throws BatchException {
+ public static List<BatchRequestPart> parseBatchRequest(final String contentType, final InputStream content, final EntityProviderBatchProperties properties) throws BatchException {
return createEntityProvider().parseBatchRequest(contentType, content, properties);
}
@@ -695,4 +722,27 @@ public final class EntityProvider {
return createEntityProvider().writeBatchResponse(batchResponseParts);
}
+ /**
+ * Create Batch Request body as InputStream.
+ *
+ * @param batchParts a list of BatchPartRequests {@link BatchPart}
+ * @param boundary
+ * @return Batch Request as InputStream
+ */
+ public static InputStream writeBatchRequest(final List<BatchPart> batchParts, final String boundary) {
+ return createEntityProvider().writeBatchRequest(batchParts, boundary);
+ }
+
+ /**
+ * Parse Batch Response body (as {@link InputStream}) and provide a list of single responses as {@link BatchSingleResponse}
+ *
+ * @param content response body
+ * @param contentType format of content in the given input stream (inclusive boundary parameter)
+ * @return list of {@link BatchSingleResponse}
+ * @throws BatchException
+ */
+ public static List<BatchSingleResponse> parseBatchResponse(final InputStream content, final String contentType) throws BatchException {
+ return createEntityProvider().parseBatchResponse(contentType, content);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProviderReadProperties.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProviderReadProperties.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProviderReadProperties.java
index f64aa93..97e4002 100644
--- a/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProviderReadProperties.java
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/ep/EntityProviderReadProperties.java
@@ -25,28 +25,28 @@ import java.util.Map;
import org.apache.olingo.odata2.api.ep.callback.OnReadInlineContent;
/**
- * The {@link EntityProviderReadProperties} contains all necessary settings to read an entity with the {@link EntityProvider}.
- *
- * The main settings are
+ * <p>The {@link EntityProviderReadProperties} contains all necessary settings
+ * to read an entity with the {@link EntityProvider}.</p>
+ * <p>The main settings are
* <ul>
* <li>the <code>mergeSemantic</code></li>
* <li>the <code>callback for inlined navigation properties</code></li>
* <li>and the <code>type mappings</code></li>
* </ul>
- *
+ * </p>
*
*/
public class EntityProviderReadProperties {
/** Callback which is necessary if entity contains inlined navigation properties. */
private OnReadInlineContent callback;
/**
- * if merge is <code>true</code> the input content is in context of an <b>merge</b> (e.g. MERGE, PATCH) read request,
- * otherwise if <code>false</code> it is an <b>none merge</b> (e.g. CREATE) read request
+ * if merge is <code>true</code> the input content is in context of a <b>merge</b> (e.g. MERGE, PATCH) read request,
+ * otherwise if <code>false</code> it is a <b>non-merge</b> (e.g. CREATE) read request
*/
private boolean merge;
/**
- * typeMappings contains mappings from <code>edm property name</code> to <code>java class</code> which should be used
- * for a type mapping during read of content. If according <code>edm property</code> can not be read
+ * typeMappings contains mappings from <code>edm property name</code> to <code>java class</code> which should be used
+ * for a type mapping during reading of content. If according <code>edm property</code> can not be read
* into given <code>java class</code> an {@link EntityProviderException} is thrown.
* Supported mappings are documented in {@link org.apache.olingo.odata2.api.edm.EdmSimpleType}.
*/
@@ -78,6 +78,14 @@ public class EntityProviderReadProperties {
return callback;
}
+ /**
+ * <p>Gets the merge semantics.</p>
+ * <p>Merge semantics is set if the input content has to be treated in the context
+ * of a request to merge incoming data with existing data (e.g., indicated by the
+ * HTTP verbs <code>MERGE</code> or <code>PATCH</code> in a server application).
+ * Otherwise the request, even if not all data are supplied, is supposed to
+ * overwrite the existing entity completely.</p>
+ */
public boolean getMergeSemantic() {
return merge;
}
@@ -97,6 +105,11 @@ public class EntityProviderReadProperties {
addTypeMappings(propertiesFrom.typeMappings);
}
+ /**
+ * Sets the merge semantics.
+ * @param mergeSemantic whether merge semantics is requested
+ * @see EntityProviderReadProperties#getMergeSemantic()
+ */
public EntityProviderReadPropertiesBuilder mergeSemantic(final boolean mergeSemantic) {
properties.merge = mergeSemantic;
return this;
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
----------------------------------------------------------------------
diff --git a/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java b/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
index 6590bc5..88c87cd 100644
--- a/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
+++ b/odata-api/src/main/java/org/apache/olingo/odata2/api/rt/RuntimeDelegate.java
@@ -22,6 +22,9 @@ import java.io.InputStream;
import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.batch.BatchResponsePart.BatchResponsePartBuilder;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet.BatchChangeSetBuilder;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart.BatchChangeSetPartBuilder;
+import org.apache.olingo.odata2.api.client.batch.BatchQueryPart.BatchQueryPartBuilder;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmSimpleType;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeFacade;
@@ -96,6 +99,12 @@ public abstract class RuntimeDelegate {
protected abstract ODataRequestBuilder createODataRequestBuilder();
+ protected abstract BatchChangeSetBuilder createBatchChangeSetBuilder();
+
+ protected abstract BatchQueryPartBuilder createBatchQueryRequestBuilder();
+
+ protected abstract BatchChangeSetPartBuilder createBatchChangeSetRequest();
+
}
/**
@@ -185,4 +194,16 @@ public abstract class RuntimeDelegate {
public static ODataRequestBuilder createODataRequestBuilder() {
return RuntimeDelegate.getInstance().createODataRequestBuilder();
}
+
+ public static BatchChangeSetBuilder createBatchChangeSetBuilder() {
+ return RuntimeDelegate.getInstance().createBatchChangeSetBuilder();
+ }
+
+ public static BatchQueryPartBuilder createBatchQueryPartBuilder() {
+ return RuntimeDelegate.getInstance().createBatchQueryRequestBuilder();
+ }
+
+ public static BatchChangeSetPartBuilder createBatchChangeSetPartBuilder() {
+ return RuntimeDelegate.getInstance().createBatchChangeSetRequest();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetImpl.java
new file mode 100644
index 0000000..2db859c
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetImpl.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.odata2.core.batch;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart;
+
+public class BatchChangeSetImpl extends BatchChangeSet {
+ private List<BatchChangeSetPart> requests = new ArrayList<BatchChangeSetPart>();
+
+ @Override
+ public void add(final BatchChangeSetPart request) {
+ requests.add(request);
+ }
+
+ @Override
+ public List<BatchChangeSetPart> getChangeSetParts() {
+ return Collections.unmodifiableList(requests);
+ }
+
+ public class BatchChangeSetBuilderImpl extends BatchChangeSetBuilder {
+
+ @Override
+ public BatchChangeSet build() {
+ return BatchChangeSetImpl.this;
+ }
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
new file mode 100644
index 0000000..9546017
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchChangeSetPartImpl.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart;
+
+public class BatchChangeSetPartImpl extends BatchChangeSetPart {
+ private String method;
+ private Map<String, String> headers = new HashMap<String, String>();
+ private String body;
+ private String uri;
+ public String contentId;
+ private static final String CHANGE_METHODS = "(PUT|POST|DELETE|MERGE|PATCH)";
+
+ @Override
+ public Map<String, String> getHeaders() {
+ return Collections.unmodifiableMap(headers);
+ }
+
+ @Override
+ public String getBody() {
+ return body;
+ }
+
+ @Override
+ public String getMethod() {
+ return method;
+ }
+
+ @Override
+ public String getUri() {
+ return uri;
+ }
+
+ @Override
+ public String getContentId() {
+ return contentId;
+ }
+
+ public class BatchChangeSetRequestBuilderImpl extends BatchChangeSetPartBuilder {
+ private String method;
+ private Map<String, String> headers = new HashMap<String, String>();
+ private String body;
+ private String uri;
+ private String contentId;
+
+ @Override
+ public BatchChangeSetPart build() {
+ if (method == null || uri == null) {
+ throw new IllegalArgumentException();
+ }
+ BatchChangeSetPartImpl.this.method = method;
+ BatchChangeSetPartImpl.this.headers = headers;
+ BatchChangeSetPartImpl.this.body = body;
+ BatchChangeSetPartImpl.this.uri = uri;
+ BatchChangeSetPartImpl.this.contentId = contentId;
+ return BatchChangeSetPartImpl.this;
+ }
+
+ @Override
+ public BatchChangeSetPartBuilder headers(final Map<String, String> headers) {
+ this.headers = headers;
+ return this;
+ }
+
+ @Override
+ public BatchChangeSetPartBuilder body(final String body) {
+ this.body = body;
+ return this;
+ }
+
+ @Override
+ public BatchChangeSetPartBuilder uri(final String uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ @Override
+ public BatchChangeSetPartBuilder method(final String method) {
+ if (method != null && method.matches(CHANGE_METHODS)) {
+ this.method = method;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ @Override
+ public BatchChangeSetPartBuilder contentId(final String contentId) {
+ this.contentId = contentId;
+ return this;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchConstants.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchConstants.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchConstants.java
deleted file mode 100644
index 052365d..0000000
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchConstants.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*******************************************************************************
- * 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.odata2.core.batch;
-
-public class BatchConstants {
-
- public static final String HTTP_APPLICATION_HTTP = "application/http";
-
- public static final String MULTIPART_MIXED = "multipart/mixed";
-
- public static final String BINARY_ENCODING = "binary";
-
- public static final String HTTP_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
-
- public static final String HTTP_CONTENT_ID = "Content-Id";
-
- public static final String MIME_HEADER_CONTENT_ID = "MimeHeader-ContentId";
-
- public static final String REQUEST_HEADER_CONTENT_ID = "RequestHeader-ContentId";
-}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
index 22dfd70..8869a33 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHandlerImpl.java
@@ -29,7 +29,7 @@ import java.util.Map;
import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.ODataServiceFactory;
import org.apache.olingo.odata2.api.batch.BatchHandler;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
@@ -55,7 +55,7 @@ public class BatchHandlerImpl implements BatchHandler {
}
@Override
- public BatchResponsePart handleBatchPart(final BatchPart batchPart) throws ODataException {
+ public BatchResponsePart handleBatchPart(final BatchRequestPart batchPart) throws ODataException {
if (batchPart.isChangeSet()) {
List<ODataRequest> changeSetRequests = batchPart.getRequests();
contentIdMap = new HashMap<String, String>();
@@ -66,8 +66,8 @@ public class BatchHandlerImpl implements BatchHandler {
}
ODataRequest request = batchPart.getRequests().get(0);
ODataRequestHandler handler = createHandler(request);
- String mimeHeaderContentId = request.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
- String requestHeaderContentId = request.getRequestHeaderValue(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+ String mimeHeaderContentId = request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+ String requestHeaderContentId = request.getRequestHeaderValue(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
ODataResponse response = setContentIdHeader(handler.handle(request), mimeHeaderContentId, requestHeaderContentId);
List<ODataResponse> responses = new ArrayList<ODataResponse>(1);
responses.add(response);
@@ -78,8 +78,8 @@ public class BatchHandlerImpl implements BatchHandler {
@Override
public ODataResponse handleRequest(final ODataRequest suppliedRequest) throws ODataException {
ODataRequest request;
- String mimeHeaderContentId = suppliedRequest.getRequestHeaderValue(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
- String requestHeaderContentId = suppliedRequest.getRequestHeaderValue(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+ String mimeHeaderContentId = suppliedRequest.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+ String requestHeaderContentId = suppliedRequest.getRequestHeaderValue(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH));
List<PathSegment> odataSegments = suppliedRequest.getPathInfo().getODataSegments();
if (!odataSegments.isEmpty() && odataSegments.get(0).getPath().matches("\\$.*")) {
@@ -142,12 +142,12 @@ public class BatchHandlerImpl implements BatchHandler {
private ODataResponse setContentIdHeader(final ODataResponse response, final String mimeHeaderContentId, final String requestHeaderContentId) {
ODataResponse modifiedResponse;
if (requestHeaderContentId != null && mimeHeaderContentId != null) {
- modifiedResponse = ODataResponse.fromResponse(response).header(BatchConstants.REQUEST_HEADER_CONTENT_ID, requestHeaderContentId)
- .header(BatchConstants.MIME_HEADER_CONTENT_ID, mimeHeaderContentId).build();
+ modifiedResponse = ODataResponse.fromResponse(response).header(BatchHelper.REQUEST_HEADER_CONTENT_ID, requestHeaderContentId)
+ .header(BatchHelper.MIME_HEADER_CONTENT_ID, mimeHeaderContentId).build();
} else if (requestHeaderContentId != null) {
- modifiedResponse = ODataResponse.fromResponse(response).header(BatchConstants.REQUEST_HEADER_CONTENT_ID, requestHeaderContentId).build();
+ modifiedResponse = ODataResponse.fromResponse(response).header(BatchHelper.REQUEST_HEADER_CONTENT_ID, requestHeaderContentId).build();
} else if (mimeHeaderContentId != null) {
- modifiedResponse = ODataResponse.fromResponse(response).header(BatchConstants.MIME_HEADER_CONTENT_ID, mimeHeaderContentId).build();
+ modifiedResponse = ODataResponse.fromResponse(response).header(BatchHelper.MIME_HEADER_CONTENT_ID, mimeHeaderContentId).build();
} else {
return response;
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
new file mode 100644
index 0000000..38d02ae
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchHelper.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import java.io.UnsupportedEncodingException;
+import java.util.UUID;
+
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+public class BatchHelper {
+
+ public static final String BINARY_ENCODING = "binary";
+
+ public static final String DEFAULT_ENCODING = "utf-8";
+
+ public static final String HTTP_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+
+ public static final String HTTP_CONTENT_ID = "Content-Id";
+
+ public static final String MIME_HEADER_CONTENT_ID = "MimeHeader-ContentId";
+
+ public static final String REQUEST_HEADER_CONTENT_ID = "RequestHeader-ContentId";
+
+ protected static String generateBoundary(final String value) {
+ return value + "_" + UUID.randomUUID().toString();
+ }
+
+ protected static byte[] getBytes(final String body) {
+ try {
+ return body.getBytes(DEFAULT_ENCODING);
+ } catch (UnsupportedEncodingException e) {
+ throw new ODataRuntimeException(e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchPartImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchPartImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchPartImpl.java
deleted file mode 100644
index 665b01b..0000000
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchPartImpl.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*******************************************************************************
- * 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.odata2.core.batch;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.olingo.odata2.api.batch.BatchPart;
-import org.apache.olingo.odata2.api.processor.ODataRequest;
-
-public class BatchPartImpl implements BatchPart {
-
- private List<ODataRequest> requests = new ArrayList<ODataRequest>();
- private boolean isChangeSet;
-
- public BatchPartImpl() {}
-
- public BatchPartImpl(final boolean isChangeSet, final List<ODataRequest> requests) {
- this.isChangeSet = isChangeSet;
- this.requests = requests;
- }
-
- @Override
- public boolean isChangeSet() {
- return isChangeSet;
- }
-
- public void setChangeSet(final boolean isChangeSet) {
- this.isChangeSet = isChangeSet;
- }
-
- @Override
- public List<ODataRequest> getRequests() {
- return Collections.unmodifiableList(requests);
- }
-
- public void setRequests(final List<ODataRequest> requests) {
- this.requests = requests;
- }
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchQueryPartImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchQueryPartImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchQueryPartImpl.java
new file mode 100644
index 0000000..e22a3b3
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchQueryPartImpl.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.client.batch.BatchQueryPart;
+
+public class BatchQueryPartImpl extends BatchQueryPart {
+ private String method;
+ private Map<String, String> headers = new HashMap<String, String>();
+ private String uri;
+ private String contentId;
+ private static final String GET = "GET";
+
+ @Override
+ public Map<String, String> getHeaders() {
+ return Collections.unmodifiableMap(headers);
+ }
+
+ @Override
+ public String getMethod() {
+ return method;
+ }
+
+ @Override
+ public String getUri() {
+ return uri;
+ }
+
+ @Override
+ public String getContentId() {
+ return contentId;
+ }
+
+ public class BatchQueryRequestBuilderImpl extends BatchQueryPartBuilder {
+ private String method;
+ private Map<String, String> headers = new HashMap<String, String>();
+ private String uri;
+ private String contentId;
+
+ @Override
+ public BatchQueryPart build() {
+ if (method == null || uri == null) {
+ throw new IllegalArgumentException();
+ }
+ BatchQueryPartImpl.this.method = method;
+ BatchQueryPartImpl.this.headers = headers;
+ BatchQueryPartImpl.this.uri = uri;
+ BatchQueryPartImpl.this.contentId = contentId;
+ return BatchQueryPartImpl.this;
+ }
+
+ @Override
+ public BatchQueryPartBuilder headers(final Map<String, String> headers) {
+ this.headers = headers;
+ return this;
+ }
+
+ @Override
+ public BatchQueryPartBuilder uri(final String uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ @Override
+ public BatchQueryPartBuilder method(final String method) {
+ if (method != null && method.matches(GET)) {
+ this.method = method;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ return this;
+ }
+
+ @Override
+ public BatchQueryPartBuilder contentId(final String contentId) {
+ this.contentId = contentId;
+ return this;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java
index 4c0ae32..e37d572 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestParser.java
@@ -21,10 +21,10 @@ package org.apache.olingo.odata2.core.batch;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@@ -37,11 +37,13 @@ import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import org.apache.olingo.odata2.api.batch.BatchException;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
import org.apache.olingo.odata2.api.processor.ODataRequest;
+import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder;
import org.apache.olingo.odata2.api.uri.PathInfo;
import org.apache.olingo.odata2.api.uri.PathSegment;
import org.apache.olingo.odata2.core.ODataPathSegmentImpl;
@@ -64,7 +66,7 @@ public class BatchRequestParser {
private static final Pattern REG_EX_ANY_BOUNDARY_STRING = Pattern.compile("--" + ANY_CHARACTERS + REG_EX_ZERO_OR_MORE_WHITESPACES);
private static final Pattern REG_EX_REQUEST_LINE = Pattern.compile("(GET|POST|PUT|DELETE|MERGE|PATCH)\\s(.*)\\s?" + REG_EX_VERSION + REG_EX_ZERO_OR_MORE_WHITESPACES);
private static final Pattern REG_EX_BOUNDARY_PARAMETER = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE + "boundary=(\".*\"|.*)" + REG_EX_ZERO_OR_MORE_WHITESPACES);
- private static final Pattern REG_EX_CONTENT_TYPE = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE + BatchConstants.MULTIPART_MIXED);
+ private static final Pattern REG_EX_CONTENT_TYPE = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE + HttpContentType.MULTIPART_MIXED);
private static final Pattern REG_EX_QUERY_PARAMETER = Pattern.compile("((?:\\$|)[^=]+)=([^=]+)");
private static final String REG_EX_BOUNDARY = "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046
@@ -74,19 +76,21 @@ public class BatchRequestParser {
private String boundary;
private String currentMimeHeaderContentId;
private int currentLineNumber = 0;
- private static Set<String> HTTP_CHANGESET_METHODS;
- private static Set<String> HTTP_BATCH_METHODS;
+ private final static Set<String> HTTP_CHANGESET_METHODS;
+ private final static Set<String> HTTP_BATCH_METHODS;
static {
- HTTP_CHANGESET_METHODS = new HashSet<String>();
- HTTP_CHANGESET_METHODS.add("POST");
- HTTP_CHANGESET_METHODS.add("PUT");
- HTTP_CHANGESET_METHODS.add("DELETE");
- HTTP_CHANGESET_METHODS.add("MERGE");
- HTTP_CHANGESET_METHODS.add("PATCH");
-
- HTTP_BATCH_METHODS = new HashSet<String>();
- HTTP_BATCH_METHODS.add("GET");
+ HashSet<String> httpChangesetMethods = new HashSet<String>();
+ httpChangesetMethods.add("POST");
+ httpChangesetMethods.add("PUT");
+ httpChangesetMethods.add("DELETE");
+ httpChangesetMethods.add("MERGE");
+ httpChangesetMethods.add("PATCH");
+ HTTP_CHANGESET_METHODS = Collections.unmodifiableSet(httpChangesetMethods);
+
+ HashSet<String> httpBatchMethods = new HashSet<String>();
+ httpBatchMethods.add("GET");
+ HTTP_BATCH_METHODS = Collections.unmodifiableSet(httpBatchMethods);
}
public BatchRequestParser(final String contentType, final EntityProviderBatchProperties properties) {
@@ -94,10 +98,10 @@ public class BatchRequestParser {
batchRequestPathInfo = properties.getPathInfo();
}
- public List<BatchPart> parse(final InputStream in) throws BatchException {
- Scanner scanner = new Scanner(in, "UTF-8").useDelimiter(LF);
+ public List<BatchRequestPart> parse(final InputStream in) throws BatchException {
+ Scanner scanner = new Scanner(in, BatchHelper.DEFAULT_ENCODING).useDelimiter(LF);
baseUri = getBaseUri();
- List<BatchPart> requestList;
+ List<BatchRequestPart> requestList;
try {
requestList = parseBatchRequest(scanner);
} finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
@@ -111,12 +115,12 @@ public class BatchRequestParser {
return requestList;
}
- private List<BatchPart> parseBatchRequest(final Scanner scanner) throws BatchException {
- List<BatchPart> requests = new LinkedList<BatchPart>();
+ private List<BatchRequestPart> parseBatchRequest(final Scanner scanner) throws BatchException {
+ List<BatchRequestPart> requests = new LinkedList<BatchRequestPart>();
if (contentTypeMime != null) {
boundary = getBoundary(contentTypeMime);
parsePreamble(scanner);
- String closeDelimiter = "--" + boundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES;
+ final String closeDelimiter = "--" + boundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES;
while (scanner.hasNext() && !scanner.hasNext(closeDelimiter)) {
requests.add(parseMultipart(scanner, boundary, false));
parseNewLine(scanner);
@@ -131,7 +135,6 @@ public class BatchRequestParser {
throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
}
return requests;
-
}
//The method parses additional information prior to the first boundary delimiter line
@@ -142,37 +145,37 @@ public class BatchRequestParser {
}
}
- private BatchPart parseMultipart(final Scanner scanner, final String boundary, final boolean isChangeSet) throws BatchException {
+ private BatchRequestPart parseMultipart(final Scanner scanner, final String boundary, final boolean isChangeSet) throws BatchException {
Map<String, String> mimeHeaders = new HashMap<String, String>();
- BatchPart multipart = null;
+ BatchRequestPart multipart = null;
List<ODataRequest> requests = new ArrayList<ODataRequest>();
if (scanner.hasNext("--" + boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) {
scanner.next();
currentLineNumber++;
mimeHeaders = parseHeaders(scanner);
- currentMimeHeaderContentId = mimeHeaders.get(BatchConstants.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+ currentMimeHeaderContentId = mimeHeaders.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
String contentType = mimeHeaders.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
if (contentType == null) {
throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
}
if (isChangeSet) {
- if (BatchConstants.HTTP_APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
- validateEncoding(mimeHeaders.get(BatchConstants.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
+ if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
+ validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
parseNewLine(scanner);// mandatory
requests.add(parseRequest(scanner, isChangeSet));
- multipart = new BatchPartImpl(false, requests);
+ multipart = new BatchRequestPartImpl(false, requests);
} else {
- throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(BatchConstants.HTTP_APPLICATION_HTTP));
+ throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.APPLICATION_HTTP));
}
} else {
- if (BatchConstants.HTTP_APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
- validateEncoding(mimeHeaders.get(BatchConstants.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
+ if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
+ validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
parseNewLine(scanner);// mandatory
requests.add(parseRequest(scanner, isChangeSet));
- multipart = new BatchPartImpl(false, requests);
- } else if (contentType.matches(REG_EX_OPTIONAL_WHITESPACE + BatchConstants.MULTIPART_MIXED + ANY_CHARACTERS)) {
+ multipart = new BatchRequestPartImpl(false, requests);
+ } else if (contentType.matches(REG_EX_OPTIONAL_WHITESPACE + HttpContentType.MULTIPART_MIXED + ANY_CHARACTERS)) {
String changeSetBoundary = getBoundary(contentType);
if (boundary.equals(changeSetBoundary)) {
throw new BatchException(BatchException.INVALID_CHANGESET_BOUNDARY.addContent(currentLineNumber));
@@ -181,16 +184,14 @@ public class BatchRequestParser {
parseNewLine(scanner);// mandatory
Pattern changeSetCloseDelimiter = Pattern.compile("--" + changeSetBoundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES);
while (!scanner.hasNext(changeSetCloseDelimiter)) {
- BatchPart part = parseMultipart(scanner, changeSetBoundary, true);
- if (part.getRequests().size() == 1) {
- changeSetRequests.add(part.getRequests().get(0));
- }
+ BatchRequestPart part = parseMultipart(scanner, changeSetBoundary, true);
+ changeSetRequests.addAll(part.getRequests());
}
scanner.next(changeSetCloseDelimiter);
currentLineNumber++;
- multipart = new BatchPartImpl(true, changeSetRequests);
+ multipart = new BatchRequestPartImpl(true, changeSetRequests);
} else {
- throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(BatchConstants.MULTIPART_MIXED + " or " + BatchConstants.HTTP_APPLICATION_HTTP));
+ throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED + " or " + HttpContentType.APPLICATION_HTTP));
}
}
} else if (scanner.hasNext(boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) {
@@ -208,60 +209,62 @@ public class BatchRequestParser {
}
private ODataRequest parseRequest(final Scanner scanner, final boolean isChangeSet) throws BatchException {
- try {
- ODataRequest request;
- if (scanner.hasNext(REG_EX_REQUEST_LINE)) {
- scanner.next(REG_EX_REQUEST_LINE);
- currentLineNumber++;
- String method = null;
- String uri = null;
- MatchResult result = scanner.match();
- if (result.groupCount() == 2) {
- method = result.group(1);
- uri = result.group(2).trim();
- } else {
- currentLineNumber++;
- throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent(currentLineNumber));
- }
- PathInfo pathInfo = parseRequestUri(uri);
- Map<String, String> queryParameters = parseQueryParameters(uri);
- if (isChangeSet) {
- if (!HTTP_CHANGESET_METHODS.contains(method)) {
- throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(currentLineNumber));
- }
- } else if (!HTTP_BATCH_METHODS.contains(method)) {
- throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD.addContent(currentLineNumber));
- }
- ODataHttpMethod httpMethod = ODataHttpMethod.valueOf(method);
- Map<String, List<String>> headers = parseRequestHeaders(scanner);
- if (currentMimeHeaderContentId != null) {
- List<String> headerList = new ArrayList<String>();
- headerList.add(currentMimeHeaderContentId);
- headers.put(BatchConstants.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList);
- }
-
- String contentType = getContentTypeHeader(headers);
- List<String> acceptHeaders = getAcceptHeader(headers);
- List<Locale> acceptLanguages = getAcceptLanguageHeader(headers);
- parseNewLine(scanner);
- InputStream body;
- body = new ByteArrayInputStream("".getBytes("UTF-8"));
- if (isChangeSet) {
- body = parseBody(scanner);
- }
- if (contentType != null) {
- request = ODataRequest.method(httpMethod).queryParameters(queryParameters).requestHeaders(headers).pathInfo(pathInfo).acceptableLanguages(acceptLanguages).contentType(contentType).body(body).acceptHeaders(acceptHeaders).build();
- } else {
- request = ODataRequest.method(httpMethod).queryParameters(queryParameters).requestHeaders(headers).pathInfo(pathInfo).acceptableLanguages(acceptLanguages).body(body).acceptHeaders(acceptHeaders).build();
- }
+ if (scanner.hasNext(REG_EX_REQUEST_LINE)) {
+ scanner.next(REG_EX_REQUEST_LINE);
+ currentLineNumber++;
+ final String method;
+ final String uri;
+ MatchResult result = scanner.match();
+ if (result.groupCount() == 2) {
+ method = result.group(1);
+ uri = result.group(2).trim();
} else {
currentLineNumber++;
throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent(currentLineNumber));
}
- return request;
- } catch (UnsupportedEncodingException e) {
- throw new ODataRuntimeException(e);
+ PathInfo pathInfo = parseRequestUri(uri);
+ Map<String, String> queryParameters = parseQueryParameters(uri);
+ if (isChangeSet) {
+ if (!HTTP_CHANGESET_METHODS.contains(method)) {
+ throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(currentLineNumber));
+ }
+ } else if (!HTTP_BATCH_METHODS.contains(method)) {
+ throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD.addContent(currentLineNumber));
+ }
+ ODataHttpMethod httpMethod = ODataHttpMethod.valueOf(method);
+ Map<String, List<String>> headers = parseRequestHeaders(scanner);
+ if (currentMimeHeaderContentId != null) {
+ List<String> headerList = new ArrayList<String>();
+ headerList.add(currentMimeHeaderContentId);
+ headers.put(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList);
+ }
+
+ String contentType = getContentTypeHeader(headers);
+ List<String> acceptHeaders = getAcceptHeader(headers);
+ List<Locale> acceptLanguages = getAcceptLanguageHeader(headers);
+ parseNewLine(scanner);
+ InputStream body = new ByteArrayInputStream(new byte[0]);
+ if (isChangeSet) {
+ body = parseBody(scanner);
+ }
+
+ ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod)
+ .queryParameters(queryParameters)
+ .requestHeaders(headers)
+ .pathInfo(pathInfo)
+ .acceptableLanguages(acceptLanguages)
+ .body(body)
+ .acceptHeaders(acceptHeaders);
+
+ if (contentType != null) {
+ requestBuilder = requestBuilder.contentType(contentType);
+ }
+ return requestBuilder.build();
+ } else {
+ currentLineNumber++;
+ throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent(currentLineNumber));
}
+
}
private Map<String, List<String>> parseRequestHeaders(final Scanner scanner) throws BatchException {
@@ -280,7 +283,7 @@ public class BatchRequestParser {
} else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerName)) {
List<String> acceptLanguageHeaders = parseAcceptableLanguages(headerValue);
headers.put(headerName, acceptLanguageHeaders);
- } else if (!BatchConstants.HTTP_CONTENT_ID.equalsIgnoreCase(headerName)) {
+ } else if (!BatchHelper.HTTP_CONTENT_ID.equalsIgnoreCase(headerName)) {
if (headers.containsKey(headerName)) {
headers.get(headerName).add(headerValue);
} else {
@@ -291,7 +294,7 @@ public class BatchRequestParser {
} else {
List<String> headerList = new ArrayList<String>();
headerList.add(headerValue);
- headers.put(BatchConstants.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList);
+ headers.put(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList);
}
}
} else {
@@ -306,40 +309,65 @@ public class BatchRequestParser {
PathInfoImpl pathInfo = new PathInfoImpl();
pathInfo.setServiceRoot(batchRequestPathInfo.getServiceRoot());
pathInfo.setPrecedingPathSegment(batchRequestPathInfo.getPrecedingSegments());
- Scanner uriScanner = new Scanner(uri);
- Pattern regexRequestUri = Pattern.compile("(?:" + baseUri + ")?/?([^?]+)(\\?.*)?");
- if (uriScanner.hasNext(regexRequestUri)) {
- uriScanner.next(regexRequestUri);
- MatchResult result = uriScanner.match();
- if (result.groupCount() == 2) {
- String odataPathSegmentsAsString = result.group(1);
- String queryParametersAsString = result.group(2) != null ? result.group(2) : "";
- pathInfo.setODataPathSegment(parseODataPathSegments(odataPathSegmentsAsString));
- try {
- if (!odataPathSegmentsAsString.startsWith("$")) {
- String requestUri = baseUri + "/" + odataPathSegmentsAsString + queryParametersAsString;
- pathInfo.setRequestUri(new URI(requestUri));
+ final String odataPathSegmentsAsString;
+ final String queryParametersAsString;
+ try {
+ Scanner uriScanner = new Scanner(uri).useDelimiter(LF);
+ URI uriObject = new URI(uri);
+ if (uriObject.isAbsolute()) {
+ Pattern regexRequestUri = Pattern.compile(baseUri + "/([^/][^?]*)(\\?.*)?");
+ if (uriScanner.hasNext(regexRequestUri)) {
+ uriScanner.next(regexRequestUri);
+ MatchResult result = uriScanner.match();
+ if (result.groupCount() == 2) {
+ odataPathSegmentsAsString = result.group(1);
+ queryParametersAsString = result.group(2) != null ? result.group(2) : "";
+ } else {
+ uriScanner.close();
+ throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
- } catch (URISyntaxException e) {
+ } else {
uriScanner.close();
- throw new BatchException(BatchException.INVALID_URI, e);
+ throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
} else {
- uriScanner.close();
- throw new BatchException(BatchException.INVALID_URI);
+ Pattern regexRequestUri = Pattern.compile("([^/][^?]*)(\\?.*)?");
+ if (uriScanner.hasNext(regexRequestUri)) {
+ uriScanner.next(regexRequestUri);
+ MatchResult result = uriScanner.match();
+ if (result.groupCount() == 2) {
+ odataPathSegmentsAsString = result.group(1);
+ queryParametersAsString = result.group(2) != null ? result.group(2) : "";
+ } else {
+ uriScanner.close();
+ throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
+ }
+ } else if (uriScanner.hasNext("/(.*)")) {
+ uriScanner.close();
+ throw new BatchException(BatchException.UNSUPPORTED_ABSOLUTE_PATH.addContent(currentLineNumber));
+ } else {
+ uriScanner.close();
+ throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
+ }
+
}
- } else {
uriScanner.close();
- throw new BatchException(BatchException.INVALID_URI);
+ pathInfo.setODataPathSegment(parseODataPathSegments(odataPathSegmentsAsString));
+ if (!odataPathSegmentsAsString.startsWith("$")) {
+ String requestUri = baseUri + "/" + odataPathSegmentsAsString + queryParametersAsString;
+ pathInfo.setRequestUri(new URI(requestUri));
+ }
+ return pathInfo;
+ } catch (URISyntaxException e) {
+ throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber), e);
}
- uriScanner.close();
- return pathInfo;
+
}
private Map<String, String> parseQueryParameters(final String uri) throws BatchException {
- Scanner uriScanner = new Scanner(uri);
+ Scanner uriScanner = new Scanner(uri).useDelimiter("\n");
Map<String, String> queryParametersMap = new HashMap<String, String>();
- Pattern regex = Pattern.compile("(?:" + baseUri + ")?/?" + "[^?]+" + "\\?(.*)");
+ Pattern regex = Pattern.compile("(?:" + baseUri + "/)?" + "[^?]+" + "\\?(.*)");
if (uriScanner.hasNext(regex)) {
uriScanner.next(regex);
MatchResult uriResult = uriScanner.match();
@@ -362,7 +390,7 @@ public class BatchRequestParser {
} else {
uriScanner.close();
- throw new BatchException(BatchException.INVALID_URI);
+ throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
}
uriScanner.close();
@@ -388,30 +416,28 @@ public class BatchRequestParser {
}
private InputStream parseBody(final Scanner scanner) {
- try {
- String body = null;
- InputStream requestBody;
- while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
- if (!scanner.hasNext(REG_EX_ZERO_OR_MORE_WHITESPACES)) {
- if (body == null) {
- body = scanner.next();
- } else {
- body = body + LF + scanner.next();
- }
+ StringBuilder body = null;
+ final InputStream requestBody;
+
+ while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
+ if (!scanner.hasNext(REG_EX_ZERO_OR_MORE_WHITESPACES)) {
+ if (body == null) {
+ body = new StringBuilder(scanner.next());
} else {
- scanner.next();
+ body.append(LF).append(scanner.next());
}
- currentLineNumber++;
- }
- if (body != null) {
- requestBody = new ByteArrayInputStream(body.getBytes("UTF-8"));
} else {
- requestBody = new ByteArrayInputStream("".getBytes("UTF-8"));
+ scanner.next();
}
- return requestBody;
- } catch (UnsupportedEncodingException e) {
- throw new ODataRuntimeException(e);
+ currentLineNumber++;
+ }
+
+ if (body != null) {
+ requestBody = new ByteArrayInputStream(BatchHelper.getBytes(body.toString()));
+ } else {
+ requestBody = new ByteArrayInputStream(new byte[0]);
}
+ return requestBody;
}
private String getBoundary(final String contentType) throws BatchException {
@@ -420,7 +446,7 @@ public class BatchRequestParser {
contentTypeScanner.next(REG_EX_CONTENT_TYPE);
} else {
contentTypeScanner.close();
- throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(BatchConstants.MULTIPART_MIXED));
+ throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED));
}
if (contentTypeScanner.hasNext(REG_EX_BOUNDARY_PARAMETER)) {
contentTypeScanner.next(REG_EX_BOUNDARY_PARAMETER);
@@ -438,7 +464,7 @@ public class BatchRequestParser {
}
private void validateEncoding(final String encoding) throws BatchException {
- if (!BatchConstants.BINARY_ENCODING.equalsIgnoreCase(encoding)) {
+ if (!BatchHelper.BINARY_ENCODING.equalsIgnoreCase(encoding)) {
throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
}
}
[3/4] Batch Support, Validation in Deserialization
Posted by jh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestPartImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestPartImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestPartImpl.java
new file mode 100644
index 0000000..80e5cd8
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestPartImpl.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.odata2.core.batch;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
+import org.apache.olingo.odata2.api.processor.ODataRequest;
+
+public class BatchRequestPartImpl implements BatchRequestPart {
+
+ private List<ODataRequest> requests = new ArrayList<ODataRequest>();
+ private boolean isChangeSet;
+
+ public BatchRequestPartImpl() {}
+
+ public BatchRequestPartImpl(final boolean isChangeSet, final List<ODataRequest> requests) {
+ this.isChangeSet = isChangeSet;
+ this.requests = requests;
+ }
+
+ @Override
+ public boolean isChangeSet() {
+ return isChangeSet;
+ }
+
+ public void setChangeSet(final boolean isChangeSet) {
+ this.isChangeSet = isChangeSet;
+ }
+
+ @Override
+ public List<ODataRequest> getRequests() {
+ return Collections.unmodifiableList(requests);
+ }
+
+ public void setRequests(final List<ODataRequest> requests) {
+ this.requests = requests;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java
new file mode 100644
index 0000000..3eda8e1
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchRequestWriter.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart;
+import org.apache.olingo.odata2.api.client.batch.BatchPart;
+import org.apache.olingo.odata2.api.client.batch.BatchQueryPart;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+
+public class BatchRequestWriter {
+ private static final String REG_EX_BOUNDARY = "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046
+ private static final String COLON = ":";
+ private static final String SP = " ";
+ private static final String LF = "\r\n";
+ private String batchBoundary;
+ private StringBuilder writer = new StringBuilder();
+
+ public InputStream writeBatchRequest(final List<BatchPart> batchParts, final String boundary) {
+ if (boundary.matches(REG_EX_BOUNDARY)) {
+ batchBoundary = boundary;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ for (BatchPart batchPart : batchParts) {
+ writer.append("--" + boundary).append(LF);
+ if (batchPart instanceof BatchChangeSet) {
+ appendChangeSet((BatchChangeSet) batchPart);
+ } else if (batchPart instanceof BatchQueryPart) {
+ BatchQueryPart request = (BatchQueryPart) batchPart;
+ appendRequestBodyPart(request.getMethod(), request.getUri(), null, request.getHeaders(), request.getContentId());
+
+ }
+ }
+ writer.append("--").append(boundary).append("--").append(LF).append(LF);
+ InputStream batchRequestBody;
+ batchRequestBody = new ByteArrayInputStream(BatchHelper.getBytes(writer.toString()));
+ return batchRequestBody;
+ }
+
+ private void appendChangeSet(final BatchChangeSet batchChangeSet) {
+ String boundary = BatchHelper.generateBoundary("changeset");
+ while (boundary.equals(batchBoundary) || !boundary.matches(REG_EX_BOUNDARY)) {
+ boundary = BatchHelper.generateBoundary("changeset");
+ }
+ writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append(HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary).append(LF).append(LF);
+ for (BatchChangeSetPart request : batchChangeSet.getChangeSetParts()) {
+ writer.append("--").append(boundary).append(LF);
+ appendRequestBodyPart(request.getMethod(), request.getUri(), request.getBody(), request.getHeaders(), request.getContentId());
+ }
+ writer.append("--").append(boundary).append("--").append(LF).append(LF);
+ }
+
+ private void appendRequestBodyPart(final String method, final String uri, final String body, final Map<String, String> headers, final String contentId) {
+ boolean isContentLengthPresent = false;
+ writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append(HttpContentType.APPLICATION_HTTP).append(LF);
+ writer.append(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING).append(COLON).append(SP).append("binary").append(LF);
+ if (contentId != null) {
+ writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP).append(contentId).append(LF);
+ }
+ String contentLength = getHeaderValue(headers, HttpHeaders.CONTENT_LENGTH);
+ if (contentLength != null && !contentLength.isEmpty()) {
+ isContentLengthPresent = true;
+ }
+ writer.append(LF);
+ writer.append(method).append(SP).append(uri).append(SP).append("HTTP/1.1");
+ writer.append(LF);
+
+ if (!isContentLengthPresent && body != null && !body.isEmpty()) {
+ writer.append(HttpHeaders.CONTENT_LENGTH).append(COLON).append(SP).append(BatchHelper.getBytes(body).length).append(LF);
+
+ }
+ appendHeader(headers);
+
+ if (body != null && !body.isEmpty()) {
+ writer.append(LF);
+ writer.append(body);
+ }
+ writer.append(LF).append(LF);
+ }
+
+ private void appendHeader(final Map<String, String> headers) {
+ for (Map.Entry<String, String> headerMap : headers.entrySet()) {
+ String name = headerMap.getKey();
+ writer.append(name).append(COLON).append(SP).append(headerMap.getValue()).append(LF);
+
+ }
+ }
+
+ private String getHeaderValue(final Map<String, String> headers, final String headerName) {
+ for (Map.Entry<String, String> header : headers.entrySet()) {
+ if (headerName.equalsIgnoreCase(header.getKey())) {
+ return header.getValue();
+ }
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseParser.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseParser.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseParser.java
new file mode 100644
index 0000000..15ce60c
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseParser.java
@@ -0,0 +1,354 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.regex.MatchResult;
+import java.util.regex.Pattern;
+
+import org.apache.olingo.odata2.api.batch.BatchException;
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
+import org.apache.olingo.odata2.api.commons.HttpHeaders;
+import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
+
+public class BatchResponseParser {
+
+ private static final String LF = "\n";
+ private static final String REG_EX_OPTIONAL_WHITESPACE = "\\s?";
+ private static final String REG_EX_ZERO_OR_MORE_WHITESPACES = "\\s*";
+ private static final String ANY_CHARACTERS = ".*";
+
+ private static final Pattern REG_EX_BLANK_LINE = Pattern.compile("(|" + REG_EX_ZERO_OR_MORE_WHITESPACES + ")");
+ private static final Pattern REG_EX_HEADER = Pattern.compile("([a-zA-Z\\-]+):" + REG_EX_OPTIONAL_WHITESPACE + "(.*)" + REG_EX_ZERO_OR_MORE_WHITESPACES);
+ private static final Pattern REG_EX_VERSION = Pattern.compile("(?:HTTP/[0-9]\\.[0-9])");
+ private static final Pattern REG_EX_ANY_BOUNDARY_STRING = Pattern.compile("--" + ANY_CHARACTERS + REG_EX_ZERO_OR_MORE_WHITESPACES);
+ private static final Pattern REG_EX_STATUS_LINE = Pattern.compile(REG_EX_VERSION + "\\s" + "([0-9]{3})\\s([\\S ]+)" + REG_EX_ZERO_OR_MORE_WHITESPACES);
+ private static final Pattern REG_EX_BOUNDARY_PARAMETER = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE + "boundary=(\".*\"|.*)" + REG_EX_ZERO_OR_MORE_WHITESPACES);
+ private static final Pattern REG_EX_CONTENT_TYPE = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE + HttpContentType.MULTIPART_MIXED);
+
+ private static final String REG_EX_BOUNDARY = "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+ \\(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046
+
+ private String contentTypeMime;
+ private String boundary;
+ private String currentContentId;
+ private int currentLineNumber = 0;
+
+ public BatchResponseParser(final String contentType) {
+ contentTypeMime = contentType;
+ }
+
+ public List<BatchSingleResponse> parse(final InputStream in) throws BatchException {
+ Scanner scanner = new Scanner(in, BatchHelper.DEFAULT_ENCODING).useDelimiter(LF);
+ List<BatchSingleResponse> responseList;
+ try {
+ responseList = Collections.unmodifiableList(parseBatchResponse(scanner));
+ } finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
+ scanner.close();
+ try {
+ in.close();
+ } catch (IOException e) {
+ throw new ODataRuntimeException(e);
+ }
+ }
+ return responseList;
+ }
+
+ private List<BatchSingleResponse> parseBatchResponse(final Scanner scanner) throws BatchException {
+ List<BatchSingleResponse> responses = new ArrayList<BatchSingleResponse>();
+ if (contentTypeMime != null) {
+ boundary = getBoundary(contentTypeMime);
+ parsePreamble(scanner);
+ final String closeDelimiter = "--" + boundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES;
+ while (scanner.hasNext() && !scanner.hasNext(closeDelimiter)) {
+ responses.addAll(parseMultipart(scanner, boundary, false));
+ }
+ if (scanner.hasNext(closeDelimiter)) {
+ scanner.next(closeDelimiter);
+ currentLineNumber++;
+ } else {
+ throw new BatchException(BatchException.MISSING_CLOSE_DELIMITER.addContent(currentLineNumber));
+ }
+ } else {
+ throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
+ }
+ return responses;
+
+ }
+
+ //The method parses additional information prior to the first boundary delimiter line
+ private void parsePreamble(final Scanner scanner) {
+ while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
+ scanner.next();
+ currentLineNumber++;
+ }
+ }
+
+ private List<BatchSingleResponse> parseMultipart(final Scanner scanner, final String boundary, final boolean isChangeSet) throws BatchException {
+ Map<String, String> mimeHeaders = new HashMap<String, String>();
+ List<BatchSingleResponse> responses = new ArrayList<BatchSingleResponse>();
+ if (scanner.hasNext("--" + boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) {
+ scanner.next();
+ currentLineNumber++;
+ mimeHeaders = parseMimeHeaders(scanner);
+ currentContentId = mimeHeaders.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
+
+ final String contentType = mimeHeaders.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
+ if (contentType == null) {
+ throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
+ }
+ if (isChangeSet) {
+ if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
+ validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
+ parseNewLine(scanner);// mandatory
+ BatchSingleResponseImpl response = parseResponse(scanner, isChangeSet);
+ responses.add(response);
+ } else {
+ throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.APPLICATION_HTTP));
+ }
+ } else {
+ if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
+ validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
+ parseNewLine(scanner);// mandatory
+ BatchSingleResponseImpl response = parseResponse(scanner, isChangeSet);
+ responses.add(response);
+ } else if (contentType.matches(REG_EX_OPTIONAL_WHITESPACE + HttpContentType.MULTIPART_MIXED + ANY_CHARACTERS)) {
+ String changeSetBoundary = getBoundary(contentType);
+ if (boundary.equals(changeSetBoundary)) {
+ throw new BatchException(BatchException.INVALID_CHANGESET_BOUNDARY.addContent(currentLineNumber));
+ }
+ parseNewLine(scanner);// mandatory
+ Pattern changeSetCloseDelimiter = Pattern.compile("--" + changeSetBoundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES);
+ while (!scanner.hasNext(changeSetCloseDelimiter)) {
+ responses.addAll(parseMultipart(scanner, changeSetBoundary, true));
+ }
+ scanner.next(changeSetCloseDelimiter);
+ currentLineNumber++;
+ parseNewLine(scanner);
+ } else {
+ throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED + " or " + HttpContentType.APPLICATION_HTTP));
+ }
+ }
+ } else if (scanner.hasNext(boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) {
+ currentLineNumber++;
+ throw new BatchException(BatchException.INVALID_BOUNDARY_DELIMITER.addContent(currentLineNumber));
+ } else if (scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
+ currentLineNumber++;
+ throw new BatchException(BatchException.NO_MATCH_WITH_BOUNDARY_STRING.addContent(boundary).addContent(currentLineNumber));
+ } else {
+ currentLineNumber++;
+ throw new BatchException(BatchException.MISSING_BOUNDARY_DELIMITER.addContent(currentLineNumber));
+ }
+ return responses;
+
+ }
+
+ private BatchSingleResponseImpl parseResponse(final Scanner scanner, final boolean isChangeSet) throws BatchException {
+ BatchSingleResponseImpl response = new BatchSingleResponseImpl();
+ if (scanner.hasNext(REG_EX_STATUS_LINE)) {
+ scanner.next(REG_EX_STATUS_LINE);
+ currentLineNumber++;
+ final String statusCode;
+ final String statusInfo;
+ MatchResult result = scanner.match();
+ if (result.groupCount() == 2) {
+ statusCode = result.group(1);
+ statusInfo = result.group(2);
+ } else {
+ currentLineNumber++;
+ throw new BatchException(BatchException.INVALID_STATUS_LINE.addContent(scanner.next()).addContent(currentLineNumber));
+ }
+
+ Map<String, String> headers = parseResponseHeaders(scanner);
+ parseNewLine(scanner);
+ String contentLengthHeader = getHeaderValue(headers, HttpHeaders.CONTENT_LENGTH);
+ String body = (contentLengthHeader != null) ? parseBody(scanner, Integer.parseInt(contentLengthHeader)) : parseBody(scanner);
+ response.setStatusCode(statusCode);
+ response.setStatusInfo(statusInfo);
+ response.setHeaders(headers);
+ response.setContentId(currentContentId);
+ response.setBody(body);
+ } else {
+ currentLineNumber++;
+ throw new BatchException(BatchException.INVALID_STATUS_LINE.addContent(scanner.next()).addContent(currentLineNumber));
+ }
+ return response;
+ }
+
+ private void validateEncoding(final String encoding) throws BatchException {
+ if (!BatchHelper.BINARY_ENCODING.equalsIgnoreCase(encoding)) {
+ throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
+ }
+ }
+
+ private Map<String, String> parseMimeHeaders(final Scanner scanner) throws BatchException {
+ Map<String, String> headers = new HashMap<String, String>();
+ while (scanner.hasNext() && !(scanner.hasNext(REG_EX_BLANK_LINE))) {
+ if (scanner.hasNext(REG_EX_HEADER)) {
+ scanner.next(REG_EX_HEADER);
+ currentLineNumber++;
+ MatchResult result = scanner.match();
+ if (result.groupCount() == 2) {
+ String headerName = result.group(1).trim().toLowerCase(Locale.ENGLISH);
+ String headerValue = result.group(2).trim();
+ headers.put(headerName, headerValue);
+ }
+ } else {
+ throw new BatchException(BatchException.INVALID_HEADER.addContent(scanner.next()));
+ }
+ }
+ return headers;
+ }
+
+ private Map<String, String> parseResponseHeaders(final Scanner scanner) throws BatchException {
+ Map<String, String> headers = new HashMap<String, String>();
+ while (scanner.hasNext() && !scanner.hasNext(REG_EX_BLANK_LINE)) {
+ if (scanner.hasNext(REG_EX_HEADER)) {
+ scanner.next(REG_EX_HEADER);
+ currentLineNumber++;
+ MatchResult result = scanner.match();
+ if (result.groupCount() == 2) {
+ String headerName = result.group(1).trim();
+ String headerValue = result.group(2).trim();
+ if (BatchHelper.HTTP_CONTENT_ID.equalsIgnoreCase(headerName)) {
+ if (currentContentId == null) {
+ currentContentId = headerValue;
+ }
+ } else {
+ headers.put(headerName, headerValue);
+ }
+ }
+ } else {
+ currentLineNumber++;
+ throw new BatchException(BatchException.INVALID_HEADER.addContent(scanner.next()).addContent(currentLineNumber));
+ }
+ }
+ return headers;
+ }
+
+ private String getHeaderValue(final Map<String, String> headers, final String headerName) {
+ for (Map.Entry<String, String> header : headers.entrySet()) {
+ if (headerName.equalsIgnoreCase(header.getKey())) {
+ return header.getValue();
+ }
+ }
+ return null;
+ }
+
+ private String parseBody(final Scanner scanner) {
+ StringBuilder body = null;
+ while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
+ if (!scanner.hasNext(REG_EX_ZERO_OR_MORE_WHITESPACES)) {
+ if (body == null) {
+ body = new StringBuilder(scanner.next());
+ } else {
+ body.append(LF).append(scanner.next());
+ }
+ } else {
+ scanner.next();
+ }
+ currentLineNumber++;
+ }
+ String responseBody = body != null ? body.toString() : null;
+ return responseBody;
+ }
+
+ private String parseBody(final Scanner scanner, final int contentLength) {
+ StringBuilder body = null;
+ int length = 0;
+ while (scanner.hasNext() && length < contentLength) {
+ if (!scanner.hasNext(REG_EX_ZERO_OR_MORE_WHITESPACES)) {
+ String nextLine = scanner.next();
+ length += BatchHelper.getBytes(nextLine).length;
+ if (body == null) {
+ body = new StringBuilder(nextLine);
+ } else {
+ body.append(LF).append(nextLine);
+ }
+ } else {
+ scanner.next();
+ }
+ currentLineNumber++;
+ if (scanner.hasNext() && scanner.hasNext(REG_EX_BLANK_LINE)) {
+ scanner.next();
+ currentLineNumber++;
+ }
+ }
+ String responseBody = body != null ? body.toString() : null;
+ return responseBody;
+ }
+
+ private String getBoundary(final String contentType) throws BatchException {
+ Scanner contentTypeScanner = new Scanner(contentType).useDelimiter(";\\s?");
+ if (contentTypeScanner.hasNext(REG_EX_CONTENT_TYPE)) {
+ contentTypeScanner.next(REG_EX_CONTENT_TYPE);
+ } else {
+ contentTypeScanner.close();
+ throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED));
+ }
+ if (contentTypeScanner.hasNext(REG_EX_BOUNDARY_PARAMETER)) {
+ contentTypeScanner.next(REG_EX_BOUNDARY_PARAMETER);
+ MatchResult result = contentTypeScanner.match();
+ contentTypeScanner.close();
+ if (result.groupCount() == 1 && result.group(1).trim().matches(REG_EX_BOUNDARY)) {
+ return trimQuota(result.group(1).trim());
+ } else {
+ throw new BatchException(BatchException.INVALID_BOUNDARY);
+ }
+ } else {
+ contentTypeScanner.close();
+ throw new BatchException(BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE);
+ }
+ }
+
+ private void parseNewLine(final Scanner scanner) throws BatchException {
+ if (scanner.hasNext() && scanner.hasNext(REG_EX_BLANK_LINE)) {
+ scanner.next();
+ currentLineNumber++;
+ } else {
+ currentLineNumber++;
+ if (scanner.hasNext()) {
+ throw new BatchException(BatchException.MISSING_BLANK_LINE.addContent(scanner.next()).addContent(currentLineNumber));
+ } else {
+ throw new BatchException(BatchException.TRUNCATED_BODY.addContent(currentLineNumber));
+
+ }
+ }
+ }
+
+ private String trimQuota(String boundary) {
+ if (boundary.matches("\".*\"")) {
+ boundary = boundary.replace("\"", "");
+ }
+ boundary = boundary.replaceAll("\\)", "\\\\)");
+ boundary = boundary.replaceAll("\\(", "\\\\(");
+ boundary = boundary.replaceAll("\\?", "\\\\?");
+ boundary = boundary.replaceAll("\\+", "\\\\+");
+ return boundary;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
index e705724..ae0c07b 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchResponseWriter.java
@@ -21,10 +21,10 @@ package org.apache.olingo.odata2.core.batch;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
-import java.util.UUID;
import org.apache.olingo.odata2.api.batch.BatchException;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.HttpStatusCodes;
import org.apache.olingo.odata2.api.exception.ODataMessageException;
@@ -34,50 +34,54 @@ public class BatchResponseWriter {
private static final String COLON = ":";
private static final String SP = " ";
private static final String LF = "\r\n";
- private StringBuilder writer = new StringBuilder();
+ private ResponseWriter writer = new ResponseWriter();
public ODataResponse writeResponse(final List<BatchResponsePart> batchResponseParts) throws BatchException {
- String boundary = generateBoundary("batch");
- appendResponseBody(batchResponseParts, boundary);
+ String boundary = BatchHelper.generateBoundary("batch");
+ appendResponsePart(batchResponseParts, boundary);
String batchResponseBody = writer.toString();
- return ODataResponse.entity(batchResponseBody).status(HttpStatusCodes.ACCEPTED).
- header(HttpHeaders.CONTENT_TYPE, BatchConstants.MULTIPART_MIXED + "; boundary=" + boundary)
- .header(HttpHeaders.CONTENT_LENGTH, "" + batchResponseBody.length()).build();
-
+ return ODataResponse.entity(batchResponseBody).status(HttpStatusCodes.ACCEPTED)
+ .header(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary)
+ .header(HttpHeaders.CONTENT_LENGTH, String.valueOf(writer.length()))
+ .build();
}
private void appendChangeSet(final BatchResponsePart batchResponsePart) throws BatchException {
- String boundary = generateBoundary("changeset");
- writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append("multipart/mixed; boundary=" + boundary).append(LF).append(LF);
+ String boundary = BatchHelper.generateBoundary("changeset");
+ writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP)
+ .append("multipart/mixed; boundary=" + boundary).append(LF).append(LF);
for (ODataResponse response : batchResponsePart.getResponses()) {
writer.append("--").append(boundary).append(LF);
- appendResponseBodyPart(response);
+ appendResponsePartBody(response);
}
writer.append("--").append(boundary).append("--").append(LF).append(LF);
}
- private void appendResponseBody(final List<BatchResponsePart> batchResponseParts, final String boundary) throws BatchException {
-
+ private void appendResponsePart(final List<BatchResponsePart> batchResponseParts, final String boundary) throws BatchException {
for (BatchResponsePart batchResponsePart : batchResponseParts) {
writer.append("--").append(boundary).append(LF);
if (batchResponsePart.isChangeSet()) {
appendChangeSet(batchResponsePart);
} else {
ODataResponse response = batchResponsePart.getResponses().get(0);
- appendResponseBodyPart(response);
+ appendResponsePartBody(response);
}
}
writer.append("--").append(boundary).append("--");
}
- private void appendResponseBodyPart(final ODataResponse response) throws BatchException {
- writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append(BatchConstants.HTTP_APPLICATION_HTTP).append(LF);
- writer.append(BatchConstants.HTTP_CONTENT_TRANSFER_ENCODING).append(COLON).append(SP).append("binary").append(LF);
- if (response.getHeader(BatchConstants.MIME_HEADER_CONTENT_ID) != null) {
- writer.append(BatchConstants.HTTP_CONTENT_ID).append(COLON).append(SP).append(response.getHeader(BatchConstants.MIME_HEADER_CONTENT_ID)).append(LF);
+ private void appendResponsePartBody(final ODataResponse response) throws BatchException {
+ writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP)
+ .append(HttpContentType.APPLICATION_HTTP).append(LF);
+ writer.append(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING).append(COLON).append(SP)
+ .append(BatchHelper.BINARY_ENCODING).append(LF);
+ if (response.getHeader(BatchHelper.MIME_HEADER_CONTENT_ID) != null) {
+ writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP)
+ .append(response.getHeader(BatchHelper.MIME_HEADER_CONTENT_ID)).append(LF);
}
writer.append(LF);
- writer.append("HTTP/1.1").append(SP).append(response.getStatus().getStatusCode()).append(SP).append(response.getStatus().getInfo()).append(LF);
+ writer.append("HTTP/1.1").append(SP).append(String.valueOf(response.getStatus().getStatusCode())).append(SP)
+ .append(response.getStatus().getInfo()).append(LF);
appendHeader(response);
if (!HttpStatusCodes.NO_CONTENT.equals(response.getStatus())) {
String body;
@@ -87,7 +91,8 @@ public class BatchResponseWriter {
} else {
body = response.getEntity().toString();
}
- writer.append(HttpHeaders.CONTENT_LENGTH).append(COLON).append(SP).append(body.length()).append(LF).append(LF);
+ writer.append(HttpHeaders.CONTENT_LENGTH).append(COLON).append(SP)
+ .append(String.valueOf(BatchHelper.getBytes(body).length)).append(LF).append(LF);
writer.append(body);
}
writer.append(LF).append(LF);
@@ -95,18 +100,15 @@ public class BatchResponseWriter {
private void appendHeader(final ODataResponse response) {
for (String name : response.getHeaderNames()) {
- if (!BatchConstants.MIME_HEADER_CONTENT_ID.equalsIgnoreCase(name) && !BatchConstants.REQUEST_HEADER_CONTENT_ID.equalsIgnoreCase(name)) {
+ if (!BatchHelper.MIME_HEADER_CONTENT_ID.equalsIgnoreCase(name) && !BatchHelper.REQUEST_HEADER_CONTENT_ID.equalsIgnoreCase(name)) {
writer.append(name).append(COLON).append(SP).append(response.getHeader(name)).append(LF);
- } else if (BatchConstants.REQUEST_HEADER_CONTENT_ID.equalsIgnoreCase(name)) {
- writer.append(BatchConstants.HTTP_CONTENT_ID).append(COLON).append(SP).append(response.getHeader(name)).append(LF);
+ } else if (BatchHelper.REQUEST_HEADER_CONTENT_ID.equalsIgnoreCase(name)) {
+ writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP)
+ .append(response.getHeader(name)).append(LF);
}
}
}
- private String generateBoundary(final String value) {
- return value + "_" + UUID.randomUUID().toString();
- }
-
private String readBody(final InputStream in) throws BatchException {
byte[] tmp = new byte[2048];
int count;
@@ -115,7 +117,7 @@ public class BatchResponseWriter {
try {
count = in.read(tmp);
while (count >= 0) {
- b.append(new String(tmp, 0, count));
+ b.append(new String(tmp, 0, count, BatchHelper.DEFAULT_ENCODING));
count = in.read(tmp);
}
} catch (IOException e) {
@@ -133,4 +135,24 @@ public class BatchResponseWriter {
return b.toString();
}
+ private static class ResponseWriter {
+ private StringBuilder sb = new StringBuilder();
+ private int length = 0;
+
+ public ResponseWriter append(final String content) {
+ length += BatchHelper.getBytes(content).length;
+ sb.append(content);
+ return this;
+ }
+
+ public int length() {
+ return length;
+ }
+
+ @Override
+ public String toString() {
+ return sb.toString();
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchSingleResponseImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchSingleResponseImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchSingleResponseImpl.java
new file mode 100644
index 0000000..337b550
--- /dev/null
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/batch/BatchSingleResponseImpl.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * 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.odata2.core.batch;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
+
+public class BatchSingleResponseImpl implements BatchSingleResponse {
+
+ private String statusCode;
+ private String statusInfo;
+ private String body;
+ private Map<String, String> headers = new HashMap<String, String>();
+ private String contentId;
+
+ @Override
+ public String getStatusCode() {
+ return statusCode;
+ }
+
+ @Override
+ public String getStatusInfo() {
+ return statusInfo;
+ }
+
+ @Override
+ public String getBody() {
+ return body;
+ }
+
+ @Override
+ public Map<String, String> getHeaders() {
+ return headers;
+ }
+
+ @Override
+ public String getContentId() {
+ return contentId;
+ }
+
+ @Override
+ public String getHeader(final String name) {
+ return headers.get(name);
+ }
+
+ @Override
+ public Set<String> getHeaderNames() {
+ return headers.keySet();
+ }
+
+ public void setStatusCode(final String statusCode) {
+ this.statusCode = statusCode;
+ }
+
+ public void setStatusInfo(final String statusInfo) {
+ this.statusInfo = statusInfo;
+ }
+
+ public void setBody(final String body) {
+ this.body = body;
+ }
+
+ public void setHeaders(final Map<String, String> headers) {
+ this.headers = headers;
+ }
+
+ public void setContentId(final String contentId) {
+ this.contentId = contentId;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/commons/Encoder.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/commons/Encoder.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/commons/Encoder.java
index 22f6cfd..8739b62 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/commons/Encoder.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/commons/Encoder.java
@@ -50,7 +50,6 @@ public class Encoder {
// Character classes from RFC 3986
private final static String UNRESERVED = "-._~"; // + ALPHA + DIGIT
- private final static String GEN_DELIMS = ":/?#[]@";
// RFC 3986 says: "For consistency, URI producers and normalizers should
// use uppercase hexadecimal digits for all percent-encodings."
private final static String[] hex = { "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F", "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27", "%28", "%29", "%2A", "%2B", "%2C", "%2D", "%2E", "%2F", "%30", "%31", "%32", "%33", "%34", "%35", "%36", "%37", "%38", "%39", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F", "%40", "%41", "%42", "%43", "%44", "%45", "%46", "%47", "%48", "%49", "%4A", "%4B", "%4C", "%4D", "%4E", "%4F", "%50", "%51", "%52", "%53", "%54", "%55", "%56", "%57", "%58", "%59", "%5A", "%5B", "%5C", "%5D", "%5E", "%5F", "%60", "%61", "%62", "%63", "%64", "%65", "%66", "%67", "%68", "%69", "%6A", "%6B", "%6C", "%6D", "%6E", "%6F", "%70", "%71", "%72", "%73", "%74", "%75", "%76", "%77", "%78", "%79", "%7A", "%7B", "%7C", "%7D", "%7E", "%7F", "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", "%88"
,
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmBinary.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmBinary.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmBinary.java
index 5485163..2c9ea44 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmBinary.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmBinary.java
@@ -146,6 +146,6 @@ public class EdmBinary extends AbstractSimpleType {
@Override
public String toUriLiteral(final String literal) throws EdmSimpleTypeException {
- return "binary'" + Hex.encodeHexString(Base64.decodeBase64(literal)).toUpperCase(Locale.ROOT) + "'";
+ return "binary'" + String.valueOf(Hex.encodeHex(Base64.decodeBase64(literal), false)) + "'";
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
index 2370a06..d1bfedd 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmDateTime.java
@@ -141,7 +141,7 @@ public class EdmDateTime extends AbstractSimpleType {
// off temporarily.
dateTimeValue.setLenient(false);
try {
- dateTimeValue.getTimeInMillis();
+ dateTimeValue.get(Calendar.MILLISECOND);
} catch (final IllegalArgumentException e) {
throw new EdmSimpleTypeException(EdmSimpleTypeException.LITERAL_ILLEGAL_CONTENT.addContent(value), e);
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
index 99d273e..217e772 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/EdmTime.java
@@ -85,15 +85,12 @@ public class EdmTime extends AbstractSimpleType {
Calendar dateTimeValue = Calendar.getInstance();
dateTimeValue.clear();
- if (matcher.group(1) != null) {
- dateTimeValue.set(Calendar.HOUR_OF_DAY, Integer.parseInt(matcher.group(1)));
- }
- if (matcher.group(2) != null) {
- dateTimeValue.set(Calendar.MINUTE, Integer.parseInt(matcher.group(2)));
- }
- if (matcher.group(3) != null) {
- dateTimeValue.set(Calendar.SECOND, Integer.parseInt(matcher.group(3)));
- }
+ dateTimeValue.set(Calendar.HOUR_OF_DAY,
+ matcher.group(1) == null ? 0 : Integer.parseInt(matcher.group(1)));
+ dateTimeValue.set(Calendar.MINUTE,
+ matcher.group(2) == null ? 0 : Integer.parseInt(matcher.group(2)));
+ dateTimeValue.set(Calendar.SECOND,
+ matcher.group(3) == null ? 0 : Integer.parseInt(matcher.group(3)));
if (matcher.group(4) != null) {
if (facets == null || facets.getPrecision() == null || facets.getPrecision() >= matcher.group(4).length()) {
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/parser/EdmParser.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/parser/EdmParser.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/parser/EdmParser.java
index 8e3e3dd..ef15551 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/parser/EdmParser.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/parser/EdmParser.java
@@ -758,7 +758,7 @@ public class EdmParser {
annotationAttribute.setName(reader.getAttributeLocalName(i));
annotationAttribute.setPrefix(reader.getAttributePrefix(i));
String namespace = reader.getAttributeNamespace(i);
- if (!DEFAULT_NAMESPACE.equals(namespace)) {
+ if (namespace != null && !isDefaultNamespace(namespace)) {
annotationAttribute.setNamespace(namespace);
}
annotationAttributes.add(annotationAttribute);
@@ -781,7 +781,8 @@ public class EdmParser {
private List<AnnotationAttribute> readAnnotationAttribute(final XMLStreamReader reader) {
List<AnnotationAttribute> annotationAttributes = new ArrayList<AnnotationAttribute>();
for (int i = 0; i < reader.getAttributeCount(); i++) {
- if (!mandatoryNamespaces.containsValue(reader.getAttributeNamespace(i)) && !DEFAULT_NAMESPACE.equals(reader.getAttributeNamespace(i))) {
+ String namespace = reader.getAttributeNamespace(i);
+ if (namespace != null && !isDefaultNamespace(namespace) && !mandatoryNamespaces.containsValue(namespace)) {
annotationAttributes.add(new AnnotationAttribute().setName(reader.getAttributeLocalName(i)).
setPrefix(reader.getAttributePrefix(i)).setNamespace(reader.getAttributeNamespace(i)).setText(reader.getAttributeValue(i)));
}
@@ -792,6 +793,10 @@ public class EdmParser {
return annotationAttributes;
}
+ private boolean isDefaultNamespace(final String namespace) {
+ return namespace.isEmpty();
+ }
+
private void checkAllMandatoryNamespacesAvailable() throws EntityProviderException {
if (!xmlNamespaceMap.containsValue(Edm.NAMESPACE_EDMX_2007_06)) {
throw new EntityProviderException(EntityProviderException.INVALID_NAMESPACE.addContent(Edm.NAMESPACE_EDMX_2007_06));
@@ -807,7 +812,7 @@ public class EdmParser {
for (int i = 0; i < namespaceCount; i++) {
String namespacePrefix = reader.getNamespacePrefix(i);
String namespaceUri = reader.getNamespaceURI(i);
- if (namespacePrefix == null || DEFAULT_NAMESPACE.equals(namespacePrefix)) {
+ if (namespacePrefix == null || isDefaultNamespace(namespacePrefix)) {
namespacePrefix = Edm.PREFIX_EDM;
}
xmlNamespaceMap.put(namespacePrefix, namespaceUri);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
index aa0056c..40cfd7a 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
@@ -293,14 +293,12 @@ public class JsonEntityProvider implements ContentTypeBasedEntityProvider {
@Override
public ODataFeed readFeed(final EdmEntitySet entitySet, final InputStream content, final EntityProviderReadProperties properties) throws EntityProviderException {
- JsonEntityConsumer jec = new JsonEntityConsumer();
- return jec.readFeed(entitySet, content, properties);
+ return new JsonEntityConsumer().readFeed(entitySet, content, properties);
}
@Override
public ODataEntry readEntry(final EdmEntitySet entitySet, final InputStream content, final EntityProviderReadProperties properties) throws EntityProviderException {
- JsonEntityConsumer jec = new JsonEntityConsumer();
- return jec.readEntry(entitySet, content, properties);
+ return new JsonEntityConsumer().readEntry(entitySet, content, properties);
}
@Override
@@ -320,8 +318,7 @@ public class JsonEntityProvider implements ContentTypeBasedEntityProvider {
@Override
public ServiceDocument readServiceDocument(final InputStream serviceDocument) throws EntityProviderException {
- JsonServiceDocumentConsumer serviceDocConsumer = new JsonServiceDocumentConsumer();
- return serviceDocConsumer.parseJson(serviceDocument);
+ return new JsonServiceDocumentConsumer().parseJson(serviceDocument);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
index 42c04b9..13eb918 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
@@ -23,8 +23,10 @@ import java.util.List;
import java.util.Map;
import org.apache.olingo.odata2.api.batch.BatchException;
-import org.apache.olingo.odata2.api.batch.BatchPart;
+import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.batch.BatchResponsePart;
+import org.apache.olingo.odata2.api.client.batch.BatchPart;
+import org.apache.olingo.odata2.api.client.batch.BatchSingleResponse;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmEntitySet;
import org.apache.olingo.odata2.api.edm.EdmFunctionImport;
@@ -43,6 +45,8 @@ import org.apache.olingo.odata2.api.processor.ODataErrorContext;
import org.apache.olingo.odata2.api.processor.ODataResponse;
import org.apache.olingo.odata2.api.servicedocument.ServiceDocument;
import org.apache.olingo.odata2.core.batch.BatchRequestParser;
+import org.apache.olingo.odata2.core.batch.BatchRequestWriter;
+import org.apache.olingo.odata2.core.batch.BatchResponseParser;
import org.apache.olingo.odata2.core.batch.BatchResponseWriter;
import org.apache.olingo.odata2.core.commons.ContentType;
import org.apache.olingo.odata2.core.edm.parser.EdmxProvider;
@@ -189,8 +193,8 @@ public class ProviderFacadeImpl implements EntityProviderInterface {
}
@Override
- public List<BatchPart> parseBatchRequest(final String contentType, final InputStream content, final EntityProviderBatchProperties properties) throws BatchException {
- List<BatchPart> batchParts = new BatchRequestParser(contentType, properties).parse(content);
+ public List<BatchRequestPart> parseBatchRequest(final String contentType, final InputStream content, final EntityProviderBatchProperties properties) throws BatchException {
+ List<BatchRequestPart> batchParts = new BatchRequestParser(contentType, properties).parse(content);
return batchParts;
}
@@ -200,4 +204,16 @@ public class ProviderFacadeImpl implements EntityProviderInterface {
return batchWriter.writeResponse(batchResponseParts);
}
+ @Override
+ public InputStream writeBatchRequest(final List<BatchPart> batchParts, final String boundary) {
+ BatchRequestWriter batchWriter = new BatchRequestWriter();
+ return batchWriter.writeBatchRequest(batchParts, boundary);
+ }
+
+ @Override
+ public List<BatchSingleResponse> parseBatchResponse(final String contentType, final InputStream content) throws BatchException {
+ List<BatchSingleResponse> responses = new BatchResponseParser(contentType).parse(content);
+ return responses;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/aggregator/EntityPropertyInfo.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/aggregator/EntityPropertyInfo.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/aggregator/EntityPropertyInfo.java
index 7f96671..83ab4df 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/aggregator/EntityPropertyInfo.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/aggregator/EntityPropertyInfo.java
@@ -30,12 +30,12 @@ import org.apache.olingo.odata2.api.edm.EdmType;
*
*/
public class EntityPropertyInfo {
- private String name;
- private EdmType type;
- private EdmFacets facets;
- private EdmCustomizableFeedMappings customMapping;
- private String mimeType;
- private EdmMapping mapping;
+ private final String name;
+ private final EdmType type;
+ private final EdmFacets facets;
+ private final EdmCustomizableFeedMappings customMapping;
+ private final String mimeType;
+ private final EdmMapping mapping;
EntityPropertyInfo(final String name, final EdmType type, final EdmFacets facets, final EdmCustomizableFeedMappings customizableFeedMapping, final String mimeType, final EdmMapping mapping) {
this.name = name;
@@ -57,13 +57,7 @@ public class EntityPropertyInfo {
}
public boolean isMandatory() {
- if (facets == null) {
- return false;
- } else if (facets.isNullable() == null) {
- return false;
- } else {
- return !facets.isNullable();
- }
+ return !(facets == null || facets.isNullable() == null || facets.isNullable());
}
public boolean isComplex() {
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntityConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntityConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntityConsumer.java
index cdfce38..4d32750 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntityConsumer.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntityConsumer.java
@@ -50,9 +50,7 @@ public class JsonEntityConsumer {
EntityInfoAggregator eia = EntityInfoAggregator.create(entitySet);
reader = createJsonReader(content);
- JsonEntryConsumer jec = new JsonEntryConsumer(reader, eia, properties);
- ODataEntry result = jec.readSingleEntry();
- return result;
+ return new JsonEntryConsumer(reader, eia, properties).readSingleEntry();
} catch (UnsupportedEncodingException e) {
cachedException = new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
throw cachedException;
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumer.java
index f81e589..5a6d486 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumer.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonEntryConsumer.java
@@ -107,11 +107,9 @@ public class JsonEntryConsumer {
private void readEntryContent() throws IOException, EdmException, EntityProviderException {
while (reader.hasNext()) {
- String name = reader.nextName();
+ final String name = reader.nextName();
handleName(name);
}
-
- //TODO: validate created entry
}
private void handleName(final String name) throws IOException, EdmException, EntityProviderException {
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumer.java
index 37c0b68..a1bd139 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumer.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/JsonPropertyConsumer.java
@@ -141,6 +141,9 @@ public class JsonPropertyConsumer {
private Object readComplexProperty(final JsonReader reader, final EntityComplexPropertyInfo complexPropertyInfo, final Object typeMapping) throws EdmException, EntityProviderException, IOException {
if (reader.peek().equals(JsonToken.NULL)) {
reader.nextNull();
+ if (complexPropertyInfo.isMandatory()) {
+ throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY_VALUE.addContent(complexPropertyInfo.getName()));
+ }
return null;
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
index 678a95f..d065d4d 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntityConsumer.java
@@ -87,12 +87,10 @@ public class XmlEntityConsumer {
EntityProviderException cachedException = null;
try {
- XmlEntryConsumer xec = new XmlEntryConsumer();
reader = createStaxReader(content);
-
EntityInfoAggregator eia = EntityInfoAggregator.create(entitySet);
- ODataEntry result = xec.readEntry(reader, eia, properties);
- return result;
+
+ return new XmlEntryConsumer().readEntry(reader, eia, properties);
} catch (EntityProviderException e) {
cachedException = e;
throw cachedException;
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
index b27c385..a71b986 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlEntryConsumer.java
@@ -19,7 +19,6 @@
package org.apache.olingo.odata2.core.ep.consumer;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -86,10 +85,6 @@ public class XmlEntryConsumer {
}
}
- if (!readProperties.getMergeSemantic()) {
- validateMandatoryPropertiesAvailable(eia, readEntryResult);
- }
-
return readEntryResult;
} catch (XMLStreamException e) {
throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
@@ -105,8 +100,7 @@ public class XmlEntryConsumer {
}
/**
- * Initialize the {@link XmlEntryConsumer} to be ready for read of an entry.
- *
+ * Initializes the {@link XmlEntryConsumer} to be ready for reading an entry.
* @param readProperties
* @throws EntityProviderException
*/
@@ -122,27 +116,6 @@ public class XmlEntryConsumer {
foundPrefix2NamespaceUri.putAll(readProperties.getValidatedPrefixNamespaceUris());
}
- /**
- * Validates that all mandatory properties are found and set at the {@link #readEntryResult} entity.
- * If a mandatory property is missing an {@link EntityProviderException} is thrown.
- *
- * @param eia entity info which contains the information which properties are mandatory
- * @param entry entry for which the mandatory properties are validated
- * @throws EntityProviderException if a mandatory property is missing
- */
- private void validateMandatoryPropertiesAvailable(final EntityInfoAggregator eia, final ODataEntryImpl entry) throws EntityProviderException {
- Collection<EntityPropertyInfo> propertyInfos = new ArrayList<EntityPropertyInfo>(eia.getPropertyInfos());
- propertyInfos.removeAll(eia.getKeyPropertyInfos());
- Map<String, Object> data = entry.getProperties();
-
- for (EntityPropertyInfo entityPropertyInfo : propertyInfos) {
- boolean mandatory = entityPropertyInfo.isMandatory();
- if (mandatory && !data.containsKey(entityPropertyInfo.getName())) {
- throw new EntityProviderException(EntityProviderException.MISSING_PROPERTY.addContent(entityPropertyInfo.getName()));
- }
- }
- }
-
private void handleStartedTag(final XMLStreamReader reader, final EntityInfoAggregator eia, final EntityProviderReadProperties readProperties)
throws EntityProviderException, XMLStreamException, EdmException {
@@ -408,8 +381,7 @@ public class XmlEntryConsumer {
*
* @param isFeed
* @param inlineEntries
- * @return list of {@link ODataEntry}, an empty list, a single {@link ODataEntry} or <code>NULL</code> based on
- * <code>isFeed</code> value and <code>inlineEntries</code> content
+ * @return
*/
private Object extractODataEntity(final boolean isFeed, final List<ODataEntry> inlineEntries) {
if (isFeed) {
@@ -453,8 +425,7 @@ public class XmlEntryConsumer {
*
* @param readProperties
* @param navigationProperty
- * @return the created {@link EntityProviderReadProperties} which can be used for reading of inline properties/entrys of navigation links within
- * this current read entry.
+ * @return
* @throws EntityProviderException
*/
private EntityProviderReadProperties createInlineProperties(final EntityProviderReadProperties readProperties, final EdmNavigationProperty navigationProperty) throws EntityProviderException {
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
index d604033..0ce8f1e 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/consumer/XmlPropertyConsumer.java
@@ -31,6 +31,7 @@ import org.apache.olingo.odata2.api.edm.EdmFacets;
import org.apache.olingo.odata2.api.edm.EdmLiteralKind;
import org.apache.olingo.odata2.api.edm.EdmProperty;
import org.apache.olingo.odata2.api.edm.EdmSimpleType;
+import org.apache.olingo.odata2.api.edm.EdmSimpleTypeException;
import org.apache.olingo.odata2.api.ep.EntityProviderException;
import org.apache.olingo.odata2.core.ep.aggregator.EntityComplexPropertyInfo;
import org.apache.olingo.odata2.core.ep.aggregator.EntityInfoAggregator;
@@ -43,7 +44,8 @@ import org.apache.olingo.odata2.core.ep.util.FormatXml;
*/
public class XmlPropertyConsumer {
- public static final String TRUE = "true";
+ protected static final String TRUE = "true";
+ protected static final String FALSE = "false";
public Map<String, Object> readProperty(final XMLStreamReader reader, final EdmProperty property, final boolean merge) throws EntityProviderException {
return readProperty(reader, property, merge, null);
@@ -102,67 +104,58 @@ public class XmlPropertyConsumer {
}
protected Object readStartedElement(final XMLStreamReader reader, final EntityPropertyInfo propertyInfo, final EntityTypeMapping typeMappings) throws EntityProviderException, EdmException {
- Map<String, Object> name2Value = new HashMap<String, Object>();
+ final String name = propertyInfo.getName();
Object result = null;
try {
- reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, propertyInfo.getName());
+ reader.require(XMLStreamConstants.START_ELEMENT, Edm.NAMESPACE_D_2007_08, name);
final String nullAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_NULL);
+ if (!(nullAttribute == null || TRUE.equals(nullAttribute) || FALSE.equals(nullAttribute))) {
+ throw new EntityProviderException(EntityProviderException.COMMON);
+ }
+
if (TRUE.equals(nullAttribute)) {
+ if (propertyInfo.isMandatory()) {
+ throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY_VALUE.addContent(name));
+ }
reader.nextTag();
} else if (propertyInfo.isComplex()) {
final String typeAttribute = reader.getAttributeValue(Edm.NAMESPACE_M_2007_08, FormatXml.M_TYPE);
- String expectedTypeAttributeValue = propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
- if (typeAttribute != null && !expectedTypeAttributeValue.equals(typeAttribute)) {
- throw new EntityProviderException(EntityProviderException.INVALID_COMPLEX_TYPE.addContent(expectedTypeAttributeValue).addContent(typeAttribute));
+ if (typeAttribute != null) {
+ final String expectedTypeAttributeValue = propertyInfo.getType().getNamespace() + Edm.DELIMITER + propertyInfo.getType().getName();
+ if (!expectedTypeAttributeValue.equals(typeAttribute)) {
+ throw new EntityProviderException(EntityProviderException.INVALID_COMPLEX_TYPE.addContent(expectedTypeAttributeValue).addContent(typeAttribute));
+ }
}
reader.nextTag();
+ Map<String, Object> name2Value = new HashMap<String, Object>();
while (reader.hasNext() && !reader.isEndElement()) {
- String childName = reader.getLocalName();
- EntityPropertyInfo childProperty = getChildProperty(childName, propertyInfo);
+ final String childName = reader.getLocalName();
+ final EntityPropertyInfo childProperty = ((EntityComplexPropertyInfo) propertyInfo).getPropertyInfo(childName);
if (childProperty == null) {
throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(childName));
}
- Object value = readStartedElement(reader, childProperty, typeMappings.getEntityTypeMapping(propertyInfo.getName()));
+ final Object value = readStartedElement(reader, childProperty, typeMappings.getEntityTypeMapping(name));
name2Value.put(childName, value);
reader.nextTag();
}
+ result = name2Value;
} else {
- Class<?> mapping = typeMappings.getMappingClass(propertyInfo.getName());
- result = convert(propertyInfo, reader.getElementText(), mapping);
+ result = convert(propertyInfo, reader.getElementText(), typeMappings.getMappingClass(name));
}
- reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, propertyInfo.getName());
+ reader.require(XMLStreamConstants.END_ELEMENT, Edm.NAMESPACE_D_2007_08, name);
- // if reading finished check which result must be returned
- if (result != null) {
- return result;
- } else if (!name2Value.isEmpty()) {
- return name2Value;
- }
+ return result;
} catch (XMLStreamException e) {
throw new EntityProviderException(EntityProviderException.EXCEPTION_OCCURRED.addContent(e.getClass().getSimpleName()), e);
}
- return null;
}
- private EntityPropertyInfo getChildProperty(final String childPropertyName, final EntityPropertyInfo property) throws EdmException, EntityProviderException {
- if (property.isComplex()) {
- EntityComplexPropertyInfo complex = (EntityComplexPropertyInfo) property;
- return complex.getPropertyInfo(childPropertyName);
- }
- throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(
- "Expected complex property but found simple for property with name '" + property.getName() + "'"));
- }
-
- private Object convert(final EntityPropertyInfo property, final String value, final Class<?> typeMapping) throws EdmException, EntityProviderException {
- if (!property.isComplex()) {
- EdmSimpleType type = (EdmSimpleType) property.getType();
- return type.valueOfString(value, EdmLiteralKind.DEFAULT, property.getFacets(),
- typeMapping == null ? type.getDefaultType() : typeMapping);
- }
- throw new EntityProviderException(EntityProviderException.INVALID_PROPERTY.addContent(
- "Expected simple property but found complex for property with name '" + property.getName() + "'"));
+ private Object convert(final EntityPropertyInfo property, final String value, final Class<?> typeMapping) throws EdmSimpleTypeException {
+ final EdmSimpleType type = (EdmSimpleType) property.getType();
+ return type.valueOfString(value, EdmLiteralKind.DEFAULT, property.getFacets(),
+ typeMapping == null ? type.getDefaultType() : typeMapping);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorService.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorService.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorService.java
index 19eb01e..f5298c1 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorService.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/processor/ODataSingleProcessorService.java
@@ -206,7 +206,8 @@ public class ODataSingleProcessorService implements ODataService {
}
if (processorFeature == BatchProcessor.class) {
- result.add(HttpContentType.MULTIPART_MIXED);
+ //set wildcard for now to ignore accept header completely, reasoning: there is only one representation for $batch
+ result.add(HttpContentType.WILDCARD);
} else if (processorFeature == EntityProcessor.class) {
result.add(HttpContentType.APPLICATION_ATOM_XML_ENTRY_UTF8);
result.add(HttpContentType.APPLICATION_ATOM_XML_UTF8);
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
----------------------------------------------------------------------
diff --git a/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java b/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
index fb127e3..0b99827 100644
--- a/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
+++ b/odata-core/src/main/java/org/apache/olingo/odata2/core/rt/RuntimeDelegateImpl.java
@@ -22,6 +22,9 @@ import java.io.InputStream;
import org.apache.olingo.odata2.api.ODataService;
import org.apache.olingo.odata2.api.batch.BatchResponsePart.BatchResponsePartBuilder;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSet.BatchChangeSetBuilder;
+import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart.BatchChangeSetPartBuilder;
+import org.apache.olingo.odata2.api.client.batch.BatchQueryPart.BatchQueryPartBuilder;
import org.apache.olingo.odata2.api.edm.Edm;
import org.apache.olingo.odata2.api.edm.EdmSimpleType;
import org.apache.olingo.odata2.api.edm.EdmSimpleTypeFacade;
@@ -36,6 +39,9 @@ import org.apache.olingo.odata2.api.rt.RuntimeDelegate.RuntimeDelegateInstance;
import org.apache.olingo.odata2.api.uri.UriParser;
import org.apache.olingo.odata2.core.ODataRequestImpl;
import org.apache.olingo.odata2.core.ODataResponseImpl;
+import org.apache.olingo.odata2.core.batch.BatchChangeSetImpl;
+import org.apache.olingo.odata2.core.batch.BatchChangeSetPartImpl;
+import org.apache.olingo.odata2.core.batch.BatchQueryPartImpl;
import org.apache.olingo.odata2.core.batch.BatchResponsePartImpl;
import org.apache.olingo.odata2.core.edm.EdmSimpleTypeFacadeImpl;
import org.apache.olingo.odata2.core.edm.parser.EdmxProvider;
@@ -102,4 +108,23 @@ public class RuntimeDelegateImpl extends RuntimeDelegateInstance {
return request.new ODataRequestBuilderImpl();
}
+ @Override
+ protected BatchChangeSetBuilder createBatchChangeSetBuilder() {
+ BatchChangeSetImpl changeSet = new BatchChangeSetImpl();
+ return changeSet.new BatchChangeSetBuilderImpl();
+ }
+
+ @Override
+ protected BatchQueryPartBuilder createBatchQueryRequestBuilder() {
+ BatchQueryPartImpl batchQueryRequest = new BatchQueryPartImpl();
+ return batchQueryRequest.new BatchQueryRequestBuilderImpl();
+ }
+
+ @Override
+ protected BatchChangeSetPartBuilder createBatchChangeSetRequest() {
+ BatchChangeSetPartImpl batchChangeSetRequest = new BatchChangeSetPartImpl();
+ ;
+ return batchChangeSetRequest.new BatchChangeSetRequestBuilderImpl();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/incubator-olingo-odata2/blob/45c27419/odata-core/src/main/resources/i18n.properties
----------------------------------------------------------------------
diff --git a/odata-core/src/main/resources/i18n.properties b/odata-core/src/main/resources/i18n.properties
index 1627223..b28bf50 100644
--- a/odata-core/src/main/resources/i18n.properties
+++ b/odata-core/src/main/resources/i18n.properties
@@ -118,7 +118,8 @@ org.apache.olingo.odata2.api.batch.BatchException.MISSING_CLOSE_DELIMITER=Missin
org.apache.olingo.odata2.api.batch.BatchException.INVALID_QUERY_OPERATION_METHOD=Invalid method: a Query Operation cannot contain insert, update or delete requests at line '%1$s'.
org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_METHOD= Invalid method: a ChangeSet cannot contain retrieve requests at line '%1$s'.
org.apache.olingo.odata2.api.batch.BatchException.INVALID_QUERY_PARAMETER=Invalid query parameters.
-org.apache.olingo.odata2.api.batch.BatchException.INVALID_URI=Invalid URI.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_URI=Invalid URI: line '%1$s'.
+org.apache.olingo.odata2.api.batch.BatchException.UNSUPPORTED_ABSOLUTE_PATH = An absolute-path in request line is not supported: line '%1$s'.
org.apache.olingo.odata2.api.batch.BatchException.INVALID_BOUNDARY=Invalid boundary at line '%1$s'.
org.apache.olingo.odata2.api.batch.BatchException.NO_MATCH_WITH_BOUNDARY_STRING=The boundary string does not match the boundary from the Content-Type header field '%1$s': line '%2$s'.
org.apache.olingo.odata2.api.batch.BatchException.MISSING_CONTENT_TYPE=No Content-Type field for MIME-header is present.
@@ -132,6 +133,7 @@ org.apache.olingo.odata2.api.batch.BatchException.MISSING_BLANK_LINE=Expected em
org.apache.olingo.odata2.api.batch.BatchException.INVALID_PATHINFO=PathInfo should not be null.
org.apache.olingo.odata2.api.batch.BatchException.MISSING_METHOD=Missing method in request line '%1$s'.
org.apache.olingo.odata2.api.batch.BatchException.INVALID_REQUEST_LINE=Invalid request line '%1$s' at line '%2$s'.
+org.apache.olingo.odata2.api.batch.BatchException.INVALID_REQUEST_LINE=Invalid status line '%1$s' at line '%2$s'.
org.apache.olingo.odata2.api.batch.BatchException.TRUNCATED_BODY=Body is truncated: line '%1$s'.
##################################