Merge "Bug 1328: Improved argument checks in generated RPC Router"
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / sal / binding / codegen / impl / RuntimeCodeGenerator.xtend
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.sal.binding.codegen.impl
9
10 import java.util.Map
11 import javassist.ClassPool
12 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
13 import org.opendaylight.yangtools.yang.binding.Notification
14 import org.opendaylight.yangtools.yang.binding.RpcImplementation
15 import org.opendaylight.yangtools.yang.binding.util.BindingReflections
16 import org.opendaylight.yangtools.yang.binding.util.ClassLoaderUtils
17
18 import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
19 import org.opendaylight.yangtools.yang.binding.RpcService
20
21 class RuntimeCodeGenerator extends AbstractRuntimeCodeGenerator {
22
23     new(ClassPool pool) {
24         super(pool)
25     }
26
27     override directProxySupplier(Class iface) {
28         return [|
29             val proxyName = iface.directProxyName;
30             val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName)
31             if(potentialClass != null) {
32                 return potentialClass.newInstance as RpcService;
33             }
34             val supertype = iface.asCtClass
35             val createdCls = createClass(iface.directProxyName, supertype) [
36                 field(DELEGATE_FIELD, iface);
37                 implementsType(RpcImplementation.asCtClass)
38                 implementMethodsFrom(supertype) [
39                     body = '''
40                     {
41                         if(«DELEGATE_FIELD» == null) {
42                             throw new java.lang.IllegalStateException("No default provider is available");
43                         }
44                         return ($r) «DELEGATE_FIELD».«it.name»($$);
45                     }
46                     '''
47                 ]
48                 implementMethodsFrom(RpcImplementation.asCtClass) [
49                     body = '''
50                     {
51                         throw new java.lang.IllegalStateException("No provider is processing supplied message");
52                         return ($r) null;
53                     }
54                     '''
55                 ]
56             ]
57             return createdCls.toClass(iface.classLoader).newInstance as RpcService
58         ]
59     }
60
61     override routerSupplier(Class iface, RpcServiceMetadata metadata) {
62         return [ |
63             val supertype = iface.asCtClass
64             val routerName = iface.routerName;
65             val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName)
66             if(potentialClass != null) {
67                 return potentialClass.newInstance as RpcService;
68             }
69
70             val targetCls = createClass(iface.routerName, supertype) [
71
72
73                 field(DELEGATE_FIELD, iface)
74                 //field(REMOTE_INVOKER_FIELD,iface);
75                 implementsType(RpcImplementation.asCtClass)
76
77                 for (ctx : metadata.contexts) {
78                     field(ctx.routingTableField, Map)
79                 }
80                 implementMethodsFrom(supertype) [
81                     if (parameterTypes.size === 1) {
82                         val rpcMeta = metadata.getRpcMethod(name);
83                         val bodyTmp = '''
84                         {
85                             if($1 == null) {
86                                 throw new IllegalArgumentException("RPC input must not be null and must contain a value for field «rpcMeta.inputRouteGetter.name»");
87                             }
88                             if($1.«rpcMeta.inputRouteGetter.name»() == null) {
89                                 throw new IllegalArgumentException("Field «rpcMeta.inputRouteGetter.name» must not be null");
90                             }
91                             final «InstanceIdentifier.name» identifier = $1.«rpcMeta.inputRouteGetter.name»()«IF rpcMeta.
92                             routeEncapsulated».getValue()«ENDIF»;
93                             «supertype.name» instance = («supertype.name») «rpcMeta.context.routingTableField».get(identifier);
94                             if(instance == null) {
95                                instance = «DELEGATE_FIELD»;
96                             }
97                             if(instance == null) {
98                                 throw new java.lang.IllegalStateException("No routable provider is processing routed message for " + String.valueOf(identifier));
99                             }
100                             return ($r) instance.«it.name»($$);
101                         }'''
102                         body = bodyTmp
103                     } else if (parameterTypes.size === 0) {
104                         body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
105                     }
106                 ]
107                 implementMethodsFrom(RpcImplementation.asCtClass) [
108                     body = '''
109                     {
110                         throw new java.lang.IllegalStateException("No provider is processing supplied message");
111                         return ($r) null;
112                     }
113                     '''
114                 ]
115             ]
116             return  targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as RpcService
117         ];
118     }
119
120     override generateListenerInvoker(Class iface) {
121         val callbacks = iface.methods.filter[BindingReflections.isNotificationCallback(it)]
122
123         val supportedNotification = callbacks.map[parameterTypes.get(0) as Class<? extends Notification>].toSet;
124
125         val targetCls = createClass(iface.invokerName, brokerNotificationListener) [
126             field(DELEGATE_FIELD, iface)
127             implementMethodsFrom(brokerNotificationListener) [
128                 body = '''
129                     {
130                         «FOR callback : callbacks SEPARATOR " else "»
131                             «val cls = callback.parameterTypes.get(0).name»
132                                 if($1 instanceof «cls») {
133                                     «DELEGATE_FIELD».«callback.name»((«cls») $1);
134                                     return null;
135                                 }
136                         «ENDFOR»
137                         return null;
138                     }
139                 '''
140             ]
141         ]
142         val finalClass = targetCls.toClass(iface.classLoader, iface.protectionDomain)
143         return new RuntimeGeneratedInvokerPrototype(supportedNotification,
144             finalClass as Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener<?>>);
145     }
146 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.