From: Tony Tkacik Date: Mon, 7 Jul 2014 09:44:06 +0000 (+0000) Subject: Merge "Bug 560: Fixed Mount Point RPC registration service" X-Git-Tag: release/helium~523 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=55e562009629fcc7163f1f05261de4b2ce4b1e77;hp=44c747db358bf0d49434d5f818121286b5928d4a;p=controller.git Merge "Bug 560: Fixed Mount Point RPC registration service" --- 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