package org.limewire.ui.swing.event;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
import org.bushe.swing.event.EventService;
import org.bushe.swing.event.EventServiceExistsException;
import org.bushe.swing.event.EventServiceLocator;
import org.bushe.swing.event.annotation.EventSubscriber;
import org.bushe.swing.event.annotation.EventTopicPatternSubscriber;
import org.bushe.swing.event.annotation.EventTopicSubscriber;
import org.bushe.swing.event.annotation.ProxyTopicPatternSubscriber;
import org.bushe.swing.event.annotation.ProxyTopicSubscriber;
import org.bushe.swing.event.annotation.ReferenceStrength;
public class EventAnnotationProcessor {
private EventAnnotationProcessor() {
}
public static void subscribe(Object subscriber) {
if (subscriber == null) {
return;
}
Class<?> cl = subscriber.getClass();
Method[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
if (method.isAnnotationPresent(RuntimeTopicEventSubscriber.class)) {
RuntimeTopicEventSubscriber annotation = method.getAnnotation(RuntimeTopicEventSubscriber.class);
if (annotation != null) {
process(annotation, subscriber, method);
}
} else if (method.isAnnotationPresent(RuntimeTopicPatternEventSubscriber.class)) {
RuntimeTopicPatternEventSubscriber annotation = method.getAnnotation(RuntimeTopicPatternEventSubscriber.class);
if (annotation != null) {
process(annotation, subscriber, method);
}
}
}
org.bushe.swing.event.annotation.AnnotationProcessor.process(subscriber);
}
private static void process(final RuntimeTopicEventSubscriber annotation, final Object subscriber, final Method method) {
EventTopicSubscriber eventTopicSubscriber = new EventTopicSubscriber() {
@Override
public Class<? extends EventService> autoCreateEventServiceClass() {
return annotation.autoCreateEventServiceClass();
}
@Override
public String eventServiceName() {
return annotation.eventServiceName();
}
@Override
public ReferenceStrength referenceStrength() {
return ReferenceStrength.WEAK;
}
@Override
public String topic() {
String t = getTopic(annotation.methodName(), subscriber, method);
return t;
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
};
process(eventTopicSubscriber, subscriber, method);
}
private static void process(final RuntimeTopicPatternEventSubscriber annotation, final Object subscriber, final Method method) {
EventTopicPatternSubscriber eventTopicSubscriber = new EventTopicPatternSubscriber() {
@Override
public Class<? extends EventService> autoCreateEventServiceClass() {
return annotation.autoCreateEventServiceClass();
}
@Override
public String eventServiceName() {
return annotation.eventServiceName();
}
@Override
public ReferenceStrength referenceStrength() {
return ReferenceStrength.WEAK;
}
@Override
public boolean exact() {
return annotation.exact();
}
@Override
public String topicPattern() {
String t = getTopic(annotation.methodName(), subscriber, method);
return t;
}
@Override
public Class<? extends Annotation> annotationType() {
return annotation.annotationType();
}
};
process(eventTopicSubscriber, subscriber, method);
}
private static String getTopic(String methodName, Object subscriber, Method method) {
try {
//TODO: Confirm that subscriber class has this method
Method runtimeEvalMethod = subscriber.getClass().getMethod(methodName, new Class[0]);
return runtimeEvalMethod.invoke(subscriber, new Object[0]).toString();
} catch (SecurityException e) {
throw new RuntimeException("Could not retrieve method for subscription. Method: " + methodName, e);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Could not retrieve method for subscription. Method: " + methodName, e);
} catch (InvocationTargetException e) {
e.getTargetException().printStackTrace();
throw new RuntimeException("Could not invoke method for subscription. Method: " + methodName, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not invoke method for subscription. Method: " + methodName, e);
}
}
private static void process(EventTopicSubscriber topicAnnotation, Object obj, Method method) {
String topic = topicAnnotation.topic();
if (topic == null) {
throw new IllegalArgumentException("Topic cannot be null for EventTopicSubscriber annotation");
}
Class<? extends EventService> eventServiceClass = topicAnnotation.autoCreateEventServiceClass();
String eventServiceName = topicAnnotation.eventServiceName();
EventService eventService = getEventServiceFromAnnotation(eventServiceName, eventServiceClass);
ProxyTopicSubscriber subscriber = new ProxyTopicSubscriber(obj, method, topicAnnotation.referenceStrength(), eventService, topic);
eventService.subscribeStrongly(topic, subscriber);
}
private static void process(EventTopicPatternSubscriber topicPatternAnnotation, Object obj, Method method) {
String topic = topicPatternAnnotation.topicPattern();
if (topic == null) {
throw new IllegalArgumentException("TopicPattern cannot be null for EventTopicPatternSubscriber annotation");
}
Class<? extends EventService> eventServiceClass = topicPatternAnnotation.autoCreateEventServiceClass();
String eventServiceName = topicPatternAnnotation.eventServiceName();
EventService eventService = getEventServiceFromAnnotation(eventServiceName, eventServiceClass);
Pattern pattern = Pattern.compile(topic);
ProxyTopicPatternSubscriber subscriber = new ProxyTopicPatternSubscriber(obj, method, topicPatternAnnotation.referenceStrength(),
eventService, topic, pattern);
eventService.subscribeStrongly(pattern, subscriber);
}
private static EventService getEventServiceFromAnnotation(String eventServiceName, Class<? extends EventService> eventServiceClass) {
EventService eventService = EventServiceLocator.getEventService(eventServiceName);
if (eventService == null) {
if (EventServiceLocator.SERVICE_NAME_EVENT_BUS.equals(eventServiceName)) {
eventService = EventServiceLocator.getSwingEventService();
} else {
// The event service does not yet exist, create it
try {
eventService = eventServiceClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Could not instance of create EventService class " + eventServiceClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Could not instance of create EventService class " + eventServiceClass, e);
}
try {
EventServiceLocator.setEventService(eventServiceName, eventService);
} catch (EventServiceExistsException e) {
// ignore it, it's OK
eventService = EventServiceLocator.getEventService(eventServiceName);
}
}
}
return eventService;
}
public static void unsubscribe(Object subscriber) {
if (subscriber == null) {
return;
}
Class<?> cl = subscriber.getClass();
Method[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
RuntimeTopicEventSubscriber dynamicTopicSubscriber = method
.getAnnotation(RuntimeTopicEventSubscriber.class);
if (dynamicTopicSubscriber != null) {
EventService eventService = EventServiceLocator
.getEventService(dynamicTopicSubscriber.eventServiceName());
eventService.unsubscribe(getTopic(dynamicTopicSubscriber.methodName(), subscriber,
method), subscriber);
}
RuntimeTopicPatternEventSubscriber dynamicTopicPatternSubscriber = method
.getAnnotation(RuntimeTopicPatternEventSubscriber.class);
if (dynamicTopicPatternSubscriber != null) {
EventService eventService = EventServiceLocator
.getEventService(dynamicTopicPatternSubscriber.eventServiceName());
eventService.unsubscribe(getTopic(dynamicTopicPatternSubscriber.methodName(),
subscriber, method), subscriber);
}
EventSubscriber classAnnotation = method.getAnnotation(EventSubscriber.class);
if (classAnnotation != null) {
EventService eventService = EventServiceLocator.getEventService(classAnnotation.eventServiceName());
if (classAnnotation.exact()) {
eventService.unsubscribeExactly(classAnnotation.eventClass(), subscriber);
} else {
eventService.unsubscribe(classAnnotation.eventClass(), subscriber);
}
}
EventTopicSubscriber topicAnnotation = method.getAnnotation(EventTopicSubscriber.class);
if (topicAnnotation != null) {
EventService eventService = EventServiceLocator.getEventService(topicAnnotation.eventServiceName());
eventService.unsubscribe(topicAnnotation.topic(), subscriber);
}
EventTopicPatternSubscriber topicPatternAnnotation = method.getAnnotation(EventTopicPatternSubscriber.class);
if (topicPatternAnnotation != null) {
EventService eventService = EventServiceLocator.getEventService(topicPatternAnnotation.eventServiceName());
eventService.unsubscribe(Pattern.compile(topicPatternAnnotation.topicPattern()),
subscriber);
}
}
}
}