Turns out we don't actually need 30MB of bloated jars to make a single HTTP post to get a Google SSO auth token. Don't need them for Firebase either. And not for Apple SSO. Shoot while we're at it, might as well get rid of pi4j too since making a JNI wrapper for PiGPio is easy enough.

This commit is contained in:
Mark Milligan
2022-05-02 18:20:03 -05:00
parent c8319d6369
commit d7edf3db4a
51 changed files with 1495 additions and 673 deletions

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>lantern-util-cloudservices</artifactId>
<name>lantern-util-cloudservices</name>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>com.lanternsoftware.util</groupId>
<artifactId>util</artifactId>
<version>1.0.0</version>
</parent>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>lantern-util-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>lantern-util-dao</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>lantern-util-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.19.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<executions>
<execution>
<goals>
<goal>testCompile</goal>
</goals>
<phase>compile</phase>
</execution>
</executions>
<configuration>
<optimize>true</optimize>
<showDeprecation>true</showDeprecation>
<encoding>UTF-8</encoding>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,70 @@
package com.lanternsoftware.util.cloudservices.apple;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.http.HttpFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.methods.HttpGet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class AppleSSO {
private static final Logger LOG = LoggerFactory.getLogger(AppleSSO.class);
private final Map<String, RSAPublicKey> publicKeys = new HashMap<>();
private final String audience;
public AppleSSO(String _credentialsPath) {
audience = ResourceLoader.loadFileAsString(_credentialsPath).trim();
}
public String getEmailFromIdToken(String _idToken) {
if (validatePublicKey()) {
try {
DecodedJWT jwt = JWT.decode(NullUtils.base64ToString(_idToken));
String kid = jwt.getHeaderClaim("kid").asString();
RSAPublicKey key = publicKeys.get(kid);
if (key != null) {
Algorithm algorithm = Algorithm.RSA256(key, null);
JWTVerifier verifier = JWT.require(algorithm).withIssuer("https://appleid.apple.com").withAudience(audience).build();
return verifier.verify(jwt).getClaim("email").asString().toLowerCase(Locale.ROOT);
}
} catch (Exception _e){
LOG.error("Failed to verify Apple JWT token", _e);
}
}
return null;
}
private synchronized boolean validatePublicKey() {
if (!publicKeys.isEmpty())
return true;
DaoEntity resp = DaoSerializer.parse(HttpFactory.pool().executeToString(new HttpGet("https://appleid.apple.com/auth/keys")));
for (DaoEntity key : DaoSerializer.getDaoEntityList(resp, "keys")) {
try {
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(new BigInteger(1, Base64.decodeBase64(DaoSerializer.getString(key, "n"))), new BigInteger(1, Base64.decodeBase64(DaoSerializer.getString(key, "e"))));
RSAPublicKey publicKey = (RSAPublicKey)fact.generatePublic(keySpec);
if (publicKey != null)
publicKeys.put(DaoSerializer.getString(key, "kid"), publicKey);
} catch (Exception _e) {
LOG.error("Failed to generate RSA public key", _e);
}
}
return !publicKeys.isEmpty();
}
}

View File

@@ -0,0 +1,97 @@
package com.lanternsoftware.util.cloudservices.google;
import com.lanternsoftware.util.dao.annotations.DBSerializable;
@DBSerializable
public class FirebaseCredentials {
private String type;
private String projectId;
private String privateKeyId;
private String privateKey;
private String clientEmail;
private String clientId;
private String authUri;
private String tokenUri;
private String authProviderX509CertUrl;
private String clientX509CertUrl;
public String getType() {
return type;
}
public void setType(String _type) {
type = _type;
}
public String getProjectId() {
return projectId;
}
public void setProjectId(String _projectId) {
projectId = _projectId;
}
public String getPrivateKeyId() {
return privateKeyId;
}
public void setPrivateKeyId(String _privateKeyId) {
privateKeyId = _privateKeyId;
}
public String getPrivateKey() {
return privateKey;
}
public void setPrivateKey(String _privateKey) {
privateKey = _privateKey;
}
public String getClientEmail() {
return clientEmail;
}
public void setClientEmail(String _clientEmail) {
clientEmail = _clientEmail;
}
public String getClientId() {
return clientId;
}
public void setClientId(String _clientId) {
clientId = _clientId;
}
public String getAuthUri() {
return authUri;
}
public void setAuthUri(String _authUri) {
authUri = _authUri;
}
public String getTokenUri() {
return tokenUri;
}
public void setTokenUri(String _tokenUri) {
tokenUri = _tokenUri;
}
public String getAuthProviderX509CertUrl() {
return authProviderX509CertUrl;
}
public void setAuthProviderX509CertUrl(String _authProviderX509CertUrl) {
authProviderX509CertUrl = _authProviderX509CertUrl;
}
public String getClientX509CertUrl() {
return clientX509CertUrl;
}
public void setClientX509CertUrl(String _clientX509CertUrl) {
clientX509CertUrl = _clientX509CertUrl;
}
}

View File

@@ -0,0 +1,109 @@
package com.lanternsoftware.util.cloudservices.google;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.lanternsoftware.util.CollectionUtils;
import com.lanternsoftware.util.DateUtils;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.http.HttpFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class FirebaseHelper {
private static final Logger LOG = LoggerFactory.getLogger(FirebaseHelper.class);
private static final String FCM_SEND_URL = "https://fcm.googleapis.com/v1/projects/%s/messages:send";
private static final List<String> SCOPES = List.of("https://www.googleapis.com/auth/firebase.database", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/identitytoolkit", "https://www.googleapis.com/auth/devstorage.full_control", "https://www.googleapis.com/auth/cloud-platform", "https://www.googleapis.com/auth/datastore");
private final FirebaseCredentials credentials;
private final RSAPrivateKey privateKey;
private final String fcmSendUrl;
private String accessToken;
private Date validUntil;
public FirebaseHelper(String _credentialsPath) {
this(DaoSerializer.parse(ResourceLoader.loadFileAsString(_credentialsPath), FirebaseCredentials.class));
}
public FirebaseHelper(FirebaseCredentials _credentials) {
credentials = _credentials;
if (credentials != null) {
privateKey = fromPEM(credentials.getPrivateKey());
fcmSendUrl = String.format(FCM_SEND_URL, credentials.getProjectId());
}
else {
LOG.error("Failed to load FCM credentials");
privateKey = null;
fcmSendUrl = null;
}
}
private RSAPrivateKey fromPEM(String _pem) {
try {
String pem = _pem.replaceAll("(-+BEGIN PRIVATE KEY-+|-+END PRIVATE KEY-+|\\r|\\n)", "");
byte[] encoded = Base64.decodeBase64(pem);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
return (RSAPrivateKey)keyFactory.generatePrivate(keySpec);
}
catch (Exception _e) {
LOG.error("Failed to generate RSA private key", _e);
return null;
}
}
private boolean validateAccessToken() {
if (isTokenValid())
return true;
Date now = new Date();
String assertion = JWT.create().withKeyId(credentials.getPrivateKeyId()).withIssuer(credentials.getClientEmail()).withIssuedAt(new Date()).withExpiresAt(DateUtils.addHours(now, 1)).withClaim("scope", CollectionUtils.delimit(SCOPES, " ")).withAudience(credentials.getTokenUri()).sign(Algorithm.RSA256(null, privateKey));
HttpPost post = new HttpPost(credentials.getTokenUri());
List<NameValuePair> payload = new ArrayList<>();
payload.add(new BasicNameValuePair("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"));
payload.add(new BasicNameValuePair("assertion", assertion));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(payload, StandardCharsets.UTF_8);
entity.setContentType("application/x-www-form-urlencoded");
post.setEntity(entity);
DaoEntity rep = DaoSerializer.parse(HttpFactory.pool().executeToString(post));
if (rep == null)
return false;
accessToken = DaoSerializer.getString(rep, "access_token");
validUntil = DateUtils.secondsFromNow(DaoSerializer.getInteger(rep, "expires_in")-10);
return isTokenValid();
}
private boolean isTokenValid() {
return NullUtils.isNotEmpty(accessToken) && (validUntil != null) && new Date().before(validUntil);
}
public boolean sendMessage(String _deviceToken, DaoEntity _payload) {
if (!validateAccessToken()) {
LOG.error("Failed to get a valid access token for Firebase, not sending message");
return false;
}
DaoEntity msg = new DaoEntity("message", new DaoEntity("token", _deviceToken).and("data", _payload).and("android", new DaoEntity("priority", "high").and("direct_boot_ok", true)));
HttpPost post = new HttpPost(fcmSendUrl);
post.addHeader("X-GOOG-API-FORMAT-VERSION", "2");
post.addHeader("X-Firebase-Client", "fire-admin-java/8.0.0");
post.addHeader("Authorization", "Bearer " + accessToken);
post.setEntity(new StringEntity(DaoSerializer.toJson(msg), StandardCharsets.UTF_8));
return NullUtils.isNotEmpty(HttpFactory.pool().executeToString(post));
}
}

View File

@@ -0,0 +1,57 @@
package com.lanternsoftware.util.cloudservices.google;
import com.auth0.jwt.JWT;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.lanternsoftware.util.NullUtils;
import com.lanternsoftware.util.ResourceLoader;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoSerializer;
import com.lanternsoftware.util.http.HttpFactory;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class GoogleSSO {
private static final Logger logger = LoggerFactory.getLogger(GoogleSSO.class);
private final String googleClientId;
private final String googleClientSecret;
public GoogleSSO(String _credentialsPath) {
DaoEntity google = DaoSerializer.parse(ResourceLoader.loadFileAsString(_credentialsPath));
googleClientId = DaoSerializer.getString(google, "id");
googleClientSecret = DaoSerializer.getString(google, "secret");
}
public String signin(String _code) {
HttpPost post = new HttpPost("https://oauth2.googleapis.com/token");
List<NameValuePair> payload = new ArrayList<>();
payload.add(new BasicNameValuePair("grant_type", "authorization_code"));
payload.add(new BasicNameValuePair("code", _code));
payload.add(new BasicNameValuePair("redirect_uri", "https://lanternsoftware.com/console"));
payload.add(new BasicNameValuePair("client_id", googleClientId));
payload.add(new BasicNameValuePair("client_secret", googleClientSecret));
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(payload, StandardCharsets.UTF_8);
entity.setContentType("application/x-www-form-urlencoded");
post.setEntity(entity);
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
String idToken = DaoSerializer.getString(DaoSerializer.parse(HttpFactory.pool().executeToString(post)), "id_token");
if (NullUtils.isNotEmpty(idToken)) {
try {
DecodedJWT jwt = JWT.decode(idToken);
return DaoSerializer.getString(DaoSerializer.parse(NullUtils.base64ToString(jwt.getPayload())), "email");
} catch (Exception _e) {
logger.error("Failed to validate google auth code", _e);
return null;
}
}
logger.error("Failed to validate google auth code");
return null;
}
}

View File

@@ -0,0 +1,58 @@
package com.lanternsoftware.util.cloudservices.google.dao;
import com.lanternsoftware.util.cloudservices.google.FirebaseCredentials;
import com.lanternsoftware.util.dao.AbstractDaoSerializer;
import com.lanternsoftware.util.dao.DaoEntity;
import com.lanternsoftware.util.dao.DaoProxyType;
import com.lanternsoftware.util.dao.DaoSerializer;
import java.util.Collections;
import java.util.List;
public class FirebaseCredentialsSerializer extends AbstractDaoSerializer<FirebaseCredentials>
{
@Override
public Class<FirebaseCredentials> getSupportedClass()
{
return FirebaseCredentials.class;
}
@Override
public List<DaoProxyType> getSupportedProxies() {
return Collections.singletonList(DaoProxyType.MONGO);
}
@Override
public DaoEntity toDaoEntity(FirebaseCredentials _o)
{
DaoEntity d = new DaoEntity();
d.put("type", _o.getType());
d.put("project_id", _o.getProjectId());
d.put("private_key_id", _o.getPrivateKeyId());
d.put("private_key", _o.getPrivateKey());
d.put("client_email", _o.getClientEmail());
d.put("client_id", _o.getClientId());
d.put("auth_uri", _o.getAuthUri());
d.put("token_uri", _o.getTokenUri());
d.put("auth_provider_x509_cert_url", _o.getAuthProviderX509CertUrl());
d.put("client_x509_cert_url", _o.getClientX509CertUrl());
return d;
}
@Override
public FirebaseCredentials fromDaoEntity(DaoEntity _d)
{
FirebaseCredentials o = new FirebaseCredentials();
o.setType(DaoSerializer.getString(_d, "type"));
o.setProjectId(DaoSerializer.getString(_d, "project_id"));
o.setPrivateKeyId(DaoSerializer.getString(_d, "private_key_id"));
o.setPrivateKey(DaoSerializer.getString(_d, "private_key"));
o.setClientEmail(DaoSerializer.getString(_d, "client_email"));
o.setClientId(DaoSerializer.getString(_d, "client_id"));
o.setAuthUri(DaoSerializer.getString(_d, "auth_uri"));
o.setTokenUri(DaoSerializer.getString(_d, "token_uri"));
o.setAuthProviderX509CertUrl(DaoSerializer.getString(_d, "auth_provider_x509_cert_url"));
o.setClientX509CertUrl(DaoSerializer.getString(_d, "client_x509_cert_url"));
return o;
}
}

View File

@@ -0,0 +1 @@
com.lanternsoftware.util.cloudservices.google.dao.FirebaseCredentialsSerializer

View File

@@ -34,7 +34,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -1,5 +1,6 @@
package com.lanternsoftware.util;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import java.io.UnsupportedEncodingException;
@@ -13,395 +14,379 @@ import java.util.Map;
import java.util.Map.Entry;
public class NullUtils {
public static boolean isNotEqual(Object a, Object b) {
return !isEqual(a, b);
public static boolean isNotEqual(Object a, Object b) {
return !isEqual(a, b);
}
public static boolean isEqual(Object a, Object b) {
if (a != null)
return (b != null) && a.equals(b);
return (b == null);
}
public static <T extends IIdentical<T>> boolean isNotIdentical(T a, T b) {
return !isIdentical(a, b);
}
public static <T extends IIdentical<T>> boolean isIdentical(T a, T b) {
if (a != null)
return (b != null) && a.isIdentical(b);
return (b == null);
}
public static <T> boolean isNotEqual(T a, T b, IEquals<T> _equals) {
return !isEqual(a, b, _equals);
}
public static <T> boolean isEqual(T a, T b, IEquals<T> _equals) {
if (a != null)
return (b != null) && _equals.equals(a, b);
return (b == null);
}
public static boolean equalsIgnoreCase(String a, String b) {
if (a != null)
return a.equalsIgnoreCase(b);
return (b == null);
}
public static int length(String _val) {
if (_val == null)
return 0;
return _val.length();
}
public static boolean isEmpty(String _sVal) {
return (_sVal == null) || (_sVal.length() == 0);
}
public static boolean isAnyEmpty(String... _vals) {
if (_vals == null)
return true;
for (String val : _vals) {
if (isEmpty(val))
return true;
}
return false;
}
public static boolean isNotEmpty(String _sVal) {
return !isEmpty(_sVal);
}
public static boolean isAnyNotEmpty(String... _vals) {
if (_vals == null)
return false;
for (String val : _vals) {
if (isNotEmpty(val))
return true;
}
return false;
}
public static boolean isAnyNull(Object... _o) {
if ((_o == null) || (_o.length == 0))
return false;
for (Object o : _o) {
if (o == null)
return true;
}
return false;
}
public static boolean isOneOf(Object _o, Object... _values) {
if ((_o == null) || (_values == null) || (_values.length == 0))
return false;
for (Object o : _values) {
if (_o.equals(o))
return true;
}
return false;
}
public static String trim(String _val) {
if (_val == null)
return null;
return _val.trim();
}
public static String toString(byte[] _arrBytes) {
if (_arrBytes == null)
return null;
try {
return new String(_arrBytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
return null;
}
}
public static byte[] toByteArray(String _value) {
if (_value == null)
return null;
try {
return _value.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
return null;
}
}
public static int toInteger(String _value) {
try {
return Integer.valueOf(makeNotNull(_value));
} catch (NumberFormatException _e) {
return 0;
}
}
public static long toLong(String _value) {
try {
return Long.valueOf(makeNotNull(_value));
} catch (NumberFormatException _e) {
return 0;
}
}
public static double toDouble(String _value) {
try {
return Double.valueOf(makeNotNull(_value));
} catch (NumberFormatException _e) {
return 0.0;
}
}
public static float toFloat(String _value) {
try {
return Float.valueOf(makeNotNull(_value));
} catch (NumberFormatException _e) {
return 0f;
}
}
public static String urlEncode(String _url) {
try {
return URLEncoder.encode(makeNotNull(_url), "UTF-8");
} catch (UnsupportedEncodingException e) {
return _url;
}
}
public static String urlDecode(String _url) {
try {
return URLDecoder.decode(makeNotNull(_url), "UTF-8");
} catch (UnsupportedEncodingException e) {
return _url;
}
}
public static String makeNotNull(String _value) {
if (_value != null)
return _value;
return "";
}
public static String after(String _value, String _search) {
if (_value == null)
return "";
int iPos = _value.lastIndexOf(_search);
if (iPos < 0)
return "";
return iPos < _value.length() - _search.length() ? _value.substring(iPos + _search.length()) : "";
}
public static <T extends Enum<T>> T toEnum(Class<T> _enumType, String _sValue) {
return toEnum(_enumType, _sValue, null);
}
public static <T extends Enum<T>> T toEnum(Class<T> _enumType, String _sValue, T _default) {
T e = null;
try {
e = Enum.valueOf(_enumType, _sValue);
} catch (Throwable t) {
return _default;
}
return e;
}
public static <T extends Enum<T>> List<T> toEnums(Class<T> _enumType, Collection<String> _values) {
List<T> listEnums = new ArrayList<T>();
for (String value : CollectionUtils.makeNotNull(_values)) {
T e = toEnum(_enumType, value, null);
if (e != null)
listEnums.add(e);
}
return listEnums;
}
public static <T extends Comparable<T>> int compare(T a, T b) {
return compare(a, b, true);
}
public static <T extends Comparable<T>> int compare(T a, T b, boolean _bNullsFirst) {
if (a != null) {
if (b != null)
return a.compareTo(b);
else
return _bNullsFirst ? 1 : -1;
}
if (b != null)
return _bNullsFirst ? -1 : 1;
return 0;
}
public static int min(int... values) {
int iMin = Integer.MAX_VALUE;
for (int value : values) {
if (value < iMin)
iMin = value;
}
return iMin;
}
public static String[] cleanSplit(String _sValue, String _sRegex) {
if (_sValue == null)
return new String[0];
return removeEmpties(_sValue.split(_sRegex));
}
public static String[] removeEmpties(String[] _arr) {
if (_arr == null)
return new String[0];
int valid = 0;
for (String s : _arr) {
if (NullUtils.isNotEmpty(s))
valid++;
}
if (valid == _arr.length)
return _arr;
String[] ret = new String[valid];
valid = 0;
for (String s : _arr) {
if (NullUtils.isNotEmpty(s))
ret[valid++] = s;
}
return ret;
}
public static String wrap(String _input, int _lineLength) {
return wrap(_input, _lineLength, false);
}
public static String wrap(String _input, int _lineLength, boolean carriageReturn) {
if (_input == null)
return null;
StringBuilder output = new StringBuilder();
int i = 0;
while (i < _input.length()) {
if ((i + _lineLength) > _input.length())
output.append(_input.substring(i, _input.length()));
else {
output.append(_input.substring(i, i + _lineLength));
if (carriageReturn)
output.append("\r");
output.append("\n");
}
i += _lineLength;
}
return output.toString();
}
public static <T> Class<? extends T> getClass(String _className, Class<T> _superClass) {
try {
return Class.forName(_className).asSubclass(_superClass);
} catch (ClassNotFoundException _e) {
return null;
}
}
public static String terminateWith(String _value, String _suffix) {
if (_value == null)
return _suffix;
if (_value.endsWith(_suffix))
return _value;
return _value + _suffix;
}
public static String toUpperCase(String _value) {
if (_value == null)
return null;
return _value.toUpperCase();
}
public static String toLowerCase(String _value) {
if (_value == null)
return null;
return _value.toLowerCase();
}
public static Map<String, List<String>> parseQueryParams(String _queryString) {
Map<String, List<String>> queryParameters = new HashMap<>();
if (isEmpty(_queryString)) {
return queryParameters;
}
String[] parameters = _queryString.split("&");
for (String parameter : parameters) {
String[] keyValuePair = parameter.split("=");
if (keyValuePair.length > 1)
CollectionUtils.addToMultiMap(keyValuePair[0], keyValuePair[1], queryParameters);
}
return queryParameters;
}
public static String toQueryString(Map<String, List<String>> _queryParameters) {
StringBuilder queryString = null;
for (Entry<String, List<String>> entry : CollectionUtils.makeNotNull(_queryParameters).entrySet()) {
for (String param : CollectionUtils.makeNotNull(entry.getValue())) {
if (NullUtils.isEmpty(param))
continue;
if (queryString == null)
queryString = new StringBuilder();
else
queryString.append("&");
queryString.append(entry.getKey());
queryString.append("=");
queryString.append(param);
}
}
return queryString == null ? "" : queryString.toString();
}
public static String toHex(String _sValue) {
return toHex(toByteArray(_sValue));
}
public static String toHexBytes(byte[] _btData) {
List<String> bytes = new ArrayList<>(_btData.length);
for (byte b : _btData) {
bytes.add(String.format("%02X ", b));
}
return CollectionUtils.delimit(bytes, " ");
}
public static String toHex(byte[] _btData) {
try {
return new String(Hex.encodeHex(_btData));
} catch (Exception e) {
return "";
}
}
public static byte[] fromHex(String _sValue) {
try {
return Hex.decodeHex(makeNotNull(_sValue).toCharArray());
} catch (Exception e) {
return null;
}
}
public static String base64ToString(String _base64) {
return toString(Base64.decodeBase64(_base64));
}
public static boolean isEqual(Object a, Object b) {
if (a != null)
return (b != null) && a.equals(b);
return (b == null);
}
public static <T extends IIdentical<T>> boolean isNotIdentical(T a, T b) {
return !isIdentical(a, b);
}
public static <T extends IIdentical<T>> boolean isIdentical(T a, T b) {
if (a != null)
return (b != null) && a.isIdentical(b);
return (b == null);
}
public static <T> boolean isNotEqual(T a, T b, IEquals<T> _equals) {
return !isEqual(a, b, _equals);
}
public static <T> boolean isEqual(T a, T b, IEquals<T> _equals) {
if (a != null)
return (b != null) && _equals.equals(a, b);
return (b == null);
}
public static boolean equalsIgnoreCase(String a, String b) {
if (a != null)
return a.equalsIgnoreCase(b);
return (b == null);
}
public static int length(String _val) {
if (_val == null)
return 0;
return _val.length();
}
public static boolean isEmpty(String _sVal) {
return (_sVal == null) || (_sVal.length() == 0);
}
public static boolean isAnyEmpty(String... _vals) {
if (_vals == null)
return true;
for (String val : _vals) {
if (isEmpty(val))
return true;
}
return false;
}
public static boolean isNotEmpty(String _sVal) {
return !isEmpty(_sVal);
}
public static boolean isAnyNotEmpty(String... _vals) {
if (_vals == null)
return false;
for (String val : _vals) {
if (isNotEmpty(val))
return true;
}
return false;
}
public static boolean isAnyNull(Object... _o) {
if ((_o == null) || (_o.length == 0))
return false;
for (Object o : _o) {
if (o == null)
return true;
}
return false;
}
public static boolean isOneOf(Object _o, Object... _values) {
if ((_o == null) || (_values == null) || (_values.length == 0))
return false;
for (Object o : _values) {
if (_o.equals(o))
return true;
}
return false;
}
public static String trim(String _val) {
if (_val == null)
return null;
return _val.trim();
}
public static String toString(byte[] _arrBytes) {
if (_arrBytes == null)
return null;
try {
return new String(_arrBytes, "UTF-8");
}
catch (UnsupportedEncodingException e) {
return null;
}
}
public static byte[] toByteArray(String _value) {
if (_value == null)
return null;
try {
return _value.getBytes("UTF-8");
}
catch (UnsupportedEncodingException e) {
return null;
}
}
public static int toInteger(String _value) {
try {
return Integer.valueOf(makeNotNull(_value));
}
catch (NumberFormatException _e) {
return 0;
}
}
public static long toLong(String _value) {
try {
return Long.valueOf(makeNotNull(_value));
}
catch (NumberFormatException _e) {
return 0;
}
}
public static double toDouble(String _value) {
try {
return Double.valueOf(makeNotNull(_value));
}
catch (NumberFormatException _e) {
return 0.0;
}
}
public static float toFloat(String _value) {
try {
return Float.valueOf(makeNotNull(_value));
}
catch (NumberFormatException _e) {
return 0f;
}
}
public static String urlEncode(String _url) {
try {
return URLEncoder.encode(makeNotNull(_url), "UTF-8");
}
catch (UnsupportedEncodingException e) {
return _url;
}
}
public static String urlDecode(String _url) {
try {
return URLDecoder.decode(makeNotNull(_url), "UTF-8");
}
catch (UnsupportedEncodingException e) {
return _url;
}
}
public static String makeNotNull(String _value) {
if (_value != null)
return _value;
return "";
}
public static String after(String _value, String _search) {
if (_value == null)
return "";
int iPos = _value.lastIndexOf(_search);
if (iPos < 0)
return "";
return iPos < _value.length() - _search.length() ? _value.substring(iPos + _search.length()) : "";
}
public static <T extends Enum<T>> T toEnum(Class<T> _enumType, String _sValue) {
return toEnum(_enumType, _sValue, null);
}
public static <T extends Enum<T>> T toEnum(Class<T> _enumType, String _sValue, T _default) {
T e = null;
try {
e = Enum.valueOf(_enumType, _sValue);
}
catch (Throwable t) {
return _default;
}
return e;
}
public static <T extends Enum<T>> List<T> toEnums(Class<T> _enumType, Collection<String> _values) {
List<T> listEnums = new ArrayList<T>();
for (String value : CollectionUtils.makeNotNull(_values)) {
T e = toEnum(_enumType, value, null);
if (e != null)
listEnums.add(e);
}
return listEnums;
}
public static <T extends Comparable<T>> int compare(T a, T b) {
return compare(a, b, true);
}
public static <T extends Comparable<T>> int compare(T a, T b, boolean _bNullsFirst) {
if (a != null) {
if (b != null)
return a.compareTo(b);
else
return _bNullsFirst ? 1 : -1;
}
if (b != null)
return _bNullsFirst ? -1 : 1;
return 0;
}
public static int min(int... values) {
int iMin = Integer.MAX_VALUE;
for (int value : values) {
if (value < iMin)
iMin = value;
}
return iMin;
}
public static String[] cleanSplit(String _sValue, String _sRegex) {
if (_sValue == null)
return new String[0];
return removeEmpties(_sValue.split(_sRegex));
}
public static String[] removeEmpties(String[] _arr) {
if (_arr == null)
return new String[0];
int valid = 0;
for (String s : _arr) {
if (NullUtils.isNotEmpty(s))
valid++;
}
if (valid == _arr.length)
return _arr;
String[] ret = new String[valid];
valid = 0;
for (String s : _arr) {
if (NullUtils.isNotEmpty(s))
ret[valid++] = s;
}
return ret;
}
public static String wrap(String _input, int _lineLength) {
return wrap(_input, _lineLength, false);
}
public static String wrap(String _input, int _lineLength, boolean carriageReturn) {
if (_input == null)
return null;
StringBuilder output = new StringBuilder();
int i = 0;
while (i < _input.length()) {
if ((i + _lineLength) > _input.length())
output.append(_input.substring(i, _input.length()));
else {
output.append(_input.substring(i, i + _lineLength));
if (carriageReturn)
output.append("\r");
output.append("\n");
}
i += _lineLength;
}
return output.toString();
}
public static <T> Class<? extends T> getClass(String _className, Class<T> _superClass) {
try {
return Class.forName(_className).asSubclass(_superClass);
}
catch (ClassNotFoundException _e) {
return null;
}
}
public static String terminateWith(String _value, String _suffix) {
if (_value == null)
return _suffix;
if (_value.endsWith(_suffix))
return _value;
return _value + _suffix;
}
public static String toUpperCase(String _value) {
if (_value == null)
return null;
return _value.toUpperCase();
}
public static String toLowerCase(String _value) {
if (_value == null)
return null;
return _value.toLowerCase();
}
public static Map<String, List<String>> parseQueryParams(String _queryString) {
Map<String, List<String>> queryParameters = new HashMap<>();
if (isEmpty(_queryString)) {
return queryParameters;
}
String[] parameters = _queryString.split("&");
for (String parameter : parameters) {
String[] keyValuePair = parameter.split("=");
if (keyValuePair.length > 1)
CollectionUtils.addToMultiMap(keyValuePair[0], keyValuePair[1], queryParameters);
}
return queryParameters;
}
public static String toQueryString(Map<String, List<String>> _queryParameters) {
StringBuilder queryString = null;
for (Entry<String, List<String>> entry : CollectionUtils.makeNotNull(_queryParameters).entrySet()) {
for (String param : CollectionUtils.makeNotNull(entry.getValue())) {
if (NullUtils.isEmpty(param))
continue;
if (queryString == null)
queryString = new StringBuilder();
else
queryString.append("&");
queryString.append(entry.getKey());
queryString.append("=");
queryString.append(param);
}
}
return queryString == null?"":queryString.toString();
}
public static String toHex(String _sValue)
{
return toHex(toByteArray(_sValue));
}
public static String toHexBytes(byte[] _btData)
{
List<String> bytes = new ArrayList<>(_btData.length);
for (byte b : _btData) {
bytes.add(String.format("%02X ", b));
}
return CollectionUtils.delimit(bytes, " ");
}
public static String toHex(byte[] _btData)
{
try
{
return new String(Hex.encodeHex(_btData));
}
catch (Exception e)
{
return "";
}
}
public static byte[] fromHex(String _sValue)
{
try
{
return Hex.decodeHex(makeNotNull(_sValue).toCharArray());
}
catch (Exception e)
{
return null;
}
}
public static int bound(int _value, int _min, int _max) {
if (_value < _min)
return _min;
if (_value > _max)
return _max;
return _value;
}
public static int bound(int _value, int _min, int _max) {
if (_value < _min)
return _min;
if (_value > _max)
return _max;
return _value;
}
}

View File

@@ -29,7 +29,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -34,7 +34,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -29,7 +29,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -30,7 +30,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -39,7 +39,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -0,0 +1,18 @@
package com.lanternsoftware.util.http;
public class HttpFactory {
private static final int CONNECTIONS = 10;
private static HttpPool pool;
public static synchronized HttpPool pool() {
if (pool == null)
pool = new HttpPool(CONNECTIONS, CONNECTIONS);
return pool;
}
public static synchronized void shutdown() {
if (pool != null) {
pool.shutdown();
pool = null;
}
}
}

View File

@@ -35,7 +35,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>3.10.1</version>
<executions>
<execution>
<goals>

View File

@@ -14,6 +14,7 @@
</parent>
<modules>
<module>lantern-util-cloudservices</module>
<module>lantern-util-common</module>
<module>lantern-util-dao</module>
<module>lantern-util-dao-ephemeral</module>