2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.sal.binding.codegen.impl
10 import javassist.ClassPool
11 import org.opendaylight.yangtools.yang.binding.RpcService
13 import javassist.CtClass
14 import static com.google.common.base.Preconditions.*
16 import javassist.CtField
17 import javassist.Modifier
18 import javassist.CtMethod
19 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
20 import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
21 import org.opendaylight.yangtools.yang.binding.BaseIdentity
24 import java.util.HashMap
25 import javassist.NotFoundException
26 import javassist.LoaderClassPath
27 import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.MethodGenerator
28 import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.ClassGenerator
29 import org.opendaylight.yangtools.yang.binding.NotificationListener
30 import org.opendaylight.yangtools.yang.binding.Notification
31 import java.util.Arrays
33 import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
34 import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
35 import java.util.HashSet
36 import java.io.ObjectOutputStream.PutField
37 import static org.opendaylight.controller.sal.binding.impl.osgi.ClassLoaderUtils.*
38 import javax.xml.ws.spi.Invoker
39 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory
40 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker
42 import java.util.Collections
43 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper
44 import java.util.WeakHashMap
45 import javassist.ClassClassPath
47 class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory {
49 val CtClass BROKER_NOTIFICATION_LISTENER;
50 val ClassPool classPool;
51 val Map<Class<? extends NotificationListener>, RuntimeGeneratedInvokerPrototype> invokerClasses;
53 public new(ClassPool pool) {
55 invokerClasses = new WeakHashMap();
56 BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass;
59 override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
60 val supertype = iface.asCtClass
61 val targetCls = createClass(iface.directProxyName, supertype) [
62 field(DELEGATE_FIELD, iface);
63 implementMethodsFrom(supertype) [
64 body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
67 return targetCls.toClass(iface.classLoader).newInstance as T
70 override <T extends RpcService> getRouterFor(Class<T> iface) {
71 val contexts = new HashSet<Class<? extends BaseIdentity>>
73 val instance = <T>withClassLoader(iface.classLoader) [ |
74 val supertype = iface.asCtClass
75 val targetCls = createClass(iface.routerName, supertype) [
76 //field(ROUTING_TABLE_FIELD,Map)
77 field(DELEGATE_FIELD, iface)
78 val ctxMap = new HashMap<String, Class<? extends BaseIdentity>>();
79 // We search for routing pairs and add fields
80 supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
81 val routingPair = method.routingContextInput;
82 if (routingPair !== null) {
83 ctxMap.put(routingPair.context.routingTableField, routingPair.context);
84 contexts.add(routingPair.context)
87 for (ctx : ctxMap.entrySet) {
90 implementMethodsFrom(supertype) [
91 if (parameterTypes.size === 1) {
92 val routingPair = routingContextInput;
95 final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»()«IF routingPair.
96 encapsulated».getValue()«ENDIF»;
97 «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier);
98 if(instance == null) {
99 instance = «DELEGATE_FIELD»;
101 if(instance == null) {
102 throw new java.lang.IllegalStateException("No provider is processing supplied message");
104 return ($r) instance.«it.name»($$);
107 } else if (parameterTypes.size === 0) {
108 body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
112 return targetCls.toClass(iface.classLoader).newInstance as T
114 return new RpcRouterCodegenInstance(iface, instance, contexts);
117 protected def generateListenerInvoker(Class<? extends NotificationListener> iface) {
118 val callbacks = iface.methods.filter[notificationCallback]
120 val supportedNotification = callbacks.map[parameterTypes.get(0) as Class<? extends Notification>].toSet;
122 val targetCls = createClass(iface.invokerName,BROKER_NOTIFICATION_LISTENER ) [
123 field(DELEGATE_FIELD, iface)
124 implementMethodsFrom(BROKER_NOTIFICATION_LISTENER) [
127 «FOR callback : callbacks SEPARATOR " else "»
128 «val cls = callback.parameterTypes.get(0).name»
129 if($1 instanceof «cls») {
130 «DELEGATE_FIELD».«callback.name»((«cls») $1);
139 val finalClass = targetCls.toClass(iface.classLoader,iface.protectionDomain)
140 return new RuntimeGeneratedInvokerPrototype(supportedNotification,
141 finalClass as Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener>);
144 def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
145 val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
146 function1.process(method);
147 it.addMethod(method);
150 private def routingContextInput(CtMethod method) {
151 val inputClass = method.parameterTypes.get(0);
152 return inputClass.contextInstance;
155 private def RoutingPair getContextInstance(CtClass dataClass) {
156 for (method : dataClass.methods) {
157 if (method.name.startsWith("get") && method.parameterTypes.size === 0) {
158 for (annotation : method.availableAnnotations) {
159 if (annotation instanceof RoutingContext) {
160 val encapsulated = !method.returnType.equals(InstanceIdentifier.asCtClass);
162 return new RoutingPair((annotation as RoutingContext).value, method, encapsulated);
167 for (iface : dataClass.interfaces) {
168 val ret = getContextInstance(iface);
169 if(ret != null) return ret;
174 private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
175 for (method : source.methods) {
176 if (method.declaringClass == source) {
177 val redeclaredMethod = new CtMethod(method, target, null);
178 function1.process(redeclaredMethod);
179 target.addMethod(redeclaredMethod);
184 private def CtClass createClass(String fqn, ClassGenerator cls) {
185 val target = classPool.makeClass(fqn);
190 private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
191 val target = classPool.makeClass(fqn);
192 target.implementsType(superInterface);
197 private def void implementsType(CtClass it, CtClass supertype) {
198 checkArgument(supertype.interface, "Supertype must be interface");
199 addInterface(supertype);
202 private def asCtClass(Class<?> class1) {
203 classPool.get(class1);
206 private def CtField field(CtClass it, String name, Class<?> returnValue) {
207 val field = new CtField(returnValue.asCtClass, name, it);
208 field.modifiers = Modifier.PUBLIC
213 def get(ClassPool pool, Class<?> cls) {
215 return pool.get(cls.name)
216 } catch (NotFoundException e) {
217 pool.appendClassPath(new LoaderClassPath(cls.classLoader));
219 return pool.get(cls.name)
221 } catch (NotFoundException ef) {
222 pool.appendClassPath(new ClassClassPath(cls));
223 return pool.get(cls.name)
228 override getInvokerFactory() {
232 override invokerFor(NotificationListener instance) {
233 val cls = instance.class
234 val prototype = resolveInvokerClass(cls);
236 return new RuntimeGeneratedInvoker(instance,prototype)
239 def resolveInvokerClass(Class<? extends NotificationListener> class1) {
240 val invoker = invokerClasses.get(class1);
241 if (invoker !== null) {
244 val newInvoker = generateListenerInvoker(class1);
245 invokerClasses.put(class1, newInvoker);
251 class RuntimeGeneratedInvoker implements NotificationInvoker {
254 val NotificationListener delegate;
258 var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy;
261 var RuntimeGeneratedInvokerPrototype prototype;
263 new(NotificationListener delegate,RuntimeGeneratedInvokerPrototype prototype) {
264 _delegate = delegate;
265 _prototype = prototype;
266 _invocationProxy = prototype.protoClass.newInstance;
267 RuntimeCodeHelper.setDelegate(_invocationProxy, delegate);
270 override getSupportedNotifications() {
271 prototype.supportedNotifications;
280 class RuntimeGeneratedInvokerPrototype {
283 val Set<Class<? extends Notification>> supportedNotifications;
286 val Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener> protoClass;