/******************************************************************************* * 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; } }