/*******************************************************************************
* Copyright 2013 SAP AG
*
* Licensed 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 com.sap.core.odata.core.batch;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import com.sap.core.odata.api.batch.BatchException;
import com.sap.core.odata.api.batch.BatchResponsePart;
import com.sap.core.odata.api.commons.HttpContentType;
import com.sap.core.odata.api.commons.HttpHeaders;
import com.sap.core.odata.api.commons.HttpStatusCodes;
import com.sap.core.odata.api.exception.ODataMessageException;
import com.sap.core.odata.api.processor.ODataResponse;
public class BatchResponseWriter {
private static final String COLON = ":";
private static final String SP = " ";
private static final String LF = "\r\n";
private ResponseWriter writer = new ResponseWriter();
public ODataResponse writeResponse(final List<BatchResponsePart> batchResponseParts) throws BatchException {
String boundary = BatchHelper.generateBoundary("batch");
appendResponsePart(batchResponseParts, boundary);
String batchResponseBody = writer.toString();
return ODataResponse.entity(batchResponseBody).status(HttpStatusCodes.ACCEPTED)
.header(HttpHeaders.CONTENT_TYPE, HttpContentType.MULTIPART_MIXED + "; boundary=" + boundary)
.header(HttpHeaders.CONTENT_LENGTH, String.valueOf(writer.length()))
.build();
}
private void appendChangeSet(final BatchResponsePart batchResponsePart) throws BatchException {
String boundary = BatchHelper.generateBoundary("changeset");
writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP)
.append("multipart/mixed; boundary=" + boundary).append(LF).append(LF);
for (ODataResponse response : batchResponsePart.getResponses()) {
writer.append("--").append(boundary).append(LF);
appendResponsePartBody(response);
}
writer.append("--").append(boundary).append("--").append(LF).append(LF);
}
private void appendResponsePart(final List<BatchResponsePart> batchResponseParts, final String boundary) throws BatchException {
for (BatchResponsePart batchResponsePart : batchResponseParts) {
writer.append("--").append(boundary).append(LF);
if (batchResponsePart.isChangeSet()) {
appendChangeSet(batchResponsePart);
} else {
ODataResponse response = batchResponsePart.getResponses().get(0);
appendResponsePartBody(response);
}
}
writer.append("--").append(boundary).append("--");
}
private void appendResponsePartBody(final ODataResponse response) throws BatchException {
writer.append(HttpHeaders.CONTENT_TYPE).append(COLON).append(SP)
.append(HttpContentType.APPLICATION_HTTP).append(LF);
writer.append(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING).append(COLON).append(SP)
.append(BatchHelper.BINARY_ENCODING).append(LF);
if (response.getHeader(BatchHelper.MIME_HEADER_CONTENT_ID) != null) {
writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP)
.append(response.getHeader(BatchHelper.MIME_HEADER_CONTENT_ID)).append(LF);
}
writer.append(LF);
writer.append("HTTP/1.1").append(SP).append(String.valueOf(response.getStatus().getStatusCode())).append(SP)
.append(response.getStatus().getInfo()).append(LF);
appendHeader(response);
if (!HttpStatusCodes.NO_CONTENT.equals(response.getStatus())) {
String body;
if (response.getEntity() instanceof InputStream) {
InputStream in = (InputStream) response.getEntity();
body = readBody(in);
} else {
body = response.getEntity().toString();
}
writer.append(HttpHeaders.CONTENT_LENGTH).append(COLON).append(SP)
.append(String.valueOf(BatchHelper.getBytes(body).length)).append(LF).append(LF);
writer.append(body);
}
writer.append(LF).append(LF);
}
private void appendHeader(final ODataResponse response) {
for (String name : response.getHeaderNames()) {
if (!BatchHelper.MIME_HEADER_CONTENT_ID.equalsIgnoreCase(name) && !BatchHelper.REQUEST_HEADER_CONTENT_ID.equalsIgnoreCase(name)) {
writer.append(name).append(COLON).append(SP).append(response.getHeader(name)).append(LF);
} else if (BatchHelper.REQUEST_HEADER_CONTENT_ID.equalsIgnoreCase(name)) {
writer.append(BatchHelper.HTTP_CONTENT_ID).append(COLON).append(SP)
.append(response.getHeader(name)).append(LF);
}
}
}
private String readBody(final InputStream in) throws BatchException {
byte[] tmp = new byte[2048];
int count;
BatchException cachedException = null;
StringBuffer b = new StringBuffer();
try {
count = in.read(tmp);
while (count >= 0) {
b.append(new String(tmp, 0, count, BatchHelper.DEFAULT_ENCODING));
count = in.read(tmp);
}
} catch (IOException e) {
cachedException = new BatchException(ODataMessageException.COMMON, e);
throw cachedException;
} finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
try {
in.close();
} catch (IOException e) {
if (cachedException != null) {
throw cachedException;
}
}
}
return b.toString();
}
private static class ResponseWriter {
private StringBuilder sb = new StringBuilder();
private int length = 0;
public ResponseWriter append(final String content) {
length += BatchHelper.getBytes(content).length;
sb.append(content);
return this;
}
public int length() {
return length;
}
@Override
public String toString() {
return sb.toString();
}
}
}