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.*
39 class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator {
41 val ClassPool classPool;
43 public new(ClassPool pool) {
47 override <T extends RpcService> getDirectProxyFor(Class<T> iface) {
48 val supertype = iface.asCtClass
49 val targetCls = createClass(iface.directProxyName, supertype) [
50 field(DELEGATE_FIELD, iface);
51 implementMethodsFrom(supertype) [
52 body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
55 return targetCls.toClass(iface.classLoader).newInstance as T
58 override <T extends RpcService> getRouterFor(Class<T> iface) {
59 val contexts = new HashSet<Class<? extends BaseIdentity>>
61 val instance = <T>withClassLoader(iface.classLoader) [ |
62 val supertype = iface.asCtClass
63 val targetCls = createClass(iface.routerName, supertype) [
64 //field(ROUTING_TABLE_FIELD,Map)
65 field(DELEGATE_FIELD, iface)
66 val ctxMap = new HashMap<String, Class<? extends BaseIdentity>>();
67 // We search for routing pairs and add fields
68 supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
69 val routingPair = method.routingContextInput;
70 if (routingPair !== null) {
71 ctxMap.put(routingPair.context.routingTableField, routingPair.context);
72 contexts.add(routingPair.context)
75 for (ctx : ctxMap.entrySet) {
78 implementMethodsFrom(supertype) [
79 if (parameterTypes.size === 1) {
80 val routingPair = routingContextInput;
83 final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»()«IF routingPair.encapsulated».getValue()«ENDIF»;
84 «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier);
85 if(instance == null) {
86 instance = «DELEGATE_FIELD»;
88 if(instance == null) {
89 throw new java.lang.IllegalStateException("No provider is processing supplied message");
91 return ($r) instance.«it.name»($$);
94 } else if (parameterTypes.size === 0) {
95 body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
99 return targetCls.toClass(iface.classLoader).newInstance as T
101 return new RpcRouterCodegenInstance(iface, instance, contexts);
104 def Class<?> generateListenerInvoker(Class<? extends NotificationListener> iface) {
105 val targetCls = createClass(iface.invokerName) [
106 field(DELEGATE_FIELD, iface)
107 it.method(Void, "invoke", Notification) [
108 val callbacks = iface.methods.filter[notificationCallback]
111 «FOR callback : callbacks SEPARATOR " else "»
112 if($1 instanceof «val cls = callback.parameterTypes.get(0).name») {
113 «DELEGATE_FIELD».«callback.name»((«cls») $1);
121 return targetCls.toClass(iface.classLoader);
124 def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
125 val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
126 function1.process(method);
127 it.addMethod(method);
130 private def routingContextInput(CtMethod method) {
131 val inputClass = method.parameterTypes.get(0);
132 return inputClass.contextInstance;
135 private def RoutingPair getContextInstance(CtClass dataClass) {
136 for (method : dataClass.methods) {
137 if (method.name.startsWith("get") && method.parameterTypes.size === 0) {
138 for (annotation : method.availableAnnotations) {
139 if (annotation instanceof RoutingContext) {
140 val encapsulated = !method.returnType.equals(InstanceIdentifier.asCtClass);
142 return new RoutingPair((annotation as RoutingContext).value, method,encapsulated);
147 for (iface : dataClass.interfaces) {
148 val ret = getContextInstance(iface);
149 if(ret != null) return ret;
154 private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
155 for (method : source.methods) {
156 if (method.declaringClass == source) {
157 val redeclaredMethod = new CtMethod(method, target, null);
158 function1.process(redeclaredMethod);
159 target.addMethod(redeclaredMethod);
164 private def CtClass createClass(String fqn, ClassGenerator cls) {
165 val target = classPool.makeClass(fqn);
170 private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
171 val target = classPool.makeClass(fqn);
172 target.implementsType(superInterface);
177 private def void implementsType(CtClass it, CtClass supertype) {
178 checkArgument(supertype.interface, "Supertype must be interface");
179 addInterface(supertype);
182 private def asCtClass(Class<?> class1) {
183 classPool.get(class1);
186 private def CtField field(CtClass it, String name, Class<?> returnValue) {
187 val field = new CtField(returnValue.asCtClass, name, it);
188 field.modifiers = Modifier.PUBLIC
193 def get(ClassPool pool, Class<?> cls) {
195 return pool.get(cls.name)
196 } catch (NotFoundException e) {
197 pool.appendClassPath(new LoaderClassPath(cls.classLoader));
198 return pool.get(cls.name)