package io.cattle.platform.eventing.annotation;
import io.cattle.platform.async.utils.TimeoutException;
import io.cattle.platform.eventing.EventListener;
import io.cattle.platform.eventing.PoolSpecificListener;
import io.cattle.platform.eventing.model.Event;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.lock.LockCallbackNoReturn;
import io.cattle.platform.lock.LockManager;
import io.cattle.platform.lock.definition.LockDefinition;
import io.cattle.platform.lock.exception.FailedToAcquireLockException;
import io.cattle.platform.util.exception.ExceptionUtils;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MethodInvokingListener implements EventListener, PoolSpecificListener {
private static final Logger log = LoggerFactory.getLogger(MethodInvokingListener.class);
LockManager lockManager;
JsonMapper jsonMapper;
Method method;
Object target;
EventHandler handler;
boolean marshall = false;
Class<?> targetType = null;
Constructor<? extends LockDefinition> ctor = null;
public MethodInvokingListener(LockManager lockManager, JsonMapper jsonMapper, EventHandler handler, Method method, Object target) {
super();
this.lockManager = lockManager;
this.jsonMapper = jsonMapper;
this.method = method;
this.target = target;
this.handler = handler;
if (method.getParameterTypes().length > 1) {
throw new IllegalArgumentException("Illegal EventHandler method, must have 0 or 1 arguments [" + method + "]");
} else if (method.getParameterTypes().length == 1) {
targetType = method.getParameterTypes()[0];
if (targetType != Event.class) {
marshall = true;
}
}
if (handler.lock() != LockDefinition.class) {
try {
ctor = handler.lock().getConstructor(Event.class);
} catch (SecurityException e) {
throw new IllegalStateException("Failed to get constructor with Event.class for [" + handler.lock() + "]");
} catch (NoSuchMethodException e) {
throw new IllegalStateException("Failed to get constructor with Event.class for [" + handler.lock() + "]");
}
}
}
@Override
public void onEvent(final Event event) {
final Object arg;
if (marshall) {
arg = jsonMapper.convertValue(event, targetType);
} else {
arg = event;
}
try {
lockManager.lock(getLock(event), new LockCallbackNoReturn() {
@Override
public void doWithLockNoResult() {
try {
method.invoke(target, arg);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
} catch (InvocationTargetException e) {
ExceptionUtils.rethrowRuntime(e.getCause());
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
}
}
});
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
} catch (InstantiationException e) {
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
} catch (InvocationTargetException e) {
ExceptionUtils.rethrowRuntime(e.getCause());
throw new IllegalStateException("Failed to invoke method [" + method + "] for event [" + event + "", e);
} catch (TimeoutException | FailedToAcquireLockException e) {
log.info(e.getMessage() + " for event [" + event + "]");
}
}
protected LockDefinition getLock(Event event) throws IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
return ctor == null ? null : ctor.newInstance(event);
}
@Override
public String getPoolKey() {
if (target instanceof PoolSpecificListener) {
;
return ((PoolSpecificListener) target).getPoolKey();
}
return handler.poolKey();
}
}