Batch handler clean up

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Christian Holzer 2014-11-05 16:02:12 +01:00 committed by Christian Amend
parent 0bd32951b8
commit 6c7d11f4d7
6 changed files with 79 additions and 111 deletions

View File

@ -162,10 +162,10 @@ public class ODataHandler {
handleResourceDispatching(request, response);
break;
case batch:
BatchProcessor bp = selectProcessor(BatchProcessor.class);
final BatchProcessor bp = selectProcessor(BatchProcessor.class);
final BatchHandler handler = new BatchHandler(this, bp);
final BatchHandler handler = new BatchHandler(this, request, bp, true);
handler.process(response);
handler.process(request, response, true);
break;
default:

View File

@ -38,7 +38,7 @@ public class BatchChangeSetSorter {
final List<ODataRequest> orderdList = new ArrayList<ODataRequest>();
private static Pattern referencePattern = Pattern.compile(REG_EX_REFERENCE);
private Set<String> knownContentId = new HashSet<String>();
private Set<String> knownContentIds = new HashSet<String>();
private Map<String, List<ODataRequest>> requestReferenceMapping = new HashMap<String, List<ODataRequest>>();
public BatchChangeSetSorter(List<ODataRequest> requests) throws BatchException {
@ -52,15 +52,19 @@ public class BatchChangeSetSorter {
private List<ODataRequest> sort(final List<ODataRequest> requests) throws BatchException {
extractUrlReference(requests);
// Add requests without reference (roots)
final List<ODataRequest> requestsWithoutReferences = getRequestsWithoutReferences();
orderdList.addAll(requestsWithoutReferences);
addRequestsToKnownContentIds(requestsWithoutReferences);
// Find all requests which can be processed (parent request has been processed)
// Compare level order
boolean areRequestsProcessed = true;
while (requestsToProcessAvailable() && areRequestsProcessed) {
areRequestsProcessed = processRemainingRequests(orderdList);
areRequestsProcessed = processNextLevel();
}
// Check if there are some requests which are not connected to a tree
if (requestsToProcessAvailable()) {
throw new BatchException("Invalid content id", MessageKeys.INVALID_CONTENT_ID, 0);
}
@ -72,7 +76,7 @@ public class BatchChangeSetSorter {
return requestReferenceMapping.keySet().size() != 0;
}
private boolean processRemainingRequests(List<ODataRequest> orderdList) {
private boolean processNextLevel() {
final List<ODataRequest> addedRequests = getRemainingRequestsWithKownContentId();
addRequestsToKnownContentIds(addedRequests);
orderdList.addAll(addedRequests);
@ -83,10 +87,10 @@ public class BatchChangeSetSorter {
private List<ODataRequest> getRemainingRequestsWithKownContentId() {
List<ODataRequest> result = new ArrayList<ODataRequest>();
for (String contextId : knownContentId) {
List<ODataRequest> processedRequests = requestReferenceMapping.get(contextId);
if (processedRequests != null && processedRequests.size() != 0) {
result.addAll(processedRequests);
for (String contextId : knownContentIds) {
final List<ODataRequest> requestsToProcess = requestReferenceMapping.get(contextId);
if (requestsToProcess != null && requestsToProcess.size() != 0) {
result.addAll(requestsToProcess);
requestReferenceMapping.remove(contextId);
}
}
@ -105,7 +109,7 @@ public class BatchChangeSetSorter {
for (ODataRequest request : requestsWithoutReference) {
final String contentId = getContentIdFromHeader(request);
if (contentId != null) {
knownContentId.add(contentId);
knownContentIds.add(contentId);
}
}
}
@ -130,18 +134,17 @@ public class BatchChangeSetSorter {
}
public static String getReferenceInURI(ODataRequest request) {
Matcher matcher = referencePattern.matcher(removeFollingPathSegments(removeFirstSplash(request.getRawODataPath())));
Matcher matcher = referencePattern.matcher(removeSlash(removeSlash(request.getRawODataPath(), true), false));
return (matcher.matches()) ? matcher.group(1) : null;
}
private static String removeFirstSplash(String rawODataPath) {
private static String removeSlash(String rawODataPath, boolean first) {
final int indexOfSlash = rawODataPath.indexOf("/");
return (indexOfSlash == 0) ? rawODataPath.substring(1) : rawODataPath;
}
private static String removeFollingPathSegments(String rawODataPath) {
final int indexOfSlash = rawODataPath.indexOf("/");
return (indexOfSlash != -1) ? rawODataPath.substring(0, indexOfSlash) : rawODataPath;
if(first) {
return (indexOfSlash == 0) ? rawODataPath.substring(1) : rawODataPath;
} else {
return (indexOfSlash != -1) ? rawODataPath.substring(0, indexOfSlash) : rawODataPath;
}
}
public static void replaceContentIdReference(ODataRequest request, String contentId, String resourceUri) {

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
@ -30,38 +30,38 @@ import org.apache.olingo.server.core.ODataHandler;
import org.apache.olingo.server.core.batch.parser.BatchParserCommon;
public class BatchHandler {
private final BatchOperation operation;
private final BatchProcessor batchProcessor;
private ODataRequest request;
private final ODataHandler oDataHandler;
public BatchHandler(final ODataHandler oDataHandler, final BatchProcessor batchProcessor) {
public BatchHandler(final ODataHandler oDataHandler, final ODataRequest request, final BatchProcessor batchProcessor,
final boolean isStrict) {
this.request = request;
this.batchProcessor = batchProcessor;
operation = new BatchOperationImpl(oDataHandler, request, batchProcessor, isStrict);
this.oDataHandler = oDataHandler;
}
public void process(ODataResponse response) throws BatchException {
validateRequest();
public void process(final ODataRequest request, final ODataResponse response, final boolean isStrict)
throws BatchException {
validateRequest(request);
final BatchOperation operation = new BatchOperationImpl(oDataHandler, request, batchProcessor, isStrict);
batchProcessor.executeBatch(operation, request, response);
}
private void validateRequest() throws BatchException {
validateHttpMethod();
validateContentType();
private void validateRequest(final ODataRequest request) throws BatchException {
validateHttpMethod(request);
validateContentType(request);
}
private void validateContentType() throws BatchException {
private void validateContentType(final ODataRequest request) throws BatchException {
final String contentType = request.getHeader(HttpHeader.CONTENT_TYPE);
if(contentType == null || !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
if (contentType == null || !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
throw new BatchException("Invalid content type", MessageKeys.INVALID_CONTENT_TYPE, 0);
}
}
private void validateHttpMethod() throws BatchException {
if(request.getMethod() != HttpMethod.POST) {
private void validateHttpMethod(final ODataRequest request) throws BatchException {
if (request.getMethod() != HttpMethod.POST) {
throw new BatchException("Invalid HTTP method", MessageKeys.INVALID_METHOD, 0);
}
}

View File

@ -58,7 +58,8 @@ public class BatchPartHandler {
final UriMapping mapping = replaceReference(request, requestPart);
response = oDataHandler.process(request);
// Store resource URI
final String resourceUri = getODataPath(request, response);
final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
@ -67,6 +68,7 @@ public class BatchPartHandler {
response = oDataHandler.process(request);
}
// Add content id to response
final String contentId = request.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
if(contentId != null) {
response.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
@ -85,7 +87,7 @@ public class BatchPartHandler {
resourceUri = uri.getRawODataPath();
} else {
// Update, Upsert (PUT, PATCH, Delete)
// These methods still addresses a given URI, so we use the URI given by the request
// These methods still addresses a given resource, so we use the URI given by the request
resourceUri = request.getRawODataPath();
}
@ -140,4 +142,15 @@ public class BatchPartHandler {
return new ODataResponsePartImpl(responses, true);
}
private static 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

@ -1,34 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.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

@ -61,9 +61,19 @@ public class MockedBatchHandlerTest {
private static final String BATCH_REQUEST_URI = "http://localhost:8080/odata/$batch";
private static final String BASE_URI = "http://localhost:8080/odata";
private static final String CRLF = "\r\n";
private ODataHandler handler;
private ODataHandler oDataHandler;
private BatchHandler batchHandler;
private int entityCounter = 1;
@Before
public void setup() {
final BatchProcessor batchProcessor = new BatchTestProcessorImpl();
entityCounter = 1;
oDataHandler = mock(ODataHandler.class);
batchHandler = new BatchHandler(oDataHandler, batchProcessor);
}
@Test
public void test() throws BatchException, IOException {
final String content = "--batch_12345" + CRLF
@ -130,9 +140,9 @@ public class MockedBatchHandlerTest {
+ "--batch_12345--";
final Map<String, List<String>> header = getMimeHeader();
final ODataResponse response = new ODataResponse();
final BatchHandler batchHandler = buildBatchHandler(content, header);
final ODataRequest request = buildODataRequest(content, header);
batchHandler.process(response);
batchHandler.process(request, response, true);
BufferedReaderIncludingLineEndings reader =
new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
@ -244,9 +254,9 @@ public class MockedBatchHandlerTest {
+ "--batch_12345--";
final Map<String, List<String>> header = getMimeHeader();
final ODataResponse response = new ODataResponse();
final BatchHandler batchHandler = buildBatchHandler(content, header);
final ODataRequest request = buildODataRequest(content, header);
batchHandler.process(response);
batchHandler.process(request, response, true);
BufferedReaderIncludingLineEndings reader =
new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
@ -365,9 +375,9 @@ public class MockedBatchHandlerTest {
final Map<String, List<String>> header = getMimeHeader();
final ODataResponse response = new ODataResponse();
final BatchHandler batchHandler = buildBatchHandler(content, header);
final ODataRequest request = buildODataRequest(content, header);
batchHandler.process(response);
batchHandler.process(request, response, true);
BufferedReaderIncludingLineEndings reader =
new BufferedReaderIncludingLineEndings(new InputStreamReader(response.getContent()));
@ -418,12 +428,6 @@ public class MockedBatchHandlerTest {
assertEquals(45, line);
}
@Before
public void setup() {
handler = null;
entityCounter = 1;
}
private String checkChangeSetPartHeader(final List<String> response, int line) {
assertEquals(CRLF, response.get(line++));
assertTrue(response.get(line++).contains("--changeset_"));
@ -442,7 +446,6 @@ public class MockedBatchHandlerTest {
/*
* Helper methods
*/
private Map<String, List<String>> getMimeHeader() {
final Map<String, List<String>> header = new HashMap<String, List<String>>();
header.put(HttpHeader.CONTENT_TYPE, Arrays.asList(new String[] { BATCH_CONTENT_TYPE }));
@ -450,24 +453,7 @@ public class MockedBatchHandlerTest {
return header;
}
private BatchHandler buildBatchHandler(final String content, Map<String, List<String>> header) throws BatchException,
UnsupportedEncodingException {
final ODataRequest request = buildODataRequest(content, header);
final ODataHandler oDataHandler = buildODataHandler(request);
final BatchProcessor batchProcessor = new BatchProcessorImpl();
return new BatchHandler(oDataHandler, request, batchProcessor, true);
}
private ODataHandler buildODataHandler(ODataRequest request) {
handler = mock(ODataHandler.class);
when(handler.process(request)).thenCallRealMethod();
return handler;
}
private ODataRequest buildODataRequest(String content, Map<String, List<String>> header)
private ODataRequest buildODataRequest(final String content, final Map<String, List<String>> header)
throws UnsupportedEncodingException {
final ODataRequest request = new ODataRequest();
@ -490,7 +476,7 @@ public class MockedBatchHandlerTest {
/**
* Batch processor
*/
private class BatchProcessorImpl implements BatchProcessor {
private class BatchTestProcessorImpl implements BatchProcessor {
@Override
public void init(OData odata, ServiceMetadata serviceMetadata) {}
@ -500,8 +486,8 @@ public class MockedBatchHandlerTest {
List<ODataResponse> responses = new ArrayList<ODataResponse>();
for (ODataRequest request : requests) {
// Mock the processor of the changeset requests
when(handler.process(request)).then(new Answer<ODataResponse>() {
// Mock the processor for a given requests
when(oDataHandler.process(request)).then(new Answer<ODataResponse>() {
@Override
public ODataResponse answer(InvocationOnMock invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
@ -565,7 +551,7 @@ public class MockedBatchHandlerTest {
// Entity Collection
oDataPath = parts[1];
} else {
// Navigationproperty
// Navigation property
final String navProperty = parts[parts.length - 1];
if (navProperty.equals("NavPropertyETTwoPrimMany")) {