/*******************************************************************************
* 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.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import org.apache.olingo.odata2.api.batch.BatchException;
import org.apache.olingo.odata2.api.batch.BatchRequestPart;
import org.apache.olingo.odata2.api.commons.HttpContentType;
import org.apache.olingo.odata2.api.commons.HttpHeaders;
import org.apache.olingo.odata2.api.commons.ODataHttpMethod;
import org.apache.olingo.odata2.api.ep.EntityProviderBatchProperties;
import org.apache.olingo.odata2.api.processor.ODataRequest;
import org.apache.olingo.odata2.api.processor.ODataRequest.ODataRequestBuilder;
import org.apache.olingo.odata2.api.uri.PathInfo;
import org.apache.olingo.odata2.api.uri.PathSegment;
import org.apache.olingo.odata2.core.ODataPathSegmentImpl;
import org.apache.olingo.odata2.core.PathInfoImpl;
import org.apache.olingo.odata2.core.commons.Decoder;
import org.apache.olingo.odata2.core.exception.ODataRuntimeException;
/**
*
*/
public class BatchRequestParser {
private static final String LF = "\n";
private static final String REG_EX_OPTIONAL_WHITESPACE = "\\s?";
private static final String REG_EX_ZERO_OR_MORE_WHITESPACES = "\\s*";
private static final String ANY_CHARACTERS = ".*";
private static final Pattern REG_EX_BLANK_LINE = Pattern.compile("(|" + REG_EX_ZERO_OR_MORE_WHITESPACES + ")");
private static final Pattern REG_EX_HEADER = Pattern.compile("([a-zA-Z\\-]+):" + REG_EX_OPTIONAL_WHITESPACE + "(.*)"
+ REG_EX_ZERO_OR_MORE_WHITESPACES);
private static final Pattern REG_EX_VERSION = Pattern.compile("(?:HTTP/[0-9]\\.[0-9])");
private static final Pattern REG_EX_ANY_BOUNDARY_STRING = Pattern.compile("--" + ANY_CHARACTERS
+ REG_EX_ZERO_OR_MORE_WHITESPACES);
private static final Pattern REG_EX_REQUEST_LINE = Pattern.compile("(GET|POST|PUT|DELETE|MERGE|PATCH)\\s(.*)\\s?"
+ REG_EX_VERSION + REG_EX_ZERO_OR_MORE_WHITESPACES);
private static final Pattern REG_EX_BOUNDARY_PARAMETER = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE
+ "boundary=(\".*\"|.*)" + REG_EX_ZERO_OR_MORE_WHITESPACES);
private static final Pattern REG_EX_CONTENT_TYPE = Pattern.compile(REG_EX_OPTIONAL_WHITESPACE
+ HttpContentType.MULTIPART_MIXED);
private static final Pattern REG_EX_QUERY_PARAMETER = Pattern.compile("((?:\\$|)[^=]+)=([^=]+)");
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 String baseUri;
private PathInfo batchRequestPathInfo;
private String contentTypeMime;
private String boundary;
private String currentMimeHeaderContentId;
private int currentLineNumber = 0;
private final static Set<String> HTTP_CHANGESET_METHODS;
private final static Set<String> HTTP_BATCH_METHODS;
static {
HashSet<String> httpChangesetMethods = new HashSet<String>();
httpChangesetMethods.add("POST");
httpChangesetMethods.add("PUT");
httpChangesetMethods.add("DELETE");
httpChangesetMethods.add("MERGE");
httpChangesetMethods.add("PATCH");
HTTP_CHANGESET_METHODS = Collections.unmodifiableSet(httpChangesetMethods);
HashSet<String> httpBatchMethods = new HashSet<String>();
httpBatchMethods.add("GET");
HTTP_BATCH_METHODS = Collections.unmodifiableSet(httpBatchMethods);
}
public BatchRequestParser(final String contentType, final EntityProviderBatchProperties properties) {
contentTypeMime = contentType;
batchRequestPathInfo = properties.getPathInfo();
}
public List<BatchRequestPart> parse(final InputStream in) throws BatchException {
Scanner scanner = new Scanner(in, BatchHelper.DEFAULT_ENCODING).useDelimiter(LF);
baseUri = getBaseUri();
List<BatchRequestPart> requestList;
try {
requestList = parseBatchRequest(scanner);
} finally {// NOPMD (suppress DoNotThrowExceptionInFinally)
scanner.close();
try {
in.close();
} catch (IOException e) {
throw new ODataRuntimeException(e);
}
}
return requestList;
}
private List<BatchRequestPart> parseBatchRequest(final Scanner scanner) throws BatchException {
List<BatchRequestPart> requests = new LinkedList<BatchRequestPart>();
if (contentTypeMime != null) {
boundary = getBoundary(contentTypeMime);
parsePreamble(scanner);
final String closeDelimiter = "--" + boundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES;
while (scanner.hasNext() && !scanner.hasNext(closeDelimiter)) {
requests.add(parseMultipart(scanner, boundary, false));
parseOptionalLine(scanner);
}
if (scanner.hasNext(closeDelimiter)) {
scanner.next(closeDelimiter);
currentLineNumber++;
} else {
throw new BatchException(BatchException.MISSING_CLOSE_DELIMITER.addContent(currentLineNumber));
}
} else {
throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
}
return requests;
}
// The method parses additional information prior to the first boundary delimiter line
private void parsePreamble(final Scanner scanner) {
while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
scanner.next();
currentLineNumber++;
}
}
private BatchRequestPart parseMultipart(final Scanner scanner, final String boundary, final boolean isChangeSet)
throws BatchException {
Map<String, String> mimeHeaders = new HashMap<String, String>();
BatchRequestPart multipart = null;
List<ODataRequest> requests = new ArrayList<ODataRequest>();
if (scanner.hasNext("--" + boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) {
scanner.next();
currentLineNumber++;
mimeHeaders = parseHeaders(scanner);
currentMimeHeaderContentId = mimeHeaders.get(BatchHelper.HTTP_CONTENT_ID.toLowerCase(Locale.ENGLISH));
String contentType = mimeHeaders.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
if (contentType == null) {
throw new BatchException(BatchException.MISSING_CONTENT_TYPE);
}
if (isChangeSet) {
if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
parseNewLine(scanner);// mandatory
requests.add(parseRequest(scanner, isChangeSet));
multipart = new BatchRequestPartImpl(false, requests);
} else {
throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.APPLICATION_HTTP));
}
} else {
if (HttpContentType.APPLICATION_HTTP.equalsIgnoreCase(contentType)) {
validateEncoding(mimeHeaders.get(BatchHelper.HTTP_CONTENT_TRANSFER_ENCODING.toLowerCase(Locale.ENGLISH)));
parseNewLine(scanner);// mandatory
requests.add(parseRequest(scanner, isChangeSet));
multipart = new BatchRequestPartImpl(false, requests);
} else if (contentType.matches(REG_EX_OPTIONAL_WHITESPACE + HttpContentType.MULTIPART_MIXED + ANY_CHARACTERS)) {
String changeSetBoundary = getBoundary(contentType);
if (boundary.equals(changeSetBoundary)) {
throw new BatchException(BatchException.INVALID_CHANGESET_BOUNDARY.addContent(currentLineNumber));
}
List<ODataRequest> changeSetRequests = new LinkedList<ODataRequest>();
parseNewLine(scanner);// mandatory
Pattern changeSetCloseDelimiter =
Pattern.compile("--" + changeSetBoundary + "--" + REG_EX_ZERO_OR_MORE_WHITESPACES);
while (!scanner.hasNext(changeSetCloseDelimiter)) {
BatchRequestPart part = parseMultipart(scanner, changeSetBoundary, true);
changeSetRequests.addAll(part.getRequests());
}
scanner.next(changeSetCloseDelimiter);
currentLineNumber++;
multipart = new BatchRequestPartImpl(true, changeSetRequests);
} else {
throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED
+ " or " + HttpContentType.APPLICATION_HTTP));
}
}
} else if (scanner.hasNext(boundary + REG_EX_ZERO_OR_MORE_WHITESPACES)) {
currentLineNumber++;
throw new BatchException(BatchException.INVALID_BOUNDARY_DELIMITER.addContent(currentLineNumber));
} else if (scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
currentLineNumber++;
throw new BatchException(BatchException.NO_MATCH_WITH_BOUNDARY_STRING.addContent(boundary).addContent(
currentLineNumber));
} else {
currentLineNumber++;
throw new BatchException(BatchException.MISSING_BOUNDARY_DELIMITER.addContent(currentLineNumber));
}
return multipart;
}
private ODataRequest parseRequest(final Scanner scanner, final boolean isChangeSet) throws BatchException {
if (scanner.hasNext(REG_EX_REQUEST_LINE)) {
scanner.next(REG_EX_REQUEST_LINE);
currentLineNumber++;
final String method;
final String uri;
MatchResult result = scanner.match();
if (result.groupCount() == 2) {
method = result.group(1);
uri = result.group(2).trim();
} else {
currentLineNumber++;
throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent(
currentLineNumber));
}
PathInfo pathInfo = parseRequestUri(uri);
Map<String, String> queryParameters = parseQueryParameters(uri);
if (isChangeSet) {
if (!HTTP_CHANGESET_METHODS.contains(method)) {
throw new BatchException(BatchException.INVALID_CHANGESET_METHOD.addContent(currentLineNumber));
}
} else if (!HTTP_BATCH_METHODS.contains(method)) {
throw new BatchException(BatchException.INVALID_QUERY_OPERATION_METHOD.addContent(currentLineNumber));
}
ODataHttpMethod httpMethod = ODataHttpMethod.valueOf(method);
Map<String, List<String>> headers = parseRequestHeaders(scanner);
if (currentMimeHeaderContentId != null) {
List<String> headerList = new ArrayList<String>();
headerList.add(currentMimeHeaderContentId);
headers.put(BatchHelper.MIME_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList);
}
String contentType = getContentTypeHeader(headers);
List<String> acceptHeaders = getAcceptHeader(headers);
List<Locale> acceptLanguages = getAcceptLanguageHeader(headers);
parseNewLine(scanner);
InputStream body = new ByteArrayInputStream(new byte[0]);
if (isChangeSet) {
body = parseBody(scanner);
} else {
parseNewLine(scanner);
}
ODataRequestBuilder requestBuilder = ODataRequest.method(httpMethod)
.queryParameters(queryParameters)
.requestHeaders(headers)
.pathInfo(pathInfo)
.acceptableLanguages(acceptLanguages)
.body(body)
.acceptHeaders(acceptHeaders);
if (contentType != null) {
requestBuilder = requestBuilder.contentType(contentType);
}
return requestBuilder.build();
} else {
currentLineNumber++;
throw new BatchException(BatchException.INVALID_REQUEST_LINE.addContent(scanner.next()).addContent(
currentLineNumber));
}
}
private Map<String, List<String>> parseRequestHeaders(final Scanner scanner) throws BatchException {
Map<String, List<String>> headers = new HashMap<String, List<String>>();
while (scanner.hasNext() && !scanner.hasNext(REG_EX_BLANK_LINE)) {
if (scanner.hasNext(REG_EX_HEADER)) {
scanner.next(REG_EX_HEADER);
currentLineNumber++;
MatchResult result = scanner.match();
if (result.groupCount() == 2) {
String headerName = result.group(1).trim().toLowerCase(Locale.ENGLISH);
String headerValue = result.group(2).trim();
if (HttpHeaders.ACCEPT.equalsIgnoreCase(headerName)) {
List<String> acceptHeaders = parseAcceptHeaders(headerValue);
headers.put(headerName, acceptHeaders);
} else if (HttpHeaders.ACCEPT_LANGUAGE.equalsIgnoreCase(headerName)) {
List<String> acceptLanguageHeaders = parseAcceptableLanguages(headerValue);
headers.put(headerName, acceptLanguageHeaders);
} else if (!BatchHelper.HTTP_CONTENT_ID.equalsIgnoreCase(headerName)) {
if (headers.containsKey(headerName)) {
headers.get(headerName).add(headerValue);
} else {
List<String> headerList = new ArrayList<String>();
headerList.add(headerValue);
headers.put(headerName, headerList);
}
} else {
List<String> headerList = new ArrayList<String>();
headerList.add(headerValue);
headers.put(BatchHelper.REQUEST_HEADER_CONTENT_ID.toLowerCase(Locale.ENGLISH), headerList);
}
}
} else {
currentLineNumber++;
throw new BatchException(BatchException.INVALID_HEADER.addContent(scanner.next())
.addContent(currentLineNumber));
}
}
return headers;
}
private PathInfo parseRequestUri(final String uri) throws BatchException {
PathInfoImpl pathInfo = new PathInfoImpl();
pathInfo.setServiceRoot(batchRequestPathInfo.getServiceRoot());
pathInfo.setPrecedingPathSegment(batchRequestPathInfo.getPrecedingSegments());
final String odataPathSegmentsAsString;
final String queryParametersAsString;
try {
Scanner uriScanner = new Scanner(uri).useDelimiter(LF);
URI uriObject = new URI(uri);
if (uriObject.isAbsolute()) {
Pattern regexRequestUri = Pattern.compile(baseUri + "/([^/][^?]*)(\\?.*)?");
if (uriScanner.hasNext(regexRequestUri)) {
uriScanner.next(regexRequestUri);
MatchResult result = uriScanner.match();
if (result.groupCount() == 2) {
odataPathSegmentsAsString = result.group(1);
queryParametersAsString = result.group(2) != null ? result.group(2) : "";
} else {
uriScanner.close();
throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
} else {
uriScanner.close();
throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
} else {
Pattern regexRequestUri = Pattern.compile("([^/][^?]*)(\\?.*)?");
if (uriScanner.hasNext(regexRequestUri)) {
uriScanner.next(regexRequestUri);
MatchResult result = uriScanner.match();
if (result.groupCount() == 2) {
odataPathSegmentsAsString = result.group(1);
queryParametersAsString = result.group(2) != null ? result.group(2) : "";
} else {
uriScanner.close();
throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
} else if (uriScanner.hasNext("/(.*)")) {
uriScanner.close();
throw new BatchException(BatchException.UNSUPPORTED_ABSOLUTE_PATH.addContent(currentLineNumber));
} else {
uriScanner.close();
throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
}
uriScanner.close();
pathInfo.setODataPathSegment(parseODataPathSegments(odataPathSegmentsAsString));
if (!odataPathSegmentsAsString.startsWith("$")) {
String requestUri = baseUri + "/" + odataPathSegmentsAsString + queryParametersAsString;
pathInfo.setRequestUri(new URI(requestUri));
}
return pathInfo;
} catch (URISyntaxException e) {
throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber), e);
}
}
private Map<String, String> parseQueryParameters(final String uri) throws BatchException {
Scanner uriScanner = new Scanner(uri).useDelimiter("\n");
Map<String, String> queryParametersMap = new HashMap<String, String>();
Pattern regex = Pattern.compile("(?:" + baseUri + "/)?" + "[^?]+" + "\\?(.*)");
if (uriScanner.hasNext(regex)) {
uriScanner.next(regex);
MatchResult uriResult = uriScanner.match();
if (uriResult.groupCount() == 1) {
String queryParams = uriResult.group(1);
Scanner queryParamsScanner = new Scanner(queryParams).useDelimiter("&");
while (queryParamsScanner.hasNext(REG_EX_QUERY_PARAMETER)) {
queryParamsScanner.next(REG_EX_QUERY_PARAMETER);
MatchResult result = queryParamsScanner.match();
if (result.groupCount() == 2) {
String systemQueryOption = result.group(1);
String value = result.group(2);
queryParametersMap.put(systemQueryOption, Decoder.decode(value));
} else {
queryParamsScanner.close();
throw new BatchException(BatchException.INVALID_QUERY_PARAMETER);
}
}
queryParamsScanner.close();
} else {
uriScanner.close();
throw new BatchException(BatchException.INVALID_URI.addContent(currentLineNumber));
}
}
uriScanner.close();
return queryParametersMap;
}
private List<PathSegment> parseODataPathSegments(final String odataPathSegmentsAsString) {
Scanner pathSegmentScanner = new Scanner(odataPathSegmentsAsString).useDelimiter("/");
List<PathSegment> odataPathSegments = new ArrayList<PathSegment>();
while (pathSegmentScanner.hasNext()) {
odataPathSegments.add(new ODataPathSegmentImpl(pathSegmentScanner.next(), null));
}
pathSegmentScanner.close();
return odataPathSegments;
}
private List<String> parseAcceptHeaders(final String headerValue) throws BatchException {
return AcceptParser.parseAcceptHeaders(headerValue);
}
private List<String> parseAcceptableLanguages(final String headerValue) throws BatchException {
return AcceptParser.parseAcceptableLanguages(headerValue);
}
private InputStream parseBody(final Scanner scanner) {
StringBuilder body = null;
final InputStream requestBody;
while (scanner.hasNext() && !scanner.hasNext(REG_EX_ANY_BOUNDARY_STRING)) {
if (!scanner.hasNext(REG_EX_ZERO_OR_MORE_WHITESPACES)) {
if (body == null) {
body = new StringBuilder(scanner.next());
} else {
body.append(LF).append(scanner.next());
}
} else {
scanner.next();
}
currentLineNumber++;
}
if (body != null) {
requestBody = new ByteArrayInputStream(BatchHelper.getBytes(body.toString()));
} else {
requestBody = new ByteArrayInputStream(new byte[0]);
}
return requestBody;
}
private String getBoundary(final String contentType) throws BatchException {
Scanner contentTypeScanner = new Scanner(contentType).useDelimiter(";\\s?");
if (contentTypeScanner.hasNext(REG_EX_CONTENT_TYPE)) {
contentTypeScanner.next(REG_EX_CONTENT_TYPE);
} else {
contentTypeScanner.close();
throw new BatchException(BatchException.INVALID_CONTENT_TYPE.addContent(HttpContentType.MULTIPART_MIXED));
}
if (contentTypeScanner.hasNext(REG_EX_BOUNDARY_PARAMETER)) {
contentTypeScanner.next(REG_EX_BOUNDARY_PARAMETER);
MatchResult result = contentTypeScanner.match();
contentTypeScanner.close();
if (result.groupCount() == 1 && result.group(1).trim().matches(REG_EX_BOUNDARY)) {
return trimQuota(result.group(1).trim());
} else {
throw new BatchException(BatchException.INVALID_BOUNDARY);
}
} else {
contentTypeScanner.close();
throw new BatchException(BatchException.MISSING_PARAMETER_IN_CONTENT_TYPE);
}
}
private void validateEncoding(final String encoding) throws BatchException {
if (!BatchHelper.BINARY_ENCODING.equalsIgnoreCase(encoding)) {
throw new BatchException(BatchException.INVALID_CONTENT_TRANSFER_ENCODING);
}
}
private Map<String, String> parseHeaders(final Scanner scanner) throws BatchException {
Map<String, String> headers = new HashMap<String, String>();
while (scanner.hasNext() && !(scanner.hasNext(REG_EX_BLANK_LINE))) {
if (scanner.hasNext(REG_EX_HEADER)) {
scanner.next(REG_EX_HEADER);
currentLineNumber++;
MatchResult result = scanner.match();
if (result.groupCount() == 2) {
String headerName = result.group(1).trim().toLowerCase(Locale.ENGLISH);
String headerValue = result.group(2).trim();
headers.put(headerName, headerValue);
}
} else {
throw new BatchException(BatchException.INVALID_HEADER.addContent(scanner.next()));
}
}
return headers;
}
private void parseNewLine(final Scanner scanner) throws BatchException {
if (scanner.hasNext() && scanner.hasNext(REG_EX_BLANK_LINE)) {
scanner.next();
currentLineNumber++;
} else {
currentLineNumber++;
if (scanner.hasNext()) {
throw new BatchException(BatchException.MISSING_BLANK_LINE.addContent(scanner.next()).addContent(
currentLineNumber));
} else {
throw new BatchException(BatchException.TRUNCATED_BODY.addContent(currentLineNumber));
}
}
}
private void parseOptionalLine(final Scanner scanner) throws BatchException {
while (scanner.hasNext() && scanner.hasNext(REG_EX_BLANK_LINE)) {
scanner.next();
currentLineNumber++;
}
}
private String getBaseUri() throws BatchException {
if (batchRequestPathInfo != null) {
if (batchRequestPathInfo.getServiceRoot() != null) {
String baseUri = batchRequestPathInfo.getServiceRoot().toASCIIString();
if (baseUri.lastIndexOf('/') == baseUri.length() - 1) {
baseUri = baseUri.substring(0, baseUri.length() - 1);
}
for (PathSegment precedingPS : batchRequestPathInfo.getPrecedingSegments()) {
baseUri = baseUri + "/" + precedingPS.getPath();
}
return baseUri;
}
} else {
throw new BatchException(BatchException.INVALID_PATHINFO);
}
return null;
}
private String trimQuota(String boundary) {
if (boundary.matches("\".*\"")) {
boundary = boundary.replace("\"", "");
}
boundary = boundary.replaceAll("\\)", "\\\\)");
boundary = boundary.replaceAll("\\(", "\\\\(");
boundary = boundary.replaceAll("\\?", "\\\\?");
boundary = boundary.replaceAll("\\+", "\\\\+");
return boundary;
}
private List<String> getAcceptHeader(final Map<String, List<String>> headers) {
List<String> acceptHeaders = new ArrayList<String>();
List<String> requestAcceptHeaderList = headers.get(HttpHeaders.ACCEPT.toLowerCase(Locale.ENGLISH));
if (requestAcceptHeaderList != null) {
acceptHeaders = requestAcceptHeaderList;
}
return acceptHeaders;
}
private List<Locale> getAcceptLanguageHeader(final Map<String, List<String>> headers) {
List<String> requestAcceptLanguageList = headers.get(HttpHeaders.ACCEPT_LANGUAGE.toLowerCase(Locale.ENGLISH));
List<Locale> acceptLanguages = new ArrayList<Locale>();
if (requestAcceptLanguageList != null) {
for (String acceptLanguage : requestAcceptLanguageList) {
String[] part = acceptLanguage.split("-");
String language = part[0];
String country = "";
if (part.length == 2) {
country = part[part.length - 1];
}
Locale locale = new Locale(language, country);
acceptLanguages.add(locale);
}
}
return acceptLanguages;
}
private String getContentTypeHeader(final Map<String, List<String>> headers) {
List<String> requestContentTypeList = headers.get(HttpHeaders.CONTENT_TYPE.toLowerCase(Locale.ENGLISH));
String contentType = null;
if (requestContentTypeList != null) {
for (String requestContentType : requestContentTypeList) {
contentType = contentType != null ? contentType + "," + requestContentType : requestContentType;
}
}
return contentType;
}
}