com.aeontronix.commons.StringUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aeon-commons-core Show documentation
Show all versions of aeon-commons-core Show documentation
Various utility classes. Except for very rare exceptions (annotation-based validation) this will not
require any dependencies beyond the JRE
The newest version!
/*
* Copyright (c) 2015 Kloudtek Ltd
*/
package com.aeontronix.commons;
import com.aeontronix.commons.exception.UnexpectedException;
import org.jetbrains.annotations.Nullable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.Character.isWhitespace;
import static java.lang.Character.toTitleCase;
/**
* Various string manipulation utility functions
*/
public class StringUtils {
public static Pattern varSubFuncPattern;
public static final String UNSAFE_URLPATH = " %$&+,/:;=?@<|>#%";
public static boolean isEmpty(String txt) {
return txt == null || txt.isEmpty();
}
public static boolean isNotEmpty(String txt) {
return !isEmpty(txt);
}
public static boolean isBlank(String txt) {
int strLen;
if (txt == null || (strLen = txt.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if ((!isWhitespace(txt.charAt(i)))) {
return false;
}
}
return true;
}
public static boolean isNotBlank(String txt) {
return !isBlank(txt);
}
/**
* URL encode a string using UTF-8
*
* @param txt String to encode.
* @return URL encoded string.
*/
public static String urlEncode(String txt) {
try {
return URLEncoder.encode(txt, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* URL decode a string using UTF-8
*
* @param txt String to decode.
* @return Decoded string.
*/
public static String urlDecode(String txt) {
try {
return URLDecoder.decode(txt, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
public static String capitalize(String txt) {
int len;
if (txt == null || (len = txt.length()) == 0) {
return txt;
}
return toTitleCase(txt.charAt(0)) +
txt.substring(1);
}
public static byte[] base64Encode(byte[] data) {
return base64Encode(data, false);
}
public static String base64EncodeToString(String data) {
return base64EncodeToString(data, false);
}
public static String base64EncodeToString(byte[] data) {
return base64EncodeToString(data, false);
}
/**
* Base64 encode a string by converting it to bytes (using UTF8)
*
* @param data String to encode
* @param urlSafe If true, base64url will be used instead of base64
* @return encoded string
*/
public static byte[] base64Encode(String data, boolean urlSafe) {
return base64Encode(utf8(data), urlSafe);
}
public static String base64EncodeToString(String data, boolean urlSafe) {
return base64EncodeToString(utf8(data), urlSafe);
}
public static byte[] base64Encode(byte[] data, boolean urlSafe) {
return getBase64Encoder(urlSafe).encode(data);
}
public static String base64EncodeToString(byte[] data, boolean urlSafe) {
return getBase64Encoder(urlSafe).encodeToString(data);
}
public static byte[] base64Decode(String data) {
return base64Decode(data, false);
}
public static String base64DecodeToString(String data) {
return base64DecodeToString(data, false);
}
public static byte[] base64Decode(String data, boolean urlSafe) {
return getBase64Decoder(urlSafe).decode(data);
}
public static String base64DecodeToString(String data, boolean urlSafe) {
return utf8(getBase64Decoder(urlSafe).decode(data));
}
public static byte[] base32Encode(byte[] data) {
return new Base32(0, Base32.CHUNK_SEPARATOR).encode(data);
}
public static String base32EncodeToString(byte[] data) {
return new Base32(0, Base32.CHUNK_SEPARATOR).encodeToString(data);
}
public static byte[] base32Decode(String data) {
return base32Decode(data, false);
}
public static String base32DecodeToString(String data) {
return utf8(base32Decode(data, false));
}
public static byte[] base32Decode(String data, boolean useHex) {
return new Base32(0, Base32.CHUNK_SEPARATOR, useHex).decode(data);
}
public static String base32DecodeToString(byte[] data, boolean useHex) {
return utf8(new Base32(0, Base32.CHUNK_SEPARATOR, useHex).decode(data));
}
public static String urlPathEncode(String path) {
StringBuilder buffer = new StringBuilder();
for (char c : path.toCharArray()) {
if (UNSAFE_URLPATH.indexOf(c) >= 0) {
buffer.append('%');
buffer.append(toHex(c / 16));
buffer.append(toHex(c % 16));
} else if (c < 32 && c > 128) {
buffer.append(urlEncode(Character.toString(c)));
} else {
buffer.append(c);
}
}
return buffer.toString();
}
private static char toHex(int ch) {
return (char) (ch < 10 ? '0' + ch : 'A' + ch - 10);
}
/**
* Convert string to an UTF-8 encoded byte array
*
* @param str String to convert.
* @return UTF-8 characters byte array
*/
public static byte[] utf8(String str) {
return str.getBytes(StandardCharsets.UTF_8);
}
/**
* Convert UTF-8 encoded byte arrays to a string
*
* @param utf8Chars UTF-8 characters byte array
* @return Converted string.
*/
public static String utf8(byte[] utf8Chars) {
try {
return new String(utf8Chars, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new UnexpectedException(e);
}
}
public static boolean containsVariableSubstitution(String str) {
char[] chars = str.toCharArray();
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == '\\') {
i++;
} else if (c == '$') {
if (nextChar(chars, i) == '{') {
return true;
}
}
}
return false;
}
/**
* Same as calling {@link #substituteVariables(String, Map)} with neverFail set to true
*/
public static String substituteVariables(String str, Map variables) throws IllegalArgumentException {
return substituteVariables(str, variables, true);
}
/**
* Substitute variables in a string.
*
* @param str String to substitute variables from
* @param variables Variables
* @param neverFail If set to true, this will suppress any errors and instead return empty string in the invalid part of the variable substituation.
* @return String with variables substituted
* @throws IllegalArgumentException If an invalid variable substituation is found and neverFail is set to false
*/
public static String substituteVariables(String str, Map variables, boolean neverFail) throws IllegalArgumentException {
if (str == null) {
return null;
}
char[] chars = str.toCharArray();
int nested = 0;
StringWriter newStr = new StringWriter();
StringWriter varStr = new StringWriter();
StringWriter cStr = newStr;
boolean varParse = false;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
if (c == '$') {
char nc = nextChar(chars, i);
if (nc == '$' && nextChar(chars, i + 1) == '{') {
i += 2;
cStr.append("${");
} else if (nc == '{') {
i++;
if (!varParse) {
varParse = true;
cStr = varStr;
} else {
nested++;
varStr.append("${");
}
} else {
cStr.append(c);
}
} else if (varParse && c == '}') {
if (nested > 0) {
nested--;
varStr.append('}');
} else {
varParse = false;
cStr = newStr;
newStr.append(resolveVarSub(varStr.toString(), variables, neverFail));
varStr = new StringWriter();
}
} else {
cStr.append(c);
}
}
return newStr.toString();
}
private static char nextChar(char[] chars, int idx) {
int newIdx = idx + 1;
if (newIdx < chars.length) {
return chars[newIdx];
} else {
return 0;
}
}
private static String resolveVarSub(String exp, Map provisioningParams, boolean neverFail) throws IllegalArgumentException {
if (containsVariableSubstitution(exp)) {
exp = substituteVariables(exp, provisioningParams, neverFail);
}
Pattern pattern = getVarSubFuncPattern();
Matcher m = pattern.matcher(exp);
if (m.find()) {
String functionName = m.group(1).toLowerCase();
String functionParams = m.group(2);
boolean prefixFunc = functionName.equals("p");
boolean suffixFunc = functionName.equals("s");
if (prefixFunc || suffixFunc) {
String[] args = splitTwoArgFunction(functionParams, neverFail);
if (args != null) {
String xfix = args[0];
String val = resolveVarSub(args[1], provisioningParams, neverFail);
if (StringUtils.isNotBlank(val)) {
return suffixFunc ? xfix + val : val + xfix;
} else {
return val;
}
} else {
resolveVarSubFail(exp, neverFail);
}
} else if (functionName.equals("u")) {
return resolveVarSub(functionParams, provisioningParams, neverFail).toUpperCase();
} else if (functionName.equals("l")) {
return resolveVarSub(functionParams, provisioningParams, neverFail).toLowerCase();
} else if (functionName.equals("c")) {
return capitalize(resolveVarSub(functionParams, provisioningParams, neverFail));
} else if (functionName.equals("eb64")) {
return base64EncodeToString(utf8(resolveVarSub(functionParams, provisioningParams, neverFail)));
} else if (functionName.equals("db64")) {
return base64DecodeToString(resolveVarSub(functionParams, provisioningParams, neverFail));
} else if (functionName.equals("t")) {
return functionParams;
} else {
resolveVarSubFail(exp, neverFail);
}
} else {
String val = provisioningParams.get(exp);
if (val == null) {
if (!neverFail) {
throw new IllegalArgumentException("Variable not found: " + exp);
}
} else {
return val;
}
}
return "";
}
private static String resolveVarSubFail(String exp, boolean neverFail) {
if (!neverFail) {
throw new IllegalArgumentException("Invalid variable substitution expression: " + exp);
} else {
return "";
}
}
private static synchronized Pattern getVarSubFuncPattern() {
if (varSubFuncPattern == null) {
varSubFuncPattern = Pattern.compile("([a-zA-Z]*?):(.*)");
}
return varSubFuncPattern;
}
@Nullable
private static String[] splitTwoArgFunction(String str, boolean neverFail) {
StringWriter arg1 = new StringWriter();
StringWriter arg2 = new StringWriter();
boolean potentialMatch = false;
boolean match = false;
for (char c : str.toCharArray()) {
if (match) {
arg2.append(c);
} else if (c == ':') {
if (potentialMatch) {
arg1.append(':');
}
potentialMatch = !potentialMatch;
} else if (potentialMatch) {
match = true;
arg2.append(c);
} else {
arg1.append(c);
}
}
if (match) {
return new String[]{arg1.toString(), arg2.toString()};
} else {
resolveVarSubFail(str, neverFail);
return null;
}
}
private static Base64.Encoder getBase64Encoder(boolean urlSafe) {
final Base64.Encoder encoder;
if (urlSafe) {
encoder = Base64.getUrlEncoder();
} else {
encoder = Base64.getEncoder();
}
return encoder.withoutPadding();
}
private static Base64.Decoder getBase64Decoder(boolean urlSafe) {
final Base64.Decoder decoder;
if (urlSafe) {
decoder = Base64.getUrlDecoder();
} else {
decoder = Base64.getDecoder();
}
return decoder;
}
public static String generateId() {
return generateId(null, true);
}
public static String generateId(String prefix) {
return generateId(prefix, true);
}
public static String generateId(String prefix, boolean b32) {
final byte[] uuidData = DataUtils.uuidToByteArray(UUID.randomUUID());
String id;
if (b32) {
id = new Base32(0, null, true).encodeToString(uuidData).replace("=", "").toLowerCase();
} else {
id = Base64.getUrlEncoder().withoutPadding().encodeToString(uuidData);
}
if (prefix != null) {
return prefix + "-" + id;
} else {
return id;
}
}
public static String uuid() {
return UUIDUtils.generate().toString();
}
}