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%2Fcodegen%2Fimpl%2FRuntimeCodeGenerator.xtend;h=465a1f7d9dd2d1e5ef33fd088ed076a2597a326b;hb=refs%2Fchanges%2F55%2F6855%2F1;hp=0aee95ea4175a72c9ebbd4b14827b827547ae335;hpb=8b6075992f1e18eb678ee4e50e13b3d2d1397a85;p=controller.git diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 0aee95ea41..465a1f7d9d 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -11,10 +11,6 @@ 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 @@ -22,84 +18,114 @@ 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 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.* -import javax.xml.ws.spi.Invoker +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.* import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker import java.util.Set -import java.util.Collections import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper import java.util.WeakHashMap -import javassist.ClassClassPath +import org.opendaylight.yangtools.yang.binding.annotations.QName +import org.opendaylight.yangtools.yang.binding.DataContainer +import org.opendaylight.yangtools.yang.binding.RpcImplementation +import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils +import org.opendaylight.yangtools.sal.binding.generator.util.ClassLoaderUtils +import javassist.LoaderClassPath class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { val CtClass BROKER_NOTIFICATION_LISTENER; - val ClassPool classPool; + val extension JavassistUtils utils; val Map, RuntimeGeneratedInvokerPrototype> invokerClasses; - public new(ClassPool pool) { - classPool = pool; + + 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)); } override getDirectProxyFor(Class iface) { - val supertype = iface.asCtClass - val targetCls = createClass(iface.directProxyName, supertype) [ - field(DELEGATE_FIELD, iface); - implementMethodsFrom(supertype) [ - body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);''' + val T instance = withClassLoaderAndLock(iface.classLoader,lock) [| + val proxyName = iface.directProxyName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + 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 T ] - return targetCls.toClass(iface.classLoader).newInstance as T + return instance; } - override getRouterFor(Class iface) { - val contexts = new HashSet> + override getRouterFor(Class iface,String routerInstanceName) { + val metadata = withClassLoader(iface.classLoader) [| + val supertype = iface.asCtClass + return supertype.rpcMetadata; + ] - val instance = withClassLoader(iface.classLoader) [ | + val instance = withClassLoaderAndLock(iface.classLoader,lock) [ | val supertype = iface.asCtClass + val routerName = iface.routerName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val targetCls = createClass(iface.routerName, supertype) [ - //field(ROUTING_TABLE_FIELD,Map) + + field(DELEGATE_FIELD, iface) - val ctxMap = new HashMap>(); - // 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.rpcMethods.get(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»($$); }''' @@ -108,162 +134,136 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);''' } ] - ] - return targetCls.toClass(iface.classLoader).newInstance as T - ]; - return new RpcRouterCodegenInstance(iface, instance, contexts); - } - - protected def generateListenerInvoker(Class iface) { - val callbacks = iface.methods.filter[notificationCallback] - - val supportedNotification = callbacks.map[parameterTypes.get(0) as Class].toSet; - - val targetCls = createClass(iface.invokerName,BROKER_NOTIFICATION_LISTENER ) [ - field(DELEGATE_FIELD, iface) - implementMethodsFrom(BROKER_NOTIFICATION_LISTENER) [ - body = ''' + implementMethodsFrom(RpcImplementation.asCtClass) [ + body = ''' { - «FOR callback : callbacks SEPARATOR " else "» - «val cls = callback.parameterTypes.get(0).name» - if($1 instanceof «cls») { - «DELEGATE_FIELD».«callback.name»((«cls») $1); - return null; - } - «ENDFOR» - return null; + throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } - ''' + ''' + ] ] - ] - val finalClass = targetCls.toClass(iface.classLoader,iface.protectionDomain) - return new RuntimeGeneratedInvokerPrototype(supportedNotification, - finalClass as Class); + return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T + + ]; + return new RpcRouterCodegenInstance(routerInstanceName,iface, instance, metadata.contexts,metadata.supportedInputs); } - 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 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; + metadata.supportedInputs.add(input); + metadata.rpcInputs.put(input,routingPair); + } + ] + return metadata; } - private def routingContextInput(CtMethod method) { + private def getRpcMetadata(CtMethod method) { val inputClass = method.parameterTypes.get(0); - return inputClass.contextInstance; + return inputClass.rpcMethodMetadata(inputClass,method.name); } - private def RoutingPair getContextInstance(CtClass dataClass) { + 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 RoutingPair((annotation as RoutingContext).value, method, encapsulated); + return new RpcMetadata(null,rpcMethod,(annotation as RoutingContext).value, method, encapsulated,inputClass); } } } } for (iface : dataClass.interfaces) { - val ret = getContextInstance(iface); + val ret = rpcMethodMetadata(iface,inputClass,rpcMethod); 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 getJavaClass(CtClass cls) { + Thread.currentThread.contextClassLoader.loadClass(cls.name) } - private def CtClass createClass(String fqn, ClassGenerator cls) { - val target = classPool.makeClass(fqn); - cls.process(target); - return target; + override getInvokerFactory() { + return this; } - private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) { - val target = classPool.makeClass(fqn); - target.implementsType(superInterface); - cls.process(target); - return target; - } + override invokerFor(NotificationListener instance) { + val cls = instance.class + val prototype = resolveInvokerClass(cls); - private def void implementsType(CtClass it, CtClass supertype) { - checkArgument(supertype.interface, "Supertype must be interface"); - addInterface(supertype); + return new RuntimeGeneratedInvoker(instance, prototype) } - private def asCtClass(Class class1) { - classPool.get(class1); - } + protected def generateListenerInvoker(Class iface) { + val callbacks = iface.methods.filter[notificationCallback] - 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; - } + val supportedNotification = callbacks.map[parameterTypes.get(0) as Class].toSet; - def get(ClassPool pool, Class cls) { - try { - return pool.get(cls.name) - } catch (NotFoundException e) { - pool.appendClassPath(new LoaderClassPath(cls.classLoader)); - try { - return pool.get(cls.name) - - } catch (NotFoundException ef) { - pool.appendClassPath(new ClassClassPath(cls)); - return pool.get(cls.name) - } - } + val targetCls = createClass(iface.invokerName, BROKER_NOTIFICATION_LISTENER) [ + field(DELEGATE_FIELD, iface) + implementMethodsFrom(BROKER_NOTIFICATION_LISTENER) [ + body = ''' + { + «FOR callback : callbacks SEPARATOR " else "» + «val cls = callback.parameterTypes.get(0).name» + if($1 instanceof «cls») { + «DELEGATE_FIELD».«callback.name»((«cls») $1); + return null; + } + «ENDFOR» + return null; + } + ''' + ] + ] + val finalClass = targetCls.toClass(iface.classLoader, iface.protectionDomain) + return new RuntimeGeneratedInvokerPrototype(supportedNotification, + finalClass as Class>); } - override getInvokerFactory() { - return this; - } - override invokerFor(NotificationListener instance) { - val cls = instance.class - val prototype = resolveInvokerClass(cls); - - return new RuntimeGeneratedInvoker(instance,prototype) - } - def resolveInvokerClass(Class class1) { - val invoker = invokerClasses.get(class1); - if (invoker !== null) { - return invoker; - } - val newInvoker = generateListenerInvoker(class1); - invokerClasses.put(class1, newInvoker); - return newInvoker + + + protected def resolveInvokerClass(Class class1) { + return withClassLoaderAndLock(class1.classLoader,lock) [| + val invoker = invokerClasses.get(class1); + if (invoker !== null) { + return invoker; + } + val newInvoker = generateListenerInvoker(class1); + invokerClasses.put(class1, newInvoker); + return newInvoker + + ] } } @Data -class RuntimeGeneratedInvoker implements NotificationInvoker { - +package class RuntimeGeneratedInvoker implements NotificationInvoker { + @Property val NotificationListener delegate; - @Property - var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; + var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; @Property var RuntimeGeneratedInvokerPrototype prototype; - new(NotificationListener delegate,RuntimeGeneratedInvokerPrototype prototype) { + new(NotificationListener delegate, RuntimeGeneratedInvokerPrototype prototype) { _delegate = delegate; _prototype = prototype; - _invocationProxy = prototype.protoClass.newInstance; + _invocationProxy = prototype.protoClass.newInstance as org.opendaylight.controller.sal.binding.api.NotificationListener; RuntimeCodeHelper.setDelegate(_invocationProxy, delegate); } @@ -272,16 +272,52 @@ class RuntimeGeneratedInvoker implements NotificationInvoker { } override close() { - } } @Data -class RuntimeGeneratedInvokerPrototype { +package class RuntimeGeneratedInvokerPrototype { @Property val Set> supportedNotifications; @Property - val Class protoClass; + val Class> protoClass; +} + +package class RpcServiceMetadata { + + @Property + val contexts = new HashSet>(); + + @Property + val rpcMethods = new HashMap(); + + @Property + val rpcInputs = new HashMap, RpcMetadata>(); + + + @Property + val supportedInputs = new HashSet>(); +} + +@Data +package class RpcMetadata { + + @Property + val QName qname; + + @Property + val String methodName; + + @Property + val Class context; + @Property + val CtMethod inputRouteGetter; + + @Property + val boolean routeEncapsulated; + + @Property + val CtClass inputType; }