Changeset Sorter

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Christian Holzer 2014-10-28 18:18:21 +01:00 committed by Christian Amend
parent 15bd15267a
commit ee2451cbd0
9 changed files with 279 additions and 62 deletions

View File

@ -27,9 +27,9 @@ import org.apache.olingo.server.api.ODataResponse;
public interface BatchOperation {
public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException;
public ODataResponse handleODataRequest(ODataRequest request);
public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart);
public ODataResponsePart handleBatchRequest(BatchRequestPart request);
public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException;
public void writeResponseParts(List<ODataResponsePart> batchResponses, ODataResponse response) throws BatchException,
IOException;

View File

@ -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
@ -23,9 +23,11 @@ import java.util.List;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.batch.BatchOperation;
import org.apache.olingo.server.api.batch.BatchRequestPart;
public interface BatchProcessor extends Processor {
void executeBatch(BatchOperation operation, ODataRequest requst, ODataResponse response);
void executeBatch(BatchOperation operation, ODataRequest requests, ODataResponse response);
List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests);
List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests,
BatchRequestPart requestPart);
}

View File

@ -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
@ -44,21 +44,21 @@ public class BatchOperationImpl implements BatchOperation {
partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this);
writer = new BatchResponseWriter();
parser = new BatchParser(getContentType(request), request.getRawBaseUri(),
request.getRawServiceResolutionUri(), isStrict);
request.getRawServiceResolutionUri(), isStrict);
}
@Override
public List<BatchRequestPart> parseBatchRequest(InputStream in) throws BatchException {
return parser.parseBatchRequest(in);
}
@Override
public ODataResponse handleODataRequest(ODataRequest request) {
return partHandler.handleODataRequest(request);
public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) {
return partHandler.handleODataRequest(request, requestPart);
}
@Override
public ODataResponsePart handleBatchRequest(BatchRequestPart request) {
public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException {
return partHandler.handleBatchRequest(request);
}

View File

@ -19,11 +19,14 @@
package org.apache.olingo.server.core.batch.handler;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.batch.BatchException;
import org.apache.olingo.server.api.batch.BatchOperation;
import org.apache.olingo.server.api.batch.BatchRequestPart;
import org.apache.olingo.server.api.batch.ODataResponsePart;
@ -36,7 +39,8 @@ public class BatchPartHandler {
private ODataHandler oDataHandler;
private BatchProcessor batchProcessor;
private BatchOperation batchOperation;
private Map<BatchRequestPart, UriMapping> uriMapping = new HashMap<BatchRequestPart, UriMapping>();
public BatchPartHandler(final ODataHandler oDataHandler, final BatchProcessor processor,
final BatchOperation batchOperation) {
this.oDataHandler = oDataHandler;
@ -44,23 +48,62 @@ public class BatchPartHandler {
this.batchOperation = batchOperation;
}
public ODataResponse handleODataRequest(ODataRequest request) {
final ODataResponse response = oDataHandler.process(request);
response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, request.getHeader(BatchParserCommon.HTTP_CONTENT_ID));
public ODataResponse handleODataRequest(ODataRequest request, BatchRequestPart requestPart) {
final ODataResponse response;
if(requestPart.isChangeSet()) {
final UriMapping mapping = getUriMappingOrDefault(requestPart);
final String reference = BatchChangeSetSorter.getReferenceInURI(request);
if(reference != null) {
BatchChangeSetSorter.replaceContentIdReference(request, reference, mapping.getUri(reference));
}
response = oDataHandler.process(request);
final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
final String locationHeader = request.getHeader(HttpHeader.LOCATION);
mapping.addMapping(contentId, locationHeader);
} else {
response = oDataHandler.process(request);
}
final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
if(contentId != null) {
response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
}
return response;
}
public ODataResponsePart handleBatchRequest(BatchRequestPart request) {
final List<ODataResponse> responses = new ArrayList<ODataResponse>();
private UriMapping getUriMappingOrDefault(final BatchRequestPart requestPart) {
UriMapping mapping = uriMapping.get(requestPart);
if(uriMapping == null) {
mapping = new UriMapping();
}
uriMapping.put(requestPart, mapping);
return mapping;
}
public ODataResponsePart handleBatchRequest(BatchRequestPart request) throws BatchException {
if (request.isChangeSet()) {
responses.addAll(batchProcessor.executeChangeSet(batchOperation, request.getRequests()));
return new ODataResponsePartImpl(responses, true);
return handleChangeSet(request);
} else {
responses.add(handleODataRequest(request.getRequests().get(0)));
final List<ODataResponse> responses = new ArrayList<ODataResponse>();
responses.add(handleODataRequest(request.getRequests().get(0), request));
return new ODataResponsePartImpl(responses, false);
}
}
private ODataResponsePart handleChangeSet(BatchRequestPart request) throws BatchException {
final List<ODataResponse> responses = new ArrayList<ODataResponse>();
final BatchChangeSetSorter sorter = new BatchChangeSetSorter(request.getRequests());
responses.addAll(batchProcessor.executeChangeSet(batchOperation, sorter.getOrderdRequests(), request));
return new ODataResponsePartImpl(responses, true);
}
}

View File

@ -0,0 +1,34 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.batch.handler;
import java.util.HashMap;
import java.util.Map;
public class UriMapping {
private Map<String, String> uriMapping = new HashMap<String, String>();
public void addMapping(final String contentId, final String uri) {
uriMapping.put(contentId, uri);
}
public String getUri(final String contentId) {
return uriMapping.get(contentId);
}
}

View File

@ -25,6 +25,10 @@ import java.util.List;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.batch.BatchRequestPart;
/**
* Has to be immutable!
*
*/
public class BatchRequestPartImpl implements BatchRequestPart {
private List<ODataRequest> requests = new ArrayList<ODataRequest>();

View File

@ -0,0 +1,164 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core.batch.handler;
import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.batch.BatchException;
import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
import org.junit.Test;
public class BatchChangeSetSorterTest {
private static final String BASE_URI = "http://localhost/odata.src";
@Test
public void test() throws BatchException {
final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Adress", "2"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
assertEquals(2, sortedChangeSet.size());
assertEquals("1", getContentId(sortedChangeSet.get(0)));
assertEquals("2", getContentId(sortedChangeSet.get(1)));
}
private String getContentId(ODataRequest request) {
return request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
}
@Test
public void testNoContentId() throws BatchException {
final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Department", "2"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('2')/Address"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('3')/Address"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$2/Manager", "3"));
BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
assertEquals(5, sortedChangeSet.size());
assertEquals("1", getContentId(sortedChangeSet.get(0)));
assertEquals(null, getContentId(sortedChangeSet.get(1)));
assertEquals(null, getContentId(sortedChangeSet.get(2)));
assertEquals("2", getContentId(sortedChangeSet.get(3)));
assertEquals("3", getContentId(sortedChangeSet.get(4)));
}
@SuppressWarnings("unused")
@Test(expected=BatchException.class)
public void testContentIdNotAvailable() throws BatchException {
final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$1/Department", "2"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "1"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('2')/Address"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('3')/Address"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$4/Manager", "3")); //4 is not available
BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
}
@Test
public void testStringAsContentId() throws BatchException {
final List<ODataRequest> changeSet = new ArrayList<ODataRequest>();
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$One/Department", "Two"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employees", "One"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('2')/Address"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "Employee('3')/Address"));
changeSet.add(createRequest(HttpMethod.POST, BASE_URI, "$Two/Manager", "Three"));
BatchChangeSetSorter sorter = new BatchChangeSetSorter(changeSet);
final List<ODataRequest> sortedChangeSet = sorter.getOrderdRequests();
assertEquals(5, sortedChangeSet.size());
assertEquals("One", getContentId(sortedChangeSet.get(0)));
assertEquals(null, getContentId(sortedChangeSet.get(1)));
assertEquals(null, getContentId(sortedChangeSet.get(2)));
assertEquals("Two", getContentId(sortedChangeSet.get(3)));
assertEquals("Three", getContentId(sortedChangeSet.get(4)));
}
@Test
public void testRewriting() {
final String CONTENT_ID = "1";
final String ODATA_PATH ="$" + CONTENT_ID + "/Address";
final String RESOURCE_URI = "Employee('1')";
final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
BatchChangeSetSorter.replaceContentIdReference(request, CONTENT_ID, RESOURCE_URI);
assertEquals(BASE_URI + "/" + "Employee('1')/Address", request.getRawRequestUri());
assertEquals("Employee('1')/Address", request.getRawODataPath());
}
@Test
public void testRewritingNoContentId() {
final String CONTENT_ID = "1";
final String ODATA_PATH = /* "$" + CONTENT_ID + */ "Address";
final String RESOURCE_URI = "Employee('1')";
final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
BatchChangeSetSorter.replaceContentIdReference(request, CONTENT_ID, RESOURCE_URI);
assertEquals(BASE_URI + "/" + "Address", request.getRawRequestUri());
assertEquals("Address", request.getRawODataPath());
}
@Test
public void testWrongRewriting() {
final String CONTENT_ID = "1";
final String ODATA_PATH = /*"$1" */ "$2" + "/Address";
final String RESOURCE_URI = "Employee('1')";
final ODataRequest request = createRequest(HttpMethod.POST, BASE_URI, ODATA_PATH);
BatchChangeSetSorter.replaceContentIdReference(request, CONTENT_ID, RESOURCE_URI);
assertEquals(BASE_URI + "/" + "$2/Address", request.getRawRequestUri());
assertEquals("$2/Address", request.getRawODataPath());
}
private ODataRequest createRequest(HttpMethod method, String baseUrl, String oDataPath) {
return createRequest(method, baseUrl, oDataPath, null);
}
private ODataRequest createRequest(HttpMethod method, String baseUrl, String oDataPath, String contentId) {
final ODataRequest request = new ODataRequest();
request.setBody(new ByteArrayInputStream(new byte[0]));
request.setMethod(HttpMethod.GET);
request.setRawBaseUri(baseUrl);
request.setRawODataPath(oDataPath);
request.setRawRequestUri(baseUrl + "/" + oDataPath);
request.setRawQueryPath("");
if(contentId != null) {
request.addHeader(BatchParserCommon.HTTP_CONTENT_ID, Arrays.asList(new String[] { contentId }));
}
return request;
}
}

View File

@ -21,7 +21,6 @@ package org.apache.olingo.server.tecsvc.processor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@ -74,7 +73,7 @@ import org.apache.olingo.server.tecsvc.data.DataProvider;
/**
* Technical Processor which provides currently implemented processor functionality.
*/
public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, PropertyProcessor, BatchProcessor {
public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor, PropertyProcessor {
private OData odata;
private DataProvider dataProvider;
@ -198,12 +197,12 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
List<UriResource> subResPaths = resourcePaths.subList(1, resourcePaths.size());
for (UriResource subResPath : subResPaths) {
UriResourceKind kind = subResPath.getKind();
if(kind != UriResourceKind.primitiveProperty
&& kind != UriResourceKind.complexProperty
&& kind != UriResourceKind.count
&& kind != UriResourceKind.value) {
if (kind != UriResourceKind.primitiveProperty
&& kind != UriResourceKind.complexProperty
&& kind != UriResourceKind.count
&& kind != UriResourceKind.value) {
throw new ODataApplicationException("Invalid resource type.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
}
@ -219,6 +218,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
final EdmEntitySet entitySet, final boolean isSingleEntity,
final ExpandOption expand, final SelectOption select,
final List<UriParameter> keys, final String propertyPath) throws SerializerException {
return ContextURL.with().entitySet(entitySet)
.selectList(serializer.buildContextURLSelectList(entitySet, expand, select))
.suffix(isSingleEntity && propertyPath == null ? Suffix.ENTITY : null)
@ -226,7 +226,6 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
.navOrPropertyPath(propertyPath)
.build();
}
@Override
public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType contentType) throws ODataApplicationException, SerializerException {
@ -334,33 +333,4 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
}
}
}
@Override
public void executeBatch(BatchOperation operation, ODataRequest requst, ODataResponse response) {
try {
final List<BatchRequestPart> parts = operation.parseBatchRequest(requst.getBody());
final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
for(BatchRequestPart part : parts) {
responseParts.add(operation.handleBatchRequest(part));
}
operation.writeResponseParts(responseParts, response);
} catch (BatchException e) {
throw new ODataRuntimeException(e);
} catch (IOException e) {
throw new ODataRuntimeException(e);
}
}
@Override
public List<ODataResponse> executeChangeSet(BatchOperation operation, List<ODataRequest> requests) {
List<ODataResponse> responses = new ArrayList<ODataResponse>();
for(ODataRequest request : requests) {
responses.add(operation.handleODataRequest(request));
}
return responses;
}
}