/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Lachlan Dowding
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package permafrost.tundra.net.uri;
import com.wm.data.IData;
import com.wm.data.IDataCursor;
import com.wm.data.IDataFactory;
import com.wm.data.IDataUtil;
import permafrost.tundra.data.IDataHelper;
import permafrost.tundra.lang.ArrayHelper;
import permafrost.tundra.lang.CharsetHelper;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* A collection of convenience methods for working with URI query strings.
*/
public final class URIQueryHelper {
public static final String QUERY_STRING_KEY_ARRAY_SUFFIX = "[]";
public static final String QUERY_STRING_KEY_VALUE_PAIR_EQUALS_OPERATOR = "=";
public static final String QUERY_STRING_KEY_VALUE_PAIR_TOKEN_SEPARATOR = "&";
/**
* Parses a query string.
*
* @param input The query string to be parsed.
* @param decode Whether to URI decode the values in the query string.
* @return An IData representation of the parsed query string.
*/
public static IData parse(String input, boolean decode) {
return parse(input, URIHelper.DEFAULT_CHARSET, decode);
}
/**
* Parses a query string.
*
* @param input The query string to be parsed.
* @param charsetName The character set to use when decoding URI encoded values.
* @param decode Whether to URI decode the values in the query string.
* @return An IData representation of the parsed query string.
*/
public static IData parse(String input, String charsetName, boolean decode) {
return parse(input, CharsetHelper.normalize(charsetName, URIHelper.DEFAULT_CHARSET), decode);
}
/**
* Parses a query string.
*
* @param input The query string to be parsed.
* @param charset The character set to use when decoding URI encoded values.
* @param decode Whether to URI decode the values in the query string.
* @return An IData representation of the parsed query string.
*/
public static IData parse(String input, Charset charset, boolean decode) {
if (input == null) return null;
IData output = IDataFactory.create();
IDataCursor outputCursor = output.getCursor();
for (String pair : input.split(QUERY_STRING_KEY_VALUE_PAIR_TOKEN_SEPARATOR)) {
String[] tokens = pair.split(QUERY_STRING_KEY_VALUE_PAIR_EQUALS_OPERATOR, 2);
String name = tokens.length > 0 ? tokens[0] : "";
String value = tokens.length > 1 ? tokens[1] : "";
if (decode) {
name = URIHelper.decode(name, charset);
value = URIHelper.decode(value, charset);
}
outputCursor.insertAfter(name, value);
}
outputCursor.destroy();
return IDataHelper.normalize(output);
}
/**
* Emits a query string given a name and value.
*
* @param name The query string parameter's name.
* @param value The query string parameter's value.
* @param charset The character set to use when URI encoding the parameter's value.
* @param encode True if the parameter's value should be URI encoded.
* @return A query string containing the specified parameter.
*/
private static String emit(String name, Object value, Charset charset, boolean encode) {
if (encode) {
name = URIHelper.encode(name, charset);
value = URIHelper.encode(value.toString(), charset);
}
return name + QUERY_STRING_KEY_VALUE_PAIR_EQUALS_OPERATOR + value;
}
/**
* Emits a query string given a name and array of values.
*
* @param name The query string parameter's name.
* @param values A list of values for the query string parameter.
* @param charset The character set to use when URI encoding the parameter's value.
* @param encode True if the parameter's value should be URI encoded.
* @return A query string containing the specified parameter.
*/
private static String emit(String name, Object[] values, Charset charset, boolean encode) {
StringBuilder output = new StringBuilder();
for (Object value : values) {
if (output.length() > 0) output.append(QUERY_STRING_KEY_VALUE_PAIR_TOKEN_SEPARATOR);
output.append(emit(name, value, charset, encode));
}
return output.toString();
}
/**
* Emits a query string given an IData containing name value pairs.
*
* @param input An IData containing keys and values to serialized as a query string.
* @param encode True if the query string parameters should be URI encoded.
* @return A query string containing the parameters in the given IData.
*/
public static String emit(IData input, boolean encode) {
return emit(input, URIHelper.DEFAULT_CHARSET_NAME, encode);
}
/**
* Emits a query string given an IData containing name value pairs.
*
* @param input An IData containing keys and values to serialized as a query string.
* @param charsetName The character set to use when URI encoding the parameters.
* @param encode True if the query string parameters should be URI encoded.
* @return A query string containing the parameters in the given IData.
*/
public static String emit(IData input, String charsetName, boolean encode) {
return emit(input, CharsetHelper.normalize(charsetName, URIHelper.DEFAULT_CHARSET), encode);
}
/**
* Emits a query string given an IData containing name value pairs.
*
* @param input An IData containing keys and values to serialized as a query string.
* @param charset The character set to use when URI encoding the parameters.
* @param encode True if the query string parameters should be URI encoded.
* @return A query string containing the parameters in the given IData.
*/
public static String emit(IData input, Charset charset, boolean encode) {
if (input == null) return null;
StringBuilder output = new StringBuilder();
input = IDataHelper.denormalize(input);
IDataCursor cursor = input.getCursor();
while (cursor.next()) {
String key = cursor.getKey();
Object value = cursor.getValue();
if (value != null) {
if (output.length() > 0) output.append(QUERY_STRING_KEY_VALUE_PAIR_TOKEN_SEPARATOR);
if (value instanceof Object[]) {
output.append(emit(key, (Object[])value, charset, encode));
} else {
output.append(emit(key, value, charset, encode));
}
}
}
return output.toString();
}
}