X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-binding-broker%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Fbinding%2Fimpl%2FListenerMapGeneration.java;h=4d893aa7be22404acfc7932e7f8c841791d4fbf7;hb=fcc36c9530a5615289b9ee697f05e3862f948f8f;hp=5ded885f8e803134bdea14f218a75766f1fcc221;hpb=e12bd40c3743a3b840c2d69c0f5f088176aa94b5;p=controller.git diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java index 5ded885f8e..4d893aa7be 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java @@ -15,7 +15,11 @@ import java.util.Set; import org.opendaylight.yangtools.yang.binding.Notification; import com.google.common.base.Predicate; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; @@ -23,14 +27,44 @@ import com.google.common.collect.Multimap; * An immutable view of the current generation of listeners. */ final class ListenerMapGeneration { - private final Multimap, NotificationListenerRegistration> listeners; + private static final int CACHE_MAX_ENTRIES = 1000; + + /** + * Constant map of notification type to subscribed listeners. + */ + private final Multimap, NotificationListenerRegistration> typeToListeners; + + /** + * Dynamic cache of notification implementation to matching listeners. This cache loads entries based on + * the contents of the {@link #typeToListeners} map. + */ + private final LoadingCache, Iterable>> implementationToListeners = + CacheBuilder.newBuilder() + .weakKeys() + .maximumSize(CACHE_MAX_ENTRIES) + .build(new CacheLoader, Iterable>>() { + @Override + public Iterable> load(final Class key) { + final Set> regs = new HashSet<>(); + + for (final Class type : getNotificationTypes(key)) { + @SuppressWarnings("unchecked") + final Collection> l = typeToListeners.get((Class) type); + if (l != null) { + regs.addAll(l); + } + } + + return ImmutableSet.copyOf(regs); + } + }); ListenerMapGeneration() { - listeners = ImmutableMultimap.of(); + typeToListeners = ImmutableMultimap.of(); } ListenerMapGeneration(final Multimap, NotificationListenerRegistration> listeners) { - this.listeners = ImmutableMultimap.copyOf(listeners); + this.typeToListeners = ImmutableMultimap.copyOf(listeners); } /** @@ -39,44 +73,34 @@ final class ListenerMapGeneration { * @return Current type-to-listener map. */ Multimap, NotificationListenerRegistration> getListeners() { - return listeners; - } - - private static Iterable> getNotificationTypes(final Notification notification) { - final Class[] ifaces = notification.getClass().getInterfaces(); - return Iterables.filter(Arrays.asList(ifaces), new Predicate>() { - @Override - public boolean apply(final Class input) { - if (Notification.class.equals(input)) { - return false; - } - return Notification.class.isAssignableFrom(input); - } - }); + return typeToListeners; } /** * Look up the listeners which need to see this notification delivered. * * @param notification Notification object - * @return Iterable of listeners, may be null - * - * FIXME: improve such that it always returns non-null. + * @return Iterable of listeners, guaranteed to be nonnull. */ public Iterable> listenersFor(final Notification notification) { - final Set> ret = new HashSet<>(); - - for (final Class type : getNotificationTypes(notification)) { - final Collection> l = listeners.get((Class) type); - if (l != null) { - ret.addAll(l); - } - } - - return ret; + // Safe to use, as our loader does not throw checked exceptions + return implementationToListeners.getUnchecked(notification.getClass()); } public Iterable> getKnownTypes() { - return listeners.keySet(); + return typeToListeners.keySet(); + } + + private static Iterable> getNotificationTypes(final Class cls) { + final Class[] ifaces = cls.getInterfaces(); + return Iterables.filter(Arrays.asList(ifaces), new Predicate>() { + @Override + public boolean apply(final Class input) { + if (Notification.class.equals(input)) { + return false; + } + return Notification.class.isAssignableFrom(input); + } + }); } } \ No newline at end of file