From d7b9d07f266accf0e2bb6fd80fe994379bafba9b Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 22 Apr 2015 13:30:54 +0200 Subject: [PATCH] Migrated Hydrogen Notification Broker to not use Javassist. Change-Id: Id85deca318041be5bbe97d18d484004daf5e290d Signed-off-by: Tony Tkacik --- ...gatedNotificationListenerRegistration.java | 3 +- .../HydrogenNotificationBrokerImpl.java | 30 +++--- .../binding/compat/NotificationInvoker.java | 91 +++++++++++++++++++ ...BindingDOMNotificationListenerAdapter.java | 2 +- .../binding/codegen/impl/SingletonHolder.java | 18 ++-- 5 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/NotificationInvoker.java diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/AggregatedNotificationListenerRegistration.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/AggregatedNotificationListenerRegistration.java index 151439945e..e93109d576 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/AggregatedNotificationListenerRegistration.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/AggregatedNotificationListenerRegistration.java @@ -7,11 +7,10 @@ */ package org.opendaylight.controller.md.sal.binding.compat; +import com.google.common.base.Preconditions; import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.yangtools.yang.binding.Notification; -import com.google.common.base.Preconditions; - /** * An aggregated listener registration. This is a result of registering an invoker which can handle multiple * interfaces at the same time. In order to support correct delivery, we need to maintain per-type registrations diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/HydrogenNotificationBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/HydrogenNotificationBrokerImpl.java index c50c4cb599..b746020e0a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/HydrogenNotificationBrokerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/HydrogenNotificationBrokerImpl.java @@ -7,16 +7,15 @@ */ package org.opendaylight.controller.md.sal.binding.compat; +import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicReference; - import javax.annotation.concurrent.GuardedBy; - import org.opendaylight.controller.sal.binding.api.NotificationListener; import org.opendaylight.controller.sal.binding.api.NotificationProviderService; -import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; -import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker; import org.opendaylight.yangtools.concepts.AbstractListenerRegistration; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.util.ListenerRegistry; @@ -24,10 +23,7 @@ import org.opendaylight.yangtools.yang.binding.Notification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.base.Preconditions; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; - +@Deprecated public class HydrogenNotificationBrokerImpl implements NotificationProviderService, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(HydrogenNotificationBrokerImpl.class); @@ -47,7 +43,7 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi @Override public void publish(final Notification notification, final ExecutorService service) { - for (NotificationListenerRegistration r : listeners.get().listenersFor(notification)) { + for (final NotificationListenerRegistration r : listeners.get().listenersFor(notification)) { service.submit(new NotifyTask(r, notification)); } } @@ -61,7 +57,7 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi synchronized (this) { final Multimap, NotificationListenerRegistration> newListeners = mutableListeners(); - for (NotificationListenerRegistration reg : registrations) { + for (final NotificationListenerRegistration reg : registrations) { newListeners.put(reg.getType(), reg); } @@ -69,7 +65,7 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi } // Notifications are dispatched out of lock... - for (NotificationListenerRegistration reg : registrations) { + for (final NotificationListenerRegistration reg : registrations) { announceNotificationSubscription(reg.getType()); } } @@ -78,7 +74,7 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi final Multimap, NotificationListenerRegistration> newListeners = mutableListeners(); - for (NotificationListenerRegistration reg : registrations) { + for (final NotificationListenerRegistration reg : registrations) { newListeners.remove(reg.getType(), reg); } @@ -89,7 +85,7 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi for (final ListenerRegistration listener : interestListeners) { try { listener.getInstance().onNotificationSubscribtion(notification); - } catch (Exception e) { + } catch (final Exception e) { LOG.warn("Listener {} reported unexpected error on notification {}", listener.getInstance(), notification, e); } @@ -121,14 +117,14 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi @Override public ListenerRegistration registerNotificationListener(final org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - final NotificationInvoker invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener); + final NotificationInvoker invoker = NotificationInvoker.invokerFor(listener); final Set> types = invoker.getSupportedNotifications(); final NotificationListenerRegistration[] regs = new NotificationListenerRegistration[types.size()]; // Populate the registrations... int i = 0; - for (Class type : types) { - regs[i] = new AggregatedNotificationListenerRegistration(type, invoker.getInvocationProxy(), regs) { + for (final Class type : types) { + regs[i] = new AggregatedNotificationListenerRegistration(type, invoker, regs) { @Override protected void removeRegistration() { // Nothing to do, will be cleaned up by parent (below) @@ -145,7 +141,7 @@ public class HydrogenNotificationBrokerImpl implements NotificationProviderServi @Override protected void removeRegistration() { removeRegistrations(regs); - for (ListenerRegistration reg : regs) { + for (final ListenerRegistration reg : regs) { reg.close(); } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/NotificationInvoker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/NotificationInvoker.java new file mode 100644 index 0000000000..08a147721f --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/NotificationInvoker.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.compat; + +import com.google.common.collect.ImmutableMap; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.opendaylight.yangtools.yang.binding.Notification; +import org.opendaylight.yangtools.yang.binding.NotificationListener; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +import org.opendaylight.yangtools.yang.binding.util.NotificationListenerInvoker; +import org.opendaylight.yangtools.yang.common.QName; + +final class NotificationInvoker implements org.opendaylight.controller.sal.binding.api.NotificationListener { + + private final NotificationListener delegate; + private final Map,InvokerContext> invokers; + + + private NotificationInvoker(final NotificationListener listener) { + delegate = listener; + final Map, InvokerContext> builder = new HashMap<>(); + for(final Class iface : listener.getClass().getInterfaces()) { + if(NotificationListener.class.isAssignableFrom(iface) && BindingReflections.isBindingClass(iface)) { + @SuppressWarnings("unchecked") + final Class listenerType = (Class) iface; + final NotificationListenerInvoker invoker = NotificationListenerInvoker.from(listenerType); + for(final Class type : getNotificationTypes(listenerType)) { + builder.put(type, new InvokerContext(BindingReflections.findQName(type) , invoker)); + } + } + } + invokers = ImmutableMap.copyOf(builder); + } + + public static NotificationInvoker invokerFor(final NotificationListener listener) { + return new NotificationInvoker(listener); + } + + public Set> getSupportedNotifications() { + return invokers.keySet(); + } + + @Override + public void onNotification(final Notification notification) { + getContext(notification.getImplementedInterface()).invoke(notification); + }; + + private InvokerContext getContext(final Class type) { + return invokers.get(type); + } + + @SuppressWarnings("unchecked") + private static Set> getNotificationTypes(final Class type) { + // TODO: Investigate possibility and performance impact if we cache this or expose + // it from NotificationListenerInvoker + final Set> ret = new HashSet<>(); + for(final Method method : type.getMethods()) { + if(BindingReflections.isNotificationCallback(method)) { + final Class notification = (Class) method.getParameterTypes()[0]; + ret.add(notification); + } + } + return ret; + } + + private class InvokerContext { + + private final QName name; + private final NotificationListenerInvoker invoker; + + private InvokerContext(final QName name, final NotificationListenerInvoker invoker) { + this.name = name; + this.invoker = invoker; + } + + public void invoke(final Notification notification) { + invoker.invokeNotification(delegate, name, notification); + } + + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMNotificationListenerAdapter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMNotificationListenerAdapter.java index 668030e1a6..86822274ef 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMNotificationListenerAdapter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMNotificationListenerAdapter.java @@ -58,7 +58,7 @@ class BindingDOMNotificationListenerAdapter implements DOMNotificationListener { return invokers.keySet(); } - private static Map createInvokerMapFor(final Class implClz) { + public static Map createInvokerMapFor(final Class implClz) { final Map builder = new HashMap<>(); for(final Class iface : implClz.getInterfaces()) { if(NotificationListener.class.isAssignableFrom(iface) && BindingReflections.isBindingClass(iface)) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java index 4664b58d2a..f5c3959151 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -22,8 +22,6 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javassist.ClassPool; import org.apache.commons.lang3.StringUtils; -import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; -import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,8 +33,6 @@ public class SingletonHolder { public static final JavassistUtils JAVASSIST = JavassistUtils.forClassPool(CLASS_POOL); public static final org.opendaylight.controller.sal.binding.codegen.impl.DefaultRuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.DefaultRuntimeCodeGenerator( CLASS_POOL); - public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL; - public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory(); public static final int CORE_NOTIFICATION_THREADS = 4; public static final int MAX_NOTIFICATION_THREADS = 32; @@ -58,12 +54,12 @@ public class SingletonHolder { if (NOTIFICATION_EXECUTOR == null) { int queueSize = MAX_NOTIFICATION_QUEUE_SIZE; - String queueValue = System.getProperty(NOTIFICATION_QUEUE_SIZE_PROPERTY); + final String queueValue = System.getProperty(NOTIFICATION_QUEUE_SIZE_PROPERTY); if (StringUtils.isNotBlank(queueValue)) { try { queueSize = Integer.parseInt(queueValue); logger.trace("Queue size was set to {}", queueSize); - } catch (NumberFormatException e) { + } catch (final NumberFormatException e) { logger.warn("Cannot parse {} as set by {}, using default {}", queueValue, NOTIFICATION_QUEUE_SIZE_PROPERTY, queueSize); } @@ -101,7 +97,7 @@ public class SingletonHolder { public void rejectedExecution(final Runnable r, final ThreadPoolExecutor executor) { try { executor.getQueue().put(r); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { throw new RejectedExecutionException("Interrupted while waiting on the queue", e); } } @@ -120,7 +116,7 @@ public class SingletonHolder { @Deprecated public static synchronized ListeningExecutorService getDefaultCommitExecutor() { if (COMMIT_EXECUTOR == null) { - ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-commit-%d").build(); + final ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-commit-%d").build(); /* * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction * ordering guarantees, which means that using a concurrent threadpool results @@ -128,7 +124,7 @@ public class SingletonHolder { * in inconsistent data being present. Once proper primitives are introduced, * concurrency can be reintroduced. */ - ExecutorService executor = Executors.newSingleThreadExecutor(factory); + final ExecutorService executor = Executors.newSingleThreadExecutor(factory); COMMIT_EXECUTOR = MoreExecutors.listeningDecorator(executor); } @@ -137,7 +133,7 @@ public class SingletonHolder { public static ExecutorService getDefaultChangeEventExecutor() { if (CHANGE_EVENT_EXECUTOR == null) { - ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-change-%d").build(); + final ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("md-sal-binding-change-%d").build(); /* * FIXME: this used to be newCacheThreadPool(), but MD-SAL does not have transaction * ordering guarantees, which means that using a concurrent threadpool results @@ -145,7 +141,7 @@ public class SingletonHolder { * in inconsistent data being present. Once proper primitives are introduced, * concurrency can be reintroduced. */ - ExecutorService executor = Executors.newSingleThreadExecutor(factory); + final ExecutorService executor = Executors.newSingleThreadExecutor(factory); CHANGE_EVENT_EXECUTOR = MoreExecutors.listeningDecorator(executor); } -- 2.36.6