The RPC Services can now be correctly registered for Mount Points. The RPCs are able to
correctly propagate between Binding Independent Broker and Binding Aware Broker.
This commit is dependant on commit: https://git.opendaylight.org/gerrit/#/c/8654/
Change-Id: I6c3c3e1f648d1faa8b4d43a24eacaf014123b880
Signed-off-by: Lukas Sedlak <lsedlak@cisco.com>
<!--sal-protocolbuffer-encoding-->
<module>sal-protocolbuffer-encoding</module>
- <!-- Karaf feature -->
- <module>feature</module>
+ <!-- Karaf feature -->
+ <module>feature</module>
+ <!-- Yang Test Models for MD-SAL -->
+ <module>sal-test-model</module>
</modules>
<build>
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import com.google.common.base.Optional;
import org.opendaylight.controller.md.sal.binding.impl.AbstractForwardedDataBroker;
import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.core.api.Provider;
import org.opendaylight.controller.sal.core.api.RpcImplementation;
import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
public void startRpcForwarding() {
if (biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher<?, ?>) {
checkState(!rpcForwarding, "Connector is already forwarding RPCs");
- domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager());
+ final DomToBindingRpcForwardingManager biFwdManager = new DomToBindingRpcForwardingManager();
+
+ domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(biFwdManager);
+ biRpcRegistry.addRpcRegistrationListener(biFwdManager);
if (baRpcRegistry instanceof RpcProviderRegistryImpl) {
baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry;
baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance());
*/
private class DomToBindingRpcForwardingManager implements
RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>, RouterInstantiationListener,
- GlobalRpcRegistrationListener {
+ GlobalRpcRegistrationListener, RpcRegistrationListener {
private final Map<Class<? extends RpcService>, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>();
private RpcProviderRegistryImpl registryImpl;
@Override
public void onGlobalRpcRegistered(final Class<? extends RpcService> cls) {
- getRpcForwarder(cls, null);
+ getRpcForwarder(cls, null).registerToDOMBroker();
}
@Override
return potential;
}
+ @Override
+ public void onRpcImplementationAdded(QName name) {
+
+ final Optional<Class<? extends RpcService>> rpcInterface = mappingService.getRpcServiceClassFor(
+ name.getNamespace().toString(), name.getFormattedRevision());
+ if (rpcInterface.isPresent()) {
+ getRpcForwarder(rpcInterface.get(), null).registerToBidningBroker();
+ }
+ }
+
+ @Override
+ public void onRpcImplementationRemoved(QName name) {
+
+ }
}
private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler {
private final Set<QName> supportedRpcs;
private final WeakReference<Class<? extends RpcService>> rpcServiceType;
- private final Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
+ private Set<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> registrations;
private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
+ private final RpcService proxy;
public DomToBindingRpcForwarder(final Class<? extends RpcService> service) {
this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
this.supportedRpcs = mappingService.getRpcQNamesFor(service);
- try {
- for (QName rpc : supportedRpcs) {
- RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
- strategiesByMethod.put(strategy.targetMethod, strategy);
- strategiesByQName.put(rpc, strategy);
- biRpcRegistry.addRpcImplementation(rpc, this);
- }
- } catch (Exception e) {
- LOG.error("Could not forward Rpcs of type {}", service.getName(), e);
- }
- registrations = ImmutableSet.of();
+ Class<?> cls = rpcServiceType.get();
+ ClassLoader clsLoader = cls.getClassLoader();
+ proxy =(RpcService) Proxy.newProxyInstance(clsLoader, new Class<?>[] { cls }, this);
+ createStrategies();
}
/**
* @param context
*/
public DomToBindingRpcForwarder(final Class<? extends RpcService> service,
- final Class<? extends BaseIdentity> context) {
- this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
- this.supportedRpcs = mappingService.getRpcQNamesFor(service);
+ final Class<? extends BaseIdentity> context) {
+ this(service);
Builder<RoutedRpcRegistration> registrationsBuilder = ImmutableSet
.<org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration> builder();
try {
for (QName rpc : supportedRpcs) {
- RpcInvocationStrategy strategy = createInvocationStrategy(rpc, service);
- strategiesByMethod.put(strategy.targetMethod, strategy);
- strategiesByQName.put(rpc, strategy);
registrationsBuilder.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this));
}
createDefaultDomForwarder();
registrations = registrationsBuilder.build();
}
+
+
+ private void createStrategies() {
+ try {
+ for (QName rpc : supportedRpcs) {
+ RpcInvocationStrategy strategy = createInvocationStrategy(rpc, rpcServiceType.get());
+ strategiesByMethod.put(strategy.targetMethod, strategy);
+ strategiesByQName.put(rpc, strategy);
+ }
+ } catch (Exception e) {
+ LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
+ }
+
+ }
+
+ public void registerToDOMBroker() {
+ try {
+ for (QName rpc : supportedRpcs) {
+ biRpcRegistry.addRpcImplementation(rpc, this);
+ }
+ } catch (Exception e) {
+ LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
+ }
+ }
+
+
public void registerPaths(final Class<? extends BaseIdentity> context,
final Class<? extends RpcService> service, final Set<InstanceIdentifier<?>> set) {
QName ctx = BindingReflections.findQName(context);
});
}
+
+ public void registerToBidningBroker() {
+ baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
+ }
}
public boolean isRpcForwarding() {
<artifactId>pax-exam-container-native</artifactId>
<scope>test</scope>
</dependency>
-
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-parser-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-test-model</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ </dependency>
</dependencies>
<build>
<plugins>
--- /dev/null
+/*
+ * Copyright (c) 2014 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.test.connect.dom;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.api.mount.MountProviderInstance;
+import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
+import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory;
+import org.opendaylight.controller.sal.binding.test.util.BindingTestContext;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.rpcservice.rev140701.OpendaylightTestRpcServiceService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.bi.ba.rpcservice.rev140701.RockTheHouseInputBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+
+/**
+ * Test case for reported bug 560
+ *
+ * @author Lukas Sedlak
+ * @see <a
+ * href="https://bugs.opendaylight.org/show_bug.cgi?id=560">https://bugs.opendaylight.org/show_bug.cgi?id=560</a>
+ */
+public class DOMRpcServiceTestBugfix560 {
+
+ private final static String RPC_SERVICE_NAMESPACE = "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:bi:ba:rpcservice";
+ private final static String REVISION_DATE = "2014-07-01";
+ private final static QName RPC_NAME = QName.create(RPC_SERVICE_NAMESPACE,
+ REVISION_DATE, "rock-the-house");
+
+ private static final NodeId MOUNT_NODE = new NodeId("id");
+ private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id");
+
+ private static final InstanceIdentifier<Node> BA_MOUNT_ID = createBANodeIdentifier(MOUNT_NODE);
+ private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_MOUNT_ID = createBINodeIdentifier(MOUNT_NODE);
+
+ private BindingTestContext testContext;
+ private MountProvisionService domMountPointService;
+ private MountProviderService bindingMountPointService;
+ private SchemaContext schemaContext;
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @Before
+ public void setUp() throws Exception {
+ BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory();
+ testFactory.setExecutor(MoreExecutors.sameThreadExecutor());
+ testFactory.setStartWithParsedSchema(true);
+ testContext = testFactory.getTestContext();
+
+ testContext.start();
+ domMountPointService = testContext.getDomMountProviderService();
+ bindingMountPointService = testContext.getBindingMountProviderService();
+ assertNotNull(domMountPointService);
+
+ final YangContextParser parser = new YangParserImpl();
+ final InputStream moduleStream = BindingReflections.getModuleInfo(
+ OpendaylightTestRpcServiceService.class)
+ .getModuleSourceStream();
+
+ assertNotNull(moduleStream);
+ List<InputStream> rpcModels = Collections.singletonList(moduleStream);
+ Set<Module> modules = parser.parseYangModelsFromStreams(rpcModels);
+ schemaContext = parser.resolveSchemaContext(modules);
+ }
+
+ private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(
+ NodeId mountNode) {
+ return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+ .builder().node(Nodes.QNAME)
+ .nodeWithKey(Node.QNAME, NODE_ID_QNAME, mountNode.getValue())
+ .toInstance();
+ }
+
+ private static InstanceIdentifier<Node> createBANodeIdentifier(
+ NodeId mountNode) {
+ return InstanceIdentifier.builder(Nodes.class)
+ .child(Node.class, new NodeKey(mountNode)).toInstance();
+ }
+
+ @Test
+ public void test() throws ExecutionException, InterruptedException {
+ testContext.getBindingDataBroker().readOperationalData(BA_MOUNT_ID);
+ final MountProvisionInstance mountPoint = domMountPointService
+ .createMountPoint(BI_MOUNT_ID);
+ mountPoint.setSchemaContext(schemaContext);
+ assertNotNull(mountPoint);
+
+ mountPoint.addRpcImplementation(RPC_NAME, new RpcImplementation() {
+
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(
+ QName rpc, CompositeNode input) {
+
+ return Futures.immediateFuture(Rpcs
+ .<CompositeNode> getRpcResult(true));
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return ImmutableSet.of(RPC_NAME);
+ }
+ });
+
+ final Set<QName> biSupportedRpcs = mountPoint.getSupportedRpcs();
+ assertNotNull(biSupportedRpcs);
+ assertTrue(!biSupportedRpcs.isEmpty());
+
+ MountProviderInstance mountInstance = bindingMountPointService
+ .getMountPoint(BA_MOUNT_ID);
+ assertNotNull(mountInstance);
+ final OpendaylightTestRpcServiceService rpcService = mountInstance
+ .getRpcService(OpendaylightTestRpcServiceService.class);
+ assertNotNull(rpcService);
+
+ try {
+ Future<RpcResult<Void>> result = rpcService
+ .rockTheHouse(new RockTheHouseInputBuilder().build());
+ assertTrue(result.get().isSuccessful());
+ } catch (IllegalStateException ex) {
+ fail("OpendaylightTestRpcServiceService class doesn't contain rockTheHouse method!");
+ }
+ }
+
+ /**
+ * @throws java.lang.Exception
+ */
+ @After
+ public void teardown() throws Exception {
+ testContext.close();
+ }
+}
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import com.google.common.base.Preconditions;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils;
RpcDefinition definition = findRpcDefinition(rpcType);
checkArgument(!isRoutedRpc(definition), "RPC Type must not be routed.");
GlobalRpcRegistration reg = new GlobalRpcRegistration(rpcType, implementation, this);
- implementations.putIfAbsent(rpcType, implementation);
+ final RpcImplementation previous = implementations.putIfAbsent(rpcType, implementation);
+ Preconditions.checkState(previous == null, "Rpc %s is already registered.",rpcType);
+ notifyRpcAdded(rpcType);
return reg;
}
+ private void notifyRpcAdded(QName rpcType) {
+ for (ListenerRegistration<RpcRegistrationListener> listener : rpcRegistrationListeners) {
+ try {
+ listener.getInstance().onRpcImplementationAdded(rpcType);
+ } catch (Exception ex) {
+ LOG.error("Unhandled exception during invoking listener {}", listener.getInstance(), ex);
+ }
+
+ }
+ }
+
private boolean isRoutedRpc(RpcDefinition definition) {
return getRoutingStrategy(definition) instanceof RoutedRpcStrategy;
}
@Override
public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener) {
- return rpcRegistrationListeners.register(listener);
+ ListenerRegistration<RpcRegistrationListener> reg = rpcRegistrationListeners.register(listener);
+ for (QName impl : implementations.keySet()) {
+ listener.onRpcImplementationAdded(impl);
+ }
+ return reg;
}
@Override
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <artifactId>sal-parent</artifactId>
+ <groupId>org.opendaylight.controller</groupId>
+ <version>1.1-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ </dependencies>
+
+ <artifactId>sal-test-model</artifactId>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>org.opendaylight.controller.*</include>
+ </includes>
+ </configuration>
+ <executions>
+ <execution>
+ <id>pre-test</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>post-test</id>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ <phase>test</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate-sources</goal>
+ </goals>
+ <configuration>
+ <codeGenerators>
+ <generator>
+ <codeGeneratorClass>
+ org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl
+ </codeGeneratorClass>
+ <outputBaseDir>${salGeneratorPath}</outputBaseDir>
+ </generator>
+ </codeGenerators>
+ <inspectDependencies>true</inspectDependencies>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <tag>HEAD</tag>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+</project>
\ No newline at end of file
--- /dev/null
+module opendaylight-test-rpc-service {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:test:bi:ba:rpcservice";
+ prefix "rpc";
+
+ description
+ "Test model for testing of registering rpc service on binding independent mount point
+ and retrieving rpc service via binding aware mount point.";
+
+ revision "2014-07-01" {
+ description
+ "Initial revision";
+ }
+
+ rpc rock-the-house {
+ input {
+ leaf zip-code {
+ type string;
+ }
+ }
+ }
+}
\ No newline at end of file