/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sal.binding.impl import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer import org.opendaylight.controller.sal.binding.api.BindingAwareProvider import org.opendaylight.yangtools.yang.binding.RpcService import javassist.ClassPool import javassist.CtMethod import javassist.CtField import org.osgi.framework.BundleContext import java.util.Map import java.util.HashMap import javassist.LoaderClassPath import org.opendaylight.controller.sal.binding.api.BindingAwareBroker import java.util.Hashtable import static extension org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils.* import static extension org.opendaylight.controller.sal.binding.impl.utils.GeneratorUtils.* import org.opendaylight.controller.sal.binding.api.NotificationProviderService import org.osgi.framework.ServiceRegistration import org.opendaylight.controller.sal.binding.impl.utils.PropertiesUtils import org.opendaylight.controller.sal.binding.api.NotificationService import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext import javassist.Modifier import org.slf4j.LoggerFactory class BindingAwareBrokerImpl implements BindingAwareBroker { private static val DELEGATE_FIELD = "_delegate" private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl) private val clsPool = ClassPool.getDefault() private Map, RpcProxyContext> managedProxies = new HashMap(); private var NotificationBrokerImpl notifyBroker private var ServiceRegistration notifyBrokerRegistration private var DataBrokerImpl dataBroker @Property var BundleContext brokerBundleContext def start() { initGenerator(); // Initialization of notificationBroker notifyBroker = new NotificationBrokerImpl(null); val brokerProperties = PropertiesUtils.newProperties(); notifyBrokerRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker, brokerProperties) brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties) } def initGenerator() { // YANG Binding Class Loader clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader)) } override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) { val ctx = consumer.createContext(bundleCtx) consumer.onSessionInitialized(ctx) return ctx } override registerProvider(BindingAwareProvider provider, BundleContext bundleCtx) { val ctx = provider.createContext(bundleCtx) provider.onSessionInitialized(ctx) provider.onSessionInitiated(ctx as ProviderContext) return ctx } private def createContext(BindingAwareConsumer consumer, BundleContext consumerCtx) { new OsgiConsumerContext(consumerCtx, this) } private def createContext(BindingAwareProvider provider, BundleContext providerCtx) { new OsgiProviderContext(providerCtx, this) } /** * Returns a Managed Direct Proxy for supplied class * * Managed direct proxy is a generated proxy class conforming to the supplied interface * which delegates all calls to the backing delegate. * * Proxy does not do any validation, null pointer checks or modifies data in any way, it * is only use to avoid exposing direct references to backing implementation of service. * * If proxy class does not exist for supplied service class it will be generated automatically. */ def getManagedDirectProxy(Class service) { var RpcProxyContext existing = null if ((existing = managedProxies.get(service)) != null) { return existing.proxy } val proxyClass = service.generateDirectProxy() val rpcProxyCtx = new RpcProxyContext(proxyClass) val properties = new Hashtable() rpcProxyCtx.proxy = proxyClass.newInstance as RpcService properties.salServiceType = Constants.SAL_SERVICE_TYPE_CONSUMER_PROXY rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties) managedProxies.put(service, rpcProxyCtx) return rpcProxyCtx.proxy } protected def generateDirectProxy(Class delegate) { val targetFqn = delegate.generatedName(Constants.PROXY_DIRECT_SUFFIX) log.debug("Generating DirectProxy for {} Proxy name: {}",delegate,targetFqn); val objCls = clsPool.get(Object) val delegateCls = clsPool.get(delegate) val proxyCls = clsPool.makeClass(targetFqn) proxyCls.addInterface(delegateCls) val delField = new CtField(delegateCls, DELEGATE_FIELD, proxyCls); delField.modifiers = Modifier.PUBLIC proxyCls.addField(delField) delegateCls.methods.filter[it.declaringClass != objCls].forEach [ val proxyMethod = new CtMethod(it, proxyCls, null); proxyMethod.body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);''' proxyCls.addMethod(proxyMethod) ] return proxyCls.toClass(delegate.classLoader) } /** * Registers RPC Implementation * */ def registerRpcImplementation(Class type, T service, OsgiProviderContext context, Hashtable properties) { val proxy = getManagedDirectProxy(type) if(proxy.delegate != null) { throw new IllegalStateException("Service " + type + "is already registered"); } val osgiReg = context.bundleContext.registerService(type, service, properties); proxy.delegate = service; return new RpcServiceRegistrationImpl(type, service, osgiReg); } /** * Helper method to return delegate from ManagedDirectedProxy with use of reflection. * * Note: This method uses reflection, but access to delegate field should be * avoided and called only if neccessary. * */ def getDelegate(RpcService proxy) { val field = proxy.class.getField(DELEGATE_FIELD) if(field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy"); return field.get(proxy) as T } /** * Helper method to set delegate to ManagedDirectedProxy with use of reflection. * * Note: This method uses reflection, but setting delegate field should not occur too much * to introduce any significant performance hits. * */ def void setDelegate(RpcService proxy, RpcService delegate) { val field = proxy.class.getField(DELEGATE_FIELD) if(field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy"); if (field.type.isAssignableFrom(delegate.class)) { field.set(proxy,delegate) } else throw new IllegalArgumentException("delegate class is not assignable to proxy"); } }