From cbcecc2bcdaa79cd684b28e4b6011841d100cfb2 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Fri, 13 Dec 2013 14:11:03 +0100 Subject: [PATCH] Fixed bug in cross-broker RPC routing - Fixed cross-broker (Binding to DOM) and (DOM to Binding) rpc routing by adding explicit routing and invocation strategies - Lowered reporting level for fingAugmentableArgument to DEBUG so it does not polute logs - Extracted and converted RpcProviderRegistry implementation from BindingAwareBrokerImpl (Xtend) to RpcProviderRegistryImpl (java). Change-Id: I8339abdc864162c70a149cf59fdbdf97093ae8c0 Signed-off-by: Tony Tkacik --- opendaylight/md-sal/pom.xml | 20 ++ .../binding/api/RpcAvailabilityListener.java | 5 + .../binding/impl/DataBrokerImplModule.java | 4 +- .../binding/impl/RuntimeMappingModule.java | 4 +- .../binding/codegen/RuntimeCodeHelper.xtend | 1 - .../impl/RpcRouterCodegenInstance.java | 161 ++++++++++ .../impl/RpcRouterCodegenInstance.xtend | 64 ---- .../codegen/impl/RpcRoutingTableImpl.java | 125 ++++++++ .../codegen/impl/RpcRoutingTableImpl.xtend | 49 --- .../codegen/impl/RuntimeCodeGenerator.xtend | 97 +++--- .../binding/codegen/impl/SingletonHolder.java | 14 + .../impl/LazyGeneratedCodecRegistry.java | 2 +- .../RuntimeGeneratedMappingServiceImpl.xtend | 42 ++- .../binding/impl/BindingAwareBrokerImpl.xtend | 294 +----------------- .../binding/impl/NotificationBrokerImpl.xtend | 11 +- .../binding/impl/OsgiConsumerContext.xtend | 3 +- .../binding/impl/RpcProviderRegistryImpl.java | 166 ++++++++++ ....java => BindingIndependentConnector.java} | 292 ++++++++++++++++- .../dom/BindingIndependentMappingService.java | 9 +- .../sal/binding/spi/RoutingContext.java | 5 + .../sal/binding/spi/RpcContextIdentifier.java | 65 ++++ .../controller/sal/binding/spi/RpcRouter.java | 15 +- .../binding/test/AbstractDataServiceTest.java | 2 +- .../test/RuntimeCodeGeneratorTest.java | 3 - .../binding/test/util/BindingTestContext.java | 81 ++++- .../test/connect/dom/CrossBrokerRpcTest.java | 159 ++++++++++ .../dom/MessageCapturingFlowService.java | 122 ++++++++ .../api/routing/RouteChangePublisher.java | 2 +- .../sal/common/impl/routing/RoutingUtils.java | 92 ++++++ opendaylight/md-sal/sal-common-util/pom.xml | 4 + .../controller/sal/common/util/Rpcs.java | 19 +- .../sal/dom/broker/BrokerImpl.xtend | 12 +- .../sal/dom/broker/impl/RpcRouterImpl.xtend | 34 ++ .../impl/SchemaAwareDataStoreAdapter.java | 42 +-- 34 files changed, 1502 insertions(+), 518 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java delete mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java delete mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java rename opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/{BindingIndependentDataServiceConnector.java => BindingIndependentConnector.java} (58%) create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java create mode 100644 opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java create mode 100644 opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java create mode 100644 opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java diff --git a/opendaylight/md-sal/pom.xml b/opendaylight/md-sal/pom.xml index 6f1b2c0c10..4f2b255afd 100644 --- a/opendaylight/md-sal/pom.xml +++ b/opendaylight/md-sal/pom.xml @@ -428,6 +428,26 @@ org.apache.felix maven-bundle-plugin + + org.codehaus.mojo + build-helper-maven-plugin + 1.8 + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/config + ${project.build.directory}/generated-sources/sal + + + + + org.apache.maven.plugins maven-jar-plugin diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java new file mode 100644 index 0000000000..e25b93918a --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcAvailabilityListener.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.api; + +public interface RpcAvailabilityListener { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java index 74b6ad8a23..01dc6b8c0c 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java @@ -16,7 +16,7 @@ import java.util.concurrent.ScheduledExecutorService; import org.opendaylight.controller.config.yang.md.sal.binding.statistics.DataBrokerRuntimeMXBeanImpl; import org.opendaylight.controller.md.sal.common.impl.routing.AbstractDataReadRouter; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.data.DataProviderService; @@ -63,7 +63,7 @@ public final class DataBrokerImplModule extends BindingIndependentMappingService mappingService = getMappingServiceDependency(); if (domBroker != null && mappingService != null) { - BindingIndependentDataServiceConnector runtimeMapping = new BindingIndependentDataServiceConnector(); + BindingIndependentConnector runtimeMapping = new BindingIndependentConnector(); runtimeMapping.setMappingService(mappingService); runtimeMapping.setBaDataService(dataBindingBroker); domBroker.registerProvider(runtimeMapping, getBundleContext()); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java index 1bf15c182f..99b7ed8acf 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java @@ -11,6 +11,7 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl; import javassist.ClassPool; +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; import org.osgi.framework.BundleContext; @@ -50,8 +51,7 @@ public final class RuntimeMappingModule extends @Override public java.lang.AutoCloseable createInstance() { RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(); - ClassPool pool = new ClassPool(); // Should be default singleton - service.setPool(pool); + service.setPool(SingletonHolder.CLASS_POOL); service.start(getBundleContext()); return service; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend index f0f92da18e..dff0d215b2 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeHelper.xtend @@ -76,7 +76,6 @@ class RuntimeCodeHelper { if (field == null) throw new UnsupportedOperationException( "Unable to set routing table. Table field does not exists"); field.set(target,routingTable); - } } 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 new file mode 100644 index 0000000000..780d0bd4c7 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.java @@ -0,0 +1,161 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*; + +import java.util.Map; +import java.util.Set; +import java.util.HashMap; + +import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable; +import org.opendaylight.yangtools.yang.binding.DataContainer; +import org.opendaylight.yangtools.yang.binding.RpcImplementation; +import org.opendaylight.controller.md.sal.common.api.routing.MutableRoutingTable; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RpcRouterCodegenInstance implements // + RpcRouter, RouteChangeListener, InstanceIdentifier> { + + private static final Logger LOG = LoggerFactory.getLogger(RpcRouterCodegenInstance.class); + + private T defaultService; + + private final Class serviceType; + + private final T invocationProxy; + + private final Set> contexts; + + private final ListenerRegistry, InstanceIdentifier>> listeners; + + private final Map, RpcRoutingTableImpl> routingTables; + + public RpcRouterCodegenInstance(Class type, T routerImpl, Set> contexts, + Set> inputs) { + this.listeners = ListenerRegistry.create(); + this.serviceType = type; + this.invocationProxy = routerImpl; + this.contexts = ImmutableSet.copyOf(contexts); + Map, RpcRoutingTableImpl> mutableRoutingTables = new HashMap<>(); + for (Class ctx : contexts) { + RpcRoutingTableImpl table = new RpcRoutingTableImpl<>(ctx); + Map invokerView = table.getRoutes(); + setRoutingTable((RpcService) invocationProxy, ctx, invokerView); + mutableRoutingTables.put(ctx, table); + table.registerRouteChangeListener(this); + } + this.routingTables = ImmutableMap.copyOf(mutableRoutingTables); + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + public T getInvocationProxy() { + return invocationProxy; + } + + @Override + @SuppressWarnings("unchecked") + public RpcRoutingTable getRoutingTable(Class routeContext) { + return (RpcRoutingTable) routingTables.get(routeContext); + } + + @Override + public T getDefaultService() { + return defaultService; + } + + @Override + public Set> getContexts() { + return contexts; + } + + @Override + public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( + L listener) { + return listeners.registerWithType(listener); + } + + @Override + public void onRouteChange(RouteChange, InstanceIdentifier> change) { + for (ListenerRegistration, InstanceIdentifier>> listener : listeners) { + try { + listener.getInstance().onRouteChange(change); + } catch (Exception e) { + LOG.error("Error occured during invoker listener {}", listener.getInstance(), e); + } + } + } + + @Override + public T getService(Class context, InstanceIdentifier path) { + return routingTables.get(context).getRoute(path); + } + + @Override + public RoutedRpcRegistration addRoutedRpcImplementation(T service) { + return new RoutedRpcRegistrationImpl(service); + } + + @Override + public RpcRegistration registerDefaultService(T service) { + // TODO Auto-generated method stub + return null; + } + + private class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { + + public RoutedRpcRegistrationImpl(T instance) { + super(instance); + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + public void registerPath(Class context, InstanceIdentifier path) { + routingTables.get(context).updateRoute(path, getInstance()); + } + + @Override + public void unregisterPath(Class context, InstanceIdentifier path) { + routingTables.get(context).removeRoute(path, getInstance()); + + } + + @Override + public void registerInstance(Class context, InstanceIdentifier instance) { + registerPath(context, instance); + } + + @Override + public void unregisterInstance(Class context, InstanceIdentifier instance) { + unregisterPath(context, instance); + } + + @Override + protected void removeRegistration() { + + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend deleted file mode 100644 index b6dcde19ee..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRouterCodegenInstance.xtend +++ /dev/null @@ -1,64 +0,0 @@ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.yangtools.yang.binding.RpcService -import org.opendaylight.controller.sal.binding.spi.RpcRouter -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.* -import java.util.Set -import java.util.HashMap -import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.DataContainer -import org.opendaylight.yangtools.yang.binding.RpcImplementation - -class RpcRouterCodegenInstance implements RpcRouter { - - @Property - val T invocationProxy - - @Property - val RpcImplementation invokerDelegate; - - @Property - val Class serviceType - - @Property - val Set> contexts - - @Property - val Set> supportedInputs; - - val routingTables = new HashMap, RpcRoutingTableImpl>; - - @Property - var T defaultService - - new(Class type, T routerImpl, Set> contexts, - Set> inputs) { - _serviceType = type - _invocationProxy = routerImpl - _invokerDelegate = routerImpl as RpcImplementation - _contexts = contexts - _supportedInputs = inputs; - - for (ctx : contexts) { - val table = XtendHelper.createRoutingTable(ctx) - invocationProxy.setRoutingTable(ctx, table.routes); - routingTables.put(ctx, table); - } - } - - override getRoutingTable(Class table) { - routingTables.get(table) as RpcRoutingTable - } - - override getService(Class context, InstanceIdentifier path) { - val table = getRoutingTable(context); - return table.getRoute(path); - } - - override invoke(Class type, T input) { - return invokerDelegate.invoke(type, input); - } - -} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java new file mode 100644 index 0000000000..f9592351f6 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.java @@ -0,0 +1,125 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import java.util.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.concepts.Mutable; + +class RpcRoutingTableImpl // +implements // + Mutable, // + RpcRoutingTable, // + RouteChangePublisher, InstanceIdentifier> { + + private final Class identifier; + private final ConcurrentMap, S> routes; + private final Map, S> unmodifiableRoutes; + + private RouteChangeListener, InstanceIdentifier> listener; + private S defaultRoute; + + public RpcRoutingTableImpl(Class identifier) { + super(); + this.identifier = identifier; + this.routes = new ConcurrentHashMap<>(); + this.unmodifiableRoutes = Collections.unmodifiableMap(routes); + } + + @Override + public void setDefaultRoute(S target) { + defaultRoute = target; + } + + @Override + public S getDefaultRoute() { + return defaultRoute; + } + + @Override + public , InstanceIdentifier>> ListenerRegistration registerRouteChangeListener( + L listener) { + return (ListenerRegistration) new SingletonListenerRegistration(listener); + } + + @Override + public Class getIdentifier() { + return identifier; + } + + @Override + @SuppressWarnings("unchecked") + public void updateRoute(InstanceIdentifier path, S service) { + S previous = this.routes.put(path, service); + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (previous == null && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.announcementChange(identifier, path)); + } + } + + + @Override + @SuppressWarnings("unchecked") + public void removeRoute(InstanceIdentifier path) { + S previous = this.routes.remove(path); + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (previous != null && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path)); + } + } + + public void removeRoute(InstanceIdentifier path, S service) { + @SuppressWarnings("rawtypes") + RouteChangeListener listenerCapture = listener; + if (routes.remove(path, service) && listenerCapture != null) { + listenerCapture.onRouteChange(RoutingUtils.removalChange(identifier, path)); + } + } + + @Override + public S getRoute(InstanceIdentifier nodeInstance) { + S route = routes.get(nodeInstance); + if (route != null) { + return route; + } + return getDefaultRoute(); + } + + @Override + public Map, S> getRoutes() { + return unmodifiableRoutes; + } + + protected void removeAllReferences(S service) { + + } + + private class SingletonListenerRegistration, InstanceIdentifier>> extends + AbstractObjectRegistration + implements ListenerRegistration { + + public SingletonListenerRegistration(L instance) { + super(instance); + listener = instance; + } + + @Override + protected void removeRegistration() { + listener = null; + } + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend deleted file mode 100644 index 116a8177f9..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RpcRoutingTableImpl.xtend +++ /dev/null @@ -1,49 +0,0 @@ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import org.opendaylight.yangtools.yang.binding.RpcService -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier -import java.util.Map -import org.opendaylight.yangtools.yang.binding.DataObject -import java.util.HashMap - -class RpcRoutingTableImpl implements RpcRoutingTable{ - - @Property - val Class identifier; - - @Property - var S defaultRoute; - - @Property - val Map,S> routes; - - new(Class ident, Map,S> route) { - _identifier = ident - _routes = route - } - - new(Class ident) { - _identifier = ident - _routes = new HashMap - } - - - override getRoute(InstanceIdentifier nodeInstance) { - val ret = routes.get(nodeInstance); - if(ret !== null) { - return ret; - } - return defaultRoute; - } - - override removeRoute(InstanceIdentifier path) { - routes.remove(path); - } - - @SuppressWarnings("rawtypes") - override updateRoute(InstanceIdentifier path, S service) { - routes.put(path as InstanceIdentifier,service); - } -} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 90fcbd99aa..7ebcf02e41 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend @@ -27,7 +27,7 @@ import org.opendaylight.yangtools.yang.binding.Notification import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.* import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.* import java.util.HashSet -import static org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils.* +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.* import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker import java.util.Set @@ -37,6 +37,8 @@ import org.opendaylight.yangtools.yang.binding.annotations.QName import org.opendaylight.yangtools.yang.binding.DataContainer import org.opendaylight.yangtools.yang.binding.RpcImplementation import org.opendaylight.controller.sal.binding.codegen.util.JavassistUtils +import org.opendaylight.controller.sal.binding.impl.util.ClassLoaderUtils +import javassist.LoaderClassPath class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { @@ -45,40 +47,70 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co val extension JavassistUtils utils; val Map, RuntimeGeneratedInvokerPrototype> invokerClasses; - public new(ClassPool pool) { + + new(ClassPool pool) { classPool = pool; utils = new JavassistUtils(pool); invokerClasses = new WeakHashMap(); BROKER_NOTIFICATION_LISTENER = org.opendaylight.controller.sal.binding.api.NotificationListener.asCtClass; + pool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); } override getDirectProxyFor(Class iface) { - val supertype = iface.asCtClass - val targetCls = createClass(iface.directProxyName, supertype) [ - field(DELEGATE_FIELD, iface); - implementMethodsFrom(supertype) [ - body = ''' - { - if(«DELEGATE_FIELD» == null) { + val T instance = withClassLoaderAndLock(iface.classLoader,lock) [| + val proxyName = iface.directProxyName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(proxyName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val supertype = iface.asCtClass + val createdCls = createClass(iface.directProxyName, supertype) [ + field(DELEGATE_FIELD, iface); + implementsType(RpcImplementation.asCtClass) + implementMethodsFrom(supertype) [ + body = ''' + { + if(«DELEGATE_FIELD» == null) { + throw new java.lang.IllegalStateException("No provider is processing supplied message"); + } + return ($r) «DELEGATE_FIELD».«it.name»($$); + } + ''' + ] + implementMethodsFrom(RpcImplementation.asCtClass) [ + body = ''' + { throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } - return ($r) «DELEGATE_FIELD».«it.name»($$); - } - ''' + ''' + ] ] + return createdCls.toClass(iface.classLoader).newInstance as T ] - return targetCls.toClass(iface.classLoader).newInstance as T + return instance; } override getRouterFor(Class iface) { - val instance = >withClassLoaderAndLock(iface.classLoader,lock) [ | + val metadata = withClassLoader(iface.classLoader) [| + val supertype = iface.asCtClass + return supertype.rpcMetadata; + ] + + val instance = withClassLoaderAndLock(iface.classLoader,lock) [ | val supertype = iface.asCtClass - val metadata = supertype.rpcMetadata; + val routerName = iface.routerName; + val potentialClass = ClassLoaderUtils.tryToLoadClassWithTCCL(routerName) + if(potentialClass != null) { + return potentialClass.newInstance as T; + } + val targetCls = createClass(iface.routerName, supertype) [ - addInterface(RpcImplementation.asCtClass) + field(DELEGATE_FIELD, iface) //field(REMOTE_INVOKER_FIELD,iface); + implementsType(RpcImplementation.asCtClass) for (ctx : metadata.contexts) { field(ctx.routingTableField, Map) @@ -105,35 +137,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } ] implementMethodsFrom(RpcImplementation.asCtClass) [ - switch (name) { - case "getSupportedInputs": - body = ''' - { - throw new java.lang.UnsupportedOperationException("Not implemented yet"); - return ($r) null; - }''' - case "invoke": { - val tmpBody = ''' - { - «FOR input : metadata.supportedInputs SEPARATOR " else "» - «val rpcMetadata = metadata.rpcInputs.get(input)» - if(«input.name».class.equals($1)) { - return ($r) this.«rpcMetadata.methodName»((«input.name») $2); - } - «ENDFOR» - throw new java.lang.IllegalArgumentException("Not supported message type"); - return ($r) null; - } - ''' - body = tmpBody - } + body = ''' + { + throw new java.lang.IllegalStateException("No provider is processing supplied message"); + return ($r) null; } + ''' ] ] - val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T - return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs); + return targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T + ]; - return instance; + return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs); } private def RpcServiceMetadata getRpcMetadata(CtClass iface) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java new file mode 100644 index 0000000000..266293fb6d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java @@ -0,0 +1,14 @@ +package org.opendaylight.controller.sal.binding.codegen.impl; + +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; +import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; + +import javassist.ClassPool; + +public class SingletonHolder { + + public static final ClassPool CLASS_POOL = new ClassPool(); + public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(CLASS_POOL); + public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL; + public static final NotificationInvokerFactory INVOKER_FACTORY = RPC_GENERATOR_IMPL.getInvokerFactory(); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java index 4b672f1140..f1ba5843ba 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/LazyGeneratedCodecRegistry.java @@ -175,7 +175,7 @@ public class LazyGeneratedCodecRegistry implements // }); return ret; } catch (Exception e) { - LOG.error("Could not find augmentable for {}", augmentation, e); + LOG.debug("Could not find augmentable for {} using {}", augmentation, augmentation.getClassLoader(), e); return null; } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend index 853e62aa38..1b3acf7674 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/dom/serializer/impl/RuntimeGeneratedMappingServiceImpl.xtend @@ -43,6 +43,11 @@ import java.util.ArrayList import org.opendaylight.yangtools.yang.data.api.Node import org.opendaylight.yangtools.yang.data.impl.SimpleNodeTOImpl import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl +import org.opendaylight.yangtools.yang.binding.RpcService +import java.util.Set +import org.opendaylight.yangtools.yang.common.QName +import com.google.common.collect.FluentIterable +import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingService, SchemaServiceListener, AutoCloseable { @@ -65,6 +70,9 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer @Property val ConcurrentMap typeToSchemaNode = new ConcurrentHashMap(); + + @Property + val ConcurrentMap> serviceTypeToRpc = new ConcurrentHashMap(); val promisedTypeDefinitions = HashMultimap.>create; @@ -85,10 +93,17 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer registry.onModuleContextAdded(schemaContext, entry.key, entry.value); binding.pathToType.putAll(entry.value.childNodes) - //val module = entry.key; + val module = entry.key; val context = entry.value; updateBindingFor(context.childNodes, schemaContext); updateBindingFor(context.cases, schemaContext); + val namespace = BindingGeneratorUtil.moduleNamespaceToPackageName(module); + + if(!module.rpcs.empty) { + val rpcs = FluentIterable.from(module.rpcs).transform[QName].toSet + val serviceClass = new ReferencedTypeImpl(namespace,BindingGeneratorUtil.parseToClassName(module.name)+"Service"); + serviceTypeToRpc.put(serviceClass,rpcs); + } val typedefs = context.typedefs; for (typedef : typedefs.entrySet) { @@ -186,15 +201,7 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer } override dataObjectFromDataDom(InstanceIdentifier path, CompositeNode node) { - return tryDeserialization[ | - if (node == null) { - return null; - } - val targetType = path.targetType - val transformer = registry.getCodecForDataObject(targetType); - val ret = transformer.deserialize(node)?.value as DataObject; - return ret; - ] + dataObjectFromDataDom(path.targetType,node) as DataObject; } override fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) { @@ -243,6 +250,10 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer listenerRegistration = ctx.registerService(SchemaServiceListener, this, new Hashtable()); } } + + override getRpcQNamesFor(Class service) { + return serviceTypeToRpc.get(new ReferencedTypeImpl(service.package.name,service.simpleName)); + } private def getSchemaWithRetry(Type type) { val typeDef = typeToSchemaNode.get(type); @@ -274,5 +285,16 @@ class RuntimeGeneratedMappingServiceImpl implements BindingIndependentMappingSer override close() throws Exception { listenerRegistration?.unregister(); } + + override dataObjectFromDataDom(Class container, CompositeNode domData) { + return tryDeserialization[ | + if (domData == null) { + return null; + } + val transformer = registry.getCodecForDataObject(container); + val ret = transformer.deserialize(domData)?.value as DataObject; + return ret; + ] + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend index 9381a5a070..8d3545fbbb 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BindingAwareBrokerImpl.xtend @@ -13,7 +13,6 @@ import org.opendaylight.yangtools.yang.binding.RpcService import javassist.ClassPool import org.osgi.framework.BundleContext import java.util.Map -import java.util.HashMap import javassist.LoaderClassPath import org.opendaylight.controller.sal.binding.api.BindingAwareBroker import java.util.Hashtable @@ -49,29 +48,14 @@ import java.util.concurrent.Callable import java.util.WeakHashMap import javax.annotation.concurrent.GuardedBy import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry +import org.opendaylight.yangtools.concepts.ListenerRegistration +import org.opendaylight.yangtools.concepts.util.ListenerRegistry -class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, AutoCloseable { +class BindingAwareBrokerImpl extends RpcProviderRegistryImpl implements BindingAwareBroker, AutoCloseable { private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl) private InstanceIdentifier root = InstanceIdentifier.builder().toInstance(); - private static val clsPool = ClassPool.getDefault() - public static var RuntimeCodeGenerator generator; - - /** - * Map of all Managed Direct Proxies - * - */ - private val Map, RpcProxyContext> managedProxies = new ConcurrentHashMap(); - - /** - * - * Map of all available Rpc Routers - * - * - */ - private val Map, RpcRouter> rpcRouters = new WeakHashMap(); - @Property private var NotificationProviderService notifyBroker @@ -81,43 +65,15 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, @Property var BundleContext brokerBundleContext - ServiceRegistration notifyProviderRegistration - - ServiceRegistration notifyConsumerRegistration - - ServiceRegistration dataProviderRegistration - - ServiceRegistration dataConsumerRegistration - - private val proxyGenerationLock = new ReentrantLock; - - private val routerGenerationLock = new ReentrantLock; - public new(BundleContext bundleContext) { _brokerBundleContext = bundleContext; } def start() { log.info("Starting MD-SAL: Binding Aware Broker"); - initGenerator(); - - val executor = Executors.newCachedThreadPool; - - // Initialization of notificationBroker - log.info("Starting MD-SAL: Binding Aware Notification Broker"); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - - log.info("Starting MD-SAL: Binding Aware Data Broker"); - log.info("MD-SAL: Binding Aware Broker Started"); } - def initGenerator() { - // YANG Binding Class Loader - clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader)); - generator = new RuntimeCodeGenerator(clsPool); - } override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) { val ctx = consumer.createContext(bundleCtx) @@ -139,247 +95,9 @@ class BindingAwareBrokerImpl implements BindingAwareBroker, RpcProviderRegistry, private def createContext(BindingAwareProvider provider, BundleContext providerCtx) { new OsgiProviderContext(providerCtx, this) } - - /** - * Returns a Managed Direct Proxy for supplied class - * - * Managed direct proxy is a generated proxy class conforming to the supplied interface - * which delegates all calls to the backing delegate. - * - * Proxy does not do any validation, null pointer checks or modifies data in any way, it - * is only use to avoid exposing direct references to backing implementation of service. - * - * If proxy class does not exist for supplied service class it will be generated automatically. - */ - private def getManagedDirectProxy(Class service) { - var RpcProxyContext existing = null - - if ((existing = managedProxies.get(service)) != null) { - return existing.proxy - } - return withLock(proxyGenerationLock) [ | - val maybeProxy = managedProxies.get(service); - if (maybeProxy !== null) { - return maybeProxy.proxy; - } - - - val proxyInstance = generator.getDirectProxyFor(service) - val rpcProxyCtx = new RpcProxyContext(proxyInstance.class) - val properties = new Hashtable() - rpcProxyCtx.proxy = proxyInstance as RpcService - properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY - rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties) - managedProxies.put(service, rpcProxyCtx) - return rpcProxyCtx.proxy - ] - } - - private static def T withLock(ReentrantLock lock, Callable method) { - try { - lock.lock(); - val ret = method.call; - return ret; - } finally { - lock.unlock(); - } - } - - /** - * Registers RPC Implementation - * - */ - override addRpcImplementation(Class type, T service) { - checkNotNull(type, "Service type should not be null") - checkNotNull(service, "Service type should not be null") - - val proxy = getManagedDirectProxy(type) - checkState(proxy.delegate === null, "The Service for type %s is already registered", type) - - proxy.delegate = service; - return new RpcServiceRegistrationImpl(type, service, this); - } - - override RoutedRpcRegistration addRoutedRpcImplementation(Class type, T service) { - checkNotNull(type, "Service type should not be null") - checkNotNull(service, "Service type should not be null") - - val router = resolveRpcRouter(type); - checkState(router !== null) - return new RoutedRpcRegistrationImpl(service, router, this) - } - override getRpcService(Class service) { - checkNotNull(service, "Service should not be null"); - return getManagedDirectProxy(service) as T; - } - - private def RpcRouter resolveRpcRouter(Class type) { - - val router = rpcRouters.get(type); - if (router !== null) { - return router as RpcRouter; - } - - // We created Router - return withLock(routerGenerationLock) [ | - val maybeRouter = rpcRouters.get(type); - if (maybeRouter !== null) { - return maybeRouter as RpcRouter; - } - - val newRouter = generator.getRouterFor(type); - checkState(newRouter !== null); - rpcRouters.put(type, newRouter); - // We create / update Direct Proxy for router - val proxy = getManagedDirectProxy(type); - proxy.delegate = newRouter.invocationProxy - return newRouter; - ] - - } - - protected def void registerPath(RoutedRpcRegistrationImpl registration, - Class context, InstanceIdentifier path) { - - val router = registration.router; - val paths = registration.registeredPaths; - - val routingTable = router.getRoutingTable(context) - checkState(routingTable != null); - - // Updating internal structure of registration - routingTable.updateRoute(path, registration.instance) - - // Update routing table / send announce to message bus - val success = paths.put(context, path); - } - - protected def void unregisterPath(RoutedRpcRegistrationImpl registration, - Class context, InstanceIdentifier path) { - - val router = registration.router; - val paths = registration.registeredPaths; - - val routingTable = router.getRoutingTable(context) - checkState(routingTable != null); - - // Updating internal structure of registration - val target = routingTable.getRoute(path) - checkState(target === registration.instance) - routingTable.removeRoute(path) - checkState(paths.remove(context, path)); - } - - protected def void unregisterRoutedRpcService(RoutedRpcRegistrationImpl registration) { - - val router = registration.router; - val paths = registration.registeredPaths; - - for (ctxMap : registration.registeredPaths.entries) { - val context = ctxMap.key - val routingTable = router.getRoutingTable(context) - val path = ctxMap.value - routingTable.removeRoute(path) - } - } - - protected def void unregisterRpcService(RpcServiceRegistrationImpl registration) { - - val type = registration.serviceType; - - val proxy = managedProxies.get(type); - if (proxy.proxy.delegate === registration.instance) { - proxy.proxy.delegate = null; - } - } - - def createDelegate(Class type) { - getManagedDirectProxy(type); - } - - def getRpcRouters() { - return Collections.unmodifiableMap(rpcRouters); - } - - override close() { - dataConsumerRegistration.unregister() - dataProviderRegistration.unregister() - notifyConsumerRegistration.unregister() - notifyProviderRegistration.unregister() - } - -} - -class RoutedRpcRegistrationImpl extends AbstractObjectRegistration implements RoutedRpcRegistration { - - @Property - private val BindingAwareBrokerImpl broker; - - @Property - private val RpcRouter router; - - @Property - private val Multimap, InstanceIdentifier> registeredPaths = HashMultimap.create(); - - private var closed = false; - - new(T instance, RpcRouter backingRouter, BindingAwareBrokerImpl broker) { - super(instance) - _router = backingRouter; - _broker = broker; - } - - override protected removeRegistration() { - closed = true - broker.unregisterRoutedRpcService(this) - } - - override registerInstance(Class context, InstanceIdentifier instance) { - registerPath(context, instance); - } - - override unregisterInstance(Class context, InstanceIdentifier instance) { - unregisterPath(context, instance); - } - - override registerPath(Class context, InstanceIdentifier path) { - checkClosed() - broker.registerPath(this, context, path); - } - - override unregisterPath(Class context, InstanceIdentifier path) { - checkClosed() - broker.unregisterPath(this, context, path); - } - - override getServiceType() { - return router.serviceType; - } - - private def checkClosed() { - if (closed) - throw new IllegalStateException("Registration was closed."); - } - -} - -class RpcServiceRegistrationImpl extends AbstractObjectRegistration implements RpcRegistration { - - private var BindingAwareBrokerImpl broker; - - @Property - val Class serviceType; - - public new(Class type, T service, BindingAwareBrokerImpl broker) { - super(service); - this._serviceType = type; - this.broker = broker; - } - - override protected removeRegistration() { - broker.unregisterRpcService(this); - broker = null; + override close() throws Exception { + } -} +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend index e8b3850b77..b10c06f0c5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.xtend @@ -20,8 +20,8 @@ import org.opendaylight.yangtools.concepts.AbstractObjectRegistration import org.opendaylight.yangtools.concepts.ListenerRegistration import org.opendaylight.yangtools.concepts.Registration import org.opendaylight.yangtools.yang.binding.Notification -import org.slf4j.LoggerFactory - +import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder + class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable { val Multimap, NotificationListener> listeners; @@ -29,6 +29,11 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab @Property var ExecutorService executor; + new() { + listeners = HashMultimap.create() + } + + @Deprecated new(ExecutorService executor) { listeners = HashMultimap.create() this.executor = executor; @@ -100,7 +105,7 @@ class NotificationBrokerImpl implements NotificationProviderService, AutoCloseab override registerNotificationListener( org.opendaylight.yangtools.yang.binding.NotificationListener listener) { - val invoker = BindingAwareBrokerImpl.generator.invokerFactory.invokerFor(listener); + val invoker = SingletonHolder.INVOKER_FACTORY.invokerFor(listener); for (notifyType : invoker.supportedNotifications) { listeners.put(notifyType, invoker.invocationProxy) } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend index bc53108675..644c50b86a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiConsumerContext.xtend @@ -45,8 +45,7 @@ class OsgiConsumerContext implements ConsumerContext { val ref = services.iterator().next() as ServiceReference; return bundleContext.getService(ref) as T; } else { - broker.createDelegate(module); - return getRpcService(module); + return broker.getRpcService(module); } } catch (InvalidSyntaxException e) { log.error("Created filter was invalid:", e.message, e) 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 new file mode 100644 index 0000000000..bc862886d7 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RpcProviderRegistryImpl.java @@ -0,0 +1,166 @@ +package org.opendaylight.controller.sal.binding.impl; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.HashMap; +import java.util.Set; +import java.util.WeakHashMap; + +import javax.swing.tree.ExpandVetoException; + +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.api.routing.RouteChangePublisher; +import org.opendaylight.controller.md.sal.common.impl.routing.RoutingUtils; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator; +import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper; +import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder; +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.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.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; + +import static com.google.common.base.Preconditions.*; + +public class RpcProviderRegistryImpl implements // + RpcProviderRegistry, // + RouteChangePublisher> { + + private RuntimeCodeGenerator rpcFactory = SingletonHolder.RPC_GENERATOR_IMPL; + + private final Map, RpcService> publicProxies = new WeakHashMap<>(); + private final Map, RpcRouter> rpcRouters = new WeakHashMap<>(); + private final ListenerRegistry>> routeChangeListeners = ListenerRegistry + .create(); + + @Override + public final RoutedRpcRegistration addRoutedRpcImplementation(Class type, + T implementation) throws IllegalStateException { + return getRpcRouter(type).addRoutedRpcImplementation(implementation); + } + + @Override + public final RpcRegistration addRpcImplementation(Class type, T implementation) + throws IllegalStateException { + RpcRouter potentialRouter = (RpcRouter) rpcRouters.get(type); + if (potentialRouter != null) { + checkState(potentialRouter.getDefaultService() == null, + "Default service for routed RPC already registered."); + return potentialRouter.registerDefaultService(implementation); + } + T publicProxy = getRpcService(type); + RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); + checkState(currentDelegate == null, "Rpc service is already registered"); + RuntimeCodeHelper.setDelegate(publicProxy, implementation); + return new RpcProxyRegistration(type, implementation, this); + } + + @Override + public final T getRpcService(Class type) { + + RpcService potentialProxy = publicProxies.get(type); + if (potentialProxy != null) { + return (T) potentialProxy; + } + T proxy = rpcFactory.getDirectProxyFor(type); + publicProxies.put(type, proxy); + return proxy; + } + + private RpcRouter getRpcRouter(Class type) { + RpcRouter potentialRouter = rpcRouters.get(type); + if (potentialRouter != null) { + return (RpcRouter) potentialRouter; + } + RpcRouter router = rpcFactory.getRouterFor(type); + router.registerRouteChangeListener(new RouteChangeForwarder(type)); + RuntimeCodeHelper.setDelegate(getRpcService(type), router.getInvocationProxy()); + rpcRouters.put(type, router); + return router; + } + + public >> ListenerRegistration registerRouteChangeListener( + L listener) { + return (ListenerRegistration) routeChangeListeners.register(listener); + } + + public RuntimeCodeGenerator getRpcFactory() { + return rpcFactory; + } + + public void setRpcFactory(RuntimeCodeGenerator rpcFactory) { + this.rpcFactory = rpcFactory; + } + + private class RouteChangeForwarder implements + RouteChangeListener, InstanceIdentifier> { + + private final Class type; + + public RouteChangeForwarder(Class type) { + this.type = type; + } + + @Override + public void onRouteChange(RouteChange, InstanceIdentifier> change) { + Map>> announcements = new HashMap<>(); + for (Entry, Set>> entry : change.getAnnouncements() + .entrySet()) { + RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey()); + announcements.put(key, entry.getValue()); + } + Map>> removals = new HashMap<>(); + for (Entry, Set>> entry : change.getRemovals() + .entrySet()) { + RpcContextIdentifier key = RpcContextIdentifier.contextFor(type, entry.getKey()); + removals.put(key, entry.getValue()); + } + RouteChange> toPublish = RoutingUtils + .> change(announcements, removals); + for (ListenerRegistration>> listener : routeChangeListeners) { + try { + listener.getInstance().onRouteChange(toPublish); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + public static class RpcProxyRegistration extends AbstractObjectRegistration implements + RpcRegistration { + + private final Class serviceType; + private RpcProviderRegistryImpl registry; + + public RpcProxyRegistration(Class type, T service, RpcProviderRegistryImpl registry) { + super(service); + serviceType = type; + } + + @Override + public Class getServiceType() { + return serviceType; + } + + @Override + protected void removeRegistration() { + if (registry != null) { + T publicProxy = registry.getRpcService(serviceType); + RpcService currentDelegate = RuntimeCodeHelper.getDelegate(publicProxy); + if (currentDelegate == getInstance()) { + RuntimeCodeHelper.setDelegate(publicProxy, null); + } + registry = null; + } + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java similarity index 58% rename from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java rename to opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java index 9eff29f8cc..daa3914cf7 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentDataServiceConnector.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentConnector.java @@ -1,42 +1,78 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; +import java.lang.ref.WeakReference; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; + import org.opendaylight.controller.md.sal.common.api.RegistrationListener; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction; import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration; import org.opendaylight.controller.md.sal.common.api.data.DataModification; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener; +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.impl.RpcProviderRegistryImpl; +import org.opendaylight.controller.sal.binding.spi.RpcContextIdentifier; +import org.opendaylight.controller.sal.binding.spi.RpcRouter; 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.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.concepts.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.BindingMapping; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcInput; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.binding.util.BindingReflections; +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.slf4j.Logger; import org.slf4j.LoggerFactory; -public class BindingIndependentDataServiceConnector implements // +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableSet; + +import static com.google.common.base.Preconditions.*; +import static org.opendaylight.yangtools.concepts.util.ClassLoaderUtils.*; + +public class BindingIndependentConnector implements // RuntimeDataProvider, // - Provider, AutoCloseable { + Provider, // + AutoCloseable { - private final Logger LOG = LoggerFactory.getLogger(BindingIndependentDataServiceConnector.class); + private final Logger LOG = LoggerFactory.getLogger(BindingIndependentConnector.class); private static final InstanceIdentifier ROOT = InstanceIdentifier.builder().toInstance(); @@ -59,26 +95,41 @@ public class BindingIndependentDataServiceConnector implements // private Registration> biCommitHandlerRegistration; + private RpcProvisionRegistry biRpcRegistry; + private RpcProviderRegistryImpl baRpcRegistry; + + private ListenerRegistration domToBindingRpcManager; + // private ListenerRegistration + // bindingToDomRpcManager; + + private Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier> toDOMInstanceIdentifier = new Function, org.opendaylight.yangtools.yang.data.api.InstanceIdentifier>() { + + @Override + public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier apply(InstanceIdentifier input) { + return mappingService.toDataDom(input); + } + + }; + @Override public DataObject readOperationalData(InstanceIdentifier path) { try { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier biPath = mappingService.toDataDom(path); - - + CompositeNode result = biDataService.readOperationalData(biPath); Class targetType = path.getTargetType(); - - if(Augmentation.class.isAssignableFrom(targetType)) { + + if (Augmentation.class.isAssignableFrom(targetType)) { path = mappingService.fromDataDom(biPath); Class> augmentType = (Class>) targetType; DataObject parentTo = mappingService.dataObjectFromDataDom(path, result); - if(parentTo instanceof Augmentable) { + if (parentTo instanceof Augmentable) { return (DataObject) ((Augmentable) parentTo).getAugmentation(augmentType); } - + } return mappingService.dataObjectFromDataDom(path, result); - + } catch (DeserializationException e) { throw new IllegalStateException(e); } @@ -183,11 +234,24 @@ public class BindingIndependentDataServiceConnector implements // this.baDataService = baDataService; } + public RpcProviderRegistry getRpcRegistry() { + return baRpcRegistry; + } + + public void setRpcRegistry(RpcProviderRegistryImpl rpcRegistry) { + this.baRpcRegistry = rpcRegistry; + } + public void start() { baDataService.registerDataReader(ROOT, this); baCommitHandlerRegistration = baDataService.registerCommitHandler(ROOT, bindingToDomCommitHandler); biCommitHandlerRegistration = biDataService.registerCommitHandler(ROOT_BI, domToBindingCommitHandler); baDataService.registerCommitHandlerListener(domToBindingCommitHandler); + + if (baRpcRegistry != null && biRpcRegistry != null) { + domToBindingRpcManager = baRpcRegistry.registerRouteChangeListener(new DomToBindingRpcForwardingManager()); + + } } public void setMappingService(BindingIndependentMappingService mappingService) { @@ -205,6 +269,14 @@ public class BindingIndependentDataServiceConnector implements // start(); } + public void onRpcRouterCreated(Class serviceType, RpcRouter router) { + + } + + public void setDomRpcRegistry(RpcProvisionRegistry registry) { + biRpcRegistry = registry; + } + @Override public void close() throws Exception { if (baCommitHandlerRegistration != null) { @@ -358,4 +430,204 @@ public class BindingIndependentDataServiceConnector implements // return forwardedTransaction; } } + + private class DomToBindingRpcForwardingManager implements + RouteChangeListener> { + + private final Map, DomToBindingRpcForwarder> forwarders = new WeakHashMap<>(); + + @Override + public void onRouteChange(RouteChange> change) { + for (Entry>> entry : change.getAnnouncements().entrySet()) { + bindingRoutesAdded(entry); + } + } + + private void bindingRoutesAdded(Entry>> entry) { + Class context = entry.getKey().getRoutingContext(); + Class service = entry.getKey().getRpcService(); + if (context != null) { + getRpcForwarder(service, context).registerPaths(context, service, entry.getValue()); + } + } + + private DomToBindingRpcForwarder getRpcForwarder(Class service, + Class context) { + DomToBindingRpcForwarder potential = forwarders.get(service); + if (potential != null) { + return potential; + } + if (context == null) { + potential = new DomToBindingRpcForwarder(service); + } else { + potential = new DomToBindingRpcForwarder(service, context); + } + forwarders.put(service, potential); + return potential; + } + + } + + private class DomToBindingRpcForwarder implements RpcImplementation { + + private final Set supportedRpcs; + private final WeakReference> rpcServiceType; + private Set registrations; + + public DomToBindingRpcForwarder(Class service) { + this.rpcServiceType = new WeakReference>(service); + this.supportedRpcs = mappingService.getRpcQNamesFor(service); + for (QName rpc : supportedRpcs) { + biRpcRegistry.addRpcImplementation(rpc, this); + } + registrations = ImmutableSet.of(); + } + + 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)); + } + registrations = ImmutableSet.copyOf(registrations); + } + + public void registerPaths(Class context, Class service, + Set> set) { + QName ctx = BindingReflections.findQName(context); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform( + toDOMInstanceIdentifier)) { + for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) { + reg.registerPath(ctx, path); + } + } + } + + public void removePaths(Class context, Class service, + Set> set) { + QName ctx = BindingReflections.findQName(context); + for (org.opendaylight.yangtools.yang.data.api.InstanceIdentifier path : FluentIterable.from(set).transform( + toDOMInstanceIdentifier)) { + for (org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration reg : registrations) { + reg.unregisterPath(ctx, path); + } + } + } + + @Override + public Set getSupportedRpcs() { + return supportedRpcs; + } + + @Override + public RpcResult invokeRpc(QName rpc, CompositeNode domInput) { + checkArgument(rpc != null); + checkArgument(domInput != null); + + Class rpcType = rpcServiceType.get(); + checkState(rpcType != null); + RpcService rpcService = baRpcRegistry.getRpcService(rpcType); + checkState(rpcService != null); + CompositeNode domUnwrappedInput = domInput.getFirstCompositeByName(QName.create(rpc, "input")); + try { + return resolveInvocationStrategy(rpc, rpcType).invokeOn(rpcService, domUnwrappedInput); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + private RpcInvocationStrategy resolveInvocationStrategy(final QName rpc, + final Class rpcType) throws Exception { + return ClassLoaderUtils.withClassLoader(rpcType.getClassLoader(), new Callable() { + @Override + public RpcInvocationStrategy call() throws Exception { + String methodName = BindingMapping.getMethodName(rpc); + Method targetMethod = null; + for (Method possibleMethod : rpcType.getMethods()) { + if (possibleMethod.getName().equals(methodName) + && BindingReflections.isRpcMethod(possibleMethod)) { + targetMethod = possibleMethod; + break; + } + } + checkState(targetMethod != null, "Rpc method not found"); + Optional> outputClass = BindingReflections.resolveRpcOutputClass(targetMethod); + Optional> inputClass = BindingReflections + .resolveRpcInputClass(targetMethod); + + RpcInvocationStrategy strategy = null; + if (outputClass.isPresent()) { + if (inputClass.isPresent()) { + strategy = new DefaultInvocationStrategy(targetMethod, outputClass.get(), inputClass.get()); + } else { + strategy = new NoInputNoOutputInvocationStrategy(targetMethod); + } + } else { + strategy = null; + } + return strategy; + } + + }); + } + } + + private abstract class RpcInvocationStrategy { + + protected final Method targetMethod; + + public RpcInvocationStrategy(Method targetMethod) { + this.targetMethod = targetMethod; + } + + public abstract RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) + throws Exception; + + public RpcResult invokeOn(RpcService rpcService, CompositeNode domInput) throws Exception { + return uncheckedInvoke(rpcService, domInput); + } + } + + private class DefaultInvocationStrategy extends RpcInvocationStrategy { + + @SuppressWarnings("rawtypes") + private WeakReference inputClass; + + @SuppressWarnings("rawtypes") + private WeakReference outputClass; + + public DefaultInvocationStrategy(Method targetMethod, Class outputClass, + Class inputClass) { + super(targetMethod); + this.outputClass = new WeakReference(outputClass); + this.inputClass = new WeakReference(inputClass); + } + + @Override + public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + DataContainer bindingInput = mappingService.dataObjectFromDataDom(inputClass.get(), domInput); + Future> result = (Future>) targetMethod.invoke(rpcService, bindingInput); + if (result == null) { + return Rpcs.getRpcResult(false); + } + RpcResult bindingResult = result.get(); + return Rpcs.getRpcResult(true); + } + + } + + private class NoInputNoOutputInvocationStrategy extends RpcInvocationStrategy { + + public NoInputNoOutputInvocationStrategy(Method targetMethod) { + super(targetMethod); + } + + public RpcResult uncheckedInvoke(RpcService rpcService, CompositeNode domInput) throws Exception { + Future> result = (Future>) targetMethod.invoke(rpcService); + RpcResult bindingResult = result.get(); + return Rpcs.getRpcResult(bindingResult.isSuccessful(), bindingResult.getErrors()); + } + + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java index b1983fe224..e16ae48ef4 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/connect/dom/BindingIndependentMappingService.java @@ -1,10 +1,13 @@ package org.opendaylight.controller.sal.binding.impl.connect.dom; import java.util.Map.Entry; +import java.util.Set; -import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; +import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.CompositeNode; public interface BindingIndependentMappingService { @@ -19,5 +22,9 @@ public interface BindingIndependentMappingService { DataObject dataObjectFromDataDom(InstanceIdentifier path, CompositeNode result) throws DeserializationException; InstanceIdentifier fromDataDom(org.opendaylight.yangtools.yang.data.api.InstanceIdentifier entry) throws DeserializationException; + + Set getRpcQNamesFor(Class service); + + DataContainer dataObjectFromDataDom(Class inputClass, CompositeNode domInput); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java new file mode 100644 index 0000000000..49e056b100 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RoutingContext.java @@ -0,0 +1,5 @@ +package org.opendaylight.controller.sal.binding.spi; + +public class RoutingContext { + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java new file mode 100644 index 0000000000..33569eb077 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcContextIdentifier.java @@ -0,0 +1,65 @@ +package org.opendaylight.controller.sal.binding.spi; + +import org.opendaylight.yangtools.concepts.Immutable; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.RpcService; + +public final class RpcContextIdentifier implements Immutable{ + + public final Class rpcService; + public final Class routingContext; + + private RpcContextIdentifier(Class rpcService, Class routingContext) { + super(); + this.rpcService = rpcService; + this.routingContext = routingContext; + } + + public Class getRpcService() { + return rpcService; + } + + public Class getRoutingContext() { + return routingContext; + } + + public static final RpcContextIdentifier contextForGlobalRpc(Class serviceType) { + return new RpcContextIdentifier(serviceType, null); + } + + public static final RpcContextIdentifier contextFor(Class serviceType,Class routingContext) { + return new RpcContextIdentifier(serviceType, routingContext); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((routingContext == null) ? 0 : routingContext.hashCode()); + result = prime * result + ((rpcService == null) ? 0 : rpcService.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + RpcContextIdentifier other = (RpcContextIdentifier) obj; + if (routingContext == null) { + if (other.routingContext != null) + return false; + } else if (!routingContext.equals(other.routingContext)) + return false; + if (rpcService == null) { + if (other.rpcService != null) + return false; + } else if (!rpcService.equals(other.rpcService)) + return false; + return true; + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java index 7db90b62fd..621d048dfd 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/RpcRouter.java @@ -9,6 +9,9 @@ package org.opendaylight.controller.sal.binding.spi; import java.util.Set; +import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcImplementation; @@ -26,7 +29,8 @@ import org.opendaylight.yangtools.yang.binding.RpcService; * Type of RpcService for which router provides routing information * and route selection. */ -public interface RpcRouter extends RpcImplementation{ +public interface RpcRouter extends // + RouteChangePublisher, InstanceIdentifier> { /** * Returns a type of RpcService which is served by this instance of router. @@ -72,12 +76,11 @@ public interface RpcRouter extends RpcImplementation{ * @return default instance responsible for processing RPCs. */ T getDefaultService(); - - /** - * - */ - void setDefaultService(T service); Set> getContexts(); + + RoutedRpcRegistration addRoutedRpcImplementation(T service); + + RpcRegistration registerDefaultService(T service); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java index a7a70c2839..633506fec6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java @@ -12,7 +12,7 @@ import org.junit.After; import org.junit.Before; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.util.BindingBrokerTestFactory; import org.opendaylight.controller.sal.binding.test.util.BindingTestContext; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java index 1a97bd693a..9c9841a4a5 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/RuntimeCodeGeneratorTest.java @@ -65,9 +65,6 @@ public class RuntimeCodeGeneratorTest { assertNotNull(product); assertNotNull(product.getInvocationProxy()); - assertNotNull(product.getSupportedInputs()); - assertTrue(product.getSupportedInputs().contains(SimpleInput.class)); - assertTrue(product.getSupportedInputs().contains(InheritedContextInput.class)); assertEquals("2 fields should be generated.", 2, product.getInvocationProxy().getClass().getFields().length); verifyRouting(product); 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 4e611c5fe2..3217a31329 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 @@ -7,15 +7,22 @@ import java.util.Set; import javassist.ClassPool; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.opendaylight.controller.sal.binding.api.data.DataProviderService; import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl; +import org.opendaylight.controller.sal.binding.impl.BindingAwareBrokerImpl; import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl; -import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentDataServiceConnector; +import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl; +import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector; import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService; import org.opendaylight.controller.sal.binding.test.AbstractDataServiceTest; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.core.api.data.DataStore; +import org.opendaylight.controller.sal.dom.broker.BrokerImpl; 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.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -31,7 +38,7 @@ import com.google.common.util.concurrent.MoreExecutors; import static com.google.common.base.Preconditions.*; -public class BindingTestContext { +public class BindingTestContext implements AutoCloseable { public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier TREE_ROOT = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier @@ -40,10 +47,15 @@ public class BindingTestContext { private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class); private RuntimeGeneratedMappingServiceImpl mappingServiceImpl; + + + private BindingAwareBrokerImpl baBrokerImpl; private DataBrokerImpl baDataImpl; + private NotificationBrokerImpl baNotifyImpl; + private BindingIndependentConnector baConnectDataServiceImpl; + private org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl; - - private BindingIndependentDataServiceConnector connectorServiceImpl; + private BrokerImpl biBrokerImpl; private HashMapDataStore rawDataStore; private SchemaAwareDataStoreAdapter schemaAwareDataStore; private DataStoreStatsWrapper dataStoreStats; @@ -56,6 +68,7 @@ public class BindingTestContext { private final ClassPool classPool; private final boolean startWithSchema; + protected BindingTestContext(ListeningExecutorService executor, ClassPool classPool, boolean startWithSchema) { this.executor = executor; @@ -93,15 +106,29 @@ public class BindingTestContext { baDataImpl.setExecutor(executor); } + public void startBindingBroker() { + checkState(executor != null,"Executor needs to be set"); + checkState(baDataImpl != null,"Binding Data Broker must be started"); + checkState(baNotifyImpl != null, "Notification Service must be started"); + baBrokerImpl = new BindingAwareBrokerImpl(null); + + baBrokerImpl.setDataBroker(baDataImpl); + baBrokerImpl.setNotifyBroker(baNotifyImpl); + + baBrokerImpl.start(); + } + public void startBindingToDomDataConnector() { checkState(baDataImpl != null,"Binding Data Broker needs to be started"); checkState(biDataImpl != null,"DOM Data Broker needs to be started."); checkState(mappingServiceImpl != null,"DOM Mapping Service needs to be started."); - connectorServiceImpl = new BindingIndependentDataServiceConnector(); - connectorServiceImpl.setBaDataService(baDataImpl); - connectorServiceImpl.setBiDataService(biDataImpl); - connectorServiceImpl.setMappingService(mappingServiceImpl); - connectorServiceImpl.start(); + baConnectDataServiceImpl = new BindingIndependentConnector(); + baConnectDataServiceImpl.setRpcRegistry(baBrokerImpl); + baConnectDataServiceImpl.setDomRpcRegistry(getDomRpcRegistry()); + baConnectDataServiceImpl.setBaDataService(baDataImpl); + baConnectDataServiceImpl.setBiDataService(biDataImpl); + baConnectDataServiceImpl.setMappingService(mappingServiceImpl); + baConnectDataServiceImpl.start(); } public void startBindingToDomMappingService() { @@ -149,8 +176,11 @@ public class BindingTestContext { public void start() { startBindingDataBroker(); + startBindingNotificationBroker(); + startBindingBroker(); startDomDataBroker(); startDomDataStore(); + startDomBroker(); startBindingToDomMappingService(); startBindingToDomDataConnector(); if(startWithSchema) { @@ -158,6 +188,19 @@ public class BindingTestContext { } } + private void startDomBroker() { + checkState(executor != null); + biBrokerImpl = new BrokerImpl(); + biBrokerImpl.setExecutor(executor); + biBrokerImpl.setRouter(new RpcRouterImpl("test")); + } + + public void startBindingNotificationBroker() { + checkState(executor != null); + baNotifyImpl = new NotificationBrokerImpl(executor); + + } + public void loadYangSchemaFromClasspath() { String[] files = getAllYangFilesOnClasspath(); updateYangSchema(files); @@ -196,4 +239,24 @@ public class BindingTestContext { dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(), dataStoreStats.getRequestCommitAverageTime()); } + + public RpcProviderRegistry getBindingRpcRegistry() { + return baBrokerImpl; + } + + public RpcProvisionRegistry getDomRpcRegistry() { + if(biBrokerImpl == null) { + return null; + } + return biBrokerImpl.getRouter(); + } + + public RpcImplementation getDomRpcInvoker() { + return biBrokerImpl.getRouter(); + } + + @Override + public void close() throws Exception { + + } } 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 new file mode 100644 index 0000000000..92a0a3a98d --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/CrossBrokerRpcTest.java @@ -0,0 +1,159 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import java.math.BigInteger; +import java.util.Collections; +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; +import org.opendaylight.controller.sal.common.util.Rpcs; +import org.opendaylight.controller.sal.core.api.RpcImplementation; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder; +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.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +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.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.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; + +public class CrossBrokerRpcTest { + + protected RpcProviderRegistry baRpcRegistry; + protected RpcProvisionRegistry biRpcRegistry; + private BindingTestContext testContext; + private RpcImplementation biRpcInvoker; + private MessageCapturingFlowService flowService; + + public static final NodeId NODE_A = new NodeId("a"); + 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"); + + public static final InstanceIdentifier BA_NODE_A_ID = createBANodeIdentifier(NODE_A); + public static final InstanceIdentifier BA_NODE_B_ID = createBANodeIdentifier(NODE_B); + public static final InstanceIdentifier BA_NODE_C_ID = createBANodeIdentifier(NODE_C); + public static final InstanceIdentifier BA_NODE_D_ID = createBANodeIdentifier(NODE_D); + + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_A_ID = createBINodeIdentifier(NODE_A); + public static final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier BI_NODE_B_ID = createBINodeIdentifier(NODE_B); + 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() { + BindingBrokerTestFactory testFactory = new BindingBrokerTestFactory(); + testFactory.setExecutor(MoreExecutors.sameThreadExecutor()); + testFactory.setStartWithParsedSchema(true); + testContext = testFactory.getTestContext(); + + testContext.start(); + baRpcRegistry = testContext.getBindingRpcRegistry(); + biRpcRegistry = testContext.getDomRpcRegistry(); + biRpcInvoker = testContext.getDomRpcInvoker(); + assertNotNull(baRpcRegistry); + assertNotNull(biRpcRegistry); + + flowService = MessageCapturingFlowService.create(baRpcRegistry); + + } + + @Test + public void bindingRoutedRpcProvider_DomInvokerTest() { + + flowService// + .registerPath(NodeContext.class, BA_NODE_A_ID) // + .registerPath(NodeContext.class, BA_NODE_B_ID) // + .setAddFlowResult(addFlowResult(true, 10)); + + SalFlowService baFlowInvoker = baRpcRegistry.getRpcService(SalFlowService.class); + assertNotSame(flowService, baFlowInvoker); + + AddFlowInput addFlowA = addFlow(BA_NODE_A_ID) // + .setPriority(100).setBarrier(true).build(); + + CompositeNode addFlowDom = toDomRpc(ADD_FLOW_QNAME, addFlowA); + assertNotNull(addFlowDom); + RpcResult domResult = biRpcInvoker.invokeRpc(ADD_FLOW_QNAME, addFlowDom); + assertNotNull(domResult); + assertTrue("DOM result is successful.", domResult.isSuccessful()); + assertTrue("Bidning Add Flow RPC was captured.", flowService.getReceivedAddFlows().containsKey(BA_NODE_A_ID)); + assertEquals(addFlowA, flowService.getReceivedAddFlows().get(BA_NODE_A_ID).iterator().next()); + } + + public void bindingRpcInvoker_DomRoutedProviderTest() { + + } + + private CompositeNode toDomRpcInput(DataObject addFlowA) { + return testContext.getBindingToDomMappingService().toDataDom(addFlowA); + } + + @After + public void teardown() throws Exception { + testContext.close(); + } + + private static InstanceIdentifier createBANodeIdentifier(NodeId node) { + return InstanceIdentifier.builder(Nodes.class).child(Node.class, new NodeKey(node)).toInstance(); + } + + private static org.opendaylight.yangtools.yang.data.api.InstanceIdentifier createBINodeIdentifier(NodeId node) { + return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().node(Nodes.QNAME) + .nodeWithKey(Node.QNAME, NODE_ID_QNAME, node.getValue()).toInstance(); + } + + private Future> addFlowResult(boolean success, long xid) { + AddFlowOutput output = new AddFlowOutputBuilder() // + .setTransactionId(new TransactionId(BigInteger.valueOf(xid))).build(); + RpcResult result = Rpcs.getRpcResult(success, output, ImmutableList. of()); + return Futures.immediateFuture(result); + } + + private static AddFlowInputBuilder addFlow(InstanceIdentifier nodeId) { + AddFlowInputBuilder builder = new AddFlowInputBuilder(); + builder.setNode(new NodeRef(nodeId)); + return builder; + } + + private CompositeNode toDomRpc(QName rpcName, AddFlowInput addFlowA) { + return new CompositeNodeTOImpl(rpcName, null, + Collections.> singletonList(toDomRpcInput(addFlowA))); + } +} diff --git a/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java new file mode 100644 index 0000000000..74f07818d5 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-dom-it/src/test/java/org/opendaylight/controller/sal/binding/test/connect/dom/MessageCapturingFlowService.java @@ -0,0 +1,122 @@ +package org.opendaylight.controller.sal.binding.test.connect.dom; + +import static junit.framework.Assert.assertNotNull; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput; +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.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +public class MessageCapturingFlowService implements SalFlowService, AutoCloseable { + + private Future> addFlowResult; + private Future> removeFlowResult; + private Future> updateFlowResult; + + private final Multimap, AddFlowInput> receivedAddFlows = HashMultimap.create(); + private final Multimap, RemoveFlowInput> receivedRemoveFlows = HashMultimap.create(); + private final Multimap, UpdateFlowInput> receivedUpdateFlows = HashMultimap.create(); + private RoutedRpcRegistration registration; + + @Override + public Future> addFlow(AddFlowInput arg0) { + receivedAddFlows.put(arg0.getNode().getValue(), arg0); + return addFlowResult; + } + + @Override + public Future> removeFlow(RemoveFlowInput arg0) { + receivedRemoveFlows.put(arg0.getNode().getValue(), arg0); + return removeFlowResult; + } + + @Override + public Future> updateFlow(UpdateFlowInput arg0) { + receivedUpdateFlows.put(arg0.getNode().getValue(), arg0); + return updateFlowResult; + } + + public Future> getAddFlowResult() { + return addFlowResult; + } + + public MessageCapturingFlowService setAddFlowResult(Future> addFlowResult) { + this.addFlowResult = addFlowResult; + return this; + } + + public Future> getRemoveFlowResult() { + return removeFlowResult; + } + + public MessageCapturingFlowService setRemoveFlowResult(Future> removeFlowResult) { + this.removeFlowResult = removeFlowResult; + return this; + } + + public Future> getUpdateFlowResult() { + return updateFlowResult; + } + + public MessageCapturingFlowService setUpdateFlowResult(Future> updateFlowResult) { + this.updateFlowResult = updateFlowResult; + return this; + } + + public Multimap, AddFlowInput> getReceivedAddFlows() { + return receivedAddFlows; + } + + public Multimap, RemoveFlowInput> getReceivedRemoveFlows() { + return receivedRemoveFlows; + } + + public Multimap, UpdateFlowInput> getReceivedUpdateFlows() { + return receivedUpdateFlows; + } + + public MessageCapturingFlowService registerTo(RpcProviderRegistry registry) { + registration = registry.addRoutedRpcImplementation(SalFlowService.class, this); + assertNotNull(registration); + return this; + } + + public void close() throws Exception { + registration.close(); + } + + public MessageCapturingFlowService registerPath(Class context, InstanceIdentifier path) { + registration.registerPath(context, path); + return this; + } + + public MessageCapturingFlowService unregisterPath(Class context, InstanceIdentifier path) { + registration.unregisterPath(context, path); + return this; + } + + public static MessageCapturingFlowService create() { + return new MessageCapturingFlowService(); + } + + public static MessageCapturingFlowService create(RpcProviderRegistry registry) { + MessageCapturingFlowService ret = new MessageCapturingFlowService(); + ret.registerTo(registry); + return ret; + } + + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java index 89851c9393..bee29a1ad1 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangePublisher.java @@ -4,5 +4,5 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; public interface RouteChangePublisher { - ListenerRegistration> registerRouteChangeListener(RouteChangeListener listener); + > ListenerRegistration registerRouteChangeListener(L listener); } diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java new file mode 100644 index 0000000000..60d0cdf766 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/routing/RoutingUtils.java @@ -0,0 +1,92 @@ +package org.opendaylight.controller.md.sal.common.impl.routing; + +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; + +public class RoutingUtils { + + public static RouteChange removalChange(C context,P path) { + final ImmutableMap> announcements = ImmutableMap.>of(); + final ImmutableMap> removals = ImmutableMap.>of(context, ImmutableSet.of(path)); + return new RouteChangeImpl(announcements, removals); + } + + public static RouteChange announcementChange(C context,P path) { + final ImmutableMap> announcements = ImmutableMap.>of(context, ImmutableSet.of(path)); + final ImmutableMap> removals = ImmutableMap.>of(); + return new RouteChangeImpl(announcements, removals); + } + + + public static RouteChange change(Map> announcements, + Map> removals) { + final ImmutableMap> immutableAnnouncements = ImmutableMap.>copyOf(announcements); + final ImmutableMap> immutableRemovals = ImmutableMap.>copyOf(removals); + return new RouteChangeImpl(immutableAnnouncements, immutableRemovals); + } + + + private static class RouteChangeImpl implements RouteChange { + private final Map> removal; + private final Map> announcement; + + public RouteChangeImpl(ImmutableMap> removal, ImmutableMap> announcement) { + super(); + this.removal = removal; + this.announcement = announcement; + } + + @Override + public Map> getAnnouncements() { + return announcement; + } + + @Override + public Map> getRemovals() { + return removal; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((announcement == null) ? 0 : announcement.hashCode()); + result = prime * result + ((removal == null) ? 0 : removal.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + RouteChangeImpl other = (RouteChangeImpl) obj; + if (announcement == null) { + if (other.announcement != null) + return false; + } else if (!announcement.equals(other.announcement)) + return false; + if (removal == null) { + if (other.removal != null) { + return false; + } + } else if (!removal.equals(other.removal)) + return false; + return true; + } + } + + + +} diff --git a/opendaylight/md-sal/sal-common-util/pom.xml b/opendaylight/md-sal/sal-common-util/pom.xml index 7e8069a9b3..ff15e72ba6 100644 --- a/opendaylight/md-sal/sal-common-util/pom.xml +++ b/opendaylight/md-sal/sal-common-util/pom.xml @@ -23,6 +23,10 @@ concepts 0.1.1-SNAPSHOT + + com.google.guava + guava + bundle diff --git a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java index 54e1a065f4..356ec8ff7c 100644 --- a/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java +++ b/opendaylight/md-sal/sal-common-util/src/main/java/org/opendaylight/controller/sal/common/util/Rpcs.java @@ -11,17 +11,31 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; + +import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; +import com.google.common.collect.ImmutableList; + public class Rpcs { + + public static RpcResult getRpcResult(boolean successful) { + RpcResult ret = new RpcResultTO(successful, null, ImmutableList.of()); + return ret; + } + public static RpcResult getRpcResult(boolean successful, T result, Collection errors) { RpcResult ret = new RpcResultTO(successful, result, errors); return ret; } - private static class RpcResultTO implements RpcResult, Serializable { + public static RpcResult getRpcResult(boolean successful, Collection errors) { + return new RpcResultTO(successful, null, errors); + } + + private static class RpcResultTO implements RpcResult, Serializable, Immutable { private final Collection errors; private final T result; @@ -31,8 +45,7 @@ public class Rpcs { Collection errors) { this.successful = successful; this.result = result; - this.errors = Collections.unmodifiableList(new ArrayList( - errors)); + this.errors = ImmutableList.copyOf(errors); } @Override 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 7ef594bad9..8f179987b9 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 @@ -29,8 +29,10 @@ import org.slf4j.LoggerFactory import org.opendaylight.controller.sal.dom.broker.spi.RpcRouter 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 -public class BrokerImpl implements Broker, AutoCloseable { +public class BrokerImpl implements Broker, RpcProvisionRegistry, AutoCloseable { private static val log = LoggerFactory.getLogger(BrokerImpl); // Broker Generic Context @@ -115,4 +117,12 @@ public class BrokerImpl implements Broker, AutoCloseable { deactivator?.close(); } + override addRpcImplementation(QName rpcType, RpcImplementation implementation) throws IllegalArgumentException { + router.addRpcImplementation(rpcType,implementation); + } + + override addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation) { + router.addRoutedRpcImplementation(rpcType,implementation); + } + } 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 index d8680ce3b4..5ee19a0e8f 100644 --- 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 @@ -15,6 +15,8 @@ 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 { @@ -35,6 +37,20 @@ class RpcRouterImpl implements RpcRouter, Identifiable { } 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 { @@ -102,5 +118,23 @@ class RpcRegistrationImpl extends AbstractObjectRegistration 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/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java index 4f4fadcc44..75e96491b6 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java @@ -151,19 +151,20 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator original) { // NOOP for now NormalizedDataModification normalized = new NormalizedDataModification(original); - for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { + for (Entry entry : original.getUpdatedConfigurationData().entrySet()) { normalized.putConfigurationData(entry.getKey(), entry.getValue()); } - for (Entry entry : original.getUpdatedOperationalData().entrySet()) { + for (Entry entry : original.getUpdatedOperationalData().entrySet()) { normalized.putOperationalData(entry.getKey(), entry.getValue()); } for (InstanceIdentifier entry : original.getRemovedConfigurationData()) { normalized.removeConfigurationData(entry); } - for(InstanceIdentifier entry : original.getRemovedOperationalData()) { + for (InstanceIdentifier entry : original.getRemovedOperationalData()) { normalized.removeOperationalData(entry); } return normalized; @@ -284,7 +285,7 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator { private Object identifier; @@ -295,12 +296,12 @@ public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator> commit() { throw new UnsupportedOperationException("Commit should not be invoked on this"); } - + @Override - protected CompositeNode mergeConfigurationData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) { - return mergeData(path,stored, modified,true); + protected CompositeNode mergeConfigurationData(InstanceIdentifier path, CompositeNode stored, + CompositeNode modified) { + return mergeData(path, stored, modified, true); } - + @Override - protected CompositeNode mergeOperationalData(InstanceIdentifier path,CompositeNode stored, CompositeNode modified) { + protected CompositeNode mergeOperationalData(InstanceIdentifier path, CompositeNode stored, + CompositeNode modified) { // TODO Auto-generated method stub - return mergeData(path,stored,modified,false); + return mergeData(path, stored, modified, false); } - } } -- 2.36.6