From: Tony Tkacik Date: Mon, 20 Jan 2014 17:47:06 +0000 (+0100) Subject: More defensive RPC handling in DOM Broker X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~27^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=928525541a36fac7aaa672d61417b853d08f7f6c More defensive RPC handling in DOM Broker - RPCs registered to DOM broker now must comform to the schema - at the time of registration of RPC implementation, the YANG schema must be present for that RPC. This does not affect RPC registrations for Binding Aware Broker. Signed-off-by: Tony Tkacik Change-Id: I9961efaf547818e08dec571ad9e2378d8e1f48cd --- diff --git a/opendaylight/md-sal/sal-binding-broker/pom.xml b/opendaylight/md-sal/sal-binding-broker/pom.xml index 87a07369bd..6dc91e014b 100644 --- a/opendaylight/md-sal/sal-binding-broker/pom.xml +++ b/opendaylight/md-sal/sal-binding-broker/pom.xml @@ -211,7 +211,7 @@ org.opendaylight.controller sal-broker-impl 1.0-SNAPSHOT - runtime + compile junit diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java index d976a0cec9..4f994e5673 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2013 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.codegen.impl; import org.opendaylight.yangtools.yang.binding.RpcService; @@ -5,6 +12,7 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcR import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; import org.opendaylight.controller.sal.binding.api.rpc.RpcRoutingTable; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -125,6 +133,7 @@ public class RpcRouterCodegenInstance implements // @Override public RpcRegistration registerDefaultService(T service) { // TODO Auto-generated method stub + RuntimeCodeHelper.setDelegate(invocationProxy, service); return null; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java index 8773476cae..ffc72657f0 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java @@ -1,5 +1,13 @@ +/* + * Copyright (c) 2013 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.impl; +import java.util.EventListener; import java.util.Map; import java.util.Map.Entry; import java.util.HashMap; @@ -42,9 +50,10 @@ public class RpcProviderRegistryImpl implements // private final Map, RpcRouter> rpcRouters = new WeakHashMap<>(); private final ListenerRegistry>> routeChangeListeners = ListenerRegistry .create(); + private final ListenerRegistry routerInstantiationListener = ListenerRegistry.create(); private final static Logger LOG = LoggerFactory.getLogger(RpcProviderRegistryImpl.class); - + private final String name; public String getName() { @@ -75,7 +84,7 @@ public class RpcProviderRegistryImpl implements // T publicProxy = getRpcService(type); RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); checkState(currentDelegate == null, "Rpc service is already registered"); - LOG.debug("Registering {} as global implementation of {} in {}",implementation,type.getSimpleName(),this); + LOG.debug("Registering {} as global implementation of {} in {}", implementation, type.getSimpleName(), this); RuntimeCodeHelper.setDelegate(publicProxy, implementation); return new RpcProxyRegistration(type, implementation, this); } @@ -89,46 +98,73 @@ public class RpcProviderRegistryImpl implements // if (potentialProxy != null) { return potentialProxy; } - synchronized(this) { + synchronized (this) { /** - * Potential proxy could be instantiated by other thread while we were - * waiting for the lock. + * Potential proxy could be instantiated by other thread while we + * were waiting for the lock. */ - + potentialProxy = (T) publicProxies.get(type); if (potentialProxy != null) { return (T) potentialProxy; } T proxy = rpcFactory.getDirectProxyFor(type); - LOG.debug("Created {} as public proxy for {} in {}",proxy,type.getSimpleName(),this); + LOG.debug("Created {} as public proxy for {} in {}", proxy, type.getSimpleName(), this); publicProxies.put(type, proxy); return proxy; } } - private RpcRouter getRpcRouter(Class type) { + @SuppressWarnings("unchecked") + public RpcRouter getRpcRouter(Class type) { RpcRouter potentialRouter = rpcRouters.get(type); if (potentialRouter != null) { return (RpcRouter) potentialRouter; } - synchronized(this) { + synchronized (this) { /** - * Potential Router could be instantiated by other thread while we were - * waiting for the lock. + * Potential Router could be instantiated by other thread while we + * were waiting for the lock. */ - potentialRouter = rpcRouters.get(type); + potentialRouter = rpcRouters.get(type); if (potentialRouter != null) { return (RpcRouter) potentialRouter; } - RpcRouter router = rpcFactory.getRouterFor(type,name); + RpcRouter router = rpcFactory.getRouterFor(type, name); router.registerRouteChangeListener(new RouteChangeForwarder(type)); - LOG.debug("Registering router {} as global implementation of {} in {}",router,type.getSimpleName(),this); + LOG.debug("Registering router {} as global implementation of {} in {}", router, type.getSimpleName(), this); RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy()); rpcRouters.put(type, router); + notifyListenersRoutedCreated(router); return router; } } + private void notifyListenersRoutedCreated(RpcRouter router) { + + for (ListenerRegistration listener : routerInstantiationListener) { + try { + listener.getInstance().onRpcRouterCreated(router); + } catch (Exception e) { + LOG.error("Unhandled exception during invoking listener {}", e); + } + } + + } + + public ListenerRegistration registerRouterInstantiationListener( + RouterInstantiationListener listener) { + ListenerRegistration reg = routerInstantiationListener.register(listener); + try { + for (RpcRouter router : rpcRouters.values()) { + listener.onRpcRouterCreated(router); + } + } catch (Exception e) { + LOG.error("Unhandled exception during invoking listener {}", e); + } + return reg; + } + @Override public >> ListenerRegistration registerRouteChangeListener( L listener) { @@ -143,6 +179,10 @@ public class RpcProviderRegistryImpl implements // this.rpcFactory = rpcFactory; } + public interface RouterInstantiationListener extends EventListener { + void onRpcRouterCreated(RpcRouter router); + } + private class RouteChangeForwarder implements RouteChangeListener, InstanceIdentifier> { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java index f200b4d08d..72b96b22d1 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingDomConnectorDeployer.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2013 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.impl.connect.dom; import static com.google.common.base.Preconditions.checkNotNull; 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 75b0138e7c..7a7e086ec4 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 @@ -1,10 +1,22 @@ +/* + * Copyright (c) 2013 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.impl.connect.dom; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.lang.reflect.Proxy; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -28,13 +40,15 @@ import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublishe import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider; +import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.controller.sal.binding.api.rpc.RpcRouter; import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl; -import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.impl.RpcProviderRegistryImpl.RouterInstantiationListener; import org.opendaylight.controller.sal.common.util.CommitHandlerTransactions; import org.opendaylight.controller.sal.common.util.Rpcs; -import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; +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.data.DataModificationTransaction; @@ -54,15 +68,18 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; +import org.opendaylight.yangtools.yang.data.api.Node; +import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; - -import static com.google.common.base.Preconditions.*; +import com.google.common.collect.ImmutableSet.Builder; +import com.google.common.util.concurrent.Futures; public class BindingIndependentConnector implements // RuntimeDataProvider, // @@ -71,11 +88,15 @@ public class BindingIndependentConnector implements // private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class); + @SuppressWarnings( "deprecation") private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); private static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier ROOT_BI = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier .builder().toInstance(); + private final static Method EQUALS_METHOD; + + private BindingIndependentMappingService mappingService; private org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService; @@ -116,18 +137,33 @@ public class BindingIndependentConnector implements // private boolean notificationForwarding = false; + private RpcProviderRegistryImpl baRpcRegistryImpl; + + private org.opendaylight.controller.sal.dom.broker.spi.RpcRouter biRouter; + + + static { + try { + EQUALS_METHOD = Object.class.getMethod("equals", Object.class); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override public DataObject readOperationalData(InstanceIdentifier path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); CompositeNode result = biDataService.readOperationalData(biPath); - return potentialAugmentationRead(path,biPath,result); + return potentialAugmentationRead(path, biPath, result); } catch (DeserializationException e) { throw new IllegalStateException(e); } } - private DataObject potentialAugmentationRead(InstanceIdentifier path, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result) throws DeserializationException { + private DataObject potentialAugmentationRead(InstanceIdentifier path, + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath, CompositeNode result) + throws DeserializationException { Class targetType = path.getTargetType(); if (Augmentation.class.isAssignableFrom(targetType)) { path = mappingService.fromDataDom(biPath); @@ -145,7 +181,7 @@ public class BindingIndependentConnector implements // try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); CompositeNode result = biDataService.readConfigurationData(biPath); - return potentialAugmentationRead(path,biPath,result); + return potentialAugmentationRead(path, biPath, result); } catch (DeserializationException e) { throw new IllegalStateException(e); } @@ -255,15 +291,22 @@ public class BindingIndependentConnector implements // baDataService.registerCommitHandlerListener(domToBindingCommitHandler); dataForwarding = true; } - + public void startRpcForwarding() { if (baRpcRegistry != null && biRpcRegistry != null && baRpcRegistry instanceof RouteChangePublisher) { - checkState(!rpcForwarding,"Connector is already forwarding RPCs"); + checkState(!rpcForwarding, "Connector is already forwarding RPCs"); domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager()); + if (baRpcRegistry instanceof RpcProviderRegistryImpl) { + baRpcRegistryImpl = (RpcProviderRegistryImpl) baRpcRegistry; + baRpcRegistryImpl.registerRouterInstantiationListener(domToBindingRpcManager.getInstance()); + } + if(biRpcRegistry instanceof org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) { + biRouter = (org.opendaylight.controller.sal.dom.broker.spi.RpcRouter) biRpcRegistry; + } rpcForwarding = true; } } - + public void startNotificationForwarding() { checkState(!notificationForwarding, "Connector is already forwarding notifications."); notificationForwarding = true; @@ -282,7 +325,7 @@ public class BindingIndependentConnector implements // public void onSessionInitiated(ProviderSession session) { setDomDataService(session.getService(org.opendaylight.controller.sal.core.api.data.DataProviderService.class)); setDomRpcRegistry(session.getService(RpcProvisionRegistry.class)); - + } public void onRpcRouterCreated(Class serviceType, RpcRouter router) { @@ -447,10 +490,32 @@ public class BindingIndependentConnector implements // } } + /** + * Manager responsible for instantiating forwarders responsible for + * forwarding of RPC invocations from DOM Broker to Binding Aware Broker + * + */ private class DomToBindingRpcForwardingManager implements - RouteChangeListener> { + RouteChangeListener>, + RouterInstantiationListener { private final Map, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>(); + private RpcProviderRegistryImpl registryImpl; + + public RpcProviderRegistryImpl getRegistryImpl() { + return registryImpl; + } + + public void setRegistryImpl(RpcProviderRegistryImpl registryImpl) { + this.registryImpl = registryImpl; + } + + + @Override + public void onRpcRouterCreated(RpcRouter router) { + Class ctx = router.getContexts().iterator().next(); + getRpcForwarder(router.getServiceType(), ctx); + } @Override public void onRouteChange(RouteChange> change) { @@ -478,35 +543,61 @@ public class BindingIndependentConnector implements // } else { potential = new DomToBindingRpcForwarder(service, context); } + forwarders.put(service, potential); return potential; } } - private class DomToBindingRpcForwarder implements RpcImplementation { + private class DomToBindingRpcForwarder implements RpcImplementation, InvocationHandler { private final Set supportedRpcs; private final WeakReference> rpcServiceType; private Set registrations; + private Map strategiesByQName = new HashMap<>(); + private WeakHashMap strategiesByMethod = new WeakHashMap<>(); public DomToBindingRpcForwarder(Class service) { this.rpcServiceType = new WeakReference>(service); this.supportedRpcs = mappingService.getRpcQNamesFor(service); - for (QName rpc : supportedRpcs) { - biRpcRegistry.addRpcImplementation(rpc, this); + 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()); } registrations = ImmutableSet.of(); } + /** + * Constructor for Routed RPC Forwareder. + * + * @param service + * @param context + */ public DomToBindingRpcForwarder(Class service, Class context) { this.rpcServiceType = new WeakReference>(service); this.supportedRpcs = mappingService.getRpcQNamesFor(service); - registrations = new HashSet<>(); - for (QName rpc : supportedRpcs) { - registrations.add(biRpcRegistry.addRoutedRpcImplementation(rpc, this)); + 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(); + } catch (Exception e) { + LOG.error("Could not forward Rpcs of type {}", service.getName(),e); } - registrations = ImmutableSet.copyOf(registrations); + registrations = registrationsBuilder.build(); } public void registerPaths(Class context, Class service, @@ -520,6 +611,22 @@ public class BindingIndependentConnector implements // } } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if(EQUALS_METHOD.equals(method)) { + return false; + } + RpcInvocationStrategy strategy = strategiesByMethod.get(method); + checkState(strategy != null); + checkArgument(args.length <= 2); + if(args.length == 1) { + checkArgument(args[0] instanceof DataObject); + return strategy.forwardToDomBroker((DataObject) args[0]); + } + return strategy.forwardToDomBroker(null); + } + public void removePaths(Class context, Class service, Set> set) { QName ctx = BindingReflections.findQName(context); @@ -536,6 +643,18 @@ public class BindingIndependentConnector implements // return supportedRpcs; } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void createDefaultDomForwarder() { + if (baRpcRegistryImpl != null) { + Class cls = rpcServiceType.get(); + ClassLoader clsLoader = cls.getClassLoader(); + RpcService proxy = (RpcService) Proxy.newProxyInstance(clsLoader, new Class[] { cls }, this); + + RpcRouter rpcRouter = baRpcRegistryImpl.getRpcRouter(rpcServiceType.get()); + rpcRouter.registerDefaultService(proxy); + } + } + @Override public RpcResult invokeRpc(QName rpc, CompositeNode domInput) { checkArgument(rpc != null); @@ -547,13 +666,17 @@ public class BindingIndependentConnector implements // checkState(rpcService != null); CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input")); try { - return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput); + return resolveInvocationStrategy(rpc).invokeOn(rpcService, domUnwrappedInput); } catch (Exception e) { throw new IllegalStateException(e); } } - private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc, + private RpcInvocationStrategy resolveInvocationStrategy(QName rpc) { + return strategiesByQName.get(rpc); + } + + private RpcInvocationStrategy createInvocationStrategy(final QName rpc, final Class rpcType) throws Exception { return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable() { @Override @@ -575,9 +698,9 @@ public class BindingIndependentConnector implements // RpcInvocationStrategy strategy = null; if (outputClass.isPresent()) { if (inputClass.isPresent()) { - strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get()); + strategy = new DefaultInvocationStrategy(rpc,targetMethod, outputClass.get(), inputClass.get()); } else { - strategy = new NoInputNoOutputInvocationStrategy(targetMethod); + strategy = new NoInputNoOutputInvocationStrategy(rpc,targetMethod); } } else { strategy = null; @@ -592,11 +715,15 @@ public class BindingIndependentConnector implements // private abstract class RpcInvocationStrategy { protected final Method targetMethod; + protected final QName rpc; - public RpcInvocationStrategy(Method targetMethod) { + public RpcInvocationStrategy(QName rpc,Method targetMethod) { this.targetMethod = targetMethod; + this.rpc = rpc; } + public abstract Future> forwardToDomBroker(DataObject input); + public abstract RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception; @@ -614,9 +741,9 @@ public class BindingIndependentConnector implements // private WeakReference outputClass; @SuppressWarnings({ "rawtypes", "unchecked" }) - public DefaultInvocationStrategy(Method targetMethod, Class outputClass, + public DefaultInvocationStrategy(QName rpc, Method targetMethod, Class outputClass, Class inputClass) { - super(targetMethod); + super(rpc,targetMethod); this.outputClass = new WeakReference(outputClass); this.inputClass = new WeakReference(inputClass); } @@ -631,13 +758,29 @@ public class BindingIndependentConnector implements // RpcResult bindingResult = result.get(); return Rpcs.getRpcResult(true); } + + @Override + public Future> forwardToDomBroker(DataObject input) { + if(biRouter != null) { + CompositeNode xml = mappingService.toDataDom(input); + CompositeNode wrappedXml = ImmutableCompositeNode.create(rpc,ImmutableList.>of(xml)); + RpcResult result = biRouter.invokeRpc(rpc, wrappedXml); + Object baResultValue = null; + if(result.getResult() != null) { + baResultValue = mappingService.dataObjectFromDataDom(outputClass.get(), result.getResult()); + } + RpcResult baResult = Rpcs.getRpcResult(result.isSuccessful(), baResultValue, result.getErrors()); + return Futures.>immediateFuture(baResult); + } + return Futures.>immediateFuture(Rpcs.getRpcResult(false)); + } } private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy { - public NoInputNoOutputInvocationStrategy(Method targetMethod) { - super(targetMethod); + public NoInputNoOutputInvocationStrategy(QName rpc, Method targetMethod) { + super(rpc,targetMethod); } public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { @@ -646,6 +789,11 @@ public class BindingIndependentConnector implements // RpcResult bindingResult = result.get(); return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors()); } + + @Override + public Future> forwardToDomBroker(DataObject input) { + return Futures.immediateFuture(null); + } } public boolean isRpcForwarding() { diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java index c03d851f5c..37a9c27d37 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java @@ -36,8 +36,9 @@ import org.opendaylight.controller.sal.dom.broker.BrokerImpl; import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl; import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper; import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore; -import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl; import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcResult; @@ -58,7 +59,7 @@ import com.google.common.util.concurrent.MoreExecutors; import static com.google.common.base.Preconditions.*; -public class BindingTestContext implements AutoCloseable { +public class BindingTestContext implements AutoCloseable, SchemaContextProvider { public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier .builder().toInstance(); @@ -88,6 +89,12 @@ public class BindingTestContext implements AutoCloseable { private MountPointManagerImpl biMountImpl; + private SchemaContext schemaContext; + + public SchemaContext getSchemaContext() { + return schemaContext; + } + protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) { this.executor = executor; this.classPool = classPool; @@ -218,12 +225,12 @@ public class BindingTestContext implements AutoCloseable { } public void updateYangSchema(String[] files) { - SchemaContext context = getContext(files); + schemaContext = getContext(files); if (schemaAwareDataStore != null) { - schemaAwareDataStore.onGlobalContextUpdated(context); + schemaAwareDataStore.onGlobalContextUpdated(schemaContext); } if (mappingServiceImpl != null) { - mappingServiceImpl.onGlobalContextUpdated(context); + mappingServiceImpl.onGlobalContextUpdated(schemaContext); } } @@ -275,7 +282,7 @@ public class BindingTestContext implements AutoCloseable { checkState(executor != null); biBrokerImpl = new BrokerImpl(); biBrokerImpl.setExecutor(executor); - biBrokerImpl.setRouter(new RpcRouterImpl("test")); + biBrokerImpl.setRouter(new SchemaAwareRpcBroker("/", this)); } public void startBindingNotificationBroker() { diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java index 92a0a3a98d..b1547b66a7 100644 --- a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java @@ -1,13 +1,25 @@ +/* + * Copyright (c) 2013 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.assertEquals; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNotSame; +import static junit.framework.Assert.assertTrue; + import java.math.BigInteger; import java.util.Collections; +import java.util.Set; import java.util.concurrent.Future; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; @@ -19,19 +31,14 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddF import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.NodeFlowRemoved; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput; -import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId; -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.inventory.rev130819.NodeContext; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef; import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes; -import org.opendaylight.yangtools.yang.binding.BaseIdentity; +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.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.QName; @@ -40,11 +47,8 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl; -import static junit.framework.Assert.*; - -import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Multimap; +import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; @@ -60,6 +64,9 @@ public class CrossBrokerRpcTest { public static final NodeId NODE_B = new NodeId("b"); public static final NodeId NODE_C = new NodeId("c"); public static final NodeId NODE_D = new NodeId("d"); + + private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); + private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow"); public static final InstanceIdentifier BA_NODE_A_ID = createBANodeIdentifier(NODE_A); public static final InstanceIdentifier BA_NODE_B_ID = createBANodeIdentifier(NODE_B); @@ -71,10 +78,7 @@ public class CrossBrokerRpcTest { public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_C_ID = createBINodeIdentifier(NODE_C); public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_D_ID = createBINodeIdentifier(NODE_D); - private static final QName NODE_ID_QNAME = QName.create(Node.QNAME, "id"); - private static final QName ADD_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "add-flow"); - private static final QName REMOVE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "remove-flow"); - private static final QName UPDATE_FLOW_QNAME = QName.create(NodeFlowRemoved.QNAME, "update-flow"); + @Before public void setup() { @@ -117,8 +121,29 @@ public class CrossBrokerRpcTest { assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next()); } - public void bindingRpcInvoker_DomRoutedProviderTest() { - + @Test + public void bindingRpcInvoker_DomRoutedProviderTest() throws Exception { + AddFlowOutputBuilder builder = new AddFlowOutputBuilder(); + builder.setTransactionId(new TransactionId(BigInteger.valueOf(10))); + final AddFlowOutput output = builder.build(); + org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration registration = biRpcRegistry.addRoutedRpcImplementation(ADD_FLOW_QNAME, new RpcImplementation() { + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + CompositeNode result = testContext.getBindingToDomMappingService().toDataDom(output); + return Rpcs.getRpcResult(true, result, ImmutableList.of()); + } + + @Override + public Set getSupportedRpcs() { + return ImmutableSet.of(ADD_FLOW_QNAME); + } + }); + registration.registerPath(NodeContext.QNAME, BI_NODE_C_ID); + + SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class); + Future> baResult = baFlowInvoker.addFlow(addFlow(BA_NODE_C_ID).setPriority(500).build()); + assertNotNull(baResult); + assertEquals(output,baResult.get().getResult()); } private CompositeNode toDomRpcInput(DataObject addFlowA) { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java index 951d5b142e..faac6501c9 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcProvisionRegistry.java @@ -1,10 +1,13 @@ package org.opendaylight.controller.sal.core.api; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -public interface RpcProvisionRegistry extends BrokerService { +public interface RpcProvisionRegistry extends BrokerService, RouteChangePublisher { /** * Registers an implementation of the rpc. @@ -28,6 +31,8 @@ public interface RpcProvisionRegistry extends BrokerService { */ RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException; + + ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener); RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java index 49b2f450a4..2ba5c4ba20 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRegistrationListener.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2013 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.core.api; import java.util.EventListener; diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java index 1680c19277..64195303e8 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/RpcRoutingContext.java @@ -5,14 +5,75 @@ * 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.core.api; +import java.io.Serializable; + +import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.QName; -public interface RpcRoutingContext { +public class RpcRoutingContext implements Immutable, Serializable { + + /** + * + */ + private static final long serialVersionUID = -9079324728075883325L; + + private final QName context; + private final QName rpc; + + + private RpcRoutingContext(QName context, QName rpc) { + super(); + this.context = context; + this.rpc = rpc; + } + + public static final RpcRoutingContext create(QName context, QName rpc) { + return new RpcRoutingContext(context, rpc); + } + + public QName getContext() { + return context; + } + + public QName getRpc() { + return rpc; + } + + @Override + public String toString() { + return "RpcRoutingContext [context=" + context + ", rpc=" + rpc + "]"; + } - public QName getContext(); + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((context == null) ? 0 : context.hashCode()); + result = prime * result + ((rpc == null) ? 0 : rpc.hashCode()); + return result; + } - public QName getRpcType(); + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RpcRoutingContext other = (RpcRoutingContext) obj; + if (context == null) { + if (other.context != null) + return false; + } else if (!context.equals(other.context)) + return false; + if (rpc == null) { + if (other.rpc != null) + return false; + } else if (!rpc.equals(other.rpc)) + return false; + return true; + } } diff --git a/opendaylight/md-sal/sal-dom-broker/pom.xml b/opendaylight/md-sal/sal-dom-broker/pom.xml index 949d59c49a..5c53f76853 100644 --- a/opendaylight/md-sal/sal-dom-broker/pom.xml +++ b/opendaylight/md-sal/sal-dom-broker/pom.xml @@ -118,9 +118,16 @@ ${project.groupId}.${project.artifactId} + + org.opendaylight.controller.sal.dom.broker.spi + - org.opendaylight.controller.sal.dom.broker.*, - org.opendaylight.controller.config.yang.md.sal.dom.impl + org.opendaylight.controller.sal.dom.broker, + org.opendaylight.controller.sal.dom.broker.impl, + org.opendaylight.controller.sal.dom.broker.osgi, + org.opendaylight.controller.config.yang.md.sal.dom.impl, + org.opendaylight.controller.config.yang.md.sal.dom.statistics, + org.opendaylight.yangtools.yang.util * diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/$ModuleInfo.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/$ModuleInfo.java deleted file mode 100644 index 3cc5a61afb..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/$ModuleInfo.java +++ /dev/null @@ -1,6 +0,0 @@ -package org.opendaylight.controller.sal.dom.broker; - -public class $ModuleInfo { - - -} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend index dc116ca979..3baae04019 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend @@ -14,7 +14,7 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier import org.opendaylight.controller.sal.core.api.data.DataStore import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener -import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker class BrokerConfigActivator implements AutoCloseable { @@ -38,13 +38,15 @@ class BrokerConfigActivator implements AutoCloseable { val emptyProperties = new Hashtable(); broker.setBundleContext(context); - broker.setRouter(new RpcRouterImpl("Rpc router")) + schemaService = new SchemaServiceImpl(); schemaService.setContext(context); schemaService.setParser(new YangParserImpl()); schemaService.start(); schemaReg = context.registerService(SchemaService, schemaService, emptyProperties); + broker.setRouter(new SchemaAwareRpcBroker("/",schemaService)); + dataService = new DataBrokerImpl(); dataService.setExecutor(broker.getExecutor()); diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend index 8f179987b9..4c84440c7e 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerImpl.xtend @@ -31,6 +31,9 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.controller.sal.core.api.RpcRegistrationListener import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry import org.opendaylight.controller.sal.core.api.RpcImplementation +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener +import org.opendaylight.controller.sal.core.api.RpcRoutingContext +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { private static val log = LoggerFactory.getLogger(BrokerImpl); @@ -125,4 +128,12 @@ public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { router.addRoutedRpcImplementation(rpcType,implementation); } + override addRpcRegistrationListener(RpcRegistrationListener listener) { + return router.addRpcRegistrationListener(listener); + } + + override > registerRouteChangeListener(L listener) { + return router.registerRouteChangeListener(listener); + } + } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java index b4fccff3b0..5a3e060a3c 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointImpl.java @@ -1,3 +1,10 @@ +/* + * Copyright (c) 2013 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.dom.broker; import java.util.List; @@ -8,34 +15,34 @@ import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; import org.opendaylight.controller.sal.common.DataStoreIdentifier; import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; -import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.controller.sal.core.api.RpcRoutingContext; import org.opendaylight.controller.sal.core.api.data.DataChangeListener; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.core.api.data.DataValidator; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.controller.sal.core.api.notify.NotificationListener; -import org.opendaylight.controller.sal.dom.broker.impl.DataReaderRouter; import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl; -import org.opendaylight.controller.sal.dom.broker.impl.RpcRouterImpl; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider; import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter; -import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; 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.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.InstanceIdentifierBuilder; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -public class MountPointImpl implements MountProvisionInstance { +public class MountPointImpl implements MountProvisionInstance, SchemaContextProvider { - private final RpcRouter rpcs; + private final SchemaAwareRpcBroker rpcs; private final DataBrokerImpl dataReader; private final NotificationRouter notificationRouter; private final DataReader readWrapper; @@ -47,7 +54,7 @@ public class MountPointImpl implements MountProvisionInstance { public MountPointImpl(InstanceIdentifier path) { this.mountPath = path; - rpcs = new RpcRouterImpl(""); + rpcs = new SchemaAwareRpcBroker(path.toString(),this); dataReader = new DataBrokerImpl(); notificationRouter = new NotificationRouterImpl(); readWrapper = new ReadWrapper(); @@ -118,7 +125,6 @@ public class MountPointImpl implements MountProvisionInstance { @Override public Future> rpc(QName type, CompositeNode input) { - // TODO Auto-generated method stub return null; } @@ -207,4 +213,10 @@ public class MountPointImpl implements MountProvisionInstance { RegistrationListener> commitHandlerListener) { return dataReader.registerCommitHandlerListener(commitHandlerListener); } + + @Override + public > ListenerRegistration registerRouteChangeListener( + L listener) { + return rpcs.registerRouteChangeListener(listener); + } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java index a6c1c508aa..8afa1eeb5f 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/SchemaServiceImpl.java @@ -27,6 +27,7 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener; +import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +42,7 @@ import com.google.common.collect.Sets; import static com.google.common.base.Preconditions.*; public class SchemaServiceImpl implements // + SchemaContextProvider, // SchemaService, // ServiceTrackerCustomizer, // AutoCloseable { @@ -100,6 +102,12 @@ public class SchemaServiceImpl implements // listenerTracker.open(); } + + @Override + public SchemaContext getSchemaContext() { + return getGlobalContext(); + } + public SchemaContext getGlobalContext() { return getSchemaContextSnapshot(); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend deleted file mode 100644 index 5ee19a0e8f..0000000000 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/RpcRouterImpl.xtend +++ /dev/null @@ -1,140 +0,0 @@ -package org.opendaylight.controller.sal.dom.broker.impl - -import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter -import org.opendaylight.yangtools.concepts.Identifiable -import org.opendaylight.yangtools.yang.common.QName -import org.opendaylight.controller.sal.core.api.RpcImplementation -import org.opendaylight.yangtools.yang.data.api.CompositeNode -import static com.google.common.base.Preconditions.*; -import java.util.Map -import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration -import java.util.concurrent.ConcurrentHashMap -import java.util.Set -import java.util.Collections -import org.opendaylight.yangtools.concepts.AbstractObjectRegistration -import org.opendaylight.controller.sal.core.api.RpcRegistrationListener -import org.slf4j.LoggerFactory -import org.opendaylight.yangtools.concepts.util.ListenerRegistry -import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier - -class RpcRouterImpl implements RpcRouter, Identifiable { - - static val log = LoggerFactory.getLogger(RpcRouterImpl) - - Map implementations = new ConcurrentHashMap(); - - @Property - val Set supportedRpcs = Collections.unmodifiableSet(implementations.keySet); - - private val rpcRegistrationListeners = new ListenerRegistry(); - - @Property - val String identifier; - - new(String name) { - _identifier = name; - } - - override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { - checkNotNull(rpcType, "Rpc Type should not be null"); - checkNotNull(implementation, "Implementation should not be null."); - val reg = new RoutedRpcRegistrationImpl(rpcType, implementation, this); - implementations.put(rpcType, reg) - - for (listener : rpcRegistrationListeners.listeners) { - try { - listener.instance.onRpcImplementationAdded(rpcType); - } catch (Exception e) { - log.error("Unhandled exception during invoking listener", e); - } - } - - return reg; - } - - override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { - checkNotNull(rpcType, "Rpc Type should not be null"); - checkNotNull(implementation, "Implementation should not be null."); - checkState(!implementations.containsKey(rpcType), "Provider for supplied rpc is already registered."); - val reg = new RpcRegistrationImpl(rpcType, implementation, this); - implementations.put(rpcType, reg) - - for (listener : rpcRegistrationListeners.listeners) { - try { - listener.instance.onRpcImplementationAdded(rpcType); - } catch (Exception e) { - log.error("Unhandled exception during invoking listener", e); - } - } - - return reg; - - } - - override invokeRpc(QName rpc, CompositeNode input) { - checkNotNull(rpc, "Rpc Type should not be null"); - - val impl = implementations.get(rpc); - checkState(impl !== null, "Provider for supplied rpc is not registered."); - - return impl.instance.invokeRpc(rpc, input); - } - - def remove(RpcRegistrationImpl impl) { - val existing = implementations.get(impl.type); - if (existing == impl) { - implementations.remove(impl.type); - } - for (listener : rpcRegistrationListeners.listeners) { - try { - listener.instance.onRpcImplementationRemoved(impl.type); - } catch (Exception e) { - log.error("Unhandled exception during invoking listener", e); - } - } - } - - override addRpcRegistrationListener(RpcRegistrationListener listener) { - rpcRegistrationListeners.register(listener); - } - -} - -class RpcRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { - - @Property - val QName type; - - @Property - var RpcRouterImpl router; - - new(QName type, RpcImplementation instance, RpcRouterImpl router) { - super(instance) - _type = type - _router = router - } - - override protected removeRegistration() { - router.remove(this); - } -} -class RoutedRpcRegistrationImpl extends RpcRegistrationImpl implements RoutedRpcRegistration { - - - new(QName type, RpcImplementation instance, RpcRouterImpl router) { - super(type,instance,router) - } - - override protected removeRegistration() { - router.remove(this); - } - override registerPath(QName context, InstanceIdentifier path) { - // - - } - - override unregisterPath(QName context, InstanceIdentifier path) { - // - } -} 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 new file mode 100644 index 0000000000..de6cfa6276 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareRpcBroker.java @@ -0,0 +1,426 @@ +package org.opendaylight.controller.sal.dom.broker.impl; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; + +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +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; +import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcRegistrationListener; +import org.opendaylight.controller.sal.core.api.RpcRoutingContext; +import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +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.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.SimpleNode; +import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +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.UnknownSchemaNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableSet; + +public class SchemaAwareRpcBroker implements RpcRouter, Identifiable { + + private static final Logger LOG = LoggerFactory.getLogger(SchemaAwareRpcBroker.class); + + private static final QName CONTEXT_REFERENCE = QName.create("urn:opendaylight:yang:extension:yang-ext", + "2013-07-09", "context-reference"); + private final ListenerRegistry rpcRegistrationListeners = new ListenerRegistry<>(); + private final ListenerRegistry> routeChangeListeners = new ListenerRegistry<>(); + + + private final String identifier; + private final ConcurrentMap implementations = new ConcurrentHashMap<>(); + private RpcImplementation defaultImplementation; + private SchemaContextProvider schemaProvider; + + public SchemaAwareRpcBroker(String identifier, SchemaContextProvider schemaProvider) { + super(); + this.identifier = identifier; + this.schemaProvider = schemaProvider; + } + + public RpcImplementation getDefaultImplementation() { + return defaultImplementation; + } + + public void setDefaultImplementation(RpcImplementation defaultImplementation) { + this.defaultImplementation = defaultImplementation; + } + + public SchemaContextProvider getSchemaProvider() { + return schemaProvider; + } + + public void setSchemaProvider(SchemaContextProvider schemaProvider) { + this.schemaProvider = schemaProvider; + } + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + checkArgument(rpcType != null, "RPC Type should not be null"); + checkArgument(implementation != null, "RPC Implementatoin should not be null"); + return getOrCreateRoutedRpcRouter(rpcType).addRoutedRpcImplementation(rpcType, implementation); + } + + private RoutedRpcSelector getOrCreateRoutedRpcRouter(QName rpcType) { + RoutedRpcSelector potential = getRoutedRpcRouter(rpcType); + if (potential != null) { + return potential; + } + synchronized (implementations) { + potential = getRoutedRpcRouter(rpcType); + if (potential != null) { + return potential; + } + RpcDefinition definition = findRpcDefinition(rpcType); + RoutingStrategy strategy = getRoutingStrategy(definition); + checkState(strategy instanceof RoutedRpcStrategy, "Rpc %s is not routed.", rpcType); + potential = new RoutedRpcSelector((RoutedRpcStrategy) strategy, this); + implementations.put(rpcType, potential); + return potential; + } + } + + private RoutedRpcSelector getRoutedRpcRouter(QName rpcType) { + RpcImplementation potential = implementations.get(rpcType); + if (potential != null) { + checkState(potential instanceof RoutedRpcSelector, "Rpc %s is not routed.", rpcType); + return (RoutedRpcSelector) potential; + } + return null; + + } + + @Override + public RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation) + throws IllegalArgumentException { + checkArgument(rpcType != null, "RPC Type should not be null"); + checkArgument(implementation != null, "RPC Implementatoin should not be null"); + checkState(!hasRpcImplementation(rpcType), "Implementation already registered"); + RpcDefinition definition = findRpcDefinition(rpcType); + checkArgument(!isRoutedRpc(definition), "RPC Type must not be routed."); + GlobalRpcRegistration reg = new GlobalRpcRegistration(rpcType, implementation, this); + return reg; + } + + private boolean isRoutedRpc(RpcDefinition definition) { + return getRoutingStrategy(definition) instanceof RoutedRpcStrategy; + } + + @Override + public ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener) { + return rpcRegistrationListeners.register(listener); + } + + @Override + public String getIdentifier() { + return identifier; + } + + @Override + public Set getSupportedRpcs() { + return ImmutableSet.copyOf(implementations.keySet()); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + return findRpcImplemention(rpc).invokeRpc(rpc, input); + } + + private RpcImplementation findRpcImplemention(QName rpc) { + checkArgument(rpc != null, "Rpc name should not be null"); + RpcImplementation potentialImpl = implementations.get(rpc); + if (potentialImpl != null) { + return potentialImpl; + } + potentialImpl = defaultImplementation; + checkState(potentialImpl != null, "Implementation is not available."); + return potentialImpl; + } + + private boolean hasRpcImplementation(QName rpc) { + return implementations.containsKey(rpc); + } + + private RpcDefinition findRpcDefinition(QName rpcType) { + checkArgument(rpcType != null, "Rpc name must be supplied."); + checkState(schemaProvider != null, "Schema Provider is not available."); + SchemaContext ctx = schemaProvider.getSchemaContext(); + checkState(ctx != null, "YANG Schema Context is not available."); + Module module = ctx.findModuleByNamespaceAndRevision(rpcType.getNamespace(), rpcType.getRevision()); + checkState(module != null, "YANG Module is not available."); + return findRpcDefinition(rpcType, module.getRpcs()); + } + + static private RpcDefinition findRpcDefinition(QName rpcType, Set rpcs) { + checkState(rpcs != null, "Rpc schema is not available."); + for (RpcDefinition rpc : rpcs) { + if (rpcType.equals(rpc.getQName())) { + return rpc; + } + } + throw new IllegalArgumentException("Supplied Rpc Type is not defined."); + } + + private RoutingStrategy getRoutingStrategy(RpcDefinition rpc) { + ContainerSchemaNode input = rpc.getInput(); + if (input != null) { + for (DataSchemaNode schemaNode : input.getChildNodes()) { + Optional context = getRoutingContext(schemaNode); + if (context.isPresent()) { + return createRoutedStrategy(rpc, context.get(), schemaNode.getQName()); + } + } + } + return createGlobalStrategy(rpc); + } + + private static RoutingStrategy createRoutedStrategy(RpcDefinition rpc, QName context, QName leafNode) { + return new RoutedRpcStrategy(rpc.getQName(), context, leafNode); + } + + private Optional getRoutingContext(DataSchemaNode schemaNode) { + for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) { + if (CONTEXT_REFERENCE.equals(extension.getNodeType())) { + return Optional.fromNullable(extension.getQName()); + } + ; + } + return Optional.absent(); + } + + private static RoutingStrategy createGlobalStrategy(RpcDefinition rpc) { + GlobalRpcStrategy ret = new GlobalRpcStrategy(rpc.getQName()); + return ret; + } + + private static abstract class RoutingStrategy implements Identifiable { + + private final QName identifier; + + public RoutingStrategy(QName identifier) { + super(); + this.identifier = identifier; + } + + @Override + public QName getIdentifier() { + return identifier; + } + } + + private static class GlobalRpcStrategy extends RoutingStrategy { + + public GlobalRpcStrategy(QName identifier) { + super(identifier); + } + } + + private static class RoutedRpcStrategy extends RoutingStrategy { + + private final QName context; + private final QName leaf; + + public RoutedRpcStrategy(QName identifier, QName ctx, QName leaf) { + super(identifier); + this.context = ctx; + this.leaf = leaf; + } + + public QName getContext() { + return context; + } + + public QName getLeaf() { + return leaf; + } + } + + private static class RoutedRpcSelector implements RpcImplementation, AutoCloseable, Identifiable { + + private final RoutedRpcStrategy strategy; + private final Set supportedRpcs; + private RpcImplementation defaultDelegate; + private final ConcurrentMap implementations = new ConcurrentHashMap<>(); + private SchemaAwareRpcBroker router; + + public RoutedRpcSelector(RoutedRpcStrategy strategy, SchemaAwareRpcBroker router) { + super(); + this.strategy = strategy; + supportedRpcs = ImmutableSet.of(strategy.getIdentifier()); + this.router = router; + } + + @Override + public QName getIdentifier() { + return strategy.getIdentifier(); + } + + @Override + public void close() throws Exception { + + } + + @Override + public Set getSupportedRpcs() { + return supportedRpcs; + } + + public RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + return new RoutedRpcRegImpl(rpcType, implementation, this); + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode input) { + CompositeNode inputContainer = input.getFirstCompositeByName(QName.create(rpc,"input")); + checkArgument(inputContainer != null, "Rpc payload must contain input element"); + SimpleNode routeContainer = inputContainer.getFirstSimpleByName(strategy.getLeaf()); + checkArgument(routeContainer != null, "Leaf %s must be set with value", strategy.getLeaf()); + Object route = routeContainer.getValue(); + RpcImplementation potential = null; + if (route != null) { + RoutedRpcRegImpl potentialReg = implementations.get(route); + if (potentialReg != null) { + potential = potentialReg.getInstance(); + } + } + if (potential == null) { + potential = defaultDelegate; + } + checkState(potential != null, "No implementation is available for rpc:%s path:%s", rpc, route); + return potential.invokeRpc(rpc, input); + } + + public void addPath(QName context, InstanceIdentifier path, RoutedRpcRegImpl routedRpcRegImpl) { + //checkArgument(strategy.getContext().equals(context),"Supplied context is not supported."); + RoutedRpcRegImpl previous = implementations.put(path, routedRpcRegImpl); + if (previous == null) { + router.notifyPathAnnouncement(context,strategy.getIdentifier(), path); + } + + } + + public void removePath(QName context, InstanceIdentifier path, RoutedRpcRegImpl routedRpcRegImpl) { + boolean removed = implementations.remove(path, routedRpcRegImpl); + if (removed) { + router.notifyPathWithdrawal(context, strategy.getIdentifier(), path); + } + } + } + + private static class GlobalRpcRegistration extends AbstractObjectRegistration implements + RpcRegistration { + private final QName type; + private SchemaAwareRpcBroker router; + + public GlobalRpcRegistration(QName type, RpcImplementation instance, SchemaAwareRpcBroker router) { + super(instance); + this.type = type; + this.router = router; + } + + @Override + public QName getType() { + return type; + } + + @Override + protected void removeRegistration() { + if (router != null) { + router.remove(this); + router = null; + } + } + } + + private static class RoutedRpcRegImpl extends AbstractObjectRegistration implements + RoutedRpcRegistration { + + private final QName type; + private RoutedRpcSelector router; + + public RoutedRpcRegImpl(QName rpcType, RpcImplementation implementation, RoutedRpcSelector routedRpcSelector) { + super(implementation); + this.type = rpcType; + router = routedRpcSelector; + } + + @Override + public void registerPath(QName context, InstanceIdentifier path) { + router.addPath(context, path, this); + } + + @Override + public void unregisterPath(QName context, InstanceIdentifier path) { + router.removePath(context, path, this); + } + + @Override + protected void removeRegistration() { + + } + + @Override + public QName getType() { + return type; + } + + } + + private void remove(GlobalRpcRegistration registration) { + implementations.remove(registration.getType(), registration); + } + + private void notifyPathAnnouncement(QName context, QName identifier, InstanceIdentifier path) { + RpcRoutingContext contextWrapped = RpcRoutingContext.create(context, identifier); + RouteChange change = RoutingUtils.announcementChange(contextWrapped , path); + for(ListenerRegistration> routeListener : routeChangeListeners) { + try { + routeListener.getInstance().onRouteChange(change); + } catch (Exception e) { + LOG.error("Unhandled exception during invoking onRouteChange for {}",routeListener.getInstance(),e); + + } + } + + } + + + + private void notifyPathWithdrawal(QName context,QName identifier, InstanceIdentifier path) { + RpcRoutingContext contextWrapped = RpcRoutingContext.create(context, identifier); + RouteChange change = RoutingUtils.removalChange(contextWrapped , path); + for(ListenerRegistration> routeListener : routeChangeListeners) { + try { + routeListener.getInstance().onRouteChange(change); + } catch (Exception e) { + LOG.error("Unhandled exception during invoking onRouteChange for {}",routeListener.getInstance(),e); + } + } + } + + @Override + public > ListenerRegistration registerRouteChangeListener( + L listener) { + return routeChangeListeners.registerWithType(listener); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaContextProvider.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaContextProvider.java new file mode 100644 index 0000000000..3cf9a5dabc --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaContextProvider.java @@ -0,0 +1,11 @@ +package org.opendaylight.controller.sal.dom.broker.impl; + +import org.opendaylight.yangtools.yang.model.api.SchemaContext; + +import com.google.common.base.Optional; + +public interface SchemaContextProvider { + + SchemaContext getSchemaContext(); + +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java index 6886f892c6..7ec8ce1d78 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/spi/RpcRouter.java @@ -26,6 +26,4 @@ public interface RpcRouter extends RpcProvisionRegistry, RpcImplementation { @Override public RpcResult invokeRpc(QName rpc, CompositeNode input); - - ListenerRegistration addRpcRegistrationListener(RpcRegistrationListener listener); }