/* Copyright (c) restSQL Project Contributors. Licensed under MIT. */
package org.restsql.core;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.restsql.core.RequestValue.Operator;
import org.restsql.core.impl.MediaTypeParser;
/**
* Contains utility methods to assist request processing.
*
* @author Mark Sawers
*/
public class RequestUtil {
private static Collection<String> supportedMediaTypes = new ArrayList<String>();
// Note that the default media type, application/xml, must be the **LAST** one added!
static {
supportedMediaTypes.add("application/x-www-form-urlencoded");
supportedMediaTypes.add("application/json");
supportedMediaTypes.add("application/xml");
}
/** Converts short form of media type to the proper internet standard, e.g. json to application/json. */
public static String convertToStandardInternetMediaType(final String mediaType) {
if (mediaType == null) {
return null;
} else if (mediaType.equalsIgnoreCase("xml")) {
return "application/xml";
} else if (mediaType.equalsIgnoreCase("json")) {
return "application/json";
} else {
return mediaType;
}
}
/**
* Returns name-value pairs, resourceId and value, for given resource and ordered value array.
*
* @throws InvalidRequestException
*/
public static List<RequestValue> getResIds(final SqlResource sqlResource, final String[] values) {
List<RequestValue> resIds = null;
if (values != null) {
resIds = new ArrayList<RequestValue>(values.length);
for (final TableMetaData table : sqlResource.getMetaData().getTableMap().values()) {
if (table.isParent()) {
for (final ColumnMetaData column : table.getPrimaryKeys()) {
for (final String value : values) {
if (value != null) {
final RequestValue resId = new RequestValue(column.getColumnLabel(), value,
Operator.Equals);
resIds.add(resId);
}
}
}
}
}
}
return resIds;
}
/** Returns best match for Content-Type header or the original media type if it doesn't match. */
public static String getRequestMediaType(final String contentMediaType) {
String requestMediaType = null;
if (contentMediaType != null && contentMediaType.length() > 0) {
try {
requestMediaType = MediaTypeParser.bestMatch(supportedMediaTypes, contentMediaType);
if (requestMediaType == null || requestMediaType.length() == 0) {
requestMediaType = contentMediaType;
}
} catch (Exception exception) {
requestMediaType = contentMediaType;
}
}
return requestMediaType;
}
/**
* Determines content type from parameters, and removing the output param if present. If it is not present then uses
* the accept media type. The accept media type can be single mime-type or an Accept header string with multiple
* mime-types, some possibly with quality factors. If the accept media type is not present, uses the request media
* type, or if it is null or form url encoded, then returns the default media type,
* {@link HttpRequestAttributes#DEFAULT_MEDIA_TYPE}. Note: The content parameter value overrides the accept media
* type!
*/
public static String getResponseMediaType(final List<RequestValue> params, final String requestMediaType,
final String acceptMediaType) {
String responseMediaType = null;
if (params != null) {
int outputIndex = -1;
for (int i = 0; i < params.size(); i++) {
final RequestValue param = params.get(i);
if (param.getName().equalsIgnoreCase(Request.PARAM_NAME_OUTPUT)) {
responseMediaType = convertToStandardInternetMediaType(param.getValue().toString());
outputIndex = i;
break;
}
}
if (outputIndex >= 0) {
params.remove(outputIndex);
}
}
if (responseMediaType == null) {
if (acceptMediaType != null && acceptMediaType.length() > 0) {
responseMediaType = MediaTypeParser.bestMatch(supportedMediaTypes, acceptMediaType);
if (responseMediaType == null || responseMediaType.length() == 0) {
responseMediaType = acceptMediaType;
}
} else if (requestMediaType == null
|| requestMediaType.equals("application/x-www-form-urlencoded")) {
responseMediaType = HttpRequestAttributes.DEFAULT_MEDIA_TYPE;
} else {
responseMediaType = requestMediaType;
}
}
return responseMediaType;
}
/**
* Checks for parameter list validity.
*
* @throws InvalidRequestException if a parameter is included more than once unless there the operators
*/
public static void checkForInvalidMultipleParameters(List<RequestValue> params)
throws InvalidRequestException {
if (params != null && params.size() > 0) {
// First organize them into a map by parameter name
Map<String, List<RequestValue>> paramsByName = new HashMap<String, List<RequestValue>>(
params.size());
for (RequestValue param : params) {
List<RequestValue> list = paramsByName.get(param.getName());
if (list == null) {
list = new ArrayList<RequestValue>(1);
paramsByName.put(param.getName(), list);
}
list.add(param);
}
// Now iterate through each and look for invalid multiples
for (List<RequestValue> list : paramsByName.values()) {
if (list.size() > 1) {
String name = list.get(0).getName();
if (list.size() == 2) {
Operator first = list.get(0).getOperator();
Operator second = list.get(1).getOperator();
if (first == Operator.Equals || second == Operator.Equals) {
throw new InvalidRequestException("Parameter " + name + " found twice");
} else if ((first == Operator.GreaterThan || first == Operator.GreaterThanOrEqualTo)
&& (second == Operator.GreaterThan || second == Operator.GreaterThanOrEqualTo)) {
throw new InvalidRequestException("Parameter " + name + " found twice with "
+ first + " and " + second + " operators");
} else if ((first == Operator.LessThan || first == Operator.LessThanOrEqualTo)
&& (second == Operator.LessThan || second == Operator.LessThanOrEqualTo)) {
throw new InvalidRequestException("Parameter " + name + " found twice with "
+ first + " and " + second + " operators");
}
} else {
throw new InvalidRequestException("Parameter " + name + " found " + list.size()
+ " times");
}
}
}
}
}
}