From cde200211e15c15312ee35944c03e88e80ceab55 Mon Sep 17 00:00:00 2001 From: Lukas Sedlak Date: Fri, 4 Jul 2014 09:25:13 +0200 Subject: [PATCH] Bug 560: Fixed Mount Point RPC registration service 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 --- opendaylight/md-sal/pom.xml | 6 +- .../dom/BindingIndependentConnector.java | 81 ++++++--- .../md-sal/sal-binding-dom-it/pom.xml | 11 +- .../dom/DOMRpcServiceTestBugfix560.java | 169 ++++++++++++++++++ .../dom/broker/impl/SchemaAwareRpcBroker.java | 22 ++- opendaylight/md-sal/sal-test-model/pom.xml | 77 ++++++++ .../yang/opendaylight-test-rpc-service.yang | 22 +++ 7 files changed, 362 insertions(+), 26 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/DOMRpcServiceTestBugfix560.java create mode 100644 opendaylight/md-sal/sal-test-model/pom.xml create mode 100644 opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-test-rpc-service.yang diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 24dcfad02b..d3f6d2d005 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -63,9 +63,11 @@ sal-protocolbuffer-encoding - - feature + + feature + + sal-test-model diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index d2472669fa..c45cb9011b 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentMap; 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; @@ -57,6 +58,7 @@ import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; 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; @@ -321,7 +323,10 @@ public class BindingIndependentConnector implements // 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()); @@ -528,7 +533,7 @@ public class BindingIndependentConnector implements // */ private class DomToBindingRpcForwardingManager implements RouteChangeListener>, RouterInstantiationListener, - GlobalRpcRegistrationListener { + GlobalRpcRegistrationListener, RpcRegistrationListener { private final Map, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>(); private RpcProviderRegistryImpl registryImpl; @@ -543,7 +548,7 @@ public class BindingIndependentConnector implements // @Override public void onGlobalRpcRegistered(final Class cls) { - getRpcForwarder(cls, null); + getRpcForwarder(cls, null).registerToDOMBroker(); } @Override @@ -588,31 +593,39 @@ public class BindingIndependentConnector implements // return potential; } + @Override + public void onRpcImplementationAdded(QName name) { + + final Optional> 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 supportedRpcs; private final WeakReference> rpcServiceType; - private final Set registrations; + private Set registrations; private final Map strategiesByQName = new HashMap<>(); private final WeakHashMap strategiesByMethod = new WeakHashMap<>(); + private final RpcService proxy; public DomToBindingRpcForwarder(final Class service) { this.rpcServiceType = new WeakReference>(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(); } /** @@ -622,16 +635,12 @@ public class BindingIndependentConnector implements // * @param context */ public DomToBindingRpcForwarder(final Class service, - final Class context) { - this.rpcServiceType = new WeakReference>(service); - this.supportedRpcs = mappingService.getRpcQNamesFor(service); + final Class context) { + this(service); Builder registrationsBuilder = ImmutableSet . 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(); @@ -641,6 +650,32 @@ public class BindingIndependentConnector implements // 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 context, final Class service, final Set> set) { QName ctx = BindingReflections.findQName(context); @@ -737,6 +772,10 @@ public class BindingIndependentConnector implements // }); } + + public void registerToBidningBroker() { + baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy); + } } public boolean isRpcForwarding() { diff --git a/opendaylight/md-sal/sal-binding-dom-it/pom.xml b/opendaylight/md-sal/sal-binding-dom-it/pom.xml index fd5c5be18d..46971ca2b8 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-dom-it/pom.xml @@ -44,12 +44,21 @@ pax-exam-container-native test - org.slf4j slf4j-simple test + + org.opendaylight.yangtools + yang-parser-impl + test + + + org.opendaylight.controller + sal-test-model + 1.1-SNAPSHOT + diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/DOMRpcServiceTestBugfix560.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/DOMRpcServiceTestBugfix560.java new file mode 100644 index 0000000000..6a6af0687a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/DOMRpcServiceTestBugfix560.java @@ -0,0 +1,169 @@ +/* + * 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 https://bugs.opendaylight.org/show_bug.cgi?id=560 + */ +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 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 rpcModels = Collections.singletonList(moduleStream); + Set 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 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> invokeRpc( + QName rpc, CompositeNode input) { + + return Futures.immediateFuture(Rpcs + . getRpcResult(true)); + } + + @Override + public Set getSupportedRpcs() { + return ImmutableSet.of(RPC_NAME); + } + }); + + final Set 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> 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(); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java index 8fc6fe2295..32139308b1 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java @@ -14,6 +14,7 @@ import java.util.Set; 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; @@ -140,17 +141,34 @@ public class SchemaAwareRpcBroker implements RpcRouter, Identifiable, Ro 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 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 addRpcRegistrationListener(RpcRegistrationListener listener) { - return rpcRegistrationListeners.register(listener); + ListenerRegistration reg = rpcRegistrationListeners.register(listener); + for (QName impl : implementations.keySet()) { + listener.onRpcImplementationAdded(impl); + } + return reg; } @Override diff --git a/opendaylight/md-sal/sal-test-model/pom.xml b/opendaylight/md-sal/sal-test-model/pom.xml new file mode 100644 index 0000000000..8d29b981dc --- /dev/null +++ b/opendaylight/md-sal/sal-test-model/pom.xml @@ -0,0 +1,77 @@ + + + + sal-parent + org.opendaylight.controller + 1.1-SNAPSHOT + + 4.0.0 + + + + org.opendaylight.yangtools + yang-binding + + + + sal-test-model + + + + org.jacoco + jacoco-maven-plugin + + + org.opendaylight.controller.* + + + + + pre-test + + prepare-agent + + + + post-test + + report + + test + + + + + org.opendaylight.yangtools + yang-maven-plugin + + + + generate-sources + + + + + + org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl + + ${salGeneratorPath} + + + true + + + + + + + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + HEAD + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + \ No newline at end of file diff --git a/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-test-rpc-service.yang b/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-test-rpc-service.yang new file mode 100644 index 0000000000..3412eb531a --- /dev/null +++ b/opendaylight/md-sal/sal-test-model/src/main/yang/opendaylight-test-rpc-service.yang @@ -0,0 +1,22 @@ +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 -- 2.36.6