|
|
@@ -1,189 +1,188 @@
|
|
|
-/*
|
|
|
- * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
- * @copyright Ranides Atterwim
|
|
|
- * @license WTFPL
|
|
|
- * @url http://ranides.net/projects/assira
|
|
|
- */
|
|
|
-package net.ranides.assira.events;
|
|
|
-
|
|
|
-import java.lang.reflect.Method;
|
|
|
-import java.util.LinkedList;
|
|
|
-import java.util.List;
|
|
|
-import net.ranides.assira.annotations.Meta;
|
|
|
-import net.ranides.assira.awt.AWTInvoker;
|
|
|
-import net.ranides.assira.reflection.*;
|
|
|
-import net.ranides.assira.reflection.MethodFactory.MethodPointer;
|
|
|
-import net.ranides.assira.reflection.inspect.MethodInspector;
|
|
|
-import net.ranides.assira.reflection.inspect.MethodInspector.MethodFilter;
|
|
|
-import net.ranides.assira.reflection.util.MethodUtils;
|
|
|
-import net.ranides.assira.trace.AdvLogger;
|
|
|
-import net.ranides.assira.trace.LoggerUtils;
|
|
|
-
|
|
|
-/**
|
|
|
- * Obserwator pozwalający tworzyć klasy pochodne, które bezpośrednio w deklaracji
|
|
|
- * klasy definiują odpowiednie wiązania z nadchodzącymi zdarzeniami. Każde zdarzenie
|
|
|
- * otrzymane przez obserwatora jest przekazywane do wszystkich metod spełniających
|
|
|
- * kryteria. Deklaracja metody obsługi zdarzeń ma następującą postać:
|
|
|
- * <ul>
|
|
|
- * <li>metoda pobiera tylko jeden argument</li>
|
|
|
- * <li>typ argumentu odpowiada typowi obserwowanego zdarzenia</li>
|
|
|
- * <li>metoda jest adnotowana za pomocą {@link net.ranides.assira.annotations.Meta.EventHandler}</li>
|
|
|
- * <li>{@link net.ranides.assira.annotations.Meta.EventHandler} opcjonalnie określa sposób synchronizacji metody względem innych wątków</li>
|
|
|
- * </ul>
|
|
|
- * <p>
|
|
|
- * Jeśli chcesz wiązać zdarzenia na podstawie typu <b>oraz nazwy</b>, zobacz klasę {@link NamedEventListener}.
|
|
|
- * </p>
|
|
|
- *
|
|
|
- * <div class="message-note">thread-safe class</div>
|
|
|
- *
|
|
|
- * @param <T>
|
|
|
- * @author ranides
|
|
|
- * @todo (migration) #4 events
|
|
|
- */
|
|
|
-public class ReflectEventListener<T extends Event> implements EventListener<T> {
|
|
|
-
|
|
|
- private static final AdvLogger LOGGER = LoggerUtils.getLogger();
|
|
|
-
|
|
|
- private static final Class[] SUPPORTED_ARGS = { Event.class };
|
|
|
-
|
|
|
- private static final Class[] EXCEPTION_ARGS = { Throwable.class };
|
|
|
-
|
|
|
- private final List<EventListener<Event>> listeners = new LinkedList<>();
|
|
|
-
|
|
|
- private final List<GenericMethod<?>> errorHandlers = new LinkedList<>();
|
|
|
-
|
|
|
- /**
|
|
|
- * Tworzy nowy obserwator, który przekazuje wszystkie zdarzenia do podanego
|
|
|
- * obiektu, wywołując na jego rzecz odpowiednie metody dopasowane na podstawie
|
|
|
- * typu zdarzenia. Przeczytaj opis klasy, aby poznać wymagania wobec metod obsługi zdarzeń.
|
|
|
- * @param delegator
|
|
|
- */
|
|
|
- public ReflectEventListener(Object delegator) {
|
|
|
- init(delegator);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * {@code ReflectEventListener} nie może tworzony bez pośrednio - można jedynie
|
|
|
- * tworzyć jego klasy pochodne. Po otrzymaniu zdarzenia uruchamia przy użyciu
|
|
|
- * refleksji odpowiednie metody obsługi zdarzeń. Przeczytaj opis klasy,
|
|
|
- * aby poznać wymagania wobec metod obsługi zdarzeń.
|
|
|
- */
|
|
|
- protected ReflectEventListener() {
|
|
|
- init(this);
|
|
|
- }
|
|
|
-
|
|
|
- private void init(Object delegator) {
|
|
|
- MethodFilter filter1 = MethodInspector.inobject(delegator)
|
|
|
- .follow().declared()
|
|
|
- .params(SUPPORTED_ARGS)
|
|
|
- .contravariant()
|
|
|
- .annotated(Meta.EventHandler.class);
|
|
|
- for(MethodPointer<?> pointer : filter1.pointers()) {
|
|
|
- listeners.add(wrap(delegator, pointer.reflective()));
|
|
|
- }
|
|
|
- MethodFilter filter2 = MethodInspector.inobject(delegator)
|
|
|
- .follow().declared()
|
|
|
- .params(EXCEPTION_ARGS)
|
|
|
- .contravariant()
|
|
|
- .annotated(Meta.ErrorHandler.class);
|
|
|
- for(MethodPointer<?> pointer : filter2.pointers()) {
|
|
|
- errorHandlers.add( pointer.bind(delegator) );
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public final void handleEvent(T event) {
|
|
|
- for(EventListener<Event> listener : listeners) {
|
|
|
- listener.handleEvent(event);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-/* ************************************************************************** */
|
|
|
-
|
|
|
- /**
|
|
|
- * Klasa do użycia wewnętrznego. Reprezentuje obserwatora, który po otrzymaniu
|
|
|
- * zdarzenia o podanej klasie wywoła określoną metodę na rzecz obiektu przekazanego
|
|
|
- * konstruktorowi. Adapter filtruje typ zdarzenia oraz dba o synchronizację
|
|
|
- * wywołania metody.
|
|
|
- * <p>
|
|
|
- * Obiekty typu {@code ReflectAdapter} nie mogą być tworzone bezpośrednio.
|
|
|
- * Do ich utworzenia należy użyj jednej z metod statycznych {@link #wrap}.
|
|
|
- */
|
|
|
- private final class ReflectAdapter implements EventListener<Event> {
|
|
|
- private final Class<?> type;
|
|
|
- private final boolean awt;
|
|
|
- private final boolean sync;
|
|
|
- private final Object object;
|
|
|
- private final Method method;
|
|
|
-
|
|
|
- ReflectAdapter(Class<?> type, Object object, Method method) {
|
|
|
- this.type = type;
|
|
|
- this.object = object;
|
|
|
- this.method = method;
|
|
|
- this.awt = false;
|
|
|
- this.sync = false;
|
|
|
- }
|
|
|
-
|
|
|
- ReflectAdapter(Class<?> type, Object object, Method method, boolean sync) {
|
|
|
- this.type = type;
|
|
|
- this.object = object;
|
|
|
- this.method = method;
|
|
|
- this.awt = true;
|
|
|
- this.sync = sync;
|
|
|
- }
|
|
|
-
|
|
|
- @Override
|
|
|
- public void handleEvent(Event event) {
|
|
|
- if( !type.isInstance(event) ) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if(awt) {
|
|
|
- AWTInvoker.run(sync, object, method, event);
|
|
|
- return;
|
|
|
- }
|
|
|
- try {
|
|
|
- MethodUtils.invoke(object, method, event);
|
|
|
- } catch(InvokeException incause) {
|
|
|
- Throwable cause = incause.getCause();
|
|
|
- for(GenericMethod<?> pointer : errorHandlers) {
|
|
|
- if(pointer.canCall(cause)) {
|
|
|
- try {
|
|
|
- pointer.call(cause);
|
|
|
- } catch(Exception fatal) {
|
|
|
- LOGGER.xfatal("Unexpected exception caused by: %s\n\tThread: %s\n\tObject: %s\n\tMethod: #%s\n\tEvent: %s\n\tHandler: %s", fatal, cause, Thread.currentThread().getName(), object, method.getName(), event, pointer);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- } catch(InspectException cause) {
|
|
|
- LOGGER.xerror("Internal event dispath error.\n\tThread: %s\n\tObject: %s\n\tMethod: #%s\n\tEvent: %s", cause, Thread.currentThread().getName(), object, method.getName(), event);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- };
|
|
|
-
|
|
|
- /**
|
|
|
- * Tworzy nowy obserwator-adapter, który po otrzymaniu zdarzenia wywołuję
|
|
|
- * podaną metodę na rzecz podanego obiektu. Jeśli typ zdarzenia nie odpowiada
|
|
|
- * podanej klasie, obserwator nie wykonuje żadnej akcji.
|
|
|
- * @param clazz
|
|
|
- * @param object
|
|
|
- * @param handler
|
|
|
- * @return
|
|
|
- */
|
|
|
- private EventListener<Event> wrap(Object object, Method handler) {
|
|
|
- Meta.EventHandler info = handler.getAnnotation(Meta.EventHandler.class);
|
|
|
- Class<?> type = handler.getParameterTypes()[0];
|
|
|
-
|
|
|
- switch(info.sync()) {
|
|
|
- case AWT:
|
|
|
- return new ReflectAdapter(type, object, handler, false);
|
|
|
- case AWT_WAIT:
|
|
|
- return new ReflectAdapter(type, object, handler, true);
|
|
|
- case NONE:
|
|
|
- return new ReflectAdapter(type, object, handler);
|
|
|
- default:
|
|
|
- throw new UnsupportedOperationException(info.sync() + " is not supported");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
+/*
|
|
|
+ * @author Ranides Atterwim <ranides@gmail.com>
|
|
|
+ * @copyright Ranides Atterwim
|
|
|
+ * @license WTFPL
|
|
|
+ * @url http://ranides.net/projects/assira
|
|
|
+ */
|
|
|
+package net.ranides.assira.events;
|
|
|
+
|
|
|
+import java.lang.reflect.Method;
|
|
|
+import java.util.LinkedList;
|
|
|
+import java.util.List;
|
|
|
+import net.ranides.assira.annotations.Meta;
|
|
|
+import net.ranides.assira.awt.AWTInvoker;
|
|
|
+import net.ranides.assira.reflection.*;
|
|
|
+import net.ranides.assira.reflection.MethodFactory.MethodPointer;
|
|
|
+import net.ranides.assira.reflection.inspect.MethodInspector;
|
|
|
+import net.ranides.assira.reflection.inspect.MethodInspector.MethodFilter;
|
|
|
+import net.ranides.assira.reflection.util.MethodUtils;
|
|
|
+import net.ranides.assira.trace.AdvLogger;
|
|
|
+import net.ranides.assira.trace.LoggerUtils;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Obserwator pozwalający tworzyć klasy pochodne, które bezpośrednio w deklaracji
|
|
|
+ * klasy definiują odpowiednie wiązania z nadchodzącymi zdarzeniami. Każde zdarzenie
|
|
|
+ * otrzymane przez obserwatora jest przekazywane do wszystkich metod spełniających
|
|
|
+ * kryteria. Deklaracja metody obsługi zdarzeń ma następującą postać:
|
|
|
+ * <ul>
|
|
|
+ * <li>metoda pobiera tylko jeden argument</li>
|
|
|
+ * <li>typ argumentu odpowiada typowi obserwowanego zdarzenia</li>
|
|
|
+ * <li>metoda jest adnotowana za pomocą {@link net.ranides.assira.annotations.Meta.EventHandler}</li>
|
|
|
+ * <li>{@link net.ranides.assira.annotations.Meta.EventHandler} opcjonalnie określa sposób synchronizacji metody względem innych wątków</li>
|
|
|
+ * </ul>
|
|
|
+ * <p>
|
|
|
+ * Jeśli chcesz wiązać zdarzenia na podstawie typu <b>oraz nazwy</b>, zobacz klasę {@link NamedEventListener}.
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * <div class="message-note">thread-safe class</div>
|
|
|
+ *
|
|
|
+ * @param <T>
|
|
|
+ * @author ranides
|
|
|
+ */
|
|
|
+public class ReflectEventListener<T extends Event> implements EventListener<T> {
|
|
|
+
|
|
|
+ private static final AdvLogger LOGGER = LoggerUtils.getLogger();
|
|
|
+
|
|
|
+ private static final Class[] SUPPORTED_ARGS = { Event.class };
|
|
|
+
|
|
|
+ private static final Class[] EXCEPTION_ARGS = { Throwable.class };
|
|
|
+
|
|
|
+ private final List<EventListener<Event>> listeners = new LinkedList<>();
|
|
|
+
|
|
|
+ private final List<GenericMethod<?>> errorHandlers = new LinkedList<>();
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tworzy nowy obserwator, który przekazuje wszystkie zdarzenia do podanego
|
|
|
+ * obiektu, wywołując na jego rzecz odpowiednie metody dopasowane na podstawie
|
|
|
+ * typu zdarzenia. Przeczytaj opis klasy, aby poznać wymagania wobec metod obsługi zdarzeń.
|
|
|
+ * @param delegator
|
|
|
+ */
|
|
|
+ public ReflectEventListener(Object delegator) {
|
|
|
+ init(delegator);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * {@code ReflectEventListener} nie może tworzony bez pośrednio - można jedynie
|
|
|
+ * tworzyć jego klasy pochodne. Po otrzymaniu zdarzenia uruchamia przy użyciu
|
|
|
+ * refleksji odpowiednie metody obsługi zdarzeń. Przeczytaj opis klasy,
|
|
|
+ * aby poznać wymagania wobec metod obsługi zdarzeń.
|
|
|
+ */
|
|
|
+ protected ReflectEventListener() {
|
|
|
+ init(this);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void init(Object delegator) {
|
|
|
+ MethodFilter filter1 = MethodInspector.inobject(delegator)
|
|
|
+ .follow().declared()
|
|
|
+ .params(SUPPORTED_ARGS)
|
|
|
+ .contravariant()
|
|
|
+ .annotated(Meta.EventHandler.class);
|
|
|
+ for(MethodPointer<?> pointer : filter1.pointers()) {
|
|
|
+ listeners.add(wrap(delegator, pointer.reflective()));
|
|
|
+ }
|
|
|
+ MethodFilter filter2 = MethodInspector.inobject(delegator)
|
|
|
+ .follow().declared()
|
|
|
+ .params(EXCEPTION_ARGS)
|
|
|
+ .contravariant()
|
|
|
+ .annotated(Meta.ErrorHandler.class);
|
|
|
+ for(MethodPointer<?> pointer : filter2.pointers()) {
|
|
|
+ errorHandlers.add( pointer.bind(delegator) );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final void handleEvent(T event) {
|
|
|
+ for(EventListener<Event> listener : listeners) {
|
|
|
+ listener.handleEvent(event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+/* ************************************************************************** */
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Klasa do użycia wewnętrznego. Reprezentuje obserwatora, który po otrzymaniu
|
|
|
+ * zdarzenia o podanej klasie wywoła określoną metodę na rzecz obiektu przekazanego
|
|
|
+ * konstruktorowi. Adapter filtruje typ zdarzenia oraz dba o synchronizację
|
|
|
+ * wywołania metody.
|
|
|
+ * <p>
|
|
|
+ * Obiekty typu {@code ReflectAdapter} nie mogą być tworzone bezpośrednio.
|
|
|
+ * Do ich utworzenia należy użyj jednej z metod statycznych {@link #wrap}.
|
|
|
+ */
|
|
|
+ private final class ReflectAdapter implements EventListener<Event> {
|
|
|
+ private final Class<?> type;
|
|
|
+ private final boolean awt;
|
|
|
+ private final boolean sync;
|
|
|
+ private final Object object;
|
|
|
+ private final Method method;
|
|
|
+
|
|
|
+ ReflectAdapter(Class<?> type, Object object, Method method) {
|
|
|
+ this.type = type;
|
|
|
+ this.object = object;
|
|
|
+ this.method = method;
|
|
|
+ this.awt = false;
|
|
|
+ this.sync = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ ReflectAdapter(Class<?> type, Object object, Method method, boolean sync) {
|
|
|
+ this.type = type;
|
|
|
+ this.object = object;
|
|
|
+ this.method = method;
|
|
|
+ this.awt = true;
|
|
|
+ this.sync = sync;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void handleEvent(Event event) {
|
|
|
+ if( !type.isInstance(event) ) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(awt) {
|
|
|
+ AWTInvoker.run(sync, object, method, event);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ MethodUtils.invoke(object, method, event);
|
|
|
+ } catch(InvokeException incause) {
|
|
|
+ Throwable cause = incause.getCause();
|
|
|
+ for(GenericMethod<?> pointer : errorHandlers) {
|
|
|
+ if(pointer.canCall(cause)) {
|
|
|
+ try {
|
|
|
+ pointer.call(cause);
|
|
|
+ } catch(Exception fatal) {
|
|
|
+ LOGGER.xfatal("Unexpected exception caused by: %s\n\tThread: %s\n\tObject: %s\n\tMethod: #%s\n\tEvent: %s\n\tHandler: %s", fatal, cause, Thread.currentThread().getName(), object, method.getName(), event, pointer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch(InspectException cause) {
|
|
|
+ LOGGER.xerror("Internal event dispath error.\n\tThread: %s\n\tObject: %s\n\tMethod: #%s\n\tEvent: %s", cause, Thread.currentThread().getName(), object, method.getName(), event);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tworzy nowy obserwator-adapter, który po otrzymaniu zdarzenia wywołuję
|
|
|
+ * podaną metodę na rzecz podanego obiektu. Jeśli typ zdarzenia nie odpowiada
|
|
|
+ * podanej klasie, obserwator nie wykonuje żadnej akcji.
|
|
|
+ * @param clazz
|
|
|
+ * @param object
|
|
|
+ * @param handler
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private EventListener<Event> wrap(Object object, Method handler) {
|
|
|
+ Meta.EventHandler info = handler.getAnnotation(Meta.EventHandler.class);
|
|
|
+ Class<?> type = handler.getParameterTypes()[0];
|
|
|
+
|
|
|
+ switch(info.sync()) {
|
|
|
+ case AWT:
|
|
|
+ return new ReflectAdapter(type, object, handler, false);
|
|
|
+ case AWT_WAIT:
|
|
|
+ return new ReflectAdapter(type, object, handler, true);
|
|
|
+ case NONE:
|
|
|
+ return new ReflectAdapter(type, object, handler);
|
|
|
+ default:
|
|
|
+ throw new UnsupportedOperationException(info.sync() + " is not supported");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|