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.*
36 class RuntimeCodeGenerator {
38 val ClassPool classPool;
40 public new(ClassPool pool) {
44 def <T extends RpcService> Class<? extends T> generateDirectProxy(Class<T> iface) {
45 val supertype = iface.asCtClass
46 val targetCls = createClass(iface.directProxyName, supertype) [
47 field(DELEGATE_FIELD, iface);
48 implementMethodsFrom(supertype) [
49 body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
52 return targetCls.toClass(iface.classLoader)
55 def <T extends RpcService> Class<? extends T> generateRouter(Class<T> iface) {
56 val supertype = iface.asCtClass
57 val targetCls = createClass(iface.routerName, supertype) [
58 //field(ROUTING_TABLE_FIELD,Map)
59 field(DELEGATE_FIELD, iface)
60 val contexts = new HashMap<String, Class<? extends BaseIdentity>>();
61 // We search for routing pairs and add fields
62 supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
63 val routingPair = method.routingContextInput;
64 if (routingPair !== null)
65 contexts.put(routingPair.context.routingTableField, routingPair.context);
67 for (ctx : contexts.entrySet) {
70 implementMethodsFrom(supertype) [
71 if (parameterTypes.size === 1) {
72 val routingPair = routingContextInput;
75 final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»();
76 «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier);
77 if(instance == null) {
78 instance = «DELEGATE_FIELD»;
80 return ($r) instance.«it.name»($$);
83 } else if (parameterTypes.size === 0) {
84 body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
88 return targetCls.toClass(iface.classLoader)
91 def Class<?> generateListenerInvoker(Class<? extends NotificationListener> iface) {
92 val targetCls = createClass(iface.invokerName) [
93 field(DELEGATE_FIELD, iface)
94 it.method(Void, "invoke", Notification) [
95 val callbacks = iface.methods.filter[notificationCallback]
98 «FOR callback : callbacks SEPARATOR " else "»
99 if($1 instanceof «val cls = callback.parameterTypes.get(0).name») {
100 «DELEGATE_FIELD».«callback.name»((«cls») $1);
108 return targetCls.toClass(iface.classLoader);
111 def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
112 val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
113 function1.process(method);
114 it.addMethod(method);
117 private def routingContextInput(CtMethod method) {
118 val inputClass = method.parameterTypes.get(0);
119 return inputClass.contextInstance;
122 private def RoutingPair getContextInstance(CtClass dataClass) {
123 for (method : dataClass.methods) {
124 if (method.parameterTypes.size === 0 && method.name.startsWith("get")) {
125 for (annotation : method.availableAnnotations) {
126 if (annotation instanceof RoutingContext) {
127 return new RoutingPair((annotation as RoutingContext).value, method)
132 for (iface : dataClass.interfaces) {
133 val ret = getContextInstance(iface);
134 if (ret != null) return ret;
139 private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
140 for (method : source.methods) {
141 if (method.declaringClass == source) {
142 val redeclaredMethod = new CtMethod(method, target, null);
143 function1.process(redeclaredMethod);
144 target.addMethod(redeclaredMethod);
149 private def CtClass createClass(String fqn, ClassGenerator cls) {
150 val target = classPool.makeClass(fqn);
155 private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
156 val target = classPool.makeClass(fqn);
157 target.implementsType(superInterface);
162 private def void implementsType(CtClass it, CtClass supertype) {
163 checkArgument(supertype.interface, "Supertype must be interface");
164 addInterface(supertype);
167 private def asCtClass(Class<?> class1) {
168 classPool.get(class1);
171 private def CtField field(CtClass it, String name, Class<?> returnValue) {
172 val field = new CtField(returnValue.asCtClass, name, it);
173 field.modifiers = Modifier.PUBLIC
178 def get(ClassPool pool, Class<?> cls) {
180 return pool.get(cls.name)
181 } catch (NotFoundException e) {
182 pool.appendClassPath(new LoaderClassPath(cls.classLoader));
183 return pool.get(cls.name)