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 com.google.common.base.Supplier;
11 import com.google.common.collect.ImmutableSet;
12 import com.google.common.collect.ImmutableSet.Builder;
13 import java.lang.reflect.Method;
15 import javassist.CannotCompileException;
16 import javassist.ClassPool;
17 import javassist.CtClass;
18 import javassist.CtMethod;
19 import javassist.NotFoundException;
20 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification;
21 import org.opendaylight.yangtools.sal.binding.generator.util.ClassGenerator;
22 import org.opendaylight.yangtools.sal.binding.generator.util.MethodGenerator;
23 import org.opendaylight.yangtools.util.ClassLoaderUtils;
24 import org.opendaylight.yangtools.yang.binding.BaseIdentity;
25 import org.opendaylight.yangtools.yang.binding.Notification;
26 import org.opendaylight.yangtools.yang.binding.NotificationListener;
27 import org.opendaylight.yangtools.yang.binding.RpcImplementation;
28 import org.opendaylight.yangtools.yang.binding.RpcService;
29 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
31 final class DefaultRuntimeCodeGenerator extends AbstractRuntimeCodeGenerator {
33 DefaultRuntimeCodeGenerator(final ClassPool pool) {
38 protected <T extends RpcService> Supplier<T> directProxySupplier(final Class<T> serviceType) {
39 return new Supplier<T>() {
40 @SuppressWarnings("unchecked")
43 final String proxyName = RuntimeCodeSpecification.getDirectProxyName(serviceType);
45 final Class<?> potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName);
46 if (potentialClass != null) {
48 return (T)potentialClass.newInstance();
49 } catch (InstantiationException | IllegalAccessException e) {
50 throw new IllegalStateException("Failed to instantiate class " + potentialClass.getName(), e);
54 final CtClass supertype = utils.asCtClass(serviceType);
55 final String directProxyName = RuntimeCodeSpecification.getDirectProxyName(serviceType);
57 final CtClass createdCls;
59 createdCls = utils.createClass(directProxyName, supertype, new ClassGenerator() {
61 public void process(final CtClass cls) throws CannotCompileException {
62 utils.field(cls, RuntimeCodeSpecification.DELEGATE_FIELD, serviceType);
63 utils.implementsType(cls, utils.asCtClass(RpcImplementation.class));
64 utils.implementMethodsFrom(cls, supertype, new MethodGenerator() {
66 public void process(final CtMethod method) throws CannotCompileException {
67 final StringBuilder sb = new StringBuilder("\n");
69 sb.append(" if (").append(RuntimeCodeSpecification.DELEGATE_FIELD).append(" == null) {\n");
70 sb.append(" throw new java.lang.IllegalStateException(\"No default provider is available\");\n");
72 sb.append(" return ($r) ").append(RuntimeCodeSpecification.DELEGATE_FIELD).append('.').append(method.getName()).append("($$);\n");
74 method.setBody(sb.toString());
78 // FIXME: copy this one...
79 utils.implementMethodsFrom(cls, utils.asCtClass(RpcImplementation.class), new MethodGenerator() {
81 public void process(final CtMethod method) throws CannotCompileException {
82 final StringBuilder sb = new StringBuilder("\n");
84 sb.append(" throw new java.lang.IllegalStateException(\"No provider is processing supplied message\");\n");
85 sb.append(" return ($r) null;\n");
87 method.setBody(sb.toString());
92 } catch (CannotCompileException e) {
93 throw new IllegalStateException("Failed to create class " + directProxyName, e);
98 c = createdCls.toClass(serviceType.getClassLoader(), serviceType.getProtectionDomain());
99 } catch (CannotCompileException e) {
100 throw new IllegalStateException(String.format("Failed to create class %s", createdCls), e);
104 return (T) c.newInstance();
105 } catch (InstantiationException | IllegalAccessException e) {
106 throw new IllegalStateException(String.format("Failed to instantiated class %s", c), e);
113 protected <T extends RpcService> Supplier<T> routerSupplier(final Class<T> serviceType, final RpcServiceMetadata metadata) {
114 return new Supplier<T>() {
115 @SuppressWarnings("unchecked")
118 final CtClass supertype = utils.asCtClass(serviceType);
119 final String routerName = RuntimeCodeSpecification.getRouterName(serviceType);
120 final Class<?> potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName);
121 if (potentialClass != null) {
123 return (T)potentialClass.newInstance();
124 } catch (InstantiationException | IllegalAccessException e) {
125 throw new IllegalStateException("Failed to instantiate class", e);
129 final CtClass targetCls;
131 targetCls = utils.createClass(routerName, supertype, new ClassGenerator() {
133 public void process(final CtClass cls) throws CannotCompileException {
134 utils.field(cls, RuntimeCodeSpecification.DELEGATE_FIELD, serviceType);
135 //utils.field(cls, REMOTE_INVOKER_FIELD,iface);
136 utils.implementsType(cls, utils.asCtClass(RpcImplementation.class));
138 for (final Class<? extends BaseIdentity> ctx : metadata.getContexts()) {
139 utils.field(cls, RuntimeCodeSpecification.getRoutingTableField(ctx), Map.class);
142 utils.implementMethodsFrom(cls, supertype, new MethodGenerator() {
144 public void process(final CtMethod method) throws CannotCompileException {
147 ptl = method.getParameterTypes().length;
148 } catch (NotFoundException e) {
149 throw new CannotCompileException(e);
151 final StringBuilder sb = new StringBuilder();
155 sb.append("return ($r) ").append(RuntimeCodeSpecification.DELEGATE_FIELD).append('.').append(method.getName()).append("($$);");
158 final RpcMetadata rpcMeta = metadata.getRpcMethod(method.getName());
159 final String rtGetter = rpcMeta.getInputRouteGetter().getName();
160 final String stName = supertype.getName();
164 sb.append(" if ($1 == null) {\n");
165 sb.append(" throw new IllegalArgumentException(\"RPC input must not be null and must contain a value for field ").append(rtGetter).append("\");\n");
167 sb.append(" if ($1.").append(rtGetter).append("() == null) {\n");
168 sb.append(" throw new IllegalArgumentException(\"Field ").append(rtGetter).append(" must not be null\");\n");
171 sb.append(" final org.opendaylight.yangtools.yang.binding.InstanceIdentifier identifier = $1.").append(rtGetter).append("()");
172 if (rpcMeta.isRouteEncapsulated()) {
173 sb.append(".getValue()");
177 sb.append(" ").append(supertype.getName()).append(" instance = (").append(stName).append(") ").append(RuntimeCodeSpecification.getRoutingTableField(rpcMeta.getContext())).append(".get(identifier);\n");
178 sb.append(" if (instance == null) {\n");
179 sb.append(" instance = ").append(RuntimeCodeSpecification.DELEGATE_FIELD).append(";\n");
182 sb.append(" if (instance == null) {\n");
183 sb.append(" throw new java.lang.IllegalStateException(\"No routable provider is processing routed message for \" + String.valueOf(identifier));\n");
185 sb.append(" return ($r) instance.").append(method.getName()).append("($$);\n");
189 throw new CannotCompileException(String.format("Unsupported parameters length %s", ptl));
192 method.setBody(sb.toString());
196 // FIXME: move this into a template class
197 utils.implementMethodsFrom(cls, utils.asCtClass(RpcImplementation.class), new MethodGenerator() {
199 public void process(final CtMethod method) throws CannotCompileException {
200 final StringBuilder sb = new StringBuilder("\n");
202 sb.append(" throw new java.lang.IllegalStateException(\"No provider is processing supplied message\");\n");
203 sb.append(" return ($r) null;\n");
206 method.setBody(sb.toString());
211 } catch (CannotCompileException e) {
212 throw new IllegalStateException("Failed to create class " + routerName, e);
217 c = targetCls.toClass(serviceType.getClassLoader(), serviceType.getProtectionDomain());
218 } catch (CannotCompileException e) {
219 throw new IllegalStateException(String.format("Failed to compile class %s", targetCls), e);
223 return (T)c.newInstance();
224 } catch (InstantiationException | IllegalAccessException e) {
225 throw new IllegalStateException(String.format("Failed to instantiate class %s", c), e);
231 @SuppressWarnings("unchecked")
233 protected RuntimeGeneratedInvokerPrototype generateListenerInvoker(final Class<? extends NotificationListener> listenerType) {
234 final String invokerName = RuntimeCodeSpecification.getInvokerName(listenerType);
235 final CtClass targetCls;
237 // Builder for a set of supported types. Filled while the target class is being generated
238 final Builder<Class<? extends Notification>> b = ImmutableSet.builder();
241 targetCls = utils.createClass(invokerName, getBrokerNotificationListener(), new ClassGenerator() {
243 public void process(final CtClass cls) throws CannotCompileException {
244 utils.field(cls, RuntimeCodeSpecification.DELEGATE_FIELD, listenerType);
245 utils.implementMethodsFrom(cls, getBrokerNotificationListener(), new MethodGenerator() {
247 public void process(final CtMethod method) throws CannotCompileException {
248 final StringBuilder sb = new StringBuilder("\n");
252 for (Method m : listenerType.getMethods()) {
253 if (BindingReflections.isNotificationCallback(m)) {
254 final Class<?> argType = m.getParameterTypes()[0];
256 // populates builder above
257 b.add((Class<? extends Notification>) argType);
259 sb.append(" if ($1 instanceof ").append(argType.getName()).append(") {\n");
260 sb.append(" ").append(RuntimeCodeSpecification.DELEGATE_FIELD).append('.').append(m.getName()).append("((").append(argType.getName()).append(") $1);\n");
261 sb.append(" return null;\n");
262 sb.append(" } else ");
266 sb.append(" return null;\n");
268 method.setBody(sb.toString());
273 } catch (CannotCompileException e) {
274 throw new IllegalStateException("Failed to create class " + invokerName, e);
277 final Class<?> finalClass;
279 finalClass = targetCls.toClass(listenerType.getClassLoader(), listenerType.getProtectionDomain());
280 } catch (CannotCompileException e) {
281 throw new IllegalStateException(String.format("Failed to compile class %s", targetCls), e);
284 return new RuntimeGeneratedInvokerPrototype(b.build(), (Class<? extends org.opendaylight.controller.sal.binding.api.NotificationListener<?>>) finalClass);