Bug 629: Make BindingDataBroker to be visible.
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / codegen / impl / RuntimeCodeGenerator.xtend
index 90be6f3476841bf2f20e53f9cc66438148722d60..00c9f1eb91a14f7f1df97a73bc871cac9e918058 100644 (file)
@@ -7,86 +7,89 @@
  */
 package org.opendaylight.controller.sal.binding.codegen.impl
 
+import java.util.Map
 import javassist.ClassPool
-import org.opendaylight.yangtools.yang.binding.RpcService
-
-import javassist.CtClass
-import static com.google.common.base.Preconditions.*
-
-import javassist.CtField
-import javassist.Modifier
-import javassist.CtMethod
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
-import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
-import org.opendaylight.yangtools.yang.binding.BaseIdentity
-
-import java.util.Map
-import java.util.HashMap
-import javassist.NotFoundException
-import javassist.LoaderClassPath
-import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.MethodGenerator
-import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.ClassGenerator
-import org.opendaylight.yangtools.yang.binding.NotificationListener
 import org.opendaylight.yangtools.yang.binding.Notification
-import java.util.Arrays
+import org.opendaylight.yangtools.yang.binding.RpcImplementation
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils
 
-import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
 import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
-import java.util.HashSet
-import java.io.ObjectOutputStream.PutField
-import static org.opendaylight.controller.sal.binding.impl.osgi.ClassLoaderUtils.*
-
-class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator {
+import org.opendaylight.yangtools.yang.binding.RpcService
 
-    val ClassPool classPool;
+class RuntimeCodeGenerator extends AbstractRuntimeCodeGenerator {
 
-    public new(ClassPool pool) {
-        classPool = pool;
+    new(ClassPool pool) {
+        super(pool)
     }
 
-    override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
-        val supertype = iface.asCtClass
-        val targetCls = createClass(iface.directProxyName, supertype) [
-            field(DELEGATE_FIELD, iface);
-            implementMethodsFrom(supertype) [
-                body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
+    override directProxySupplier(Class iface) {
+        return [|
+            val proxyName = iface.directProxyName;
+            val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName)
+            if(potentialClass != null) {
+                return potentialClass.newInstance as RpcService;
+            }
+            val supertype = iface.asCtClass
+            val createdCls = createClass(iface.directProxyName, supertype) [
+                field(DELEGATE_FIELD, iface);
+                implementsType(RpcImplementation.asCtClass)
+                implementMethodsFrom(supertype) [
+                    body = '''
+                    {
+                        if(«DELEGATE_FIELD» == null) {
+                            throw new java.lang.IllegalStateException("No default provider is available");
+                        }
+                        return ($r) «DELEGATE_FIELD».«it.name»($$);
+                    }
+                    '''
+                ]
+                implementMethodsFrom(RpcImplementation.asCtClass) [
+                    body = '''
+                    {
+                        throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                        return ($r) null;
+                    }
+                    '''
+                ]
             ]
+            return createdCls.toClass(iface.classLoader).newInstance as RpcService
         ]
-        return targetCls.toClass(iface.classLoader).newInstance as T
     }
 
-    override <T extends RpcService> getRouterFor(Class<T> iface) {
-        val contexts = new HashSet<Class<? extends BaseIdentity>>
-
-        val instance = <T>withClassLoader(iface.classLoader) [ |
+    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 RpcService;
+            }
+
             val targetCls = createClass(iface.routerName, supertype) [
-                //field(ROUTING_TABLE_FIELD,Map)
+
+
                 field(DELEGATE_FIELD, iface)
-                val ctxMap = new HashMap<String, Class<? extends BaseIdentity>>();
-                // We search for routing pairs and add fields
-                supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
-                    val routingPair = method.routingContextInput;
-                    if (routingPair !== null) {
-                        ctxMap.put(routingPair.context.routingTableField, routingPair.context);
-                        contexts.add(routingPair.context)
-                    }
-                ]
-                for (ctx : ctxMap.entrySet) {
-                    field(ctx.key, Map)
+                //field(REMOTE_INVOKER_FIELD,iface);
+                implementsType(RpcImplementation.asCtClass)
+
+                for (ctx : metadata.contexts) {
+                    field(ctx.routingTableField, Map)
                 }
                 implementMethodsFrom(supertype) [
                     if (parameterTypes.size === 1) {
-                        val routingPair = routingContextInput;
+                        val rpcMeta = metadata.getRpcMethod(name);
                         val bodyTmp = '''
                         {
-                            final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»()«IF routingPair.encapsulated».getValue()«ENDIF»;
-                            «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier);
+                            final «InstanceIdentifier.name» identifier = $1.«rpcMeta.inputRouteGetter.name»()«IF rpcMeta.
+                            routeEncapsulated».getValue()«ENDIF»;
+                            «supertype.name» instance = («supertype.name») «rpcMeta.context.routingTableField».get(identifier);
                             if(instance == null) {
                                instance = «DELEGATE_FIELD»;
                             }
                             if(instance == null) {
-                                throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                                throw new java.lang.IllegalStateException("No routable provider is processing routed message for " + String.valueOf(identifier));
                             }
                             return ($r) instance.«it.name»($$);
                         }'''
@@ -95,107 +98,43 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co
                         body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
                     }
                 ]
+                implementMethodsFrom(RpcImplementation.asCtClass) [
+                    body = '''
+                    {
+                        throw new java.lang.IllegalStateException("No provider is processing supplied message");
+                        return ($r) null;
+                    }
+                    '''
+                ]
             ]
-            return targetCls.toClass(iface.classLoader).newInstance as T
+            return  targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as RpcService
         ];
-        return new RpcRouterCodegenInstance(iface, instance, contexts);
     }
 
-    def Class<?> generateListenerInvoker(Class<? extends NotificationListener> iface) {
-        val targetCls = createClass(iface.invokerName) [
+    override generateListenerInvoker(Class iface) {
+        val callbacks = iface.methods.filter[BindingReflections.isNotificationCallback(it)]
+
+        val supportedNotification = callbacks.map[parameterTypes.get(0) as Class<? extends Notification>].toSet;
+
+        val targetCls = createClass(iface.invokerName, brokerNotificationListener) [
             field(DELEGATE_FIELD, iface)
-            it.method(Void, "invoke", Notification) [
-                val callbacks = iface.methods.filter[notificationCallback]
+            implementMethodsFrom(brokerNotificationListener) [
                 body = '''
                     {
                         «FOR callback : callbacks SEPARATOR " else "»
-                            if($1 instanceof «val cls = callback.parameterTypes.get(0).name») {
-                                «DELEGATE_FIELD».«callback.name»((«cls») $1);
-                                return;
-                            }
+                            «val cls = callback.parameterTypes.get(0).name»
+                                if($1 instanceof «cls») {
+                                    «DELEGATE_FIELD».«callback.name»((«cls») $1);
+                                    return null;
+                                }
                         «ENDFOR»
+                        return null;
                     }
                 '''
             ]
         ]
-        return targetCls.toClass(iface.classLoader);
-    }
-
-    def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
-        val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
-        function1.process(method);
-        it.addMethod(method);
-    }
-
-    private def routingContextInput(CtMethod method) {
-        val inputClass = method.parameterTypes.get(0);
-        return inputClass.contextInstance;
-    }
-
-    private def RoutingPair getContextInstance(CtClass dataClass) {
-        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 RoutingPair((annotation as RoutingContext).value, method,encapsulated);
-                    }
-                }
-            }
-        }
-        for (iface : dataClass.interfaces) {
-            val ret = getContextInstance(iface);
-            if(ret != null) return ret;
-        }
-        return null;
-    }
-
-    private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
-        for (method : source.methods) {
-            if (method.declaringClass == source) {
-                val redeclaredMethod = new CtMethod(method, target, null);
-                function1.process(redeclaredMethod);
-                target.addMethod(redeclaredMethod);
-            }
-        }
-    }
-
-    private def CtClass createClass(String fqn, ClassGenerator cls) {
-        val target = classPool.makeClass(fqn);
-        cls.process(target);
-        return target;
-    }
-
-    private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
-        val target = classPool.makeClass(fqn);
-        target.implementsType(superInterface);
-        cls.process(target);
-        return target;
-    }
-
-    private def void implementsType(CtClass it, CtClass supertype) {
-        checkArgument(supertype.interface, "Supertype must be interface");
-        addInterface(supertype);
-    }
-
-    private def asCtClass(Class<?> class1) {
-        classPool.get(class1);
-    }
-
-    private def CtField field(CtClass it, String name, Class<?> returnValue) {
-        val field = new CtField(returnValue.asCtClass, name, it);
-        field.modifiers = Modifier.PUBLIC
-        addField(field);
-        return field;
-    }
-
-    def get(ClassPool pool, Class<?> cls) {
-        try {
-            return pool.get(cls.name)
-        } catch (NotFoundException e) {
-            pool.appendClassPath(new LoaderClassPath(cls.classLoader));
-            return pool.get(cls.name)
-        }
+        val finalClass = targetCls.toClass(iface.classLoader, iface.protectionDomain)
+        return new RuntimeGeneratedInvokerPrototype(supportedNotification,
+            finalClass as Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener<?>>);
     }
 }