All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.remondis.limbus.events.MulticastHandler Maven / Gradle / Ivy

Go to download

Module for a datastructure that allows to multicast method invocations to subscribers.

There is a newer version: 3.1.0
Show newest version
package com.remondis.limbus.events;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.remondis.limbus.utils.ReflectionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Implementation of an {@link EventMulticaster} that uses {@link Proxy}-classes to multicast event calls to
 * subscribers.
 * 

* Note: The {@link EventMulticaster} can be configured to act in to different ways: *

    *
  • If throwException * is false and a subscriber throws an exception this only creates a warning in the * logs.
  • *
  • If throwException is true
  • a potential exception will be re-thrown by the multicast * event method. The processing of further subscribers is then aborted and not all subscribers may be notified. *

    * * @author schuettec * * @param */ final class MulticastHandler implements EventMulticaster { private static final Logger log = LoggerFactory.getLogger(MulticastHandler.class); private ConcurrentLinkedQueue subscribers; private I localProxy; private I silentLocalProxy; /** * Holds the handler that re-throws exceptions from subscribers */ private InvocationHandler throwingInvocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Iterator it = subscribers.iterator(); while (it.hasNext()) { I subscriber = it.next(); try { method.invoke(subscriber, args); } catch (InvocationTargetException e) { // Translate to the cause of the invocation target exception because thats the business logic exception. throw e.getCause(); } catch (Exception e) { String message = String.format("Cannot multicast event to subscriber of type %s", subscriber.getClass() .getName()); throw new Exception(message, e); } } return null; } }; /** * Holds the invocation handler that supresses exceptions from subscribers */ private InvocationHandler silentInvocationHandler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Iterator it = subscribers.iterator(); while (it.hasNext()) { I subscriber = it.next(); try { method.invoke(subscriber, args); } catch (InvocationTargetException e) { // Skip exceptions thrown from the implementation. // Translate to the cause of the invocation target exception because thats the business logic exception. // Be silent but log exceptions due to implementation faults. logInvocationError(subscriber, e.getCause()); } catch (Exception e) { // Be silent but log exceptions due to implementation faults. logInvocationError(subscriber, e); } } return null; } private void logInvocationError(I subscriber, Throwable e) { log.debug(String.format("Cannot multicast event to subscriber of type %s", subscriber.getClass() .getName()), e); } }; MulticastHandler(Class subscriberInterface) { this.subscribers = new ConcurrentLinkedQueue(); this.localProxy = createMulticasterProxy(subscriberInterface, throwingInvocationHandler); this.silentLocalProxy = createMulticasterProxy(subscriberInterface, silentInvocationHandler); } @Override public I multicast() { return localProxy; } @Override public I multicastSilently() { return silentLocalProxy; } @Override public void addSubscriber(I subscriber) { subscribers.add(subscriber); } @Override public void addAllSubscribers(I[] subscribers) { this.subscribers.addAll(Arrays.asList(subscribers)); } @Override public void removeSubscriber(I subscriber) { subscribers.remove(subscriber); } @Override public void clear() { subscribers.clear(); } @SuppressWarnings("unchecked") protected I createMulticasterProxy(Class subscriberInterface, InvocationHandler handler) { ClassLoader classLoader = ReflectionUtil.getClassLoader(getClass()); Object proxy = Proxy.newProxyInstance(classLoader, new Class[] { subscriberInterface }, handler); return (I) proxy; } @Override public Set getSubscribers() { return new HashSet(subscribers); } }