| /******************************************************************************* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| ******************************************************************************/ |
| package org.apache.olingo.odata2.core.batch; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.InputStream; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.olingo.odata2.api.client.batch.BatchChangeSet; |
| import org.apache.olingo.odata2.api.client.batch.BatchChangeSetPart; |
| import org.apache.olingo.odata2.api.client.batch.BatchPart; |
| import org.apache.olingo.odata2.api.client.batch.BatchQueryPart; |
| import org.apache.olingo.odata2.api.commons.HttpContentType; |
| import org.apache.olingo.odata2.api.commons.HttpHeaders; |
| |
| public class BatchRequestWriter { |
| private static final String REG_EX_BOUNDARY = |
| "([a-zA-Z0-9_\\-\\.'\\+]{1,70})|\"([a-zA-Z0-9_\\-\\.'\\+\\s\\" + |
| "(\\),/:=\\?]{1,69}[a-zA-Z0-9_\\-\\.'\\+\\(\\),/:=\\?])\""; // See RFC 2046 |
| |
| private static final String COLON = ":"; |
| private static final String SP = " "; |
| private static final String CRLF = "\r\n"; |
| public static final String BOUNDARY_PREAMBLE = "changeset"; |
| public static final String HTTP_1_1 = "HTTP/1.1"; |
| private String batchBoundary; |
| private BatchHelper.BodyBuilder writer = new BatchHelper.BodyBuilder(); |
| |
| public InputStream writeBatchRequest(final List<BatchPart> batchParts, final String boundary) { |
| if (boundary.matches(REG_EX_BOUNDARY)) { |
| batchBoundary = boundary; |
| } else { |
| throw new IllegalArgumentException(); |
| } |
| for (BatchPart batchPart : batchParts) { |
| writer.append("--").append(boundary).append(CRLF); |
| if (batchPart instanceof BatchChangeSet) { |
| appendChangeSet((BatchChangeSet) batchPart); |
| } else if (batchPart instanceof BatchQueryPart) { |
| BatchQueryPart request = (BatchQueryPart) batchPart; |
| appendRequestBodyPart(request); |
| } |
| |
| } |
| writer.append("--").append(boundary).append("--"); |
| InputStream batchRequestBody; |
| batchRequestBody = new ByteArrayInputStream(writer.getContent()); |
| return batchRequestBody; |
| } |
| |
| |
| private void appendChangeSet(final BatchChangeSet batchChangeSet) { |
| String boundary = BatchHelper.generateBoundary(BOUNDARY_PREAMBLE); |
| while (boundary.equals(batchBoundary) || !boundary.matches(REG_EX_BOUNDARY)) { |
| boundary = BatchHelper.generateBoundary(BOUNDARY_PREAMBLE); |
| } |
| writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append( |
| HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary).append(CRLF); |
| for (BatchChangeSetPart request : batchChangeSet.getChangeSetParts()) { |
| writer.append(CRLF).append("--").append(boundary).append(CRLF); |
| appendRequestBodyPart(request); |
| } |
| writer.append(CRLF).append("--").append(boundary).append("--").append(CRLF); |
| } |
| |
| private void appendRequestBodyPart(final BatchQueryPart request) { |
| appendRequestBodyPart(request.getMethod(), request.getUri(), request.getHeaders(), |
| new BatchHelper.Body(), request.getContentId()); |
| } |
| |
| private void appendRequestBodyPart(final BatchChangeSetPart request) { |
| appendRequestBodyPart(request.getMethod(), request.getUri(), request.getHeaders(), |
| new BatchHelper.Body(request), request.getContentId()); |
| } |
| |
| private void appendRequestBodyPart(final String method, final String uri, final Map<String, String> headers, |
| final BatchHelper.Body body, final String contentId) { |
| |
| boolean isContentLengthPresent = false; |
| writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP).append(HttpContentType.APPLICATION_HTTP) |
| .append(CRLF); |
| writer.append(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING).append(COLON).append(SP) |
| .append(BatchHelper.BINARY_ENCODING).append(CRLF); |
| if (contentId != null) { |
| writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP).append(contentId).append(CRLF); |
| } |
| String contentLength = getHeaderValue(headers, HttpHeaders.CONTENT_LENGTH); |
| if (contentLength != null && !contentLength.isEmpty()) { |
| isContentLengthPresent = true; |
| } |
| writer.append(CRLF); |
| writer.append(method).append(SP).append(uri).append(SP).append(HTTP_1_1); |
| writer.append(CRLF); |
| |
| if (!isContentLengthPresent && !body.isEmpty()) { |
| writer.append(HttpHeaders.CONTENT_LENGTH).append(COLON).append(SP).append(body.getLength()).append(CRLF); |
| } |
| appendHeader(headers); |
| writer.append(CRLF); |
| |
| if (!body.isEmpty()) { |
| writer.append(body); |
| } else { |
| writer.append(CRLF); |
| } |
| } |
| |
| private void appendHeader(final Map<String, String> headers) { |
| for (Map.Entry<String, String> headerMap : headers.entrySet()) { |
| String name = headerMap.getKey(); |
| writer.append(name).append(COLON).append(SP).append(headerMap.getValue()).append(CRLF); |
| } |
| } |
| |
| private String getHeaderValue(final Map<String, String> headers, final String headerName) { |
| for (Map.Entry<String, String> header : headers.entrySet()) { |
| if (headerName.equalsIgnoreCase(header.getKey())) { |
| return header.getValue(); |
| } |
| } |
| return null; |
| } |
| } |