Wait for RPCService registered in RpcServiceMetadata
[controller.git] / opendaylight / blueprint / src / main / java / org / opendaylight / controller / blueprint / ext / RpcServiceMetadata.java
index 7fc077d2870fa417b09168402044f610db6af2f7..e2260a6d74142d0537bc11e784da4fb82e2e364c 100644 (file)
@@ -7,13 +7,23 @@
  */
 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 java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
 import org.apache.aries.blueprint.services.ExtendedBlueprintContainer;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.osgi.service.blueprint.container.ComponentDefinitionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -24,54 +34,104 @@ import org.slf4j.LoggerFactory;
  *
  * @author Thomas Pantelis
  */
-class RpcServiceMetadata implements ComponentFactoryMetadata {
+class RpcServiceMetadata extends AbstractDependentComponentFactoryMetadata {
     private static final Logger LOG = LoggerFactory.getLogger(RpcServiceMetadata.class);
 
-    private final String id;
     private final String interfaceName;
-    private ExtendedBlueprintContainer container;
+    private volatile Set<SchemaPath> rpcSchemaPaths;
+    private volatile RpcProviderRegistry rpcRegistry;
+    private volatile ListenerRegistration<DOMRpcAvailabilityListener> rpcListenerReg;
+    private volatile Class<RpcService> rpcInterface;
 
     RpcServiceMetadata(String id, String interfaceName) {
-        this.id = id;
+        super(id);
         this.interfaceName = interfaceName;
     }
 
     @Override
-    public String getId() {
-        return id;
+    @SuppressWarnings("unchecked")
+    public void init(ExtendedBlueprintContainer container) {
+        super.init(container);
+
+        try {
+            Class<?> interfaceClass = container().getBundleContext().getBundle().loadClass(interfaceName);
+            if(!RpcService.class.isAssignableFrom(interfaceClass)) {
+                throw new ComponentDefinitionException(String.format(
+                        "%s: The specified interface %s is not an RpcService", logName(), interfaceName));
+            }
+
+            rpcInterface = (Class<RpcService>)interfaceClass;
+        } catch(Exception e) {
+            throw new ComponentDefinitionException(String.format("%s: Error obtaining interface class %s",
+                    logName(), interfaceName), e);
+        }
     }
 
     @Override
-    public int getActivation() {
-        return ACTIVATION_LAZY;
+    protected void startTracking() {
+        // First get the SchemaContext. This will be used to get the RPC SchemaPaths.
+
+        retrieveService("SchemaService", SchemaService.class,
+                service -> retrievedSchemaContext(((SchemaService)service).getGlobalContext()));
     }
 
-    @Override
-    public List<String> getDependsOn() {
-        return Collections.singletonList(OpendaylightNamespaceHandler.RPC_REGISTRY_NAME);
+    private void retrievedSchemaContext(SchemaContext schemaContext) {
+        LOG.debug("{}: retrievedSchemaContext", logName());
+
+        QNameModule moduleName = BindingReflections.getQNameModule(rpcInterface);
+        Module module = schemaContext.findModuleByNamespaceAndRevision(moduleName.getNamespace(), moduleName.getRevision());
+
+        LOG.debug("{}: Got Module: {}", logName(), module);
+
+        rpcSchemaPaths = new HashSet<>();
+        for(RpcDefinition rpcDef : module.getRpcs()) {
+            rpcSchemaPaths.add(rpcDef.getPath());
+        }
+
+        LOG.debug("{}: Got SchemaPaths: {}", logName(), rpcSchemaPaths);
+
+        // First get the DOMRpcService OSGi service. This will be used to register a listener to be notified
+        // when the underlying DOM RPC service is available.
+
+        retrieveService("DOMRpcService", DOMRpcService.class, service -> retrievedDOMRpcService((DOMRpcService)service));
     }
 
-    @Override
-    public void init(ExtendedBlueprintContainer container) {
-        this.container = container;
+    private void retrievedDOMRpcService(DOMRpcService domRpcService) {
+        LOG.debug("{}: retrievedDOMRpcService", logName());
+
+        rpcListenerReg = domRpcService.registerRpcListener(new DOMRpcAvailabilityListener() {
+            @Override
+            public void onRpcAvailable(Collection<DOMRpcIdentifier> rpcs) {
+                onRpcsAvailable(rpcs);
+            }
 
-        LOG.debug("{}: In init", logName());
+            @Override
+            public void onRpcUnavailable(Collection<DOMRpcIdentifier> rpcs) {
+            }
+        });
+    }
+
+    protected void onRpcsAvailable(Collection<DOMRpcIdentifier> rpcs) {
+        for(DOMRpcIdentifier identifier: rpcs) {
+            if(rpcSchemaPaths.contains(identifier.getType())) {
+                LOG.debug("{}: onRpcsAvailable - found SchemaPath {}", logName(), identifier.getType());
+
+                retrieveService("RpcProviderRegistry", RpcProviderRegistry.class, service -> {
+                    rpcRegistry = (RpcProviderRegistry)service;
+                    setSatisfied();
+                });
+
+                break;
+            }
+        }
     }
 
-    @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);
+            RpcService rpcService = rpcRegistry.getRpcService(rpcInterface);
 
             LOG.debug("{}: create returning service {}", logName(), rpcService);
 
@@ -82,16 +142,26 @@ class RpcServiceMetadata implements ComponentFactoryMetadata {
     }
 
     @Override
-    public void destroy(Object instance) {
+    public void stopTracking() {
+        super.stopTracking();
+        closeRpcListenerReg();
+    }
+
+    private void closeRpcListenerReg() {
+        if(rpcListenerReg != null) {
+            rpcListenerReg.close();
+            rpcListenerReg = null;
+        }
     }
 
-    private String logName() {
-        return (container != null ? container.getBundleContext().getBundle().getSymbolicName() : "") +
-                " (" + id + ")";
+    @Override
+    public void destroy(Object instance) {
+        super.destroy(instance);
+        closeRpcListenerReg();
     }
 
     @Override
     public String toString() {
-        return "RpcServiceMetadata [id=" + id + ", interfaceName=" + interfaceName + ", container=" + container + "]";
+        return "RpcServiceMetadata [id=" + getId() + ", interfaceName=" + interfaceName + "]";
     }
 }