/*
* Copyright (c) 2016 Red Hat, Inc.
*
* 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 org.ovirt.engine.api.restapi.util;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.PathSegment;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.ovirt.engine.api.restapi.invocation.Current;
import org.ovirt.engine.api.restapi.invocation.CurrentManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is a helper that extracts parameters from HTTP headers, matrix parameters and query parameters.
*/
public class ParametersHelper {
private static final Logger log = LoggerFactory.getLogger(ParametersHelper.class);
// Regular expressions for boolean values:
private static final Pattern FALSE_PATTERN = Pattern.compile("^(f(alse)?|n(o)?|0)$", Pattern.CASE_INSENSITIVE);
private static final Pattern TRUE_PATTERN = Pattern.compile("^(t(rue)?|y(es)?|1)$", Pattern.CASE_INSENSITIVE);
/**
* Some parameters must also be allowed in headers, for backwards compatibility mostly.
*/
private static final Set<String> HEADER_PARAMETERS = new HashSet<>();
static {
HEADER_PARAMETERS.add("filter");
}
private ParametersHelper() {
// No instances allowed.
}
/**
* Gets the value of a parameter, from a header, matrix parameter or query parameter.
*
* @param headers the object that gives access to the HTTP headers of the request, may be {@code null} in which case
* it will be completely ignored
* @param uri the object that gives access to the URI information, may be {@code null} in which case it will be
* completely ignored
* @param name the name of the parameter
* @return the value of the parameter, may be empty, or {@code null} if there is no such parameter in the request
*/
public static String getParameter(HttpHeaders headers, UriInfo uri, String name) {
// Check if there is a request parameter providing the value:
Current current = CurrentManager.get();
if (current != null) {
Map<String, String> parameters = current.getParameters();
if (MapUtils.isNotEmpty(parameters)) {
if (parameters.containsKey(name)) {
String value = parameters.get(name);
if (value == null) {
value = "";
}
return value;
}
}
}
// Check if there is a query parameter providing the value:
if (uri != null) {
MultivaluedMap<String, String> parameters = uri.getQueryParameters();
if (MapUtils.isNotEmpty(parameters)) {
if (parameters.containsKey(name)) {
String value = parameters.getFirst(name);
if (value == null) {
value = "";
}
return value;
}
}
}
// Check if there is a matrix parameter providing the value:
if (uri != null) {
List<PathSegment> segments = uri.getPathSegments();
if (CollectionUtils.isNotEmpty(segments)) {
PathSegment last = segments.get(segments.size() - 1);
if (last != null) {
MultivaluedMap<String, String> parameters = last.getMatrixParameters();
if (MapUtils.isNotEmpty(parameters)) {
if (parameters.containsKey(name)) {
String value = parameters.getFirst(name);
if (value == null) {
value = "";
}
return value;
}
}
}
}
}
// Check if there is a header providing the value:
if (headers != null && HEADER_PARAMETERS.contains(name)) {
List<String> values = headers.getRequestHeader(name);
if (CollectionUtils.isNotEmpty(values)) {
String value = values.get(0);
if (value != null) {
return value;
}
}
}
// No luck:
return null;
}
/**
* Returns the boolean value of the given parameter. If the parameter is present in the request but it doesn't have
* a value then the value of the {@code empty} parameter will be returned. If the parameter isn't present, or has an
* invalid boolean value then the value of the {@code missing} parameter will be returned.
*
* @param headers the HTTP headers to extract the parameter from
* @param uri the URL to extract the parameter from
* @param name the name of the parameter
* @param empty the value that will be returned if the parameter is present but has no value
* @param missing the value that will be returned if the parameter isn't present or has an invalid boolean value
*/
public static Boolean getBooleanParameter(HttpHeaders headers, UriInfo uri, String name, Boolean empty,
Boolean missing) {
String text = getParameter(headers, uri, name);
if (text == null) {
return missing;
}
if (text.isEmpty()) {
return empty;
}
if (FALSE_PATTERN.matcher(text).matches()) {
return Boolean.FALSE;
}
if (TRUE_PATTERN.matcher(text).matches()) {
return Boolean.TRUE;
}
log.error("The value \"{}\" of parameter \"{}\" isn't a valid boolean, it will be ignored.", text, name);
return missing;
}
/**
* Returns the integer value of the given parameter. If the parameter is present in the request but it doesn't have
* a value then the value of the {@code empty} parameter will be returned. If the matrix parameter isn't present, or
* has an invalid integer value then the value of the {@code missing} parameter will be returned.
*
* @param headers the HTTP headers to extract the parameter from
* @param uri the URL to extract the parameter from
* @param name the name of the parameter
* @param empty the value that will be returned if the parameter is present but has no value
* @param missing the value that will be returned if the parameter isn't present or has in invalid integer value
*/
public static int getIntegerParameter(HttpHeaders headers, UriInfo uri, String name, int empty, int missing) {
String text = getParameter(headers, uri, name);
if (text == null) {
return missing;
}
if (text.isEmpty()) {
return empty;
}
try {
return Integer.parseInt(text);
}
catch (NumberFormatException exception) {
log.error("The value \"{}\" of parameter \"{}\" isn't a valid integer, it will be ignored.", text, name);
return missing;
}
}
}