<!--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