Merge "BUG-614: introduce AbstractRuntimeCodeGenerator"
authorTony Tkacik <ttkacik@cisco.com>
Tue, 10 Jun 2014 11:30:21 +0000 (11:30 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 10 Jun 2014 11:30:21 +0000 (11:30 +0000)
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/AbstractRuntimeCodeGenerator.java [new file with mode: 0644]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcServiceMetadata.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend

diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/AbstractRuntimeCodeGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/AbstractRuntimeCodeGenerator.java
new file mode 100644 (file)
index 0000000..9605a4d
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2014 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.sal.binding.codegen.impl;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.NotFoundException;
+
+import javax.annotation.concurrent.GuardedBy;
+
+import org.eclipse.xtext.xbase.lib.Extension;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter;
+import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils;
+
+import com.google.common.base.Supplier;
+
+abstract class AbstractRuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory {
+    @GuardedBy("this")
+    private final Map<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses = new WeakHashMap<>();
+    private final CtClass brokerNotificationListener;
+
+    @Extension
+    protected final JavassistUtils utils;
+
+    protected AbstractRuntimeCodeGenerator(final ClassPool pool) {
+        utils = JavassistUtils.forClassPool(pool);
+
+        /*
+         * Make sure Javassist ClassPool sees the classloader of RpcService
+         */
+        utils.ensureClassLoader(RpcService.class);
+
+        brokerNotificationListener = utils.asCtClass(org.opendaylight.controller.sal.binding.api.NotificationListener.class);
+    }
+
+    protected final CtClass getBrokerNotificationListener() {
+        return brokerNotificationListener;
+    }
+
+    protected abstract RuntimeGeneratedInvokerPrototype generateListenerInvoker(Class<? extends NotificationListener> cls);
+    protected abstract <T extends RpcService> Supplier<T> directProxySupplier(final Class<T> serviceType);
+    protected abstract <T extends RpcService> Supplier<T> routerSupplier(final Class<T> serviceType, RpcServiceMetadata metadata);
+
+    private RpcServiceMetadata getRpcMetadata(final CtClass iface) throws ClassNotFoundException, NotFoundException {
+        final RpcServiceMetadata metadata = new RpcServiceMetadata();
+
+        for (CtMethod method : iface.getMethods()) {
+            if (iface.equals(method.getDeclaringClass()) && method.getParameterTypes().length == 1) {
+                final RpcMetadata routingPair = getRpcMetadata(method);
+                if (routingPair != null) {
+                    metadata.addContext(routingPair.getContext());
+                    metadata.addRpcMethod(method.getName(), routingPair);
+
+                    /*
+                     * Force-load the RPC class representing the "input" of this RPC.
+                     *
+                     * FIXME: this is pre-existing side-effect of the original code, which
+                     *        kept a reference to the loaded class, but it did not use it.
+                     *
+                     *        There was no explanation as to why forcing this load was
+                     *        necessary. As far as I can tell now is that it forces the
+                     *        resolution of method arguments, which would (according to
+                     *        my reading of JLS) occur only when the method is invoked via
+                     *        binding-aware class action, not when coming from
+                     *        binding-independent world. Whether that makes sense or not,
+                     *        remains to be investigated.
+                     */
+                    Thread.currentThread().getContextClassLoader().loadClass(routingPair.getInputType().getName());
+                }
+            }
+        }
+
+        return metadata;
+    }
+
+    private RpcMetadata getRpcMetadata(final CtMethod method) throws NotFoundException {
+        final CtClass inputClass = method.getParameterTypes()[0];
+        return rpcMethodMetadata(inputClass, inputClass, method.getName());
+    }
+
+    private RpcMetadata rpcMethodMetadata(final CtClass dataClass, final CtClass inputClass, final String rpcMethod) throws NotFoundException {
+        for (CtMethod method : dataClass.getMethods()) {
+            if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
+                for (Object annotation : method.getAvailableAnnotations()) {
+                    if (annotation instanceof RoutingContext) {
+                        boolean encapsulated = !method.getReturnType().equals(utils.asCtClass(InstanceIdentifier.class));
+                        return new RpcMetadata(rpcMethod, ((RoutingContext)annotation).value(), method, encapsulated, inputClass);
+                    }
+                }
+            }
+        }
+
+        for (CtClass iface : dataClass.getInterfaces()) {
+            final RpcMetadata ret = rpcMethodMetadata(iface, inputClass, rpcMethod);
+            if(ret != null) {
+                return ret;
+            }
+        }
+        return null;
+    }
+
+    private synchronized RuntimeGeneratedInvokerPrototype resolveInvokerClass(final Class<? extends NotificationListener> cls) {
+        RuntimeGeneratedInvokerPrototype invoker = invokerClasses.get(cls);
+        if (invoker != null) {
+            return invoker;
+        }
+
+        utils.getLock().lock();
+        try {
+            invoker = ClassLoaderUtils.withClassLoader(cls.getClassLoader(), new Supplier<RuntimeGeneratedInvokerPrototype>() {
+                @Override
+                public RuntimeGeneratedInvokerPrototype get() {
+                    return generateListenerInvoker(cls);
+                }
+            });
+
+            invokerClasses.put(cls, invoker);
+            return invoker;
+        } finally {
+            utils.getLock().unlock();
+        }
+    }
+
+    @Override
+    public final NotificationInvokerFactory getInvokerFactory() {
+        return this;
+    }
+
+    @Override
+    public final <T extends RpcService> T getDirectProxyFor(final Class<T> serviceType) {
+        utils.getLock().lock();
+        try {
+            return ClassLoaderUtils.withClassLoader(serviceType.getClassLoader(), directProxySupplier(serviceType));
+        } finally {
+            utils.getLock().unlock();
+        }
+    }
+
+    @Override
+    public final <T extends RpcService> RpcRouter<T> getRouterFor(final Class<T> serviceType, final String name) {
+        final RpcServiceMetadata metadata = ClassLoaderUtils.withClassLoader(serviceType.getClassLoader(), new Supplier<RpcServiceMetadata>() {
+            @Override
+            public RpcServiceMetadata get() {
+                try {
+                    return getRpcMetadata(utils.asCtClass(serviceType));
+                } catch (ClassNotFoundException | NotFoundException e) {
+                    throw new IllegalStateException(String.format("Failed to load metadata for class {}", serviceType), e);
+                }
+            }
+        });
+
+        utils.getLock().lock();
+        try {
+            final T instance = ClassLoaderUtils.withClassLoader(serviceType.getClassLoader(), routerSupplier(serviceType, metadata));
+            return new RpcRouterCodegenInstance<T>(name, serviceType, instance, metadata.getContexts());
+        } finally {
+            utils.getLock().unlock();
+        }
+    }
+
+    @Override
+    public NotificationInvoker invokerFor(final NotificationListener instance) {
+        final Class<? extends NotificationListener> cls = instance.getClass();
+        final RuntimeGeneratedInvokerPrototype prototype = resolveInvokerClass(cls);
+
+        try {
+            return RuntimeGeneratedInvoker.create(instance, prototype);
+        } catch (InstantiationException | IllegalAccessException e) {
+            throw new IllegalStateException(String.format("Failed to create invoker for %s", instance), e);
+        }
+    }
+}
index 5578f75ae21d6800cf2c73661afa15a071bd6ef8..052fd2169a523b955a427f036e2a0ab6b7a03bc4 100644 (file)
@@ -24,7 +24,6 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.slf4j.Logger;
@@ -34,7 +33,7 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
 public class RpcRouterCodegenInstance<T extends RpcService> implements //
-        RpcRouter<T>, RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
+RpcRouter<T>, RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>> {
 
     private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class);
 
@@ -53,8 +52,7 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
     private final String name;
 
     @SuppressWarnings("unchecked")
-    public RpcRouterCodegenInstance(String name,Class<T> type, T routerImpl, Set<Class<? extends BaseIdentity>> contexts,
-            Set<Class<? extends DataContainer>> inputs) {
+    public RpcRouterCodegenInstance(final String name,final Class<T> type, final T routerImpl, final Iterable<Class<? extends BaseIdentity>> contexts) {
         this.name = name;
         this.listeners = ListenerRegistry.create();
         this.serviceType = type;
@@ -86,7 +84,7 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
 
     @Override
     @SuppressWarnings("unchecked")
-    public <C extends BaseIdentity> RpcRoutingTable<C, T> getRoutingTable(Class<C> routeContext) {
+    public <C extends BaseIdentity> RpcRoutingTable<C, T> getRoutingTable(final Class<C> routeContext) {
         return (RpcRoutingTable<C, T>) routingTables.get(routeContext);
     }
 
@@ -102,12 +100,12 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
 
     @Override
     public <L extends RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(
-            L listener) {
+            final L listener) {
         return listeners.registerWithType(listener);
     }
 
     @Override
-    public void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
+    public void onRouteChange(final RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change) {
         for (ListenerRegistration<RouteChangeListener<Class<? extends BaseIdentity>, InstanceIdentifier<?>>> listener : listeners) {
             try {
                 listener.getInstance().onRouteChange(change);
@@ -118,17 +116,17 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
     }
 
     @Override
-    public T getService(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+    public T getService(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
         return routingTables.get(context).getRoute(path);
     }
 
     @Override
-    public RoutedRpcRegistration<T> addRoutedRpcImplementation(T service) {
+    public RoutedRpcRegistration<T> addRoutedRpcImplementation(final T service) {
         return new RoutedRpcRegistrationImpl(service);
     }
 
     @Override
-    public RpcRegistration<T> registerDefaultService(T service) {
+    public RpcRegistration<T> registerDefaultService(final T service) {
         // TODO Auto-generated method stub
         RuntimeCodeHelper.setDelegate(invocationProxy, service);
         return null;
@@ -136,7 +134,7 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
 
     private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration<T> implements RoutedRpcRegistration<T> {
 
-        public RoutedRpcRegistrationImpl(T instance) {
+        public RoutedRpcRegistrationImpl(final T instance) {
             super(instance);
         }
 
@@ -146,22 +144,22 @@ public class RpcRouterCodegenInstance<T extends RpcService> implements //
         }
 
         @Override
-        public void registerPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+        public void registerPath(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
             routingTables.get(context).updateRoute(path, getInstance());
         }
 
         @Override
-        public void unregisterPath(Class<? extends BaseIdentity> context, InstanceIdentifier<?> path) {
+        public void unregisterPath(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> path) {
             routingTables.get(context).removeRoute(path, getInstance());
         }
 
         @Override
-        public void registerInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+        public void registerInstance(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> instance) {
             registerPath(context, instance);
         }
 
         @Override
-        public void unregisterInstance(Class<? extends BaseIdentity> context, InstanceIdentifier<?> instance) {
+        public void unregisterInstance(final Class<? extends BaseIdentity> context, final InstanceIdentifier<?> instance) {
             unregisterPath(context, instance);
         }
 
index 399afe74e8704f3832f9fc161e21fa7f68b890f1..430b7a7e319a04e8216da93e9e9ba594e1885361 100644 (file)
@@ -9,29 +9,31 @@ package org.opendaylight.controller.sal.binding.codegen.impl;
 
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
+
+import com.google.common.collect.Iterables;
 
 final class RpcServiceMetadata {
-    private final HashMap<Class<? extends DataContainer>, RpcMetadata> rpcInputs = new HashMap<>();
-    private final HashSet<Class<? extends DataContainer>> supportedInputs = new HashSet<>();
-    private final HashSet<Class<? extends BaseIdentity>> contexts = new HashSet<>();
-    private final HashMap<String, RpcMetadata> rpcMethods = new HashMap<>();
+    private final Set<Class<? extends BaseIdentity>> contexts = new HashSet<>();
+    private final Map<String, RpcMetadata> rpcMethods = new HashMap<>();
+    private final Iterable<Class<? extends BaseIdentity>> roContexts = Iterables.unmodifiableIterable(contexts);
 
-    public HashSet<Class<? extends BaseIdentity>> getContexts() {
-        return this.contexts;
+    public Iterable<Class<? extends BaseIdentity>> getContexts() {
+        return roContexts;
     }
 
-    public HashMap<String, RpcMetadata> getRpcMethods() {
-        return this.rpcMethods;
+    public RpcMetadata getRpcMethod(final String name) {
+        return rpcMethods.get(name);
     }
 
-    public HashMap<Class<? extends DataContainer>, RpcMetadata> getRpcInputs() {
-        return this.rpcInputs;
+    public void addContext(final Class<? extends BaseIdentity> context) {
+        contexts.add(context);
     }
 
-    public HashSet<Class<? extends DataContainer>> getSupportedInputs() {
-        return this.supportedInputs;
+    public void addRpcMethod(final String name, final RpcMetadata routingPair) {
+        rpcMethods.put(name, routingPair);
     }
 }
index ac782051a85b708ad5d2d7ac1444b408753acef0..1be6e2dfb112f5b5f56194d24e865b24cb802e23 100644 (file)
@@ -8,45 +8,27 @@
 package org.opendaylight.controller.sal.binding.codegen.impl
 
 import java.util.Map
-import java.util.WeakHashMap
 import javassist.ClassPool
-import javassist.CtClass
-import javassist.CtMethod
-import javassist.LoaderClassPath
-import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory
-import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils
-import org.opendaylight.yangtools.yang.binding.DataContainer
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
 import org.opendaylight.yangtools.yang.binding.Notification
-import org.opendaylight.yangtools.yang.binding.NotificationListener
 import org.opendaylight.yangtools.yang.binding.RpcImplementation
-import org.opendaylight.yangtools.yang.binding.RpcService
-import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
+import org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper
 import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils
 
 import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
-import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
-
-class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory {
-
-    val CtClass BROKER_NOTIFICATION_LISTENER;
-    val extension JavassistUtils utils;
-    val Map<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses;
 
+class RuntimeCodeGenerator extends AbstractRuntimeCodeGenerator {
 
     new(ClassPool pool) {
-        utils = new JavassistUtils(pool);
-        invokerClasses = new WeakHashMap();
-        BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass;
-        pool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
+        super(pool)
     }
 
-    override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
-        val T instance = ClassLoaderUtils.withClassLoaderAndLock(iface.classLoader,lock) [|
+    override directProxySupplier(Class iface) {
+        return [|
             val proxyName = iface.directProxyName;
             val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName)
             if(potentialClass != null) {
-                return potentialClass.newInstance as T;
+                return potentialClass.newInstance;
             }
             val supertype = iface.asCtClass
             val createdCls = createClass(iface.directProxyName, supertype) [
@@ -71,23 +53,17 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
                     '''
                 ]
             ]
-            return createdCls.toClass(iface.classLoader).newInstance as T
+            return createdCls.toClass(iface.classLoader).newInstance
         ]
-        return instance;
     }
 
-    override <T extends RpcService> getRouterFor(Class<T> iface,String routerInstanceName) {
-        val metadata = ClassLoaderUtils.withClassLoader(iface.classLoader) [|
-            val supertype = iface.asCtClass
-            return supertype.rpcMetadata;
-        ]
-
-        val instance = ClassLoaderUtils.<T>withClassLoaderAndLock(iface.classLoader,lock) [ |
+    override routerSupplier(Class iface, RpcServiceMetadata metadata) {
+        return [ |
             val supertype = iface.asCtClass
             val routerName = iface.routerName;
             val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName)
             if(potentialClass != null) {
-                return potentialClass.newInstance as T;
+                return potentialClass.newInstance;
             }
 
             val targetCls = createClass(iface.routerName, supertype) [
@@ -102,7 +78,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
                 }
                 implementMethodsFrom(supertype) [
                     if (parameterTypes.size === 1) {
-                        val rpcMeta = metadata.rpcMethods.get(name);
+                        val rpcMeta = metadata.getRpcMethod(name);
                         val bodyTmp = '''
                         {
                             final «InstanceIdentifier.name» identifier = $1.«rpcMeta.inputRouteGetter.name»()«IF rpcMeta.
@@ -130,74 +106,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
                     '''
                 ]
             ]
-            return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
-
+            return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance
         ];
-        return new RpcRouterCodegenInstance(routerInstanceName,iface, instance, metadata.contexts,metadata.supportedInputs);
     }
 
-    private def RpcServiceMetadata getRpcMetadata(CtClass iface) {
-        val metadata = new RpcServiceMetadata;
-
-        iface.methods.filter[declaringClass == iface && parameterTypes.size === 1].forEach [ method |
-            val routingPair = method.rpcMetadata;
-            if (routingPair !== null) {
-                metadata.contexts.add(routingPair.context)
-                metadata.rpcMethods.put(method.name,routingPair)
-                val input = routingPair.inputType.javaClass as Class<? extends DataContainer>;
-                metadata.supportedInputs.add(input);
-                metadata.rpcInputs.put(input,routingPair);
-            }
-        ]
-        return metadata;
-    }
-
-    private def getRpcMetadata(CtMethod method) {
-        val inputClass = method.parameterTypes.get(0);
-        return inputClass.rpcMethodMetadata(inputClass,method.name);
-    }
-
-    private def RpcMetadata rpcMethodMetadata(CtClass dataClass, CtClass inputClass, String rpcMethod) {
-        for (method : dataClass.methods) {
-            if (method.name.startsWith("get") && method.parameterTypes.size === 0) {
-                for (annotation : method.availableAnnotations) {
-                    if (annotation instanceof RoutingContext) {
-                        val encapsulated = !method.returnType.equals(InstanceIdentifier.asCtClass);
-                        return new RpcMetadata(rpcMethod,(annotation as RoutingContext).value, method, encapsulated,inputClass);
-                    }
-                }
-            }
-        }
-        for (iface : dataClass.interfaces) {
-            val ret = rpcMethodMetadata(iface,inputClass,rpcMethod);
-            if(ret != null) return ret;
-        }
-        return null;
-    }
-
-    private def getJavaClass(CtClass cls) {
-        Thread.currentThread.contextClassLoader.loadClass(cls.name)
-    }
-
-    override getInvokerFactory() {
-        return this;
-    }
-
-    override invokerFor(NotificationListener instance) {
-        val cls = instance.class
-        val prototype = resolveInvokerClass(cls);
-
-        return RuntimeGeneratedInvoker.create(instance, prototype)
-    }
-
-    protected def generateListenerInvoker(Class<? extends NotificationListener> iface) {
-        val callbacks = iface.methods.filter[notificationCallback]
+    override generateListenerInvoker(Class iface) {
+        val callbacks = iface.methods.filter[YangtoolsMappingHelper.isNotificationCallback(it)]
 
         val supportedNotification = callbacks.map[parameterTypes.get(0) as Class<? extends Notification>].toSet;
 
-        val targetCls = createClass(iface.invokerName, BROKER_NOTIFICATION_LISTENER) [
+        val targetCls = createClass(iface.invokerName, brokerNotificationListener) [
             field(DELEGATE_FIELD, iface)
-            implementMethodsFrom(BROKER_NOTIFICATION_LISTENER) [
+            implementMethodsFrom(brokerNotificationListener) [
                 body = '''
                     {
                         «FOR callback : callbacks SEPARATOR " else "»
@@ -216,16 +136,4 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
         return new RuntimeGeneratedInvokerPrototype(supportedNotification,
             finalClass as Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener<?>>);
     }
-
-    protected def resolveInvokerClass(Class<? extends NotificationListener> class1) {
-        return ClassLoaderUtils.<RuntimeGeneratedInvokerPrototype>withClassLoaderAndLock(class1.classLoader,lock) [|
-            val invoker = invokerClasses.get(class1);
-            if (invoker !== null) {
-                return invoker;
-            }
-            val newInvoker = generateListenerInvoker(class1);
-            invokerClasses.put(class1, newInvoker);
-            return newInvoker
-        ]
-    }
 }