Add blueprint extensions to get and register RPC services 85/36485/20
authorTom Pantelis <tpanteli@brocade.com>
Mon, 21 Mar 2016 08:41:47 +0000 (04:41 -0400)
committerTom Pantelis <tpanteli@brocade.com>
Fri, 8 Apr 2016 21:00:06 +0000 (21:00 +0000)
Added several blueprint extension elements to support RPCs:

<rpc-implementation> - registers a global RPC implementation. If
"interface" isn't specified, it registers all RpcService interfaces
implemented by the ref'ed instance.

<routed-rpc-implementation> - registers a routed RPC implementation
and returns a RoutedRpcRegistration instance for injection into other
beans via the specified "id. If "interface" isn't specified, it looks
for a single RpcService interface implemented by the ref'ed instance.
If multiple are found it fails since only one RoutedRpcRegistration
instance can be returned.

<rpc-service> - finds the registered RpcService corresponding to the
specified "interface" and makes it available for injection into other
beans via the specified "id".

Internally the bean implementations obtain the binding
RpcServiceRegistry.

Change-Id: I432dfb5378ca8368e41fb5375c9d5515dd3e714d
Signed-off-by: Tom Pantelis <tpanteli@brocade.com>
opendaylight/blueprint/pom.xml
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/OpendaylightNamespaceHandler.java
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcMetadata.java [new file with mode: 0644]
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcRegistrationConverter.java [new file with mode: 0644]
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RpcImplementationBean.java [new file with mode: 0644]
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RpcServiceMetadata.java [new file with mode: 0644]
opendaylight/blueprint/src/main/resources/opendaylight-blueprint-ext-1.0.0.xsd

index 511a185cd4d1cea8d1aa712e7eac730b8456fa3e..fc033947b2db13e381a06a7030f4c79d257d9a67 100644 (file)
       <artifactId>org.apache.aries.blueprint.core</artifactId>
       <version>1.4.2</version>
     </dependency>
       <artifactId>org.apache.aries.blueprint.core</artifactId>
       <version>1.4.2</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
index 0b361263f60516fab8031e5036eee4d9d6b8fc06..bafc1f7a7347ec6165de5bad3932dd48921dec94 100644 (file)
@@ -14,6 +14,7 @@ import java.util.Set;
 import org.apache.aries.blueprint.ComponentDefinitionRegistry;
 import org.apache.aries.blueprint.NamespaceHandler;
 import org.apache.aries.blueprint.ParserContext;
 import org.apache.aries.blueprint.ComponentDefinitionRegistry;
 import org.apache.aries.blueprint.NamespaceHandler;
 import org.apache.aries.blueprint.ParserContext;
+import org.apache.aries.blueprint.ext.ComponentFactoryMetadata;
 import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
 import org.apache.aries.blueprint.mutable.MutableRefMetadata;
 import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
 import org.apache.aries.blueprint.mutable.MutableBeanMetadata;
 import org.apache.aries.blueprint.mutable.MutableRefMetadata;
 import org.apache.aries.blueprint.mutable.MutableReferenceMetadata;
@@ -21,6 +22,7 @@ import org.apache.aries.blueprint.mutable.MutableServiceMetadata;
 import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata;
 import org.apache.aries.blueprint.mutable.MutableValueMetadata;
 import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
 import org.apache.aries.blueprint.mutable.MutableServiceReferenceMetadata;
 import org.apache.aries.blueprint.mutable.MutableValueMetadata;
 import org.opendaylight.controller.blueprint.BlueprintContainerRestartService;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.osgi.service.blueprint.container.ComponentDefinitionException;
 import org.osgi.service.blueprint.reflect.BeanMetadata;
 import org.osgi.service.blueprint.reflect.ComponentMetadata;
 import org.osgi.service.blueprint.container.ComponentDefinitionException;
 import org.osgi.service.blueprint.reflect.BeanMetadata;
 import org.osgi.service.blueprint.reflect.ComponentMetadata;
@@ -43,12 +45,18 @@ import org.w3c.dom.Node;
  */
 public class OpendaylightNamespaceHandler implements NamespaceHandler {
     public static final String NAMESPACE_1_0_0 = "http://opendaylight.org/xmlns/blueprint/v1.0.0";
  */
 public class OpendaylightNamespaceHandler implements NamespaceHandler {
     public static final String NAMESPACE_1_0_0 = "http://opendaylight.org/xmlns/blueprint/v1.0.0";
+    static final String ROUTED_RPC_REG_CONVERTER_NAME = "org.opendaylight.blueprint.RoutedRpcRegConverter";
+    static final String RPC_REGISTRY_NAME = "org.opendaylight.blueprint.RpcRegistry";
 
     private static final Logger LOG = LoggerFactory.getLogger(OpendaylightNamespaceHandler.class);
     private static final String COMPONENT_PROCESSOR_NAME = ComponentProcessor.class.getName();
     private static final String RESTART_DEPENDENTS_ON_UPDATES = "restart-dependents-on-updates";
     private static final String USE_DEFAULT_FOR_REFERENCE_TYPES = "use-default-for-reference-types";
     private static final String TYPE_ATTR = "type";
 
     private static final Logger LOG = LoggerFactory.getLogger(OpendaylightNamespaceHandler.class);
     private static final String COMPONENT_PROCESSOR_NAME = ComponentProcessor.class.getName();
     private static final String RESTART_DEPENDENTS_ON_UPDATES = "restart-dependents-on-updates";
     private static final String USE_DEFAULT_FOR_REFERENCE_TYPES = "use-default-for-reference-types";
     private static final String TYPE_ATTR = "type";
+    private static final String INTERFACE = "interface";
+    private static final String REF_ATTR = "ref";
+    private static final String ID_ATTR = "id";
+    private static final String RPC_SERVICE = "rpc-service";
 
     @SuppressWarnings("rawtypes")
     @Override
 
     @SuppressWarnings("rawtypes")
     @Override
@@ -70,6 +78,15 @@ public class OpendaylightNamespaceHandler implements NamespaceHandler {
     @Override
     public Metadata parse(Element element, ParserContext context) {
         LOG.debug("In parse for {}", element);
     @Override
     public Metadata parse(Element element, ParserContext context) {
         LOG.debug("In parse for {}", element);
+
+        if (nodeNameEquals(element, RpcImplementationBean.RPC_IMPLEMENTATION)) {
+            return parseRpcImplementation(element, context);
+        } else if (nodeNameEquals(element, RoutedRpcMetadata.ROUTED_RPC_IMPLEMENTATION)) {
+            return parseRoutedRpcImplementation(element, context);
+        } else if (nodeNameEquals(element, RPC_SERVICE)) {
+            return parseRpcService(element, context);
+        }
+
         throw new ComponentDefinitionException("Unsupported standalone element: " + element.getNodeName());
     }
 
         throw new ComponentDefinitionException("Unsupported standalone element: " + element.getNodeName());
     }
 
@@ -193,6 +210,73 @@ public class OpendaylightNamespaceHandler implements NamespaceHandler {
         return metadata;
     }
 
         return metadata;
     }
 
+    private Metadata parseRpcImplementation(Element element, ParserContext context) {
+        registerRpcRegistryServiceRefBean(context);
+
+        MutableBeanMetadata metadata = context.createMetadata(MutableBeanMetadata.class);
+        metadata.setId(context.generateId());
+        metadata.setScope(BeanMetadata.SCOPE_SINGLETON);
+        metadata.setActivation(ReferenceMetadata.ACTIVATION_EAGER);
+        metadata.setRuntimeClass(RpcImplementationBean.class);
+        metadata.setInitMethod("init");
+        metadata.setDestroyMethod("destroy");
+        metadata.addProperty("bundle", createRef(context, "blueprintBundle"));
+        metadata.addProperty("rpcRegistry", createRef(context, RPC_REGISTRY_NAME));
+        metadata.addProperty("implementation", createRef(context, element.getAttribute(REF_ATTR)));
+
+        if(element.hasAttribute(INTERFACE)) {
+            metadata.addProperty("interfaceName", createValue(context, element.getAttribute(INTERFACE)));
+        }
+
+        LOG.debug("parseAddRpcImplementation returning {}", metadata);
+
+        return metadata;
+    }
+
+    private Metadata parseRoutedRpcImplementation(Element element, ParserContext context) {
+        registerRpcRegistryServiceRefBean(context);
+        registerRoutedRpcRegistrationConverter(context);
+
+        ComponentFactoryMetadata metadata = new RoutedRpcMetadata(getId(context, element),
+                element.getAttribute(INTERFACE), element.getAttribute(REF_ATTR));
+
+        LOG.debug("parseRoutedRpcImplementation returning {}", metadata);
+
+        return metadata;
+    }
+
+    private Metadata parseRpcService(Element element, ParserContext context) {
+        registerRpcRegistryServiceRefBean(context);
+
+        ComponentFactoryMetadata metadata = new RpcServiceMetadata(getId(context, element),
+                element.getAttribute(INTERFACE));
+
+        LOG.debug("parseRpcService returning {}", metadata);
+
+        return metadata;
+    }
+
+    private void registerRoutedRpcRegistrationConverter(ParserContext context) {
+        ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry();
+        if(registry.getComponentDefinition(ROUTED_RPC_REG_CONVERTER_NAME) == null) {
+            MutableBeanMetadata metadata = context.createMetadata(MutableBeanMetadata.class);
+            metadata.setId(ROUTED_RPC_REG_CONVERTER_NAME);
+            metadata.setScope(BeanMetadata.SCOPE_SINGLETON);
+            metadata.setActivation(ReferenceMetadata.ACTIVATION_LAZY);
+            metadata.setRuntimeClass(RoutedRpcRegistrationConverter.class);
+            registry.registerTypeConverter(metadata);
+        }
+    }
+
+    private void registerRpcRegistryServiceRefBean(ParserContext context) {
+        ComponentDefinitionRegistry registry = context.getComponentDefinitionRegistry();
+        if(registry.getComponentDefinition(RPC_REGISTRY_NAME) == null) {
+            MutableReferenceMetadata metadata = createServiceRef(context, RpcProviderRegistry.class, null);
+            metadata.setId(RPC_REGISTRY_NAME);
+            registry.registerComponentDefinition(metadata);
+        }
+    }
+
     private static ValueMetadata createValue(ParserContext context, String value) {
         MutableValueMetadata m = context.createMetadata(MutableValueMetadata.class);
         m.setStringValue(value);
     private static ValueMetadata createValue(ParserContext context, String value) {
         MutableValueMetadata m = context.createMetadata(MutableValueMetadata.class);
         m.setStringValue(value);
@@ -213,12 +297,20 @@ public class OpendaylightNamespaceHandler implements NamespaceHandler {
         return m;
     }
 
         return m;
     }
 
-    private static RefMetadata createRef(ParserContext context, String value) {
+    private static RefMetadata createRef(ParserContext context, String id) {
         MutableRefMetadata metadata = context.createMetadata(MutableRefMetadata.class);
         MutableRefMetadata metadata = context.createMetadata(MutableRefMetadata.class);
-        metadata.setComponentId(value);
+        metadata.setComponentId(id);
         return metadata;
     }
 
         return metadata;
     }
 
+    private static String getId(ParserContext context, Element element) {
+        if(element.hasAttribute(ID_ATTR)) {
+            return element.getAttribute(ID_ATTR);
+        } else {
+            return context.generateId();
+        }
+    }
+
     private static boolean nodeNameEquals(Node node, String name) {
         return name.equals(node.getNodeName()) || name.equals(node.getLocalName());
     }
     private static boolean nodeNameEquals(Node node, String name) {
         return name.equals(node.getNodeName()) || name.equals(node.getLocalName());
     }
diff --git a/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcMetadata.java b/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcMetadata.java
new file mode 100644 (file)
index 0000000..4b71d92
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2016 Brocade Communications 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.blueprint.ext;
+
+import java.util.Arrays;
+import java.util.List;
+import org.apache.aries.blueprint.ext.ComponentFactoryMetadata;
+import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory metadata corresponding to the "routed-rpc-implementation" element that registers an RPC
+ * implementation with the RpcProviderRegistry and provides the RoutedRpcRegistration instance to the
+ * Blueprint container.
+ *
+ * @author Thomas Pantelis
+ */
+class RoutedRpcMetadata implements ComponentFactoryMetadata {
+    private static final Logger LOG = LoggerFactory.getLogger(RoutedRpcMetadata.class);
+    static final String ROUTED_RPC_IMPLEMENTATION = "routed-rpc-implementation";
+
+    private final String id;
+    private final String interfaceName;
+    private final String implementationRefId;
+    private ExtendedBlueprintContainer container;
+
+    RoutedRpcMetadata(String id, String interfaceName, String implementationRefId) {
+        this.id = id;
+        this.interfaceName = interfaceName;
+        this.implementationRefId = implementationRefId;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public int getActivation() {
+        return ACTIVATION_LAZY;
+    }
+
+    @Override
+    public List<String> getDependsOn() {
+        return Arrays.asList(OpendaylightNamespaceHandler.RPC_REGISTRY_NAME, implementationRefId);
+    }
+
+    @Override
+    public void init(ExtendedBlueprintContainer container) {
+        this.container = container;
+
+        LOG.debug("{}: In init", logName());
+    }
+
+    @Override
+    public Object create() throws ComponentDefinitionException {
+        RpcProviderRegistry rpcRegistry = (RpcProviderRegistry) container.getComponentInstance(
+                OpendaylightNamespaceHandler.RPC_REGISTRY_NAME);
+
+        Object implementation = container.getComponentInstance(implementationRefId);
+
+        try {
+            if(!RpcService.class.isAssignableFrom(implementation.getClass())) {
+                throw new ComponentDefinitionException(String.format(
+                        "Implementation \"ref\" instance %s for \"%s\" is not an RpcService",
+                        implementation.getClass(), ROUTED_RPC_IMPLEMENTATION));
+            }
+
+            List<Class<RpcService>> rpcInterfaces = RpcImplementationBean.getImplementedRpcServiceInterfaces(
+                    interfaceName, implementation.getClass(), container.getBundleContext().getBundle(),
+                    ROUTED_RPC_IMPLEMENTATION);
+
+            if(rpcInterfaces.size() > 1) {
+                throw new ComponentDefinitionException(String.format(
+                        "Implementation \"ref\" instance %s for \"%s\" implements more than one RpcService " +
+                        "interface (%s). Please specify the exact \"interface\"", implementation.getClass(),
+                        ROUTED_RPC_IMPLEMENTATION, rpcInterfaces));
+            }
+
+            Class<RpcService> rpcInterface = rpcInterfaces.iterator().next();
+
+            LOG.debug("{}: create - adding routed implementation {} for RpcService {}", logName(),
+                    implementation, rpcInterface);
+
+            return rpcRegistry.addRoutedRpcImplementation(rpcInterface, (RpcService)implementation);
+        } catch(ComponentDefinitionException e) {
+            throw e;
+        } catch(Exception e) {
+            throw new ComponentDefinitionException(String.format(
+                    "Error processing \"%s\" for %s", ROUTED_RPC_IMPLEMENTATION, implementation.getClass()), e);
+        }
+    }
+
+    @Override
+    public void destroy(Object instance) {
+        LOG.debug("{}: In destroy: instance: {}", logName(), instance);
+
+        (( RoutedRpcRegistration<?>)instance).close();
+    }
+
+    private String logName() {
+        return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") +
+                " (" + id + ")";
+    }
+}
diff --git a/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcRegistrationConverter.java b/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RoutedRpcRegistrationConverter.java
new file mode 100644 (file)
index 0000000..acc6a01
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016 Brocade Communications 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.blueprint.ext;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
+import org.osgi.service.blueprint.container.Converter;
+import org.osgi.service.blueprint.container.ReifiedType;
+
+/**
+ * Implements a Converter that converts RoutedRpcRegistration instances. This is to work around an issue
+ * when injecting a RoutedRpcRegistration instance into a bean where Aries is not able to convert the instance
+ * returned from the RpcRegistryProvider to the desired generic RoutedRpcRegistration type specified in the
+ * bean's setter method. This is because the actual instance class specifies a generic type variable T and,
+ * even though it extends RpcService and should match, Aries doesn't handle it correctly.
+ *
+ * @author Thomas Pantelis
+ */
+public class RoutedRpcRegistrationConverter implements Converter {
+    @Override
+    public boolean canConvert(Object sourceObject, ReifiedType targetType) {
+        return sourceObject instanceof RoutedRpcRegistration &&
+                RoutedRpcRegistration.class.isAssignableFrom(targetType.getRawClass());
+    }
+
+    @Override
+    public Object convert(Object sourceObject, ReifiedType targetType) throws Exception {
+        return sourceObject;
+    }
+}
diff --git a/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RpcImplementationBean.java b/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RpcImplementationBean.java
new file mode 100644 (file)
index 0000000..b81f833
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016 Brocade Communications 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.blueprint.ext;
+
+import com.google.common.base.Strings;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.Bundle;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Blueprint bean corresponding to the "rpc-implementation" element that registers an RPC implementation with
+ * the RpcProviderRegistry.
+ *
+ * @author Thomas Pantelis
+ */
+public class RpcImplementationBean {
+    private static final Logger LOG = LoggerFactory.getLogger(RpcImplementationBean.class);
+    static final String RPC_IMPLEMENTATION = "rpc-implementation";
+
+    private RpcProviderRegistry rpcRegistry;
+    private Bundle bundle;
+    private String interfaceName;
+    private RpcService implementation;
+    private final List<RpcRegistration<RpcService>> rpcRegistrations = new ArrayList<>();;
+
+    public void setRpcRegistry(RpcProviderRegistry rpcRegistry) {
+        this.rpcRegistry = rpcRegistry;
+    }
+
+    public void setBundle(Bundle bundle) {
+        this.bundle = bundle;
+    }
+
+    public void setInterfaceName(String interfaceName) {
+        this.interfaceName = interfaceName;
+    }
+
+    public void setImplementation(RpcService implementation) {
+        this.implementation = implementation;
+    }
+
+    public void init() {
+        try {
+            List<Class<RpcService>> rpcInterfaces = getImplementedRpcServiceInterfaces(interfaceName,
+                    implementation.getClass(), bundle, RPC_IMPLEMENTATION);
+
+            LOG.debug("{}: init - adding implementation {} for RpcService interface(s) {}", bundle.getSymbolicName(),
+                    implementation, rpcInterfaces);
+
+            for(Class<RpcService> rpcInterface: rpcInterfaces) {
+                rpcRegistrations.add(rpcRegistry.addRpcImplementation(rpcInterface, implementation));
+            }
+        } catch(ComponentDefinitionException e) {
+            throw e;
+        } catch(Exception e) {
+            throw new ComponentDefinitionException(String.format(
+                    "Error processing \"%s\" for %s", RPC_IMPLEMENTATION, implementation.getClass()), e);
+        }
+    }
+
+    public void destroy() {
+        for(RpcRegistration<RpcService> reg: rpcRegistrations) {
+            reg.close();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static List<Class<RpcService>> getImplementedRpcServiceInterfaces(String interfaceName,
+            Class<?> implementationClass, Bundle bundle, String logName) throws ClassNotFoundException {
+        if(!Strings.isNullOrEmpty(interfaceName)) {
+            Class<?> rpcInterface = bundle.loadClass(interfaceName);
+
+            if(!rpcInterface.isAssignableFrom(implementationClass)) {
+                throw new ComponentDefinitionException(String.format(
+                        "The specified \"interface\" %s for \"%s\" is not implemented by RpcService \"ref\" %s",
+                        interfaceName, logName, implementationClass));
+            }
+
+            return Collections.singletonList((Class<RpcService>)rpcInterface);
+        }
+
+        List<Class<RpcService>> rpcInterfaces = new ArrayList<>();
+        for(Class<?> intface: implementationClass.getInterfaces()) {
+            if(RpcService.class.isAssignableFrom(intface)) {
+                rpcInterfaces.add((Class<RpcService>) intface);
+            }
+        }
+
+        if(rpcInterfaces.isEmpty()) {
+            throw new ComponentDefinitionException(String.format(
+                    "The \"ref\" instance %s for \"%s\" does not implemented any RpcService interfaces",
+                    implementationClass, logName));
+        }
+
+        return rpcInterfaces;
+    }
+}
diff --git a/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RpcServiceMetadata.java b/opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/ext/RpcServiceMetadata.java
new file mode 100644 (file)
index 0000000..b48d042
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Brocade Communications 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.blueprint.ext;
+
+import com.google.common.base.Preconditions;
+import java.util.Collections;
+import java.util.List;
+import org.apache.aries.blueprint.ext.ComponentFactoryMetadata;
+import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.service.blueprint.container.ComponentDefinitionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Factory metadata corresponding to the "rpc-service" element that gets an RPC service implementation from
+ * the RpcProviderRegistry and provides it to the Blueprint container.
+ *
+ * @author Thomas Pantelis
+ */
+class RpcServiceMetadata implements ComponentFactoryMetadata {
+    private static final Logger LOG = LoggerFactory.getLogger(RpcServiceMetadata.class);
+
+    private final String id;
+    private final String interfaceName;
+    private ExtendedBlueprintContainer container;
+
+    RpcServiceMetadata(String id, String interfaceName) {
+        this.id = id;
+        this.interfaceName = interfaceName;
+    }
+
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public int getActivation() {
+        return ACTIVATION_LAZY;
+    }
+
+    @Override
+    public List<String> getDependsOn() {
+        return Collections.singletonList(OpendaylightNamespaceHandler.RPC_REGISTRY_NAME);
+    }
+
+    @Override
+    public void init(ExtendedBlueprintContainer container) {
+        this.container = container;
+
+        LOG.debug("{}: In init", logName());
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Object create() throws ComponentDefinitionException {
+        LOG.debug("{}: In create: interfaceName: {}", logName(), interfaceName);
+
+        RpcProviderRegistry rpcRegistry = (RpcProviderRegistry) container.getComponentInstance(
+                OpendaylightNamespaceHandler.RPC_REGISTRY_NAME);
+
+        try {
+            Class<?> rpcInterface = container.getBundleContext().getBundle().loadClass(interfaceName);
+            Preconditions.checkArgument(RpcService.class.isAssignableFrom(rpcInterface),
+                    "Specified interface %s is not an RpcService", interfaceName);
+
+            RpcService rpcService = rpcRegistry.getRpcService((Class<RpcService>)rpcInterface);
+
+            LOG.debug("{}: create returning service {}", logName(), rpcService);
+
+            return rpcService;
+        } catch(Exception e) {
+            throw new ComponentDefinitionException("Error getting RPC service for " + interfaceName, e);
+        }
+    }
+
+    @Override
+    public void destroy(Object instance) {
+    }
+
+    private String logName() {
+        return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") +
+                " (" + id + ")";
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append("RpcServiceMetadata [id=").append(id).append(", interfaceName=").append(interfaceName)
+                .append("]");
+        return builder.toString();
+    }
+}
index 088e2fc5e3cf9b5fdb26df853efff2d03ab675fc..3632ccb3a48020c944f61b9021838184066e4444 100644 (file)
@@ -3,10 +3,29 @@
     targetNamespace="http://opendaylight.org/xmlns/blueprint/v1.0.0" elementFormDefault="qualified" 
     attributeFormDefault="unqualified" version="1.0.0">
 
     targetNamespace="http://opendaylight.org/xmlns/blueprint/v1.0.0" elementFormDefault="qualified" 
     attributeFormDefault="unqualified" version="1.0.0">
 
-<!-- <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/> -->
+  <xsd:import namespace="http://www.osgi.org/xmlns/blueprint/v1.0.0"/>
 
   <xsd:attribute name="restart-dependents-on-updates" type="xsd:boolean"/>
   <xsd:attribute name="use-default-for-reference-types" type="xsd:boolean"/>
   <xsd:attribute name="type" type="xsd:string"/>
 
 
   <xsd:attribute name="restart-dependents-on-updates" type="xsd:boolean"/>
   <xsd:attribute name="use-default-for-reference-types" type="xsd:boolean"/>
   <xsd:attribute name="type" type="xsd:string"/>
 
+  <xsd:complexType name="TrpcImplementation">
+    <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
+    <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
+  </xsd:complexType>
+  <xsd:element name="rpc-implementation" type="TrpcImplementation"/>
+
+  <xsd:complexType name="TroutedRpcImplementation">
+    <xsd:attribute name="interface" type="bp:Tclass" use="optional"/>
+    <xsd:attribute name="ref" type="bp:Tidref" use="required"/>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+  <xsd:element name="routed-rpc-implementation" type="TroutedRpcImplementation"/>
+
+  <xsd:complexType name="TrpcService">
+    <xsd:attribute name="interface" type="bp:Tclass" use="required"/>
+    <xsd:attribute name="id" type="xsd:ID"/>
+  </xsd:complexType>
+  <xsd:element name="rpc-service" type="TrpcService"/>
+
 </xsd:schema>
\ No newline at end of file
 </xsd:schema>
\ No newline at end of file