Code cleanup and utility functions for plutolib

This commit is contained in:
Tefek 2020-09-03 13:56:13 +02:00
parent 27c79917c5
commit 859a23cdc9
4 changed files with 273 additions and 254 deletions

View File

@ -0,0 +1,6 @@
package cz.tefek.pluto;
public class Pluto
{
public static final boolean DEBUG_MODE = Boolean.valueOf(System.getProperty("cz.tefek.pluto.debug"));
}

View File

@ -1,25 +1,25 @@
package cz.tefek.pluto.eventsystem.staticmode; package cz.tefek.pluto.eventsystem.staticmode;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE; import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import cz.tefek.pluto.eventsystem.EventData; import cz.tefek.pluto.eventsystem.EventData;
@Retention(RUNTIME) /**
@Target(ANNOTATION_TYPE) * @author 493msi
/** *
* @author 493msi */
* @Retention(RUNTIME)
*/ @Target(ANNOTATION_TYPE)
public @interface StaticPlutoEvent public @interface StaticPlutoEvent
{ {
/** /**
* This actually does nothing. ¯\_()_/¯ Well, you can use it for improved * This actually does nothing. ¯\_()_/¯ Well, you can use it for improved
* code readability. * code readability.
* *
*/ */
Class<?> passingParamClass() default EventData.class; Class<?> passingParamClass() default EventData.class;
} }

View File

@ -1,228 +1,223 @@
package cz.tefek.pluto.eventsystem.staticmode; package cz.tefek.pluto.eventsystem.staticmode;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap; import java.util.Map.Entry;
import java.util.List;
import java.util.Map; import java.lang.annotation.Annotation;
import java.util.Map.Entry; import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import cz.tefek.pluto.eventsystem.EventData;
import java.lang.reflect.Modifier; import cz.tefek.pluto.io.logger.Logger;
import cz.tefek.pluto.io.logger.SmartSeverity;
import cz.tefek.pluto.eventsystem.EventData;
import cz.tefek.pluto.io.logger.Logger; /**
import cz.tefek.pluto.io.logger.SmartSeverity; * A universal event manager. Register an event {@link Annotation} of your
* choice (must be annotated with {@link StaticPlutoEvent &commat;Event}), then
/** * annotate some public static method and you are done! Now you can trigger the
* A universal event manager. Register an event {@link Annotation} of your * callbacks with ease. Multiple per-method events are possible! <i>Note that
* choice (must be annotated with {@link StaticPlutoEvent &commat;Event}), then * event callbacks require a data-passing parameter
* annotate some public static method and you are done! Now you can trigger the * <tt>(extends {@link EventData})</tt>. The method will not be invoked
* callbacks with ease. Multiple per-method events are possible! <i>Note that * otherwise!</i>
* event callbacks require a data-passing parameter *
* <tt>(extends {@link EventData})</tt>. The method will not be invoked * @author 493msi
* otherwise!</i> *
* */
* @author 493msi public class StaticPlutoEventManager
* {
*/ private static Map<Class<? extends Annotation>, List<Method>> eventRegistry = new HashMap<>();
public class StaticPlutoEventManager private static List<Method> orphans = new ArrayList<>();
{
private static Map<Class<? extends Annotation>, List<Method>> eventRegistry = new HashMap<Class<? extends Annotation>, List<Method>>(); public static void registerEventHandler(Class<?> clazz)
private static List<Method> orphans = new ArrayList<Method>(); {
Method[] methods = clazz.getMethods();
public static void registerEventHandler(Class<?> clazz)
{ int methodsFound = 0;
Method[] methods = clazz.getMethods();
for (Method method : methods)
int methodsFound = 0; {
// The callback method must be static and public!
for (Method method : methods) if (!(Modifier.isStatic(method.getModifiers()) && Modifier.isPublic(method.getModifiers())))
{ {
// The callback method must be static and public! continue;
if (!(Modifier.isStatic(method.getModifiers()) && Modifier.isPublic(method.getModifiers()))) }
{
continue; for (Annotation annotation : method.getDeclaredAnnotations())
} {
if (annotation.annotationType().getAnnotation(StaticPlutoEvent.class) != null)
for (Annotation annotation : method.getDeclaredAnnotations()) {
{ methodsFound++;
if (annotation.annotationType().getAnnotation(StaticPlutoEvent.class) != null)
{ var parentAnnotation = eventRegistry.get(annotation.annotationType());
methodsFound++;
// Find a parent annotation.
var parentAnnotation = eventRegistry.get(annotation.annotationType()); if (parentAnnotation != null)
{
// Find a parent annotation. parentAnnotation.add(method);
if (parentAnnotation != null) }
{ // No parent annotation and fix for methods with 2+ event
parentAnnotation.add(method); // annotations.
} else if (!orphans.contains(method))
// No parent annotation and fix for methods with 2+ event {
// annotations. orphans.add(method);
else if (!orphans.contains(method)) }
{ }
orphans.add(method); }
} }
}
} Logger.log(SmartSeverity.EVENT_PLUS, "Event handler " + clazz.getCanonicalName() + " scan found " + methodsFound + " method callback(s).");
} }
Logger.log(SmartSeverity.EVENT_PLUS, "Event handler " + clazz.getCanonicalName() + " scan found " + methodsFound + " method callback(s)."); public static void registerEvent(Class<? extends Annotation> annotation)
} {
// @Event is necessary.
public static void registerEvent(Class<? extends Annotation> annotation) if (annotation.getAnnotation(StaticPlutoEvent.class) != null)
{ {
// @Event is necessary. if (eventRegistry.containsKey(annotation))
if (annotation.getAnnotation(StaticPlutoEvent.class) != null) {
{ Logger.log(SmartSeverity.EVENT_ERROR, "Annotation " + annotation.getCanonicalName() + " is already registered!");
if (eventRegistry.containsKey(annotation)) return;
{ }
Logger.log(SmartSeverity.EVENT_ERROR, "Annotation " + annotation.getCanonicalName() + " is already registered!");
return; eventRegistry.put(annotation, new ArrayList<>());
}
else Logger.log(SmartSeverity.EVENT_PLUS, "Event " + annotation.getCanonicalName() + " successfully registered!");
{
eventRegistry.put(annotation, new ArrayList<Method>()); short retroactivelyFound = 0;
Logger.log(SmartSeverity.EVENT_PLUS, "Event " + annotation.getCanonicalName() + " successfully registered!"); // Let's check all existing event Methods for this event.
for (Entry<Class<? extends Annotation>, List<Method>> entry : eventRegistry.entrySet())
short retroactivelyFound = 0; {
// Checking the Method list for this event would make no
// Let's check all existing event Methods for this event. // sense.
for (Entry<Class<? extends Annotation>, List<Method>> entry : eventRegistry.entrySet()) if (annotation.equals(entry.getKey()))
{ {
// Checking the Method list for this event would make no continue;
// sense. }
if (annotation.equals(entry.getKey()))
{ for (Method method : entry.getValue())
continue; {
} // Just in case.
if (method.isAnnotationPresent(annotation))
for (Method method : entry.getValue()) {
{ eventRegistry.get(annotation).add(method);
// Just in case. retroactivelyFound++;
if (method.isAnnotationPresent(annotation)) }
{ }
eventRegistry.get(annotation).add(method); }
retroactivelyFound++;
} Logger.log(SmartSeverity.EVENT_PLUS, "Retroactive method checking found " + retroactivelyFound + " item(s).");
}
} // Let's check the Method orphanage for some potential
// candidates.
Logger.log(SmartSeverity.EVENT_PLUS, "Retroactive method checking found " + retroactivelyFound + " item(s).");
short orphansFound = 0;
// Let's check the Method orphanage for some potential
// candidates. int orphansBefore = orphans.size();
short orphansFound = 0; List<Method> foundParents = new ArrayList<>();
int orphansBefore = orphans.size(); for (Method method : orphans)
{
List<Method> foundParents = new ArrayList<Method>(); if (method.isAnnotationPresent(annotation))
{
for (Method method : orphans) foundParents.add(method);
{
if (method.isAnnotationPresent(annotation)) // No duplicates.
{ if (!eventRegistry.get(annotation).contains(method))
foundParents.add(method); {
eventRegistry.get(annotation).add(method);
// No duplicates. orphansFound++;
if (!eventRegistry.get(annotation).contains(method)) }
{ }
eventRegistry.get(annotation).add(method); }
orphansFound++;
} orphans.removeAll(foundParents);
}
} Logger.log(SmartSeverity.EVENT_PLUS, orphansFound + " orphan method(s) was/were bound and " + (orphansBefore - orphans.size()) + " removed from the storage!");
}
orphans.removeAll(foundParents); else
{
Logger.log(SmartSeverity.EVENT_PLUS, orphansFound + " orphan method(s) was/were bound and " + (orphansBefore - orphans.size()) + " removed from the storage!"); Logger.log(SmartSeverity.EVENT_ERROR, "Annotation " + annotation.getCanonicalName() + " is not annotated with @Event, can't register it.");
} }
} }
else
{ public static void fireEvent(Class<? extends Annotation> event, EventData data)
Logger.log(SmartSeverity.EVENT_ERROR, "Annotation " + annotation.getCanonicalName() + " is not annotated with @Event, can't register it."); {
} if (event.getAnnotation(StaticPlutoEvent.class) != null)
} {
List<Method> methodList = eventRegistry.get(event);
public static void fireEvent(Class<? extends Annotation> event, EventData data)
{ if (methodList != null)
if (event.getAnnotation(StaticPlutoEvent.class) != null) {
{ for (Method m : methodList)
List<Method> methodList = eventRegistry.get(event); {
// If a method contains more than one parameter, the most
if (methodList != null) // viable one will be chosen. Also, methods with no
{ // parameters are not valid.
for (Method m : methodList)
{ Class<?>[] params = m.getParameterTypes();
// If a method contains more than one parameter, the most
// viable one will be chosen. Also, methods with no Class<?> mostSuitableParam = null;
// parameters are not valid. EventData[] paramOut = new EventData[params.length];
Class<?>[] params = m.getParameterTypes(); if (params.length == 0)
{
Class<?> mostSuitableParam = null; Logger.log(SmartSeverity.EVENT_WARNING, "Method " + m.toGenericString() + " has no parameters, will not be invoked by event!");
EventData[] paramOut = new EventData[params.length]; }
if (params.length == 0) for (int i = 0; i < params.length; i++) {
{ Class<?> parameter = params[i];
Logger.log(SmartSeverity.EVENT_WARNING, "Method " + m.toGenericString() + " has no parameters, will not be invoked by event!");
} if (!EventData.class.isAssignableFrom(parameter)) {
Logger.log(SmartSeverity.EVENT_ERROR, "Method " + m.toGenericString() + " contains invalid parameters. Only EventData instances are permitted.");
for (int i = 0; i < params.length; i++) mostSuitableParam = null;
{ break;
Class<?> parameter = params[i]; }
if (!EventData.class.isAssignableFrom(parameter)) if (parameter.isInstance(data))
{ {
Logger.log(SmartSeverity.EVENT_ERROR, "Method " + m.toGenericString() + " contains invalid parameters. Only EventData instances are permitted."); if (mostSuitableParam == null)
mostSuitableParam = null; {
break; mostSuitableParam = parameter;
} paramOut[i] = data;
}
if (mostSuitableParam == null && parameter.isInstance(data)) else if (mostSuitableParam.isAssignableFrom(parameter))
{ {
mostSuitableParam = parameter; mostSuitableParam = parameter;
paramOut[i] = data; Arrays.fill(paramOut, 0, i, null);
} paramOut[i] = data;
}
if (parameter.isInstance(data) && mostSuitableParam.isAssignableFrom(parameter)) }
{ }
mostSuitableParam = parameter;
paramOut = new EventData[params.length]; if (mostSuitableParam != null)
paramOut[i] = data; {
} try
} {
m.invoke(null, (Object[]) paramOut);
if (mostSuitableParam != null) }
{ catch (Exception e)
try {
{ Logger.logException(e);
m.invoke(null, (Object[]) paramOut); }
} }
catch (Exception e) }
{ }
Logger.logException(e); else
} {
} Logger.log(SmartSeverity.EVENT_ERROR, "There is no event like " + event.getCanonicalName() + " registered.");
} }
} }
else else
{ {
Logger.log(SmartSeverity.EVENT_ERROR, "There is no event like " + event.getCanonicalName() + " registered."); Logger.log(SmartSeverity.EVENT_ERROR, event.getCanonicalName() + " is not an event!");
} }
} }
else
{ public static void unregisterAll()
Logger.log(SmartSeverity.EVENT_ERROR, event.getCanonicalName() + " is not an event!"); {
} eventRegistry.clear();
} orphans.clear();
}
public static void unregisterAll() }
{
eventRegistry.clear();
orphans.clear();
}
}

View File

@ -1,7 +1,10 @@
package cz.tefek.pluto.io.asl.resource; package cz.tefek.pluto.io.asl.resource;
import java.io.IOException;
import java.nio.file.Files;
/** /**
* Doesn't do much right now. Just holds the default resource location. * Helper functions for {@link ResourceAddress}es.
* *
* @author 493msi * @author 493msi
*/ */
@ -9,4 +12,19 @@ public class ResourceHelper
{ {
public static final String GLOBAL_ROOT = ""; public static final String GLOBAL_ROOT = "";
public static final String DEFAULT_RESOURCE_ROOT = GLOBAL_ROOT + "data"; public static final String DEFAULT_RESOURCE_ROOT = GLOBAL_ROOT + "data";
/**
* Retrieves the size of the file denoted by {@link ResourceAddress}
*
* @param addr The input {@link ResourceAddress}
*
* @throws IOException On I/O errors.
*
* @return the file size
* @since 0.3
*/
public static long fileSize(ResourceAddress addr) throws IOException
{
return Files.size(addr.toNIOPath());
}
} }