@Override
  public synchronized <L extends IThingLogic> L addThingLogic(L tl) {
    long time;
    if (DEBUG) {
      time = System.nanoTime();
    }
    tl.setBNAWorld(bnaWorld);
    checkArgument(!logics.contains(tl), "Logic was already added: %s", tl);
    logics.add(tl);
    typedLogics.put(tl.getClass(), tl);
    if (DEBUG) {
      time = System.nanoTime() - time;
      debugStats.getUnchecked(tl).addAndGet(time);
    }
    fireThingLogicManagerEvent(EventType.LOGIC_ADDED, tl);

    return tl;
  }
 @Override
 public synchronized void removeThingLogic(IThingLogic tl) {
   fireThingLogicManagerEvent(EventType.LOGIC_REMOVING, tl);
   long time;
   if (DEBUG) {
     time = System.nanoTime();
   }
   logics.remove(tl);
   tl.setBNAWorld(null);
   typedLogics.remove(tl.getClass());
   if (DEBUG) {
     time = System.nanoTime() - time;
     debugStats.getUnchecked(tl).addAndGet(time);
   }
   fireThingLogicManagerEvent(EventType.LOGIC_REMOVED, tl);
 }
public class DefaultThingLogicManager implements IThingLogicManager {

  protected static final boolean DEBUG = true;
  protected final LoadingCache<Object, AtomicLong> debugStats =
      !DEBUG
          ? null
          : CacheBuilder.newBuilder()
              .weakKeys()
              .build(
                  new CacheLoader<Object, AtomicLong>() {
                    @Override
                    public AtomicLong load(Object input) {
                      return new AtomicLong();
                    }
                  });

  protected final IBNAWorld bnaWorld;

  public DefaultThingLogicManager(IBNAWorld bnaWorld) {
    this.bnaWorld = bnaWorld;
  }

  CopyOnWriteArrayList<IThingLogicManagerListener> listeners = Lists.newCopyOnWriteArrayList();
  FilterableCopyOnWriteArrayList<IThingLogic> logics = FilterableCopyOnWriteArrayList.create();
  Map<Class<?>, IThingLogic> typedLogics = Maps.newHashMap();

  @Override
  public void addThingLogicManagerListener(IThingLogicManagerListener l) {
    listeners.add(l);
  }

  @Override
  public void removeThingLogicManagerListener(IThingLogicManagerListener l) {
    listeners.remove(l);
  }

  protected void fireThingLogicManagerEvent(EventType eventType, IThingLogic tl) {
    if (!listeners.isEmpty()) {
      ThingLogicManagerEvent evt = new ThingLogicManagerEvent(eventType, tl);
      for (IThingLogicManagerListener l : listeners) {
        l.handleThingLogicManagerEvent(evt);
      }
    }
  }

  @SuppressWarnings("unchecked")
  @Override
  public <L extends IThingLogic> L addThingLogic(Class<L> logicClass) {
    try {
      L logic = (L) typedLogics.get(logicClass);
      if (logic != null) {
        return logic;
      }
      for (Constructor<?> c : logicClass.getConstructors()) {
        Class<?>[] paramTypes = c.getParameterTypes();
        if (paramTypes.length == 0) {
          return addThingLogic((L) c.newInstance());
        }
      }
    } catch (Exception e) {
      throw new IllegalArgumentException("Unable to instantiate logic: " + logicClass, e);
    }
    throw new IllegalArgumentException("Unable to instantiate logic: " + logicClass);
  }

  @Override
  public synchronized <L extends IThingLogic> L addThingLogic(L tl) {
    long time;
    if (DEBUG) {
      time = System.nanoTime();
    }
    tl.setBNAWorld(bnaWorld);
    checkArgument(!logics.contains(tl), "Logic was already added: %s", tl);
    logics.add(tl);
    typedLogics.put(tl.getClass(), tl);
    if (DEBUG) {
      time = System.nanoTime() - time;
      debugStats.getUnchecked(tl).addAndGet(time);
    }
    fireThingLogicManagerEvent(EventType.LOGIC_ADDED, tl);

    return tl;
  }

  @Override
  public synchronized void removeThingLogic(IThingLogic tl) {
    fireThingLogicManagerEvent(EventType.LOGIC_REMOVING, tl);
    long time;
    if (DEBUG) {
      time = System.nanoTime();
    }
    logics.remove(tl);
    tl.setBNAWorld(null);
    typedLogics.remove(tl.getClass());
    if (DEBUG) {
      time = System.nanoTime() - time;
      debugStats.getUnchecked(tl).addAndGet(time);
    }
    fireThingLogicManagerEvent(EventType.LOGIC_REMOVED, tl);
  }

  @Override
  public Iterable<IThingLogic> getAllThingLogics() {
    return Lists.newArrayList(logics);
  }

  @Override
  public <LT> Iterable<LT> getThingLogics(Class<LT> implementingInterface) {
    return Iterables.filter(logics, implementingInterface);
  }

  @Override
  public void destroy() {
    // perform removals in reverse order since latter logics often depend on former logics
    for (IThingLogic logic : Lists.newArrayList(Lists.reverse(logics))) {
      removeThingLogic(logic);
    }
  }
}