| /******************************************************************************* |
| * 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 static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.when; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.List; |
| |
| 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.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; |
| import org.apache.olingo.odata2.api.edm.Edm; |
| import org.apache.olingo.odata2.api.ep.EntityProvider; |
| import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties; |
| import org.apache.olingo.odata2.api.exception.ODataException; |
| import org.apache.olingo.odata2.api.processor.ODataContext; |
| import org.apache.olingo.odata2.api.processor.ODataProcessor; |
| import org.apache.olingo.odata2.api.processor.ODataRequest; |
| import org.apache.olingo.odata2.api.processor.ODataResponse; |
| import org.apache.olingo.odata2.api.processor.part.BatchProcessor; |
| import org.apache.olingo.odata2.api.processor.part.EntityMediaProcessor; |
| import org.apache.olingo.odata2.api.processor.part.EntityProcessor; |
| import org.apache.olingo.odata2.api.processor.part.EntitySetProcessor; |
| import org.apache.olingo.odata2.api.processor.part.EntitySimplePropertyProcessor; |
| import org.apache.olingo.odata2.api.uri.PathInfo; |
| import org.apache.olingo.odata2.api.uri.PathSegment; |
| import org.apache.olingo.odata2.api.uri.info.GetEntitySetCountUriInfo; |
| import org.apache.olingo.odata2.api.uri.info.GetEntitySetUriInfo; |
| import org.apache.olingo.odata2.api.uri.info.GetSimplePropertyUriInfo; |
| import org.apache.olingo.odata2.api.uri.info.PostUriInfo; |
| import org.apache.olingo.odata2.api.uri.info.PutMergePatchUriInfo; |
| import org.apache.olingo.odata2.core.ODataPathSegmentImpl; |
| import org.apache.olingo.odata2.core.PathInfoImpl; |
| import org.apache.olingo.odata2.testutil.helper.StringHelper; |
| import org.apache.olingo.odata2.testutil.mock.MockFacade; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| public class BatchHandlerTest { |
| |
| private BatchHandler handler; |
| private static final String CONTENT_TYPE = HttpContentType.MULTIPART_MIXED + "; boundary=batch_123"; |
| private static final String CRLF = "\r\n"; |
| private static String SERVICE_BASE = "http://localhost/odata/"; |
| private static String SERVICE_ROOT = null; |
| |
| @Before |
| public void setupBatchHandler() throws Exception { |
| ODataProcessor processor = new LocalProcessor(); |
| ODataService serviceMock = mock(ODataService.class); |
| when(serviceMock.getBatchProcessor()).thenReturn((BatchProcessor) processor); |
| when(serviceMock.getEntitySetProcessor()).thenReturn((EntitySetProcessor) processor); |
| when(serviceMock.getEntitySimplePropertyProcessor()).thenReturn((EntitySimplePropertyProcessor) processor); |
| when(serviceMock.getProcessor()).thenReturn(processor); |
| Edm mockEdm = MockFacade.getMockEdm(); |
| when(serviceMock.getEntityDataModel()).thenReturn(mockEdm); |
| List<String> supportedContentTypes = Arrays.asList( |
| HttpContentType.APPLICATION_JSON_UTF8, HttpContentType.APPLICATION_JSON); |
| when(serviceMock.getSupportedContentTypes(EntityMediaProcessor.class)).thenReturn(supportedContentTypes); |
| when(serviceMock.getSupportedContentTypes(EntityProcessor.class)).thenReturn(supportedContentTypes); |
| when(serviceMock.getSupportedContentTypes(EntitySimplePropertyProcessor.class)).thenReturn(supportedContentTypes); |
| handler = new BatchHandlerImpl(mock(ODataServiceFactory.class), serviceMock); |
| } |
| |
| @Test |
| public void contentIdReferencing() throws Exception { |
| SERVICE_ROOT = SERVICE_BASE; |
| PathInfoImpl pathInfo = new PathInfoImpl(); |
| pathInfo.setServiceRoot(new URI(SERVICE_ROOT)); |
| pathInfo.setODataPathSegment(Collections.<PathSegment> singletonList( |
| new ODataPathSegmentImpl("$batch", null))); |
| EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build(); |
| InputStream content = readFile("/batchContentIdReferencing.batch"); |
| List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties); |
| |
| PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo(); |
| assertFirst(firstPathInfo); |
| |
| handler.handleBatchPart(parsedRequest.get(0)); |
| } |
| |
| @Test |
| public void contentIdReferencingForGet() throws Exception { |
| SERVICE_ROOT = SERVICE_BASE; |
| PathInfoImpl pathInfo = new PathInfoImpl(); |
| pathInfo.setServiceRoot(new URI(SERVICE_ROOT)); |
| pathInfo.setODataPathSegment(Collections.<PathSegment> singletonList( |
| new ODataPathSegmentImpl("$batch", null))); |
| EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build(); |
| InputStream content = readFile("/batchContentIdReferencingForGet.batch"); |
| List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties); |
| |
| PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo(); |
| assertFirst(firstPathInfo); |
| |
| handler.handleBatchPart(parsedRequest.get(0)); |
| handler.handleBatchPart(parsedRequest.get(1)); |
| } |
| |
| |
| @Test |
| public void contentIdReferencingWithAdditionalSegments() throws Exception { |
| SERVICE_ROOT = SERVICE_BASE + "seg1/seg2/"; |
| PathInfoImpl pathInfo = new PathInfoImpl(); |
| pathInfo.setPrecedingPathSegment(Arrays.asList( |
| (PathSegment) new ODataPathSegmentImpl("seg1", null), |
| (PathSegment) new ODataPathSegmentImpl("seg2", null))); |
| pathInfo.setServiceRoot(new URI(SERVICE_ROOT)); |
| pathInfo.setODataPathSegment(Collections.<PathSegment> singletonList( |
| new ODataPathSegmentImpl("$batch", null))); |
| EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build(); |
| InputStream content = readFile("/batchContentIdReferencing.batch"); |
| List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties); |
| |
| PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo(); |
| assertFirst(firstPathInfo); |
| |
| handler.handleBatchPart(parsedRequest.get(0)); |
| } |
| |
| @Test |
| public void contentIdReferencingWithAdditionalSegmentsAndMatrixParameter() throws Exception { |
| SERVICE_ROOT = SERVICE_BASE + "seg1;v=1/seg2;v=2/"; |
| PathInfoImpl pathInfo = new PathInfoImpl(); |
| pathInfo.setPrecedingPathSegment(Arrays.asList( |
| (PathSegment) new ODataPathSegmentImpl("seg1", |
| Collections.singletonMap("v", Collections.singletonList("1"))), |
| (PathSegment) new ODataPathSegmentImpl("seg2", |
| Collections.singletonMap("v", Collections.singletonList("2"))))); |
| pathInfo.setServiceRoot(new URI(SERVICE_ROOT)); |
| pathInfo.setODataPathSegment(Collections.<PathSegment> singletonList( |
| new ODataPathSegmentImpl("$batch", null))); |
| EntityProviderBatchProperties properties = EntityProviderBatchProperties.init().pathInfo(pathInfo).build(); |
| InputStream content = readFile("/batchContentIdReferencing.batch"); |
| List<BatchRequestPart> parsedRequest = EntityProvider.parseBatchRequest(CONTENT_TYPE, content, properties); |
| |
| PathInfo firstPathInfo = parsedRequest.get(0).getRequests().get(0).getPathInfo(); |
| assertFirst(firstPathInfo); |
| |
| handler.handleBatchPart(parsedRequest.get(0)); |
| } |
| |
| private void assertFirst(PathInfo pathInfo) { |
| assertEquals(SERVICE_ROOT + "Employees", pathInfo.getRequestUri().toString()); |
| assertEquals(SERVICE_ROOT, pathInfo.getServiceRoot().toString()); |
| } |
| |
| private InputStream readFile(String fileName) throws IOException { |
| InputStream in = ClassLoader.class.getResourceAsStream(fileName); |
| if (in == null) { |
| throw new IOException("Requested file '" + fileName + "' was not found."); |
| } |
| |
| return StringHelper.toStream(in).asStreamWithLineSeparation(CRLF); |
| } |
| |
| public class LocalProcessor implements BatchProcessor, EntitySetProcessor, EntitySimplePropertyProcessor { |
| |
| private ODataContext context; |
| |
| @Override |
| public void setContext(ODataContext context) throws ODataException { |
| this.context = context; |
| } |
| |
| @Override |
| public ODataContext getContext() throws ODataException { |
| return context; |
| } |
| |
| @Override |
| public BatchResponsePart executeChangeSet(BatchHandler handler, List<ODataRequest> requests) throws ODataException { |
| List<ODataResponse> responses = new ArrayList<ODataResponse>(); |
| |
| // handle create |
| ODataResponse response = handler.handleRequest(requests.get(0)); |
| assertEquals(HttpStatusCodes.OK, response.getStatus()); |
| assertEquals(SERVICE_ROOT + "Employees('1')", response.getIdLiteral()); |
| responses.add(response); |
| |
| // handle update |
| response = handler.handleRequest(requests.get(1)); |
| assertEquals(HttpStatusCodes.OK, response.getStatus()); |
| responses.add(response); |
| |
| return BatchResponsePart.responses(responses).changeSet(true).build(); |
| } |
| |
| @Override |
| public ODataResponse createEntity(PostUriInfo uriInfo, InputStream content, String requestContentType, |
| String contentType) throws ODataException { |
| PathInfo pathInfo = getContext().getPathInfo(); |
| assertFirst(pathInfo); |
| assertEquals("Employees", uriInfo.getTargetEntitySet().getName()); |
| return ODataResponse.newBuilder().status(HttpStatusCodes.OK).idLiteral(SERVICE_ROOT + "Employees('1')").build(); |
| } |
| |
| @Override |
| public ODataResponse updateEntitySimpleProperty(PutMergePatchUriInfo uriInfo, InputStream content, |
| String requestContentType, String contentType) throws ODataException { |
| PathInfo pathInfo = getContext().getPathInfo(); |
| assertEquals(SERVICE_ROOT + "Employees('1')/EmployeeName", pathInfo.getRequestUri().toString()); |
| assertEquals(SERVICE_ROOT, pathInfo.getServiceRoot().toString()); |
| assertEquals("Employees", uriInfo.getTargetEntitySet().getName()); |
| return ODataResponse.newBuilder().status(HttpStatusCodes.OK).build(); |
| } |
| |
| @Override |
| public ODataResponse readEntitySimpleProperty(GetSimplePropertyUriInfo uriInfo, String contentType) |
| throws ODataException { |
| // this method is not needed. |
| return null; |
| } |
| |
| @Override |
| public ODataResponse readEntitySet(GetEntitySetUriInfo uriInfo, String contentType) throws ODataException { |
| // this method is not needed. |
| return null; |
| } |
| |
| @Override |
| public ODataResponse countEntitySet(GetEntitySetCountUriInfo uriInfo, String contentType) throws ODataException { |
| // this method is not needed. |
| return null; |
| } |
| |
| @Override |
| public ODataResponse executeBatch(BatchHandler handler, String contentType, InputStream content) |
| throws ODataException { |
| // this method is not needed. |
| return null; |
| } |
| } |
| } |