Modularise project

This commit is contained in:
Frank van der Heijden 2020-07-03 15:52:56 +02:00
parent 2be3825438
commit 4416d55173
No known key found for this signature in database
GPG key ID: 26DA56488D314D11
55 changed files with 388 additions and 331 deletions

11
Common/build.gradle Normal file
View file

@ -0,0 +1,11 @@
group = rootProject.group + '.common'
version = rootProject.version
archivesBaseName = rootProject.name + '-Common'
repositories {
mavenCentral()
}
dependencies {
compileOnly 'com.google.code.gson:gson:2.8.6'
}

View file

@ -0,0 +1,15 @@
package net.frankheijden.serverutils.common.reflection;
public class FieldParam {
public String field;
public VersionParam versionParam;
private FieldParam(String field, VersionParam versionParam) {
this.field = field;
this.versionParam = versionParam;
}
public static FieldParam fieldOf(String field, VersionParam versionParam) {
return new FieldParam(field, versionParam);
}
}

View file

@ -0,0 +1,18 @@
package net.frankheijden.serverutils.common.reflection;
public class MethodParam {
public String method;
public VersionParam versionParam;
public Class<?>[] params;
private MethodParam(String method, VersionParam versionParam, Class<?>... params) {
this.method = method;
this.versionParam = versionParam;
this.params = params;
}
public static MethodParam methodOf(String method, VersionParam versionParam, Class<?>... params) {
return new MethodParam(method, versionParam, params);
}
}

View file

@ -0,0 +1,172 @@
package net.frankheijden.serverutils.common.reflection;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public abstract class ReflectionUtils {
private static ReflectionUtils instance;
public ReflectionUtils() {
instance = this;
}
public static ReflectionUtils getInstance() {
return instance;
}
public abstract boolean isCompatible(VersionParam param);
/**
* Retrieves a declared field from a class and makes it accessible.
* @param clazz The class of the method.
* @param field The field name.
* @return The specified field.
* @throws NoSuchFieldException iff field doesn't exist.
*/
public static Field getDeclaredField(Class<?> clazz, String field) throws NoSuchFieldException {
Field f = clazz.getDeclaredField(field);
f.setAccessible(true);
return f;
}
/**
* Retrieves a field from a class and makes it accessible.
* @param clazz The class of the method.
* @param field The field name.
* @return The specified field.
* @throws NoSuchFieldException iff field doesn't exist.
*/
public static Field getField(Class<?> clazz, String field) throws NoSuchFieldException {
Field f = clazz.getField(field);
f.setAccessible(true);
return f;
}
/**
* Retrieves a declared method from a class and makes it accessible.
* @param clazz The class of the method.
* @param method The method name.
* @param params The parameters of the method.
* @return The specified method.
* @throws NoSuchMethodException iff method doesn't exist.
*/
public static Method getDeclaredMethod(Class<?> clazz, String method, Class<?>... params)
throws NoSuchMethodException {
Method m = clazz.getDeclaredMethod(method, params);
m.setAccessible(true);
return m;
}
/**
* Retrieves a method from a class and makes it accessible.
* @param clazz The class of the method.
* @param method The method name.
* @param params The parameters of the method.
* @return The specified method.
* @throws NoSuchMethodException iff method doesn't exist.
*/
public static Method getMethod(Class<?> clazz, String method, Class<?>... params)
throws NoSuchMethodException {
Method m = clazz.getMethod(method, params);
m.setAccessible(true);
return m;
}
/**
* Retrieves fields from a class based on the specified FieldParams.
* @param clazz The class of the fields.
* @param fieldParams The fields which will be collected.
* @return A map with key the field name and value the actual field.
*/
public static Map<String, Field> getAllFields(Class<?> clazz, FieldParam... fieldParams) {
Map<String, Field> map = new HashMap<>();
for (FieldParam fieldParam : fieldParams) {
if (!getInstance().isCompatible(fieldParam.versionParam)) continue;
try {
map.put(fieldParam.field, getDeclaredField(clazz, fieldParam.field));
} catch (NoSuchFieldException ignored) {
try {
map.put(fieldParam.field, getField(clazz, fieldParam.field));
} catch (NoSuchFieldException ex) {
ex.printStackTrace();
}
}
}
return map;
}
/**
* Retrieves methods from a class based on the specified MethodParams.
* @param clazz The class of the methods.
* @param methodParams The methods which will be collected.
* @return A map with key the method name and value the actual method.
*/
public static Map<String, Method> getAllMethods(Class<?> clazz, MethodParam... methodParams) {
Map<String, Method> map = new HashMap<>();
for (MethodParam methodParam : methodParams) {
if (!getInstance().isCompatible(methodParam.versionParam)) continue;
try {
map.put(methodParam.method, getDeclaredMethod(clazz, methodParam.method, methodParam.params));
} catch (NoSuchMethodException ignored) {
try {
map.put(methodParam.method, getMethod(clazz, methodParam.method, methodParam.params));
} catch (NoSuchMethodException ex) {
ex.printStackTrace();
}
}
}
return map;
}
/**
* Invokes a method on an instance.
* Will return null if method not present in map.
* @param map The map with methods.
* @param instance The instance of the class.
* @param methodName The name of the method.
* @param params The parameters of the method.
* @return The object returned by the method, or null if not present in map.
* @throws InvocationTargetException If the method call produced an exception.
* @throws IllegalAccessException When prohibited access to the method.
*/
public static Object invoke(Map<String, Method> map, Object instance, String methodName, Object... params)
throws InvocationTargetException, IllegalAccessException {
Method method = map.get(methodName);
if (method == null) return null;
return method.invoke(instance, params);
}
/**
* Retrieves the specified field from an object instance.
* Returns null if the field is not in the map.
* @param map The map with fields.
* @param instance The instance of the class.
* @param fieldName The field name.
* @throws IllegalAccessException When prohibited access to the field.
*/
public static Object get(Map<String, Field> map, Object instance, String fieldName) throws IllegalAccessException {
Field field = map.get(fieldName);
if (field == null) return null;
return field.get(instance);
}
/**
* Sets the specified field to the specified value.
* Will silently fail if the field is not in the map.
* @param map The map with fields.
* @param instance The instance of the class.
* @param fieldName The field name.
* @param value The value to set the field to.
* @throws IllegalAccessException When prohibited access to the field.
*/
public static void set(Map<String, Field> map, Object instance, String fieldName, Object value)
throws IllegalAccessException {
Field field = map.get(fieldName);
if (field == null) return;
field.set(instance, value);
}
}

View file

@ -0,0 +1,30 @@
package net.frankheijden.serverutils.common.reflection;
public class VersionParam {
public static VersionParam ALL_VERSIONS = new VersionParam(Integer.MIN_VALUE, Integer.MAX_VALUE);
public int min;
public int max;
private VersionParam(int min, int max) {
this.min = min;
this.max = max;
}
public static VersionParam versionOf(int ver) {
return new VersionParam(ver, ver);
}
public static VersionParam between(int min, int max) {
return new VersionParam(min, max);
}
public static VersionParam min(int min) {
return between(min, Integer.MAX_VALUE);
}
public static VersionParam max(int max) {
return between(Integer.MIN_VALUE, max);
}
}

View file

@ -0,0 +1,83 @@
package net.frankheijden.serverutils.common.utils;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
public class FileUtils {
private static final String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:77.0)"
+ " Gecko/20100101"
+ " Firefox/77.0";
/**
* Downloads file from a URL to a file location.
* @param urlString The url to download.
* @param target The location to save the output to.
* @throws IOException If an I/O exception occurs.
*/
public static void download(String urlString, File target) throws IOException {
try (InputStream is = stream(urlString)) {
if (is == null) return;
try (ReadableByteChannel rbc = Channels.newChannel(is);
FileOutputStream fos = new FileOutputStream(target)) {
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
}
}
}
/**
* Opens a stream to an url.
* @param url The url to stream.
* @return An InputStream of the url.
* @throws IOException If an I/O exception occurs.
*/
public static InputStream stream(String url) throws IOException {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestProperty("User-Agent", USER_AGENT);
conn.setConnectTimeout(10000);
int res = conn.getResponseCode();
return (res >= 200 && res <= 299) ? conn.getInputStream() : conn.getErrorStream();
}
/**
* Reads all bytes from a reader and appends them to a string result.
* @param reader The reader to read from.
* @return All byte characters.
* @throws IOException If an I/O exception occurs.
*/
public static String readAll(BufferedReader reader) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = reader.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
/**
* Reads an url and converts it into a JsonElement.
* @param url The url to read from.
* @return The JsonElement.
* @throws IOException If an I/O exception occurs.
*/
public static JsonElement readJsonFromUrl(String url) throws IOException {
try (InputStream is = stream(url)) {
if (is == null) return null;
BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
String jsonText = readAll(reader);
return new JsonParser().parse(jsonText);
}
}
}

View file

@ -0,0 +1,67 @@
package net.frankheijden.serverutils.common.utils;
import java.util.List;
public class ListBuilder<T> {
private final List<T> list;
private ListFormat<T> formatter;
private String seperator;
private String lastSeperator;
private ListBuilder(List<T> list) {
this.list = list;
}
public static <T> ListBuilder<T> create(List<T> list) {
return new ListBuilder<>(list);
}
/**
* Creates a pre-defined ListBuilder with type String.
* @param list The collection to be used.
* @return The ListBuilder.
*/
@SuppressWarnings("unchecked")
public static ListBuilder<String> createStrings(List<? extends String> list) {
ListBuilder<String> builder = create((List<String>) list);
builder.format(ListFormat.stringFormat);
return builder;
}
public ListBuilder<T> format(ListFormat<T> formatter) {
this.formatter = formatter;
return this;
}
public ListBuilder<T> seperator(String seperator) {
this.seperator = seperator;
return this;
}
public ListBuilder<T> lastSeperator(String lastSeperator) {
this.lastSeperator = lastSeperator;
return this;
}
@Override
public String toString() {
if (list.size() == 1) {
return formatter.format(list.iterator().next());
} else {
StringBuilder sb = new StringBuilder();
int i = 1;
for (T t : list) {
sb.append(formatter.format(t));
if (i == list.size() - 1 && lastSeperator != null) {
sb.append(lastSeperator);
} else if (i != list.size() && seperator != null) {
sb.append(seperator);
}
i++;
}
return sb.toString();
}
}
}

View file

@ -0,0 +1,9 @@
package net.frankheijden.serverutils.common.utils;
public interface ListFormat<T> {
ListFormat<String> stringFormat = String::toString;
String format(T t);
}

View file

@ -0,0 +1,41 @@
package net.frankheijden.serverutils.common.utils;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
public class MapUtils {
/**
* Removes keys from a map using a predicate.
* @param map The map.
* @param predicate The predicate used to test removal.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static void removeKeys(Map map, Predicate<Object> predicate) {
Set<Object> keysToRemove = new HashSet<>();
map.forEach((k, v) -> {
if (predicate.test(k)) {
keysToRemove.add(k);
}
});
keysToRemove.forEach(map::remove);
}
/**
* Removes values from a map using a predicate.
* @param map The map.
* @param predicate The predicate used to test removal.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static void removeValues(Map map, Predicate<Object> predicate) {
Set<Object> keysToRemove = new HashSet<>();
map.forEach((k, v) -> {
if (predicate.test(v)) {
keysToRemove.add(k);
}
});
keysToRemove.forEach(map::remove);
}
}

View file

@ -0,0 +1,30 @@
package net.frankheijden.serverutils.common.utils;
import java.util.function.Predicate;
import java.util.logging.Filter;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
public class PredicateFilter implements Filter {
private Predicate<LogRecord> predicate;
private Filter filter;
public void setPredicate(Predicate<LogRecord> predicate) {
this.predicate = predicate;
}
public void start(Logger logger) {
this.filter = logger.getFilter();
logger.setFilter(this);
}
public void stop(Logger logger) {
logger.setFilter(filter);
}
@Override
public boolean isLoggable(LogRecord record) {
return predicate.test(record);
}
}

View file

@ -0,0 +1,37 @@
package net.frankheijden.serverutils.common.utils;
import java.util.regex.Pattern;
public class VersionUtils {
private static final Pattern integerPattern = Pattern.compile("[^0-9]");
/**
* Compares two versions in X.X.X format.
* Returns true if version is newer than the old one.
* @param oldVersion The old version.
* @param newVersion The new version.
* @return true iff new version is newer than old version.
*/
public static boolean isNewVersion(String oldVersion, String newVersion) {
if (oldVersion == null || newVersion == null) return false;
String[] oldVersionSplit = oldVersion.split("\\.");
String[] newVersionSplit = newVersion.split("\\.");
int i = 0;
while (i < oldVersionSplit.length && i < newVersionSplit.length) {
int o = extractInteger(oldVersionSplit[i]);
int n = extractInteger(newVersionSplit[i]);
if (i != oldVersionSplit.length - 1 && i != newVersionSplit.length - 1) {
if (n < o) return false;
}
if (n > o) return true;
i++;
}
return false;
}
private static Integer extractInteger(String str) {
return Integer.parseInt(integerPattern.matcher(str).replaceAll(""));
}
}

View file

@ -0,0 +1,67 @@
package net.frankheijden.serverutils.common.utils;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;
import org.junit.jupiter.api.Test;
class ListBuilderTest {
private final String seperator = ", ";
private final String lastSeperator = " and ";
@Test
void testToStringOneElement() {
String list = ListBuilder.createStrings(singletonList("Nice"))
.seperator(seperator)
.lastSeperator(lastSeperator)
.toString();
assertEquals("Nice", list);
}
@Test
void testToStringTwoElements() {
String list = ListBuilder.createStrings(asList("Nice", "List"))
.seperator(seperator)
.lastSeperator(lastSeperator)
.toString();
assertEquals("Nice and List", list);
}
@Test
void testToStringMultipleElements() {
String list = ListBuilder.createStrings(asList("Nice", "List", "You", "Having", "There"))
.seperator(seperator)
.lastSeperator(lastSeperator)
.toString();
assertEquals("Nice, List, You, Having and There", list);
}
@Test
void testToStringCustomFormat() {
List<TestObject> objects = asList(
new TestObject("pre1", 2),
new TestObject("pre2", 3),
new TestObject("pre3", 4)
);
String list = ListBuilder.create(objects)
.format(obj -> obj.prefix + "-" + obj.value)
.seperator("; ")
.lastSeperator(" and at last ")
.toString();
assertEquals("pre1-2; pre2-3 and at last pre3-4", list);
}
private static class TestObject {
private final String prefix;
private final int value;
public TestObject(String prefix, int value) {
this.prefix = prefix;
this.value = value;
}
}
}

View file

@ -0,0 +1,42 @@
package net.frankheijden.serverutils.common.utils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.of;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
class VersionUtilsTest {
@ParameterizedTest(name = "old = {0}, new = {1}, expected = {2}")
@MethodSource("versionGenerator")
void isNewVersion(String oldVersion, String newVersion, boolean expected) {
assertThat(VersionUtils.isNewVersion(oldVersion, newVersion)).isEqualTo(expected);
}
private static Stream<Arguments> versionGenerator() {
return Stream.of(
of("0", "1", true),
of("1", "0", false),
of("9", "10", true),
of("10", "9", false),
of("-1", "5", true),
of("5", "-1", false),
of("10.1", "10.0", false),
of("100.0", "120.0", true),
of("1.0.0", "1.0.1", true),
of("1.0.0", "1.1.0", true),
of("1.0.0", "2.0.0", true),
of("0.0.1", "0.0.1", false),
of("0.0.1", "0.0.0", false),
of("0.1.0", "0.0.1", false),
of("1.0.0", "0.0.1", false),
of("1.1.0", "0.1.1", false),
of("1.0.0.0", "1.0.0.1", true),
of("1.0.1-DEV", "1.0.2", true)
);
}
}