http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmEntityContainerImplProv.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmEntityContainerImplProv.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmEntityContainerImplProv.java index e4026e6..1472388 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmEntityContainerImplProv.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmEntityContainerImplProv.java @@ -260,7 +260,7 @@ public class EdmEntityContainerImplProv implements EdmEntityContainer, EdmAnnota return entityContainerHierachy; } - List<EntityContainer> entityContainerHierachy = new ArrayList<EntityContainer>(); + entityContainerHierachy = new ArrayList<EntityContainer>(); Map<String, EntityContainer> name2Container = getEntityContainerMap(); String currentName = getName(); while (currentName != null) {
http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmServiceMetadataImplProv.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmServiceMetadataImplProv.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmServiceMetadataImplProv.java index 16262fc..e7853eb 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmServiceMetadataImplProv.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/edm/provider/EdmServiceMetadataImplProv.java @@ -23,6 +23,7 @@ import java.io.InputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import javax.xml.stream.XMLOutputFactory; @@ -104,29 +105,23 @@ public class EdmServiceMetadataImplProv implements EdmServiceMetadata { if (dataServiceVersion == null) { dataServiceVersion = ODataServiceVersion.V10; - if (schemas != null) { - for (Schema schema : schemas) { - List<EntityType> entityTypes = schema.getEntityTypes(); - if (entityTypes != null) { - for (EntityType entityType : entityTypes) { - List<Property> properties = entityType.getProperties(); - if (properties != null) { - for (Property property : properties) { - if (property.getCustomizableFeedMappings() != null) { - if (property.getCustomizableFeedMappings().getFcKeepInContent() != null) { - if (!property.getCustomizableFeedMappings().getFcKeepInContent()) { - dataServiceVersion = ODataServiceVersion.V20; - return dataServiceVersion; - } - } - } + for (Schema schema : listOrEmptyList(schemas)) { + List<EntityType> entityTypes = listOrEmptyList(schema.getEntityTypes()); + for (EntityType entityType : entityTypes) { + List<Property> properties = listOrEmptyList(entityType.getProperties()); + for (Property property : properties) { + if (property.getCustomizableFeedMappings() != null) { + if (property.getCustomizableFeedMappings().getFcKeepInContent() != null) { + if (!property.getCustomizableFeedMappings().getFcKeepInContent()) { + dataServiceVersion = ODataServiceVersion.V20; + return dataServiceVersion; } - if (entityType.getCustomizableFeedMappings() != null) { - if (entityType.getCustomizableFeedMappings().getFcKeepInContent() != null) { - if (entityType.getCustomizableFeedMappings().getFcKeepInContent()) { - dataServiceVersion = ODataServiceVersion.V20; - return dataServiceVersion; - } + } + if (entityType.getCustomizableFeedMappings() != null) { + if (entityType.getCustomizableFeedMappings().getFcKeepInContent() != null) { + if (entityType.getCustomizableFeedMappings().getFcKeepInContent()) { + dataServiceVersion = ODataServiceVersion.V20; + return dataServiceVersion; } } } @@ -148,8 +143,8 @@ public class EdmServiceMetadataImplProv implements EdmServiceMetadata { } for (Schema schema : schemas) { - for (EntityContainer entityContainer : schema.getEntityContainers()) { - for (EntitySet entitySet : entityContainer.getEntitySets()) { + for (EntityContainer entityContainer : listOrEmptyList(schema.getEntityContainers())) { + for (EntitySet entitySet : listOrEmptyList(entityContainer.getEntitySets())) { EdmEntitySetInfo entitySetInfo = new EdmEntitySetInfoImplProv(entitySet, entityContainer); entitySetInfos.add(entitySetInfo); } @@ -160,4 +155,18 @@ public class EdmServiceMetadataImplProv implements EdmServiceMetadata { return entitySetInfos; } + + /** + * Return original list if parameter is not NULL or an empty list. + * + * @param list list which is checked and probably returned + * @param <T> type of list + * @return original list if parameter is not NULL or an empty list + */ + private <T> List<T> listOrEmptyList(List<T> list) { + if(list == null) { + return Collections.emptyList(); + } + return list; + } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java index c76109b..4937e30 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java @@ -45,10 +45,9 @@ import org.apache.olingo.odata2.api.exception.ODataNotAcceptableException; 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.batch.v2.BatchParser; import org.apache.olingo.odata2.core.commons.ContentType; import org.apache.olingo.odata2.core.edm.provider.EdmImplProv; import org.apache.olingo.odata2.core.edm.provider.EdmxProvider; @@ -235,7 +234,7 @@ public class ProviderFacadeImpl implements EntityProviderInterface { @Override public List<BatchRequestPart> parseBatchRequest(final String contentType, final InputStream content, final EntityProviderBatchProperties properties) throws BatchException { - List<BatchRequestPart> batchParts = new BatchRequestParser(contentType, properties).parse(content); + List<BatchRequestPart> batchParts = new BatchParser(contentType, properties, true).parseBatchRequest(content); return batchParts; } @@ -254,7 +253,7 @@ public class ProviderFacadeImpl implements EntityProviderInterface { @Override public List<BatchSingleResponse> parseBatchResponse(final String contentType, final InputStream content) throws BatchException { - List<BatchSingleResponse> responses = new BatchResponseParser(contentType).parse(content); + List<BatchSingleResponse> responses = new BatchParser(contentType, true).parseBatchResponse(content); return responses; } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rest/ODataSubLocator.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rest/ODataSubLocator.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rest/ODataSubLocator.java index 7ab9ee1..5727b1d 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rest/ODataSubLocator.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/rest/ODataSubLocator.java @@ -34,6 +34,8 @@ import org.apache.olingo.odata2.api.ODataServiceFactory; import org.apache.olingo.odata2.api.commons.ODataHttpMethod; import org.apache.olingo.odata2.api.exception.MessageReference; import org.apache.olingo.odata2.api.exception.ODataException; +import org.apache.olingo.odata2.api.exception.ODataInternalServerErrorException; +import org.apache.olingo.odata2.api.exception.ODataMessageException; import org.apache.olingo.odata2.api.exception.ODataNotImplementedException; import org.apache.olingo.odata2.api.processor.ODataContext; import org.apache.olingo.odata2.api.processor.ODataRequest; @@ -110,6 +112,10 @@ public final class ODataSubLocator { private Response returnNotImplementedResponse(final MessageReference messageReference) { // RFC 2616, 5.1.1: "An origin server SHOULD return the status code [...] // 501 (Not Implemented) if the method is unrecognized [...] by the origin server." + return returnException(new ODataNotImplementedException(messageReference)); + } + + private Response returnException(final ODataMessageException messageException) { ODataContextImpl context = new ODataContextImpl(request, serviceFactory); context.setRequest(request); context.setAcceptableLanguages(request.getAcceptableLanguages()); @@ -119,9 +125,13 @@ public final class ODataSubLocator { ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(context, request.getQueryParameters(), request.getAcceptHeaders()); ODataResponse response = - exceptionWrapper.wrapInExceptionResponse(new ODataNotImplementedException(messageReference)); + exceptionWrapper.wrapInExceptionResponse(messageException); return RestUtil.convertResponse(response); } + + private Response returnNoServiceResponse(MessageReference messageReference) { + return returnException(new ODataInternalServerErrorException(messageReference)); + } @OPTIONS public Response handleOptions() throws ODataException { @@ -146,7 +156,9 @@ public final class ODataSubLocator { context.setParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT, httpRequest); ODataService service = serviceFactory.createService(context); - + if(service == null){ + return returnNoServiceResponse(ODataInternalServerErrorException.NOSERVICE); + } service.getProcessor().setContext(context); context.setService(service); @@ -158,6 +170,8 @@ public final class ODataSubLocator { return response; } + + public static ODataSubLocator create(final SubLocatorParameter param) throws ODataException { ODataSubLocator subLocator = new ODataSubLocator(); http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java index 1d4dfe3..2312170 100644 --- a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java +++ b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/servlet/ODataServlet.java @@ -35,6 +35,7 @@ import org.apache.olingo.odata2.api.exception.MessageReference; import org.apache.olingo.odata2.api.exception.ODataBadRequestException; import org.apache.olingo.odata2.api.exception.ODataException; import org.apache.olingo.odata2.api.exception.ODataHttpException; +import org.apache.olingo.odata2.api.exception.ODataInternalServerErrorException; import org.apache.olingo.odata2.api.exception.ODataMethodNotAllowedException; import org.apache.olingo.odata2.api.exception.ODataNotAcceptableException; import org.apache.olingo.odata2.api.exception.ODataNotImplementedException; @@ -174,6 +175,9 @@ public class ODataServlet extends HttpServlet { context.setParameter(ODataContext.HTTP_SERVLET_REQUEST_OBJECT, req); ODataService service = serviceFactory.createService(context); + if(service == null){ + createServiceUnavailableResponse(req, ODataInternalServerErrorException.NOSERVICE, resp); + } context.setService(service); service.getProcessor().setContext(context); @@ -271,7 +275,14 @@ public class ODataServlet extends HttpServlet { ODataResponse response = exceptionWrapper.wrapInExceptionResponse(new ODataNotAcceptableException(messageReference)); createResponse(resp, response); + } + private void createServiceUnavailableResponse(HttpServletRequest req, MessageReference messageReference, + HttpServletResponse resp) throws IOException { + ODataExceptionWrapper exceptionWrapper = new ODataExceptionWrapper(req); + ODataResponse response = + exceptionWrapper.wrapInExceptionResponse(new ODataInternalServerErrorException(messageReference)); + createResponse(resp, response); } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/resources/i18n.properties ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/resources/i18n.properties b/odata2-lib/odata-core/src/main/resources/i18n.properties index 90b7045..2adda81 100644 --- a/odata2-lib/odata-core/src/main/resources/i18n.properties +++ b/odata2-lib/odata-core/src/main/resources/i18n.properties @@ -118,36 +118,38 @@ org.apache.olingo.odata2.api.ep.EntityProviderException.INVALID_DELETED_ENTRY_ME ################################## # BatchParserexceptions ################################## -org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_BOUNDARY=The boundary of the ChangeSet should be different from that used by the Batch: line '%1$s'. +org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_LANGUAGE_HEADER=Invalid Accept-Language: '%1$s'. +org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_HEADER=Invalid Accept header: '%1$s'. org.apache.olingo.odata2.api.batch.BatchException.INVALID_BOUNDARY_DELIMITER=The boundary delimiter must begin with two hyphen characters: line '%1$s'. -org.apache.olingo.odata2.api.batch.BatchException.MISSING_BOUNDARY_DELIMITER=Missing boundary delimiter at line '%1$s'. -org.apache.olingo.odata2.api.batch.BatchException.MISSING_CLOSE_DELIMITER=Missing close delimiter at line '%1$s'. -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: 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. -org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TYPE=Content-Type should be '%1$s'. -org.apache.olingo.odata2.api.batch.BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE=The Content-Type field for multipart entities requires boundary parameter. -org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TRANSFER_ENCODING=The Content-Transfer-Encoding should be binary. -org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_HEADER=Invalid Accept header: '%1$s'. -org.apache.olingo.odata2.api.batch.BatchException.INVALID_ACCEPT_LANGUAGE_HEADER=Invalid Accept-Language: '%1$s'. org.apache.olingo.odata2.api.batch.BatchException.INVALID_HEADER=Invalid header: '%1$s' at line '%2$s'. -org.apache.olingo.odata2.api.batch.BatchException.MISSING_BLANK_LINE=Expected empty line but was '%1$s': line '%2$s' . +org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TRANSFER_ENCODING=The Content-Transfer-Encoding should be binary: line '%1$s'. +org.apache.olingo.odata2.api.batch.BatchException.INVALID_CONTENT_TYPE=Content-Type should be '%1$s'. +org.apache.olingo.odata2.api.batch.BatchException.INVALID_CHANGESET_BOUNDARY=The boundary of the ChangeSet should be different from that used by the Batch: 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_REQUEST_LINE=Invalid request line '%1$s' at line '%2$s'. org.apache.olingo.odata2.api.batch.BatchException.INVALID_PATHINFO=PathInfo should not be null. +org.apache.olingo.odata2.api.batch.BatchException.INVALID_URI=Invalid URI: line '%1$s'. +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_QUERY_PARAMETER=Invalid query parameters. +org.apache.olingo.odata2.api.batch.BatchException.MISSING_BLANK_LINE=Expected empty line but was '%1$s': line '%2$s' . +org.apache.olingo.odata2.api.batch.BatchException.MISSING_BOUNDARY_DELIMITER=Missing boundary delimiter at line '%1$s'. +org.apache.olingo.odata2.api.batch.BatchException.MISSING_CONTENT_TYPE=No Content-Type field for MIME-header is present. +org.apache.olingo.odata2.api.batch.BatchException.MISSING_CLOSE_DELIMITER=Missing close delimiter at line '%1$s'. +org.apache.olingo.odata2.api.batch.BatchException.MISSING_MANDATORY_HEADER=Missing mandatory header '%1$s'. 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.MISSING_PARAMETER_IN_CONTENT_TYPE=The Content-Type field for multipart entities requires boundary parameter. +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.TRUNCATED_BODY=Body is truncated: 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'. ################################## # HttpExceptions ################################## org.apache.olingo.odata2.api.exception.ODataHttpException.COMMON=Common exception +org.apache.olingo.odata2.api.exception.ODataInternalServerErrorException.NOSERVICE=Service unavailable. + org.apache.olingo.odata2.api.exception.ODataBadRequestException.COMMON=Bad Request. org.apache.olingo.odata2.api.exception.ODataBadRequestException.NOTSUPPORTED=The request is not supported by the processor. org.apache.olingo.odata2.api.exception.ODataBadRequestException.INVALID_HEADER=The request contains an invalid header parameter '%1$s' with value '%2$s'. http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/main/resources/i18n_en.properties ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/main/resources/i18n_en.properties b/odata2-lib/odata-core/src/main/resources/i18n_en.properties index 564dfef..7de9229 100644 --- a/odata2-lib/odata-core/src/main/resources/i18n_en.properties +++ b/odata2-lib/odata-core/src/main/resources/i18n_en.properties @@ -97,6 +97,8 @@ org.apache.olingo.odata2.api.ep.EntityProviderException.ILLEGAL_ARGUMENT=Illegal ################################## org.apache.olingo.odata2.api.exception.ODataHttpException.COMMON=Common exception +org.apache.olingo.odata2.api.exception.ODataInternalServerErrorException.NOSERVICE=Service unavailable. + org.apache.olingo.odata2.api.exception.ODataBadRequestException.COMMON=Bad Request. org.apache.olingo.odata2.api.exception.ODataBadRequestException.NOTSUPPORTED=The request is not supported by the processor. org.apache.olingo.odata2.api.exception.ODataBadRequestException.URLTOOSHORT=The URL is too short. http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java index a3c0512..b7d7fac 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/AcceptParserTest.java @@ -31,8 +31,10 @@ public class AcceptParserTest { @Test public void testAcceptHeader() throws BatchException { - List<String> acceptHeaders = - AcceptParser.parseAcceptHeaders("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(4, acceptHeaders.size()); assertEquals("text/html", acceptHeaders.get(0)); @@ -43,48 +45,58 @@ public class AcceptParserTest { @Test public void testAcceptHeaderWithParameter() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;odata=verbose;q=1.0, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/json;odata=verbose;q=1.0, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/json;odata=verbose", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeaderWithParameterAndLws() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json; odata=verbose;q=1.0, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/json; odata=verbose;q=1.0, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/json; odata=verbose", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeaderWithTabulator() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/json;\todata=verbose;q=1.0, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/json;\todata=verbose;q=1.0, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/json;" + TAB + "odata=verbose", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeaderWithTwoParameters() throws BatchException { - List<String> acceptHeaders = - AcceptParser.parseAcceptHeaders("application/xml;another=test ; param=alskdf, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/xml;another=test ; param=alskdf, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/xml;another=test ; param=alskdf", acceptHeaders.get(0)); - ; assertEquals("*/*", acceptHeaders.get(1)); } @Test public void testAcceptHeader2() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("text/html;level=1, application/*, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("text/html;level=1, application/*, */*;q=0.1"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(3, acceptHeaders.size()); assertEquals("text/html;level=1", acceptHeaders.get(0)); @@ -94,7 +106,10 @@ public class AcceptParserTest { @Test public void testMoreSpecificMediaType() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, application/xml"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/*, application/xml"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); assertEquals(2, acceptHeaders.size()); assertEquals("application/xml", acceptHeaders.get(0)); @@ -103,28 +118,40 @@ public class AcceptParserTest { @Test public void testQualityParameter() throws BatchException { - List<String> acceptHeaders = AcceptParser.parseAcceptHeaders("application/*, */*; q=0.012"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("application/*, */*; q=0.012"); + List<String> acceptHeaders = parser.parseAcceptHeaders(); + assertNotNull(acceptHeaders); } @Test(expected = BatchException.class) public void testInvalidAcceptHeader() throws BatchException { - AcceptParser.parseAcceptHeaders("appi cation/*, */*;q=0.1"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("appi cation/*, */*;q=0.1"); + parser.parseAcceptHeaders(); } @Test(expected = BatchException.class) public void testInvalidQualityParameter() throws BatchException { - AcceptParser.parseAcceptHeaders("appication/*, */*;q=0,9"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("appication/*, */*;q=0,9"); + parser.parseAcceptHeaders(); } @Test(expected = BatchException.class) public void testInvalidQualityParameter2() throws BatchException { - AcceptParser.parseAcceptHeaders("appication/*, */*;q=1.0001"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptHeaderValue("appication/*, */*;q=1.0001"); + parser.parseAcceptHeaders(); } @Test public void testAcceptLanguages() throws BatchException { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("en-US,en;q=0.7,en-UK;q=0.9"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("en-US,en;q=0.7,en-UK;q=0.9"); + List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages(); + assertNotNull(acceptLanguageHeaders); assertEquals(3, acceptLanguageHeaders.size()); assertEquals("en-US", acceptLanguageHeaders.get(0)); @@ -134,20 +161,28 @@ public class AcceptParserTest { @Test public void testAllAcceptLanguages() throws BatchException { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("*"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("*"); + List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages(); + assertNotNull(acceptLanguageHeaders); assertEquals(1, acceptLanguageHeaders.size()); } @Test public void testLongAcceptLanguageValue() throws BatchException { - List<String> acceptLanguageHeaders = AcceptParser.parseAcceptableLanguages("english"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("english"); + List<String> acceptLanguageHeaders = parser.parseAcceptableLanguages(); + assertNotNull(acceptLanguageHeaders); assertEquals("english", acceptLanguageHeaders.get(0)); } @Test(expected = BatchException.class) public void testInvalidAcceptLanguageValue() throws BatchException { - AcceptParser.parseAcceptableLanguages("en_US"); + AcceptParser parser = new AcceptParser(); + parser.addAcceptLanguageHeaderValue("en_US"); + parser.parseAcceptableLanguages(); } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java new file mode 100644 index 0000000..89eb14a --- /dev/null +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchParserCommonTest.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * 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.*; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.olingo.odata2.api.batch.BatchException; +import org.apache.olingo.odata2.api.commons.HttpHeaders; +import org.apache.olingo.odata2.core.batch.v2.BatchParserCommon; +import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line; +import org.apache.olingo.odata2.core.batch.v2.Header; +import org.junit.Test; + +public class BatchParserCommonTest { + + private static final String CRLF = "\r\n"; + + @Test + public void testMultipleHeader() throws BatchException { + String[] messageRaw = new String[] { + "Content-Id: 1" + CRLF, + "Content-Id: 2" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> contentIdHeaders = header.getHeaders(BatchHelper.HTTP_CONTENT_ID); + assertNotNull(contentIdHeaders); + assertEquals(2, contentIdHeaders.size()); + assertEquals("1", contentIdHeaders.get(0)); + assertEquals("2", contentIdHeaders.get(1)); + } + + @Test + public void testMultipleHeaderSameValue() throws BatchException { + String[] messageRaw = new String[] { + "Content-Id: 1" + CRLF, + "Content-Id: 1" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> contentIdHeaders = header.getHeaders(BatchHelper.HTTP_CONTENT_ID); + assertNotNull(contentIdHeaders); + assertEquals(1, contentIdHeaders.size()); + assertEquals("1", contentIdHeaders.get(0)); + } + + @Test + public void testHeaderSperatedByComma() throws BatchException { + String[] messageRaw = new String[] { + "Content-Id: 1" + CRLF, + "Upgrade: HTTP/2.0, SHTTP/1.3, IRC/6.9, RTA/x11" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> upgradeHeader = header.getHeaders("upgrade"); + assertNotNull(upgradeHeader); + assertEquals(4, upgradeHeader.size()); + assertEquals("HTTP/2.0", upgradeHeader.get(0)); + assertEquals("SHTTP/1.3", upgradeHeader.get(1)); + assertEquals("IRC/6.9", upgradeHeader.get(2)); + assertEquals("RTA/x11", upgradeHeader.get(3)); + } + + @Test + public void testMultipleAcceptHeader() throws BatchException { + String[] messageRaw = new String[] { + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF, + "Accept: text/plain;q=0.3" + CRLF, + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> acceptHeader = header.getHeaders(HttpHeaders.ACCEPT); + assertNotNull(acceptHeader); + assertEquals(4, acceptHeader.size()); + } + + @Test + public void testMultipleAcceptHeaderSameValue() throws BatchException { + String[] messageRaw = new String[] { + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF, + "Accept: application/atomsvc+xml;q=0.8" + CRLF, + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> acceptHeader = header.getHeaders(HttpHeaders.ACCEPT); + assertNotNull(acceptHeader); + assertEquals(3, acceptHeader.size()); + } + + @Test + public void testMultipleAccepLanguagetHeader() throws BatchException { + String[] messageRaw = new String[] { + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "Accept-Language: de-DE;q=0.3" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> acceptLanguageHeader = header.getHeaders(HttpHeaders.ACCEPT_LANGUAGE); + assertNotNull(acceptLanguageHeader); + assertEquals(4, acceptLanguageHeader.size()); + } + + @Test + public void testMultipleAccepLanguagetHeaderSameValue() throws BatchException { + String[] messageRaw = new String[] { + "Accept-Language:en-US,en;q=0.7,en-UK;q=0.9" + CRLF, + "Accept-Language:en-US,en;q=0.7" + CRLF, + "content-type: Application/http" + CRLF, + "content-transfer-encoding: Binary" + CRLF + }; + List<Line> message = toLineList(messageRaw); + + final Header header = BatchParserCommon.consumeHeaders(message); + assertNotNull(header); + + final List<String> acceptLanguageHeader = header.getHeaders(HttpHeaders.ACCEPT_LANGUAGE); + assertNotNull(acceptLanguageHeader); + assertEquals(3, acceptLanguageHeader.size()); + } + + @Test + public void testRemoveEndingCRLF() { + String line = "Test\r\n"; + assertEquals("Test", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveLastEndingCRLF() { + String line = "Test\r\n\r\n"; + assertEquals("Test\r\n", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveEndingCRLFWithWS() { + String line = "Test\r\n "; + assertEquals("Test", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveEndingCRLFNothingToRemove() { + String line = "Hallo\r\nBla"; + assertEquals("Hallo\r\nBla", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveEndingCRLFAll() { + String line = "\r\n"; + assertEquals("", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveEndingCRLFSpace() { + String line = "\r\n "; + assertEquals("", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveLastEndingCRLFWithWS() { + String line = "Test \r\n"; + assertEquals("Test ", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + @Test + public void testRemoveLastEndingCRLFWithWSLong() { + String line = "Test \r\nTest2 \r\n"; + assertEquals("Test \r\nTest2 ", BatchParserCommon.removeEndingCRLF(new Line(line,1)).toString()); + } + + private List<Line> toLineList(String[] messageRaw) { + final List<Line> lineList = new ArrayList<Line>(); + int counter = 1; + + for(final String currentLine : messageRaw) { + lineList.add(new Line(currentLine, counter++)); + } + + return lineList; + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java index f9b19b9..447049e 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestParserTest.java @@ -6,9 +6,9 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -38,14 +38,11 @@ import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties; 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.core.batch.v2.BatchParser; import org.apache.olingo.odata2.testutil.helper.StringHelper; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Test; -/** - * - */ public class BatchRequestParserTest { private static final String CRLF = "\r\n"; @@ -67,7 +64,6 @@ public class BatchRequestParserTest { PathInfoImpl pathInfo = new PathInfoImpl(); pathInfo.setServiceRoot(new URI(SERVICE_ROOT)); batchProperties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build(); - } @Test @@ -78,8 +74,8 @@ public class BatchRequestParserTest { throw new IOException("Requested file '" + fileName + "' was not found."); } - BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties); - List<BatchRequestPart> batchRequestParts = parser.parse(in); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); assertNotNull(batchRequestParts); assertEquals(false, batchRequestParts.isEmpty()); for (BatchRequestPart object : batchRequestParts) { @@ -122,7 +118,7 @@ public class BatchRequestParserTest { } } } - + @Test public void testImageInContent() throws IOException, BatchException, URISyntaxException { String fileName = "/batchWithContent.batch"; @@ -169,7 +165,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(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase())); + assertEquals("1", request.getRequestHeaderValue(BatchHelper.MIME_HEADER_CONTENT_ID)); assertEquals("application/octet-stream", request.getContentType()); InputStream body = request.getBody(); assertEquals(content, StringHelper.inputStreamToString(body)); @@ -194,6 +190,7 @@ public class BatchRequestParserTest { + CRLF + "--changeset_f980-1cb6-94dd" + CRLF + MIME_HEADERS + + "Content-ID: changeRequest1" + CRLF + CRLF + "POST Employees('2') HTTP/1.1" + CRLF + "Content-Length: 100" + CRLF @@ -225,8 +222,8 @@ public class BatchRequestParserTest { + GET_REQUEST + "--batch_1.2+34:2j)0?--"; InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties); - List<BatchRequestPart> batchRequestParts = parser.parse(in); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); assertNotNull(batchRequestParts); assertEquals(false, batchRequestParts.isEmpty()); } @@ -239,8 +236,8 @@ public class BatchRequestParserTest { + GET_REQUEST + "--batch_1740-bb84-2f7f--"; InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(invalidContentType, batchProperties); - parser.parse(in); + BatchParser parser = new BatchParser(invalidContentType, batchProperties, true); + parser.parseBatchRequest(in); } @Test(expected = BatchException.class) @@ -250,19 +247,19 @@ public class BatchRequestParserTest { + GET_REQUEST + "--batch_1740-bb84-2f7f--"; InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(invalidContentType, batchProperties); - parser.parse(in); + BatchParser parser = new BatchParser(invalidContentType, batchProperties, true); + parser.parseBatchRequest(in); } @Test(expected = BatchException.class) public void testBoundaryParameterWithoutQuota() throws BatchException { - String invalidContentType = "multipart;boundary=batch_1740-bb:84-2f7f"; + String invalidContentType = "multipart/mixed;boundary=batch_1740-bb:84-2f7f"; String batch = "--batch_1740-bb:84-2f7f" + CRLF + GET_REQUEST + "--batch_1740-bb:84-2f7f--"; InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(invalidContentType, batchProperties); - parser.parse(in); + BatchParser parser = new BatchParser(invalidContentType, batchProperties, true); + parser.parseBatchRequest(in); } @Test(expected = BatchException.class) @@ -273,6 +270,51 @@ public class BatchRequestParserTest { parseInvalidBatchBody(batch); } + @Test(expected=BatchException.class) + public void testMissingHttpVersion() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding:binary" + CRLF + + CRLF + + "GET Employees?$format=json" + CRLF + + "Host: localhost:8080" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + + parseInvalidBatchBody(batch); + } + + @Test(expected=BatchException.class) + public void testMissingHttpVersion2() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding:binary" + CRLF + + CRLF + + "GET Employees?$format=json " + CRLF + + "Host: localhost:8080" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + + parseInvalidBatchBody(batch); + } + + @Test(expected=BatchException.class) + public void testMissingHttpVersion3() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding:binary" + CRLF + + CRLF + + "GET Employees?$format=json SMTP:3.1" + CRLF + + "Host: localhost:8080" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + + parseInvalidBatchBody(batch); + } + @Test(expected = BatchException.class) public void testBoundaryWithoutHyphen() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -290,6 +332,7 @@ public class BatchRequestParserTest { // + no boundary string + GET_REQUEST + "--batch_8194-cf13-1f56--"; + parseInvalidBatchBody(batch); } @@ -346,20 +389,21 @@ public class BatchRequestParserTest { + "--batch_8194-cf13-1f56--"; parseInvalidBatchBody(batch); } - + @Test(expected = BatchException.class) - @Ignore("What should here throw an exception") - public void testMimeHeaderContentId() throws BatchException { + public void testGetRequestMissingCRLF() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF + MIME_HEADERS + "Content-ID: 1" + CRLF + CRLF + "GET Employees('1')/EmployeeName HTTP/1.1" + CRLF - + CRLF + //+ CRLF // Belongs to the GET request + + CRLF //Belongs to the + "--batch_8194-cf13-1f56--"; + parseInvalidBatchBody(batch); } - + @Test(expected = BatchException.class) public void testInvalidMethodForBatch() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -372,6 +416,22 @@ public class BatchRequestParserTest { } @Test(expected = BatchException.class) + public void testNoBoundaryFound() throws BatchException { + String batch = "batch_8194-cf13-1f56" + CRLF + + MIME_HEADERS + + CRLF + + "POST Employees('1')/EmployeeName HTTP/1.1" + CRLF + + CRLF; + parseInvalidBatchBody(batch); + } + + @Test(expected = BatchException.class) + public void testBadRequest() throws BatchException { + String batch = "This is a bad request. There is no syntax and also no semantic"; + parseInvalidBatchBody(batch); + } + + @Test(expected = BatchException.class) public void testNoMethod() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF + MIME_HEADERS @@ -398,7 +458,7 @@ public class BatchRequestParserTest { parseInvalidBatchBody(batch); } - @Test(expected = BatchException.class) + @Test(expected=BatchException.class) public void testInvalidChangeSetBoundary() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF @@ -410,6 +470,69 @@ public class BatchRequestParserTest { + "Content-Type: application/json;odata=verbose" + CRLF + "MaxDataServiceVersion: 2.0" + CRLF + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + parseInvalidBatchBody(batch); + } + + @Test(expected=BatchException.class) + public void testNestedChangeset() throws BatchException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd2" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd2" + CRLF + + MIME_HEADERS + + CRLF + + "POST Employees('2') HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "MaxDataServiceVersion: 2.0" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + parse(batch); + } + + @Test(expected = BatchException.class) + public void testMissingContentTransferEncoding() throws BatchException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + "Content-Type: application/http" + CRLF + // + "Content-Transfer-Encoding: binary" + CRLF + + CRLF + + "POST Employees('2') HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "MaxDataServiceVersion: 2.0" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + "--batch_8194-cf13-1f56--"; + parseInvalidBatchBody(batch); + } + + @Test(expected = BatchException.class) + public void testMissingContentType() throws BatchException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + // + "Content-Type: application/http" + CRLF + + "Content-Transfer-Encoding: binary" + CRLF + + CRLF + + "POST Employees('2') HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "MaxDataServiceVersion: 2.0" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + "--batch_8194-cf13-1f56--"; parseInvalidBatchBody(batch); } @@ -552,6 +675,197 @@ public class BatchRequestParserTest { } } + @SuppressWarnings("unused") + @Test + public void testNegativeContentLengthChangeSet() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + } + + @SuppressWarnings("unused") + @Test(expected = BatchException.class) + public void testNegativeContentLengthRequest() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + } + + @Test + public void testContentLengthGreatherThanBodyLength() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + "Content-Length: 100000" + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + assertNotNull(batchRequestParts); + for (BatchRequestPart multipart : batchRequestParts) { + if (multipart.isChangeSet()) { + assertEquals(1, multipart.getRequests().size()); + ODataRequest request = multipart.getRequests().get(0); + assertEquals("{\"EmployeeName\":\"Peter Fall\"}", inputStreamToString(request.getBody())); + } + } + } + + @Test + public void testContentLengthSmallerThanBodyLength() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + "Content-Length: 10" + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + assertNotNull(batchRequestParts); + for (BatchRequestPart multipart : batchRequestParts) { + if (multipart.isChangeSet()) { + assertEquals(1, multipart.getRequests().size()); + ODataRequest request = multipart.getRequests().get(0); + assertEquals("{\"Employee", inputStreamToString(request.getBody())); + } + } + } + + @Test(expected = BatchException.class) + public void testNonNumericContentLength() throws BatchException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + "Content-Length: 10abc" + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + parser.parseBatchRequest(in); + } + + @Test + public void testNonStrictParser() throws BatchException, IOException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_8194-cf13-1f56" + CRLF + + "--changeset_8194-cf13-1f56" + CRLF + + MIME_HEADERS + + "Content-ID: myRequest" + CRLF + + "PUT Employees('2')/EmployeeName HTTP/1.1" + CRLF + + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "MaxDataServiceVersion: 2.0" + CRLF + + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + CRLF + + "--changeset_8194-cf13-1f56--" + CRLF + + "--batch_8194-cf13-1f56--"; + + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, false); + List<BatchRequestPart> requests = parser.parseBatchRequest(in); + assertNotNull(requests); + assertEquals(1, requests.size()); + + BatchRequestPart part = requests.get(0); + assertTrue(part.isChangeSet()); + assertNotNull(part.getRequests()); + assertEquals(1, part.getRequests().size()); + + ODataRequest changeRequest = part.getRequests().get(0); + assertEquals("{\"EmployeeName\":\"Frederic Fall MODIFIED\"}", inputStreamToString(changeRequest.getBody())); + assertEquals("application/json;odata=verbose", changeRequest.getContentType()); + assertEquals(ODataHttpMethod.PUT, changeRequest.getMethod()); + } + + @Test(expected = BatchException.class) + public void testNonStrictParserMoreCRLF() throws BatchException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed;boundary=changeset_8194-cf13-1f56" + CRLF + + "--changeset_8194-cf13-1f56" + CRLF + + MIME_HEADERS + + CRLF + + CRLF // Only one CRLF allowed + + "PUT Employees('2')/EmployeeName HTTP/1.1" + CRLF + + "Accept: application/atomsvc+xml;q=0.8, application/json;odata=verbose;q=0.5, */*;q=0.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "MaxDataServiceVersion: 2.0" + CRLF + + "{\"EmployeeName\":\"Frederic Fall MODIFIED\"}" + CRLF + + "--changeset_8194-cf13-1f56--" + CRLF + + "--batch_8194-cf13-1f56--"; + + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, false); + parser.parseBatchRequest(in); + } + @Test public void testContentId() throws BatchException { String batch = "--batch_8194-cf13-1f56" + CRLF @@ -586,8 +900,8 @@ public class BatchRequestParserTest { + CRLF + "--batch_8194-cf13-1f56--"; InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties); - List<BatchRequestPart> batchRequestParts = parser.parse(in); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); assertNotNull(batchRequestParts); for (BatchRequestPart multipart : batchRequestParts) { if (!multipart.isChangeSet()) { @@ -612,10 +926,241 @@ public class BatchRequestParserTest { } } + @Test + public void testNoContentId() throws BatchException { + String batch = "--batch_8194-cf13-1f56" + CRLF + + MIME_HEADERS + + CRLF + + "GET Employees HTTP/1.1" + CRLF + + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF + + CRLF + CRLF + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + CRLF + + "POST Employees HTTP/1.1" + CRLF + + "Content-type: application/octet-stream" + CRLF + + CRLF + + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); // No exception should be thrown + assertNotNull(batchRequestParts); + } + + @Test + public void testPreamble() throws BatchException, IOException { + String batch = "" + + "This is a preamble and must be ignored" + CRLF + + CRLF + + CRLF + + "----1242" + CRLF + + "--batch_8194-cf13-1f56" + CRLF + + MIME_HEADERS + + CRLF + + "GET Employees HTTP/1.1" + CRLF + + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF + + "Content-Id: BBB" + CRLF + + CRLF + + CRLF + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "This is a preamble and must be ignored" + CRLF + + CRLF + + CRLF + + "----1242" + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-Id: " + CONTENT_ID_REFERENCE + CRLF + + CRLF + + "POST Employees HTTP/1.1" + CRLF + + "Content-type: application/octet-stream" + CRLF + + CRLF + + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + + assertNotNull(batchRequestParts); + assertEquals(2, batchRequestParts.size()); + + BatchRequestPart getRequestPart = batchRequestParts.get(0); + assertEquals(1, getRequestPart.getRequests().size()); + ODataRequest getRequest = getRequestPart.getRequests().get(0); + assertEquals(ODataHttpMethod.GET, getRequest.getMethod()); + + BatchRequestPart changeSetPart = batchRequestParts.get(1); + assertEquals(2, changeSetPart.getRequests().size()); + assertEquals("/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + + CRLF, + inputStreamToString(changeSetPart.getRequests().get(0).getBody())); + assertEquals("{\"EmployeeName\":\"Peter Fall\"}", + inputStreamToString(changeSetPart.getRequests().get(1).getBody())); + } + + @SuppressWarnings("unused") + @Test + public void testContentTypeCaseInsensitive() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: muLTiParT/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + } + + @Test + public void testContentTypeBoundaryCaseInsensitive() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; bOunDaRy=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + "Content-Length: -2" + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "--batch_8194-cf13-1f56--"; + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + + assertNotNull(batchRequestParts); + assertEquals(1, batchRequestParts.size()); + assertTrue(batchRequestParts.get(0).isChangeSet()); + assertEquals(1, batchRequestParts.get(0).getRequests().size()); + } + + @Test + public void testEpilog() throws BatchException, IOException { + String batch = "" + + "--batch_8194-cf13-1f56" + CRLF + + MIME_HEADERS + + CRLF + + "GET Employees HTTP/1.1" + CRLF + + "accept: */*,application/atom+xml,application/atomsvc+xml,application/xml" + CRLF + + "Content-Id: BBB" + CRLF + + CRLF + + CRLF + + "--batch_8194-cf13-1f56" + CRLF + + "Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-Id: " + CONTENT_ID_REFERENCE + CRLF + + CRLF + + "POST Employees HTTP/1.1" + CRLF + + "Content-type: application/octet-stream" + CRLF + + CRLF + + "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + CRLF + + CRLF + + "--changeset_f980-1cb6-94dd" + CRLF + + MIME_HEADERS + + "Content-ID: " + PUT_MIME_HEADER_CONTENT_ID + CRLF + + CRLF + + "PUT $" + CONTENT_ID_REFERENCE + "/EmployeeName HTTP/1.1" + CRLF + + "Content-Type: application/json;odata=verbose" + CRLF + + "Content-Id:" + PUT_REQUEST_HEADER_CONTENT_ID + CRLF + + CRLF + + "{\"EmployeeName\":\"Peter Fall\"}" + CRLF + + "--changeset_f980-1cb6-94dd--" + CRLF + + CRLF + + "This is an epilog and must be ignored" + CRLF + + CRLF + + CRLF + + "----1242" + + CRLF + + "--batch_8194-cf13-1f56--" + + CRLF + + "This is an epilog and must be ignored" + CRLF + + CRLF + + CRLF + + "----1242"; + + InputStream in = new ByteArrayInputStream(batch.getBytes()); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); + + assertNotNull(batchRequestParts); + assertEquals(2, batchRequestParts.size()); + + BatchRequestPart getRequestPart = batchRequestParts.get(0); + assertEquals(1, getRequestPart.getRequests().size()); + ODataRequest getRequest = getRequestPart.getRequests().get(0); + assertEquals(ODataHttpMethod.GET, getRequest.getMethod()); + + BatchRequestPart changeSetPart = batchRequestParts.get(1); + assertEquals(2, changeSetPart.getRequests().size()); + assertEquals("/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAAEaAAUAAAABAAAAYgEbAAUAAAA" + + CRLF, + inputStreamToString(changeSetPart.getRequests().get(0).getBody())); + assertEquals("{\"EmployeeName\":\"Peter Fall\"}", + inputStreamToString(changeSetPart.getRequests().get(1).getBody())); + } + + @Test + public void testLargeBatch() throws BatchException, IOException { + String fileName = "/batchLarge.batch"; + InputStream in = ClassLoader.class.getResourceAsStream(fileName); + if (in == null) { + throw new IOException("Requested file '" + fileName + "' was not found."); + } + BatchParser parser = new BatchParser(contentType, batchProperties, true); + parser.parseBatchRequest(in); + } + private List<BatchRequestPart> parse(final String batch) throws BatchException { InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties); - List<BatchRequestPart> batchRequestParts = parser.parse(in); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + List<BatchRequestPart> batchRequestParts = parser.parseBatchRequest(in); assertNotNull(batchRequestParts); assertEquals(false, batchRequestParts.isEmpty()); return batchRequestParts; @@ -623,7 +1168,18 @@ public class BatchRequestParserTest { private void parseInvalidBatchBody(final String batch) throws BatchException { InputStream in = new ByteArrayInputStream(batch.getBytes()); - BatchRequestParser parser = new BatchRequestParser(contentType, batchProperties); - parser.parse(in); + BatchParser parser = new BatchParser(contentType, batchProperties, true); + parser.parseBatchRequest(in); + } + + private String inputStreamToString(final InputStream in) throws IOException { + int input; + final StringBuilder builder = new StringBuilder(); + + while ((input = in.read()) != -1) { + builder.append((char) input); + } + + return builder.toString(); } } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java index ca6b655..f526920 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestTest.java @@ -39,6 +39,7 @@ import org.apache.olingo.odata2.api.client.batch.BatchPart; import org.apache.olingo.odata2.api.client.batch.BatchQueryPart; import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties; import org.apache.olingo.odata2.core.PathInfoImpl; +import org.apache.olingo.odata2.core.batch.v2.BatchParser; import org.apache.olingo.odata2.testutil.helper.StringHelper; import org.junit.Test; @@ -88,8 +89,8 @@ public class BatchRequestTest { checkHeaders(headers, requestBody); String contentType = "multipart/mixed; boundary=" + BOUNDARY; - BatchRequestParser parser = new BatchRequestParser(contentType, parseProperties); - List<BatchRequestPart> parseResult = parser.parse(batchRequestStream.asStream()); + BatchParser parser = new BatchParser(contentType, parseProperties, true); + List<BatchRequestPart> parseResult = parser.parseBatchRequest(batchRequestStream.asStream()); assertEquals(1, parseResult.size()); } @@ -100,7 +101,7 @@ public class BatchRequestTest { headers.put("content-type", "application/json"); BatchChangeSetPart request = BatchChangeSetPart.method(PUT) .uri("Employees('2')") - .body("{\"ÐозÑаÑÑ\":40}") + .body("{\"Ãâþ÷Ãâ¬Ã°Ã�Ãâ\":40}") .headers(headers) .contentId("111") .build(); @@ -120,12 +121,12 @@ public class BatchRequestTest { assertTrue(requestBody.contains("--batch_")); assertTrue(requestBody.contains("--changeset_")); assertTrue(requestBody.contains("PUT Employees('2') HTTP/1.1")); - assertTrue(requestBody.contains("{\"ÐозÑаÑÑ\":40}")); + assertTrue(requestBody.contains("{\"Ãâþ÷Ãâ¬Ã°Ã�Ãâ\":40}")); assertEquals(16, batchRequestStream.linesCount()); String contentType = "multipart/mixed; boundary=" + BOUNDARY; - BatchRequestParser parser = new BatchRequestParser(contentType, parseProperties); - List<BatchRequestPart> parseResult = parser.parse(batchRequestStream.asStream()); + BatchParser parser = new BatchParser(contentType, parseProperties, true); + List<BatchRequestPart> parseResult = parser.parseBatchRequest(batchRequestStream.asStream()); assertEquals(1, parseResult.size()); } @@ -152,7 +153,6 @@ public class BatchRequestTest { BatchRequestWriter writer = new BatchRequestWriter(); InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY); assertNotNull(batchRequest); - StringHelper.Stream batchRequestStream = StringHelper.toStream(batchRequest); String requestBody = batchRequestStream.asString(); checkMimeHeaders(requestBody); @@ -162,14 +162,14 @@ public class BatchRequestTest { assertTrue(requestBody.contains("GET Employees HTTP/1.1")); assertTrue(requestBody.contains("POST Employees HTTP/1.1")); assertTrue(requestBody.contains(body)); - assertEquals(23, batchRequestStream.linesCount()); + assertEquals(25, batchRequestStream.linesCount()); String contentType = "multipart/mixed; boundary=" + BOUNDARY; - BatchRequestParser parser = new BatchRequestParser(contentType, parseProperties); - List<BatchRequestPart> parseResult = parser.parse(batchRequestStream.asStream()); + BatchParser parser = new BatchParser(contentType, parseProperties, true); + List<BatchRequestPart> parseResult = parser.parseBatchRequest(batchRequestStream.asStream()); assertEquals(2, parseResult.size()); } - + @Test public void testChangeSetWithContentIdReferencing() throws BatchException, IOException { List<BatchPart> batch = new ArrayList<BatchPart>(); @@ -212,8 +212,8 @@ public class BatchRequestTest { assertTrue(requestBody.contains(body)); String contentType = "multipart/mixed; boundary=" + BOUNDARY; - BatchRequestParser parser = new BatchRequestParser(contentType, parseProperties); - List<BatchRequestPart> parseResult = parser.parse(batchRequestStream.asStream()); + BatchParser parser = new BatchParser(contentType, parseProperties, true); + List<BatchRequestPart> parseResult = parser.parseBatchRequest(batchRequestStream.asStream()); assertEquals(1, parseResult.size()); } @@ -227,6 +227,7 @@ public class BatchRequestTest { String body = "/9j/4AAQSkZJRgABAQEBLAEsAAD/4RM0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEA"; BatchChangeSetPart changeRequest = BatchChangeSetPart.method(POST) .uri("Employees") + .contentId("111request") .body(body) .headers(changeSetHeaders) .build(); @@ -239,6 +240,7 @@ public class BatchRequestTest { changeSetHeaders2.put("content-Id", "222"); BatchChangeSetPart changeRequest2 = BatchChangeSetPart.method(PUT) .uri("Employees('2')/ManagerId") + .contentId("222request") .body("{\"ManagerId\":1}") .headers(changeSetHeaders2) .build(); @@ -260,8 +262,8 @@ public class BatchRequestTest { assertTrue(requestBody.contains(body)); String contentType = "multipart/mixed; boundary=" + BOUNDARY; - BatchRequestParser parser = new BatchRequestParser(contentType, parseProperties); - List<BatchRequestPart> parseResult = parser.parse(batchRequestStream.asStream()); + BatchParser parser = new BatchParser(contentType, parseProperties, true); + List<BatchRequestPart> parseResult = parser.parseBatchRequest(batchRequestStream.asStream()); assertEquals(2, parseResult.size()); } http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/a6e2fbe5/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java ---------------------------------------------------------------------- diff --git a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java index 051e1da..e8f7cd4 100644 --- a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java +++ b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/batch/BatchRequestWriterTest.java @@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -34,6 +35,8 @@ 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.core.batch.v2.BufferedReaderIncludingLineEndings; +import org.apache.olingo.odata2.core.batch.v2.BufferedReaderIncludingLineEndings.Line; import org.apache.olingo.odata2.testutil.helper.StringHelper; import org.junit.Test; @@ -43,6 +46,7 @@ public class BatchRequestWriterTest { private static final String GET = "GET"; private static final String PUT = "PUT"; private static final String BOUNDARY = "batch_123"; + private static final Object CRLF = "\r\n"; private void checkMimeHeaders(final String requestBody) { assertTrue(requestBody.contains("Content-Type: application/http")); @@ -67,7 +71,7 @@ public class BatchRequestWriterTest { assertTrue(requestBody.contains("--batch_")); assertTrue(requestBody.contains("GET Employees HTTP/1.1")); checkHeaders(headers, requestBody); - assertEquals(8, StringHelper.countLines(requestBody)); + assertEquals(9, StringHelper.countLines(requestBody)); } @Test @@ -122,7 +126,7 @@ public class BatchRequestWriterTest { BatchRequestWriter writer = new BatchRequestWriter(); InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY); - String requestBody = StringHelper.inputStreamToString(batchRequest); + String requestBody = StringHelper.inputStreamToString(batchRequest, true); assertNotNull(batchRequest); checkMimeHeaders(requestBody); @@ -134,6 +138,50 @@ public class BatchRequestWriterTest { } @Test + public void testGetRequest() throws 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("123").build(); + + batch.add(request); + batch.add(request); + + BatchRequestWriter writer = new BatchRequestWriter(); + InputStream batchRequest = writer.writeBatchRequest(batch, BOUNDARY); + + BufferedReaderIncludingLineEndings reader = + new BufferedReaderIncludingLineEndings(new InputStreamReader(batchRequest)); + List<Line> lines = reader.toList(); + reader.close(); + + int line = 0; + assertEquals("--" + BOUNDARY + CRLF, lines.get(line++).toString()); + assertEquals("Content-Type: application/http" + CRLF, lines.get(line++).toString()); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, lines.get(line++).toString()); + assertEquals("Content-Id: 123" + CRLF, lines.get(line++).toString()); + assertEquals(CRLF, lines.get(line++).toString()); + assertEquals("GET Employees HTTP/1.1" + CRLF, lines.get(line++).toString()); + assertEquals("Accept: application/json" + CRLF, lines.get(line++).toString()); + assertEquals(CRLF, lines.get(line++).toString()); // Belongs to the GET request [OData Protocol - 2.2.7.2.1] + + assertEquals(CRLF, lines.get(line++).toString()); // Belongs conceptually to the boundary [RFC 2046 - 5.1.1] + assertEquals("--" + BOUNDARY + CRLF, lines.get(line++).toString()); + assertEquals("Content-Type: application/http" + CRLF, lines.get(line++).toString()); + assertEquals("Content-Transfer-Encoding: binary" + CRLF, lines.get(line++).toString()); + assertEquals("Content-Id: 123" + CRLF, lines.get(line++).toString()); + assertEquals(CRLF, lines.get(line++).toString()); + assertEquals("GET Employees HTTP/1.1" + CRLF, lines.get(line++).toString()); + assertEquals("Accept: application/json" + CRLF, lines.get(line++).toString()); + assertEquals(CRLF, lines.get(line++).toString()); // Belongs to the GET request [OData Protocol - 2.2.7.2.1] + + assertEquals(CRLF, lines.get(line++).toString()); // Belongs conceptually to the boundary [RFC 2046 - 5.1.1] + assertEquals("--" + BOUNDARY + "--", lines.get(line++).toString()); + assertEquals(19, lines.size()); + } + + @Test public void testChangeSetWithContentIdReferencing() throws BatchException, IOException { List<BatchPart> batch = new ArrayList<BatchPart>();
