All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.rest.RequestQuery Maven / Gradle / Ivy

There is a newer version: 9.0.1
Show newest version
// ***************************************************************************************************************************
// * 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.juneau.rest;

import static org.apache.juneau.internal.ArrayUtils.*;

import java.lang.reflect.*;
import java.util.*;

import javax.servlet.http.*;

import org.apache.juneau.*;
import org.apache.juneau.internal.*;
import org.apache.juneau.json.*;
import org.apache.juneau.parser.*;
import org.apache.juneau.urlencoding.*;
import org.apache.juneau.utils.*;
import org.apache.juneau.xml.*;

/**
 * Represents the query parameters in an HTTP request.
 */
@SuppressWarnings("unchecked")
public final class RequestQuery extends LinkedHashMap {
	private static final long serialVersionUID = 1L;

	private UrlEncodingParser parser;
	private BeanSession beanSession;

	RequestQuery setParser(UrlEncodingParser parser) {
		this.parser = parser;
		return this;
	}

	RequestQuery setBeanSession(BeanSession beanSession) {
		this.beanSession = beanSession;
		return this;
	}

	/**
	 * Create a copy of the request query parameters.
	 */
	RequestQuery copy() {
		RequestQuery rq = new RequestQuery();
		rq.putAll(this);
		return rq;
	}

	/**
	 * Adds default entries to these query parameters.
	 *
	 * 

* This includes the default queries defined on the servlet and method levels. * * @param defaultEntries The default entries. Can be null. * @return This object (for method chaining). */ public RequestQuery addDefault(Map defaultEntries) { if (defaultEntries != null) { for (Map.Entry e : defaultEntries.entrySet()) { String key = e.getKey(), value = e.getValue(); String[] v = get(key); if (v == null || v.length == 0 || StringUtils.isEmpty(v[0])) put(key, new String[]{value}); } } return this; } /** * Sets a request query parameter value. * * @param name The parameter name. * @param value The parameter value. */ public void put(String name, Object value) { put(name, new String[]{StringUtils.toString(value)}); } /** * Returns a query parameter value. * *

* Same as {@link HttpServletRequest#getParameter(String)} except only looks in the URL string, not parameters from * URL-Encoded FORM posts. * *

* This method can be used to retrieve a parameter without triggering the underlying servlet API to load and parse * the request body. * *

* If multiple query parameters have the same name, this returns only the first instance. * * @param name The URL parameter name. * @return The parameter value, or null if parameter not specified or has no value (e.g. "&foo". */ public String getString(String name) { String[] v = get(name); if (v == null || v.length == 0) return null; // Fix for behavior difference between Tomcat and WAS. // getParameter("foo") on "&foo" in Tomcat returns "". // getParameter("foo") on "&foo" in WAS returns null. if (v.length == 1 && v[0] == null) return ""; return v[0]; } /** * Same as {@link #getString(String)} but returns the specified default value if the query parameter was not * specified. * * @param name The URL parameter name. * @param def The default value. * @return * The parameter value, or the default value if parameter not specified or has no value * (e.g. "&foo". */ public String getString(String name, String def) { String s = getString(name); return StringUtils.isEmpty(s) ? def : s; } /** * Same as {@link #getString(String)} but converts the value to an integer. * * @param name The URL parameter name. * @return * The parameter value, or 0 if parameter not specified or has no value * (e.g. "&foo". */ public int getInt(String name) { return getInt(name, 0); } /** * Same as {@link #getString(String,String)} but converts the value to an integer. * * @param name The URL parameter name. * @param def The default value. * @return * The parameter value, or the default value if parameter not specified or has no value * (e.g. "&foo". */ public int getInt(String name, int def) { String s = getString(name); return StringUtils.isEmpty(s) ? def : Integer.parseInt(s); } /** * Same as {@link #getString(String)} but converts the value to a boolean. * * @param name The URL parameter name. * @return * The parameter value, or false if parameter not specified or has no value * (e.g. "&foo". */ public boolean getBoolean(String name) { return getBoolean(name, false); } /** * Same as {@link #getString(String,String)} but converts the value to a boolean. * * @param name The URL parameter name. * @param def The default value. * @return * The parameter value, or the default value if parameter not specified or has no value * (e.g. "&foo". */ public boolean getBoolean(String name, boolean def) { String s = getString(name); return StringUtils.isEmpty(s) ? def : Boolean.parseBoolean(s); } /** * Returns the specified query parameter value converted to a POJO. * *

* This method can be used to retrieve a parameter without triggering the underlying servlet API to load and parse * the request body. * *

Examples:
*

* // Parse into an integer. * int myparam = req.getQueryParameter("myparam", int.class); * * // Parse into an int array. * int[] myparam = req.getQueryParameter("myparam", int[].class); * // Parse into a bean. * MyBean myparam = req.getQueryParameter("myparam", MyBean.class); * * // Parse into a linked-list of objects. * List myparam = req.getQueryParameter("myparam", LinkedList.class); * * // Parse into a map of object keys/values. * Map myparam = req.getQueryParameter("myparam", TreeMap.class); *

* * @param name The parameter name. * @param type The class type to convert the parameter value to. * @param The class type to convert the parameter value to. * @return The parameter value converted to the specified class type. * @throws ParseException */ public T get(String name, Class type) throws ParseException { return get(name, beanSession.getClassMeta(type)); } /** * Same as {@link #get(String, Class)} except returns a default value if not found. * * @param name The parameter name. * @param def The default value if the parameter was not specified or is null. * @param type The class type to convert the parameter value to. * @param The class type to convert the parameter value to. * @return The parameter value converted to the specified class type. * @throws ParseException */ public T get(String name, T def, Class type) throws ParseException { return get(name, def, beanSession.getClassMeta(type)); } /** * Returns the specified query parameter value converted to a POJO. * *

* This method can be used to retrieve a parameter without triggering the underlying servlet API to load and parse * the request body. * *

* Use this method if you want to parse into a parameterized Map/Collection object. * *

Examples:
*

* // Parse into a linked-list of strings. * List<String> myparam = req.getQueryParameter("myparam", LinkedList.class, String.class); * * // Parse into a linked-list of linked-lists of strings. * List<List<String>> myparam = req.getQueryParameter("myparam", LinkedList.class, LinkedList.class, String.class); * * // Parse into a map of string keys/values. * Map<String,String> myparam = req.getQueryParameter("myparam", TreeMap.class, String.class, String.class); * * // Parse into a map containing string keys and values of lists containing beans. * Map<String,List<MyBean>> myparam = req.getQueryParameter("myparam", TreeMap.class, String.class, List.class, MyBean.class); *

* * @param name The parameter name. * @param type * The type of object to create. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} * @param args * The type arguments of the class if it's a collection or map. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} *
Ignored if the main type is not a map or collection. * @param The class type to convert the parameter value to. * @return The parameter value converted to the specified class type. * @throws ParseException */ public T get(String name, Type type, Type...args) throws ParseException { return (T)parse(name, beanSession.getClassMeta(type, args)); } /** * Same as {@link #get(String, Class)} except returns a default value if not found. * * @param name The parameter name. * @param type * The type of object to create. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} * @param args * The type arguments of the class if it's a collection or map. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} *
Ignored if the main type is not a map or collection. * @param def The default value if the parameter was not specified or is null. * @param The class type to convert the parameter value to. * @return The parameter value converted to the specified class type. * @throws ParseException */ public T get(String name, Object def, Type type, Type...args) throws ParseException { return (T)parse(name, def, beanSession.getClassMeta(type, args)); } /** * Same as {@link #get(String, Class)} except for use on multi-part parameters * (e.g. "&key=1&key=2&key=3" instead of "&key=(1,2,3)"). * *

* This method must only be called when parsing into classes of type Collection or array. * * @param name The query parameter name. * @param c The class type to convert the parameter value to. * @param The class type to convert the parameter value to. * @return The query parameter value converted to the specified class type. * @throws ParseException */ public T getAll(String name, Class c) throws ParseException { return getAll(name, beanSession.getClassMeta(c)); } /** * Same as {@link #get(String, Type, Type...)} except for use on multi-part parameters * (e.g. "&key=1&key=2&key=3" instead of "&key=(1,2,3)"). * *

* This method must only be called when parsing into classes of type Collection or array. * * @param name The query parameter name. * @param type * The type of object to create. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} * @param args * The type arguments of the class if it's a collection or map. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} *
Ignored if the main type is not a map or collection. * @param The class type to convert the parameter value to. * @return The query parameter value converted to the specified class type. * @throws ParseException */ public T getAll(String name, Type type, Type...args) throws ParseException { return (T)parseAll(name, beanSession.getClassMeta(type, args)); } /** * Returns true if the request contains any of the specified query parameters. * * @param params The list of parameters to check for. * @return true if the request contains any of the specified query parameters. */ public boolean containsAnyKeys(String...params) { for (String p : params) if (containsKey(p)) return true; return false; } /** * Locates the special search query arguments in the query and returns them as a {@link SearchArgs} object. * *

* The query arguments are as follows: *

    *
  • * "&s=" - A comma-delimited list of column-name/search-token pairs. *
    Example: "&s=column1=foo*,column2=*bar" *
  • * "&v=" - A comma-delimited list column names to view. *
    Example: "&v=column1,column2" *
  • * "&o=" - A comma-delimited list column names to sort by. *
    Column names can be suffixed with '-' to indicate descending order. *
    Example: "&o=column1,column2-" *
  • * "&p=" - The zero-index row number of the first row to display. *
    Example: "&p=100" *
  • * "&l=" - The number of rows to return. *
    0 implies return all rows. *
    Example: "&l=100" *
  • * "&i=" - The case-insensitive search flag. *
    Example: "&i=true" *
* *

* Whitespace is trimmed in the parameters. * * @return * A new {@link SearchArgs} object initialized with the special search query arguments. * null if no search arguments were found. */ public SearchArgs getSearchArgs() { if (hasAny("s","v","o","p","l","i")) { return new SearchArgs.Builder() .search(getString("s")) .view(getString("v")) .sort(getString("o")) .position(getInt("p")) .limit(getInt("l")) .ignoreCase(getBoolean("i")) .build(); } return null; } /** * Returns true if the query parameters contains any of the specified names. * * @param paramNames The parameter names to check for. * @return true if the query parameters contains any of the specified names. */ public boolean hasAny(String...paramNames) { for (String p : paramNames) if (containsKey(p)) return true; return false; } /* Workhorse method */ private T parse(String name, T def, ClassMeta cm) throws ParseException { String val = getString(name); if (val == null) return def; return parseValue(val, cm); } /* Workhorse method */ private T parse(String name, ClassMeta cm) throws ParseException { String val = getString(name); if (cm.isPrimitive() && (val == null || val.isEmpty())) return cm.getPrimitiveDefault(); return parseValue(val, cm); } /* Workhorse method */ @SuppressWarnings("rawtypes") private T parseAll(String name, ClassMeta cm) throws ParseException { String[] p = get(name); if (p == null) return null; if (cm.isArray()) { List c = new ArrayList(); for (int i = 0; i < p.length; i++) c.add(parseValue(p[i], cm.getElementType())); return (T)toArray(c, cm.getElementType().getInnerClass()); } else if (cm.isCollection()) { try { Collection c = (Collection)(cm.canCreateNewInstance() ? cm.newInstance() : new ObjectList()); for (int i = 0; i < p.length; i++) c.add(parseValue(p[i], cm.getElementType())); return (T)c; } catch (ParseException e) { throw e; } catch (Exception e) { // Typically an instantiation exception. throw new ParseException(e); } } throw new ParseException("Invalid call to getQueryParameters(String, ClassMeta). Class type must be a Collection or array."); } private T parseValue(String val, ClassMeta c) throws ParseException { return parser.parse(PartType.QUERY, val, c); } /** * Converts the query parameters to a readable string. * * @param sorted Sort the query parameters by name. * @return A JSON string containing the contents of the query parameters. */ public String toString(boolean sorted) { Map m = (sorted ? new TreeMap() : new LinkedHashMap()); for (Map.Entry e : this.entrySet()) { String[] v = e.getValue(); m.put(e.getKey(), v.length == 1 ? v[0] : v); } return JsonSerializer.DEFAULT_LAX.toString(m); } /** * Converts this object to a query string. * *

* Returned query string does not start with '?'. * * @return A new query string, or an empty string if this object is empty. */ public String toQueryString() { StringBuilder sb = new StringBuilder(); for (Map.Entry e : this.entrySet()) { for (int i = 0; i < e.getValue().length; i++) { if (sb.length() > 0) sb.append("&"); sb.append(XmlUtils.urlEncode(e.getKey())).append('=').append(XmlUtils.urlEncode(e.getValue()[i])); } } return sb.toString(); } @Override /* Object */ public String toString() { return toString(false); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy