*/
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 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 org.opendaylight.yangtools.yang.binding.NotificationListener
import org.opendaylight.yangtools.yang.binding.Notification
-
-
-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 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 org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper
-import java.util.WeakHashMap
-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
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections
+import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils
-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<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses;
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+import org.opendaylight.yangtools.yang.binding.RpcService
+class RuntimeCodeGenerator extends AbstractRuntimeCodeGenerator {
new(ClassPool pool) {
- 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 = 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 as RpcService;
}
val supertype = iface.asCtClass
val createdCls = createClass(iface.directProxyName, supertype) [
'''
]
]
- return createdCls.toClass(iface.classLoader).newInstance as T
+ return createdCls.toClass(iface.classLoader).newInstance as RpcService
]
- return instance;
}
- override <T extends RpcService> getRouterFor(Class<T> iface,String routerInstanceName) {
- val metadata = withClassLoader(iface.classLoader) [|
- val supertype = iface.asCtClass
- return supertype.rpcMetadata;
- ]
-
- val instance = <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 as RpcService;
}
val targetCls = createClass(iface.routerName, supertype) [
}
implementMethodsFrom(supertype) [
if (parameterTypes.size === 1) {
- val rpcMeta = metadata.rpcMethods.get(name);
+ val rpcMeta = metadata.getRpcMethod(name);
val bodyTmp = '''
{
+ if($1 == null) {
+ throw new IllegalArgumentException("RPC input must not be null and must contain a value for field «rpcMeta.inputRouteGetter.name»");
+ }
+ if($1.«rpcMeta.inputRouteGetter.name»() == null) {
+ throw new IllegalArgumentException("Field «rpcMeta.inputRouteGetter.name» must not be null");
+ }
final «InstanceIdentifier.name» identifier = $1.«rpcMeta.inputRouteGetter.name»()«IF rpcMeta.
routeEncapsulated».getValue()«ENDIF»;
«supertype.name» instance = («supertype.name») «rpcMeta.context.routingTableField».get(identifier);
'''
]
]
- return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T
-
+ return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as RpcService
];
- 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(null,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 new RuntimeGeneratedInvoker(instance, prototype)
}
- protected def generateListenerInvoker(Class<? extends NotificationListener> iface) {
- val callbacks = iface.methods.filter[notificationCallback]
+ 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, 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 "»
return new RuntimeGeneratedInvokerPrototype(supportedNotification,
finalClass as Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener<?>>);
}
-
-
-
-
-
- protected def resolveInvokerClass(Class<? extends NotificationListener> class1) {
- return <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
-
- ]
- }
-}
-
-@Data
-package class RuntimeGeneratedInvoker implements NotificationInvoker {
-
- @Property
- val NotificationListener delegate;
-
- @Property
- var org.opendaylight.controller.sal.binding.api.NotificationListener<Notification> invocationProxy;
-
- @Property
- var RuntimeGeneratedInvokerPrototype prototype;
-
- new(NotificationListener delegate, RuntimeGeneratedInvokerPrototype prototype) {
- _delegate = delegate;
- _prototype = prototype;
- _invocationProxy = prototype.protoClass.newInstance as org.opendaylight.controller.sal.binding.api.NotificationListener<Notification>;
- RuntimeCodeHelper.setDelegate(_invocationProxy, delegate);
- }
-
- override getSupportedNotifications() {
- prototype.supportedNotifications;
- }
-
- override close() {
- }
-}
-
-@Data
-package class RuntimeGeneratedInvokerPrototype {
-
- @Property
- val Set<Class<? extends Notification>> supportedNotifications;
-
- @Property
- val Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener<?>> protoClass;
-}
-
-package class RpcServiceMetadata {
-
- @Property
- val contexts = new HashSet<Class<? extends BaseIdentity>>();
-
- @Property
- val rpcMethods = new HashMap<String, RpcMetadata>();
-
- @Property
- val rpcInputs = new HashMap<Class<? extends DataContainer>, RpcMetadata>();
-
-
- @Property
- val supportedInputs = new HashSet<Class<? extends DataContainer>>();
-}
-
-@Data
-package class RpcMetadata {
-
- @Property
- val QName qname;
-
- @Property
- val String methodName;
-
- @Property
- val Class<? extends BaseIdentity> context;
- @Property
- val CtMethod inputRouteGetter;
-
- @Property
- val boolean routeEncapsulated;
-
- @Property
- val CtClass inputType;
}