From a3dbf5335c352c7463674e31314ce2b5285cb6fe Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Wed, 23 Oct 2013 19:13:35 +0200 Subject: [PATCH] Updated implementation of broker (data services, generated code), added Integration test. - Added Javadoc to Bidning Aware APIs - Updated implementation of data services - Added default data store for integration testing - added integration test for data modifications and reads - Updated implementation of generated RpcRouters to get rid of reflection in cases where invoker does not known RPC name, only payload. Change-Id: I30b8d8b5b4b35ff1879d0a67c2f8717294841063 Signed-off-by: Tony Tkacik --- .../sal/binding/api/BindingAwareBroker.java | 31 +-- .../api/NotificationProviderService.java | 28 ++- .../sal/binding/api/NotificationService.java | 38 ++- .../sal/binding/api/RpcConsumerRegistry.java | 20 ++ .../sal/binding/api/RpcProviderRegistry.java | 39 +++ .../binding/api/data/DataBrokerService.java | 28 +++ .../api/data/DataModificationTransaction.java | 58 ++++- .../binding/api/data/DataProviderService.java | 21 +- .../binding/api/data/RuntimeDataProvider.java | 6 + .../sal/binding/api/mount/MountInstance.java | 12 +- .../api/mount/MountProviderInstance.java | 22 ++ .../api/mount/MountProviderService.java | 18 ++ .../binding/codegen/RuntimeCodeGenerator.java | 1 + .../binding/codegen/impl/RoutingPair.xtend | 24 -- .../impl/RpcRouterCodegenInstance.xtend | 25 +- .../codegen/impl/RuntimeCodeGenerator.xtend | 219 +++++++++++------ .../binding/impl/BindingAwareBrokerImpl.xtend | 8 + .../sal/binding/impl/BrokerActivator.java | 7 +- .../sal/binding/impl/DataBrokerImpl.xtend | 231 ++++++++++++++++-- .../sal/binding/impl/DataTransactionImpl.java | 100 ++++++++ .../impl/DeprecatedDataAPISupport.xtend | 59 +++++ .../sal/binding/impl/HashMapDataStore.xtend | 85 +++++++ .../binding/impl/OsgiProviderContext.xtend | 14 -- .../sal/binding/impl/util/MapUtils.xtend | 31 +++ .../controller/sal/binding/spi/RpcRouter.java | 6 +- .../binding/spi/remote/RemoteRpcRouter.java | 17 ++ .../spi/remote/RouteChangeListener.java | 13 + .../test/RuntimeCodeGeneratorTest.java | 4 + .../sal/binding/test/mock/FooService.java | 2 +- opendaylight/md-sal/sal-binding-it/pom.xml | 6 + .../test/sal/binding/it/TestHelper.java | 3 +- .../test/sal/binding/it/AbstractTest.java | 1 + .../test/sal/binding/it/DataServiceTest.java | 103 ++++++++ .../md/sal/common/api/data/DataReader.java | 9 + opendaylight/md-sal/sal-common-impl/pom.xml | 69 ++++-- .../common/impl/AbstractDataModification.java | 29 ++- .../md/sal/common/impl/ListenerRegistry.java | 55 +++++ .../provider/impl/ToastConsumerImpl.java | 2 - .../sample/toaster/it/ToasterTest.java | 3 +- 39 files changed, 1214 insertions(+), 233 deletions(-) create mode 100644 opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java create mode 100644 opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java create mode 100644 opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java create mode 100644 opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java delete mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/HashMapDataStore.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/MapUtils.xtend create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java create mode 100644 opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RouteChangeListener.java create mode 100644 opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java create mode 100644 opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java index 84e0561b9f..19ca06a265 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/BindingAwareBroker.java @@ -126,7 +126,7 @@ public interface BindingAwareBroker { * * */ - public interface ConsumerContext { + public interface ConsumerContext extends RpcConsumerRegistry { /** * Returns a session specific instance (implementation) of requested @@ -138,15 +138,7 @@ public interface BindingAwareBroker { */ T getSALService(Class service); - /** - * Returns a session specific instance (implementation) of requested - * YANG module implentation / service provided by consumer. - * - * @param service - * Broker service - * @return Session specific implementation of service - */ - T getRpcService(Class module); + } /** @@ -165,25 +157,12 @@ public interface BindingAwareBroker { * functionality provided by other {@link BindingAwareConsumer}s. * */ - public interface ProviderContext extends ConsumerContext { - /** - * Registers an global RpcService implementation. - * - * @param type - * @param implementation - * @return - */ - RpcRegistration addRpcImplementation(Class type, T implementation) - throws IllegalStateException; - - RpcRegistration addMountRpcImplementation(Class type, InstanceIdentifier mount, - T implementation) throws IllegalStateException; - - RoutedRpcRegistration addRoutedRpcImplementation(Class type, T implementation) - throws IllegalStateException; + public interface ProviderContext extends ConsumerContext, RpcProviderRegistry { + @Deprecated void registerFunctionality(ProviderFunctionality functionality); + @Deprecated void unregisterFunctionality(ProviderFunctionality functionality); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java index 64aab6ec0c..cb201c5fd1 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationProviderService.java @@ -15,23 +15,35 @@ import org.opendaylight.yangtools.yang.binding.Notification; public interface NotificationProviderService extends NotificationService, NotificationPublishService { + /** + * Deprecated. Use {@link #publish(Notification)}. + * + * @param notification + */ @Deprecated void notify(Notification notification); + /** + * Deprecated. Use {@link #publish(Notification,ExecutorService)}. + * + * @param notification + */ @Deprecated void notify(Notification notification, ExecutorService service); + /** + * Publishes a notification. + * + * @param Notification notification to publish. + * + */ @Override void publish(Notification notification); + /** + * Publishes a notification, listener calls are done in provided executor. + * + */ @Override void publish(Notification notification, ExecutorService service); - - @Override - public Registration> registerNotificationListener( - Class notificationType, NotificationListener listener); - - @Override - public Registration registerNotificationListener( - org.opendaylight.yangtools.yang.binding.NotificationListener listener); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java index 922acb9821..10b29f7218 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/NotificationService.java @@ -8,27 +8,63 @@ package org.opendaylight.controller.sal.binding.api; import org.opendaylight.controller.md.sal.common.api.notify.NotificationSubscriptionService; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.Notification; public interface NotificationService extends BindingAwareService { - + /** + * + * Deprecated: use {@link #addNotificationListener(Class, NotificationListener)} istead. + * + * @param listener + */ @Deprecated void addNotificationListener(Class notificationType, NotificationListener listener); + /** + * + * Deprecated: use {@link #addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener)} istead. + * + * @param listener + */ @Deprecated void addNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener); + /** + * Deprecated: use {@link Registration#close()} istead. + * @param listener + */ @Deprecated void removeNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener listener); + /** + * Deprecated: use {@link Registration#close()} istead. + * @param listener + */ @Deprecated void removeNotificationListener(Class notificationType, NotificationListener listener); + + /** + * Register a generic listener for specified notification type only. + * + * @param notificationType + * @param listener + * @return Registration for listener. To unregister listener invoke {@link Registration#close()} method. + */ Registration> registerNotificationListener( Class notificationType, NotificationListener listener); + /** + * Register a listener which implements generated notification interfaces derived from + * {@link org.opendaylight.yangtools.yang.binding.NotificationListener}. + * Listener is registered for all notifications present in implemented interfaces. + * + * @param listener + * @return Registration for listener. To unregister listener invoke {@link Registration#close()} method. + */ Registration registerNotificationListener( org.opendaylight.yangtools.yang.binding.NotificationListener listener); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java new file mode 100644 index 0000000000..e20640d420 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcConsumerRegistry.java @@ -0,0 +1,20 @@ +package org.opendaylight.controller.sal.binding.api; + +import org.opendaylight.yangtools.yang.binding.RpcService; + +/** + * Base interface defining contract for retrieving MD-SAL + * version of RpcServices + * + */ +public interface RpcConsumerRegistry { + /** + * Returns a session specific instance (implementation) of requested + * YANG module implentation / service provided by consumer. + * + * @param service + * Broker service + * @return Session specific implementation of service + */ + T getRpcService(Class module); +} diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java new file mode 100644 index 0000000000..972e64faf6 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/RpcProviderRegistry.java @@ -0,0 +1,39 @@ +package org.opendaylight.controller.sal.binding.api; + +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcService; + +/** + * Interface defining provider's access to the Rpc Registry + * which could be used to register their implementations of service to the MD-SAL. + * + * @author ttkacik + * + */ +public interface RpcProviderRegistry extends RpcConsumerRegistry { + /** + * Registers an global RpcService implementation. + * + * @param type + * @param implementation + * @return + */ + RpcRegistration addRpcImplementation(Class type, T implementation) + throws IllegalStateException; + + /** + * + * Register an Routed RpcService where routing is determined on annotated (in YANG model) + * context-reference and value of annotated leaf. + * + * @param type Type of RpcService, use generated interface class, not your implementation clas + * @param implementation Implementation of RpcService + * @return Registration object for routed Rpc which could be used to close an + * + * @throws IllegalStateException + */ + RoutedRpcRegistration addRoutedRpcImplementation(Class type, T implementation) + throws IllegalStateException; +} diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java index 50ee740718..aa846ff78d 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataBrokerService.java @@ -14,6 +14,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataModificationTransa import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.sal.binding.api.BindingAwareService; import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.DataRoot; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -165,4 +166,31 @@ public interface DataBrokerService extends // @Deprecated public void unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener); + /** + * Reads data subtree from configurational store. + * (Store which is populated by consumer, which is usually used to + * inject state into providers. E.g. Flow configuration)- + * + */ + @Override + public DataObject readConfigurationData(InstanceIdentifier path); + + /** + * Reads data subtree from operational store. + * (Store which is populated by providers, which is usually used to + * capture state of providers. E.g. Topology) + * + */ + @Override + public DataObject readOperationalData(InstanceIdentifier path); + + /** + * Register a data change listener for particular subtree. + * + * Callback is invoked each time data in subtree changes. + * + */ + @Override + public ListenerRegistration registerDataChangeListener( + InstanceIdentifier path, DataChangeListener listener); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java index 4f69f0b38a..9ce11c71e4 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataModificationTransaction.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.binding.api.data; import java.util.EventListener; +import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataModification; @@ -15,17 +16,68 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; public interface DataModificationTransaction extends DataModification, DataObject> { + /** + * Returns an unique identifier for transaction + * + */ + @Override + public Object getIdentifier(); + + /** + * Initiates a two-phase commit of candidate data. + * + *

+ * The {@link Consumer} could initiate a commit of candidate data + * + *

+ * The successful commit changes the state of the system and may affect + * several components. + * + *

+ * The effects of successful commit of data are described in the + * specifications and YANG models describing the {@link Provider} components + * of controller. It is assumed that {@link Consumer} has an understanding + * of this changes. + * + * + * @see DataCommitHandler for further information how two-phase commit is + * processed. + * @param store + * Identifier of the store, where commit should occur. + * @return Result of the commit, containing success information or list of + * encountered errors, if commit was not successful. + */ + @Override + public Future> commit(); + + + + /** + * Register a listener for transaction + * + * @param listener + * @return + */ ListenerRegistration registerListener(DataTransactionListener listener); - //FIXME: After 0.6 Release of YANG-Binding - //public T readOperationalData(InstanceIdentifier path); - //public T readConfigurationData(InstanceIdentifier path); + /** + * Listener for transaction state changes + * + * + */ public interface DataTransactionListener extends EventListener { + /** + * Callback is invoked after each transaction status change. + * + * @param transaction Transaction + * @param status New status + */ void onStatusUpdated(DataModificationTransaction transaction,TransactionStatus status); } } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java index 32b1d933cf..523abb50ca 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataProviderService.java @@ -9,11 +9,30 @@ package org.opendaylight.controller.sal.binding.api.data; import org.opendaylight.controller.md.sal.common.api.data.DataProvisionService; +import org.opendaylight.controller.md.sal.common.api.data.DataReader; +import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; import org.opendaylight.controller.sal.common.DataStoreIdentifier; +import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; - +/** + * DataProviderService is common access point for {@link BindingAwareProvider} providers + * to access data trees described by the YANG model. + * + */ public interface DataProviderService extends DataBrokerService, DataProvisionService, DataObject> { + + /** + * Registers a data reader for particular subtree of overal YANG data tree. + * + * Registered data reader is called if anyone tries to read data from + * paths which are nested to provided path. + * + * @param path Subpath which is handled by registered data reader + * @param reader Instance of reader which + * @return Registration object for reader. Invoking {@link Registration#close()} will unregister reader. + */ + Registration,DataObject>> registerDataReader(InstanceIdentifier path,DataReader,DataObject> reader); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java index f7116594ff..652e14bfa5 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/RuntimeDataProvider.java @@ -16,6 +16,12 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.DataRoot; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * Utility interface which does type capture for BindingAware DataReader. + * + * @author + * + */ public interface RuntimeDataProvider extends ProviderFunctionality,DataReader, DataObject> { diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java index b926e953b8..844b03a180 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountInstance.java @@ -8,11 +8,17 @@ package org.opendaylight.controller.sal.binding.api.mount; import org.opendaylight.controller.sal.binding.api.NotificationService; +import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry; import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.yangtools.concepts.Identifiable; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; -public interface MountInstance extends NotificationService, DataBrokerService { - - T getRpcService(Class rpcService); +public interface MountInstance // + extends // + RpcConsumerRegistry, // + Identifiable>, // + NotificationService, // + DataBrokerService { } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java new file mode 100644 index 0000000000..81a4a2431b --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderInstance.java @@ -0,0 +1,22 @@ +package org.opendaylight.controller.sal.binding.api.mount; + +import org.opendaylight.controller.sal.binding.api.NotificationProviderService; +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.controller.sal.binding.api.data.DataProviderService; + +/** + * Provider's version of Mount Point, this version allows access to MD-SAL + * services specific for this mountpoint and registration / provision of + * interfaces for mount point. + * + * @author ttkacik + * + */ +public interface MountProviderInstance // + extends // + MountInstance, // + DataProviderService, // + RpcProviderRegistry, // + NotificationProviderService { + +} diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java new file mode 100644 index 0000000000..d91a216baa --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/mount/MountProviderService.java @@ -0,0 +1,18 @@ +package org.opendaylight.controller.sal.binding.api.mount; + +import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; +import org.opendaylight.yangtools.concepts.Registration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +/** + * Provider MountProviderService, this version allows access to MD-SAL + * services specific for this mountpoint and registration / provision of + * interfaces for mount point. + * + * @author ttkacik + * + */ +public interface MountProviderService extends MountInstance { + + MountProviderInstance createMountPoint(InstanceIdentifier path); +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java index f94be9c6a6..1d828077b8 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/RuntimeCodeGenerator.java @@ -11,6 +11,7 @@ import org.opendaylight.controller.sal.binding.spi.DelegateProxy; import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory; import org.opendaylight.controller.sal.binding.spi.RpcRouter; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcImplementation; import org.opendaylight.yangtools.yang.binding.RpcService; import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext; diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend deleted file mode 100644 index f60816d954..0000000000 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RoutingPair.xtend +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License v1.0 which accompanies this distribution, - * and is available at http://www.eclipse.org/legal/epl-v10.html - */ -package org.opendaylight.controller.sal.binding.codegen.impl - -import org.opendaylight.yangtools.yang.binding.BaseIdentity -import javassist.CtMethod -import java.lang.reflect.Method - -@Data -class RoutingPair { - - @Property - val Class context; - @Property - val CtMethod getter; - - @Property - val boolean encapsulated; -} 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 index f63f2a313e..5b11ec7207 100644 --- 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 @@ -8,8 +8,9 @@ import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeC import java.util.Set import java.util.HashMap import org.opendaylight.controller.sal.binding.spi.RpcRoutingTable -import org.opendaylight.yangtools.yang.binding.DataObject import static org.opendaylight.controller.sal.binding.codegen.impl.XtendHelper.* +import org.opendaylight.yangtools.yang.binding.DataContainer +import org.opendaylight.yangtools.yang.binding.RpcImplementation class RpcRouterCodegenInstance implements RpcRouter { @@ -17,20 +18,29 @@ class RpcRouterCodegenInstance implements RpcRouter { val T invocationProxy @Property - val Class rpcServiceType + val RpcImplementation invokerDelegate; + + @Property + val Class serviceType @Property val Set> contexts - val routingTables = new HashMap, RpcRoutingTableImpl>; + @Property + val Set> supportedInputs; + + val routingTables = new HashMap, RpcRoutingTableImpl>; @Property var T defaultService - new(Class type, T routerImpl, Set> contexts) { - _rpcServiceType = type + 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) @@ -47,4 +57,9 @@ class RpcRouterCodegenInstance implements RpcRouter { 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/RuntimeCodeGenerator.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/RuntimeCodeGenerator.xtend index 0aee95ea41..87cc42c6e4 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 @@ -33,16 +33,16 @@ import java.util.Arrays 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 java.io.ObjectOutputStream.PutField import static org.opendaylight.controller.sal.binding.impl.osgi.ClassLoaderUtils.* -import javax.xml.ws.spi.Invoker import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory.NotificationInvoker import java.util.Set -import java.util.Collections import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper import java.util.WeakHashMap import javassist.ClassClassPath +import org.opendaylight.yangtools.yang.binding.annotations.QName +import org.opendaylight.yangtools.yang.binding.DataContainer +import org.opendaylight.yangtools.yang.binding.RpcImplementation class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator, NotificationInvokerFactory { @@ -70,31 +70,26 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co override getRouterFor(Class iface) { val contexts = new HashSet> - val instance = withClassLoader(iface.classLoader) [ | + val instance = >withClassLoader(iface.classLoader) [ | val supertype = iface.asCtClass + val metadata = supertype.rpcMetadata; val targetCls = createClass(iface.routerName, supertype) [ - //field(ROUTING_TABLE_FIELD,Map) + addInterface(RpcImplementation.asCtClass) + field(DELEGATE_FIELD, iface) - val ctxMap = new HashMap>(); - // We search for routing pairs and add fields - supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method | - val routingPair = method.routingContextInput; - if (routingPair !== null) { - ctxMap.put(routingPair.context.routingTableField, routingPair.context); - contexts.add(routingPair.context) - } - ] - for (ctx : ctxMap.entrySet) { - field(ctx.key, Map) + //field(REMOTE_INVOKER_FIELD,iface); + + for (ctx : metadata.contexts) { + field(ctx.routingTableField, Map) } implementMethodsFrom(supertype) [ if (parameterTypes.size === 1) { - val routingPair = routingContextInput; + val rpcMeta = metadata.rpcMethods.get(name); val bodyTmp = ''' { - final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»()«IF routingPair. - encapsulated».getValue()«ENDIF»; - «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier); + final «InstanceIdentifier.name» identifier = $1.«rpcMeta.inputRouteGetter.name»()«IF rpcMeta. + routeEncapsulated».getValue()«ENDIF»; + «supertype.name» instance = («supertype.name») «rpcMeta.context.routingTableField».get(identifier); if(instance == null) { instance = «DELEGATE_FIELD»; } @@ -108,10 +103,90 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);''' } ] + 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 + } + } + ] ] - return targetCls.toClass(iface.classLoader).newInstance as T + val instance = targetCls.toClass(iface.classLoader,iface.protectionDomain).newInstance as T + return new RpcRouterCodegenInstance(iface, instance, metadata.contexts,metadata.supportedInputs); ]; - return new RpcRouterCodegenInstance(iface, instance, contexts); + return instance; + } + + private def RpcServiceMetadata getRpcMetadata(CtClass iface) { + val metadata = new RpcServiceMetadata; + + iface.methods.filter[declaringClass == iface && parameterTypes.size === 1].forEach [ method | + val routingPair = method.rpcMetadata; + if (routingPair !== null) { + metadata.contexts.add(routingPair.context) + metadata.rpcMethods.put(method.name,routingPair) + val input = routingPair.inputType.javaClass as Class; + metadata.supportedInputs.add(input); + metadata.rpcInputs.put(input,routingPair); + } + ] + return metadata; + } + + private def getRpcMetadata(CtMethod method) { + val inputClass = method.parameterTypes.get(0); + return inputClass.rpcMethodMetadata(inputClass,method.name); + } + + private def RpcMetadata rpcMethodMetadata(CtClass dataClass,CtClass inputClass,String rpcMethod) { + for (method : dataClass.methods) { + if (method.name.startsWith("get") && method.parameterTypes.size === 0) { + for (annotation : method.availableAnnotations) { + if (annotation instanceof RoutingContext) { + val encapsulated = !method.returnType.equals(InstanceIdentifier.asCtClass); + return new RpcMetadata(null,rpcMethod,(annotation as RoutingContext).value, method, encapsulated,inputClass); + } + } + } + } + for (iface : dataClass.interfaces) { + val ret = rpcMethodMetadata(iface,inputClass,rpcMethod); + if(ret != null) return ret; + } + return null; + } + + private def getJavaClass(CtClass cls) { + Thread.currentThread.contextClassLoader.loadClass(cls.name) + } + + override getInvokerFactory() { + return this; + } + + override invokerFor(NotificationListener instance) { + val cls = instance.class + val prototype = resolveInvokerClass(cls); + + return new RuntimeGeneratedInvoker(instance, prototype) } protected def generateListenerInvoker(Class iface) { @@ -119,58 +194,34 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co val supportedNotification = callbacks.map[parameterTypes.get(0) as Class].toSet; - val targetCls = createClass(iface.invokerName,BROKER_NOTIFICATION_LISTENER ) [ + val targetCls = createClass(iface.invokerName, BROKER_NOTIFICATION_LISTENER) [ field(DELEGATE_FIELD, iface) implementMethodsFrom(BROKER_NOTIFICATION_LISTENER) [ body = ''' { «FOR callback : callbacks SEPARATOR " else "» - «val cls = callback.parameterTypes.get(0).name» - if($1 instanceof «cls») { - «DELEGATE_FIELD».«callback.name»((«cls») $1); - return null; - } + «val cls = callback.parameterTypes.get(0).name» + if($1 instanceof «cls») { + «DELEGATE_FIELD».«callback.name»((«cls») $1); + return null; + } «ENDFOR» return null; } ''' ] ] - val finalClass = targetCls.toClass(iface.classLoader,iface.protectionDomain) + val finalClass = targetCls.toClass(iface.classLoader, iface.protectionDomain) return new RuntimeGeneratedInvokerPrototype(supportedNotification, finalClass as Class); } - def void method(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { + private def void method(CtClass it, Class returnType, String name, Class parameter, MethodGenerator function1) { val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it); function1.process(method); it.addMethod(method); } - private def routingContextInput(CtMethod method) { - val inputClass = method.parameterTypes.get(0); - return inputClass.contextInstance; - } - - private def RoutingPair getContextInstance(CtClass dataClass) { - for (method : dataClass.methods) { - if (method.name.startsWith("get") && method.parameterTypes.size === 0) { - for (annotation : method.availableAnnotations) { - if (annotation instanceof RoutingContext) { - val encapsulated = !method.returnType.equals(InstanceIdentifier.asCtClass); - - return new RoutingPair((annotation as RoutingContext).value, method, encapsulated); - } - } - } - } - for (iface : dataClass.interfaces) { - val ret = getContextInstance(iface); - if(ret != null) return ret; - } - return null; - } - private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) { for (method : source.methods) { if (method.declaringClass == source) { @@ -225,18 +276,7 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } } - override getInvokerFactory() { - return this; - } - - override invokerFor(NotificationListener instance) { - val cls = instance.class - val prototype = resolveInvokerClass(cls); - - return new RuntimeGeneratedInvoker(instance,prototype) - } - - def resolveInvokerClass(Class class1) { + protected def resolveInvokerClass(Class class1) { val invoker = invokerClasses.get(class1); if (invoker !== null) { return invoker; @@ -248,19 +288,18 @@ class RuntimeCodeGenerator implements org.opendaylight.controller.sal.binding.co } @Data -class RuntimeGeneratedInvoker implements NotificationInvoker { - +package class RuntimeGeneratedInvoker implements NotificationInvoker { + @Property val NotificationListener delegate; - @Property var org.opendaylight.controller.sal.binding.api.NotificationListener invocationProxy; @Property var RuntimeGeneratedInvokerPrototype prototype; - new(NotificationListener delegate,RuntimeGeneratedInvokerPrototype prototype) { + new(NotificationListener delegate, RuntimeGeneratedInvokerPrototype prototype) { _delegate = delegate; _prototype = prototype; _invocationProxy = prototype.protoClass.newInstance; @@ -272,12 +311,11 @@ class RuntimeGeneratedInvoker implements NotificationInvoker { } override close() { - } } @Data -class RuntimeGeneratedInvokerPrototype { +package class RuntimeGeneratedInvokerPrototype { @Property val Set> supportedNotifications; @@ -285,3 +323,40 @@ class RuntimeGeneratedInvokerPrototype { @Property val Class protoClass; } + +package class RpcServiceMetadata { + + @Property + val contexts = new HashSet>(); + + @Property + val rpcMethods = new HashMap(); + + @Property + val rpcInputs = new HashMap, RpcMetadata>(); + + + @Property + val supportedInputs = new HashSet>(); +} + +@Data +package class RpcMetadata { + + @Property + val QName qname; + + @Property + val String methodName; + + @Property + val Class context; + @Property + val CtMethod inputRouteGetter; + + @Property + val boolean routeEncapsulated; + + @Property + val CtClass inputType; +} 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 bd7f25c02f..1dc2a88bde 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 @@ -48,6 +48,7 @@ class BindingAwareBrokerImpl implements BindingAwareBroker { private val clsPool = ClassPool.getDefault() private var RuntimeCodeGenerator generator; + /** * Map of all Managed Direct Proxies @@ -63,8 +64,12 @@ class BindingAwareBrokerImpl implements BindingAwareBroker { */ private val Map, RpcRouter> rpcRouters = new ConcurrentHashMap(); + @Property private var NotificationBrokerImpl notifyBroker + + @Property private var DataBrokerImpl dataBroker + private var ServiceRegistration notifyBrokerRegistration @Property @@ -78,12 +83,15 @@ class BindingAwareBrokerImpl implements BindingAwareBroker { notifyBroker = new NotificationBrokerImpl(executor); notifyBroker.invokerFactory = generator.invokerFactory; dataBroker = new DataBrokerImpl(); + dataBroker.executor = executor; val brokerProperties = newProperties(); notifyBrokerRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker, brokerProperties) brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties) brokerBundleContext.registerService(DataProviderService, dataBroker, brokerProperties) brokerBundleContext.registerService(DataBrokerService, dataBroker, brokerProperties) + + } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java index 9a5cbfffcd..fd6e0f0421 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/BrokerActivator.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.sal.binding.impl; import java.util.Hashtable; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; @@ -21,13 +22,17 @@ public class BrokerActivator implements BundleActivator { private static final Logger log = LoggerFactory.getLogger(BrokerActivator.class); private BindingAwareBrokerImpl baSal; private ServiceRegistration baSalRegistration; - + private HashMapDataStore store = new HashMapDataStore(); + private InstanceIdentifier root = InstanceIdentifier.builder().toInstance(); + @Override public void start(BundleContext context) throws Exception { log.info("Binding Aware Broker initialized"); baSal = new BindingAwareBrokerImpl(); baSal.setBrokerBundleContext(context); baSal.start(); + baSal.getDataBroker().registerDataReader(root, store); + baSal.getDataBroker().registerCommitHandler(root, store); BindingAwareBroker baSalService = baSal; Hashtable properties = new Hashtable<>(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend index 99afbab0b5..9356ecda88 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataBrokerImpl.xtend @@ -3,65 +3,242 @@ package org.opendaylight.controller.sal.binding.impl import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler import org.opendaylight.controller.sal.binding.api.data.DataChangeListener import org.opendaylight.controller.sal.binding.api.data.DataProviderService -import org.opendaylight.controller.sal.common.DataStoreIdentifier import org.opendaylight.yangtools.yang.binding.DataObject -import org.opendaylight.yangtools.yang.binding.DataRoot import org.opendaylight.yangtools.yang.binding.InstanceIdentifier - -class DataBrokerImpl implements DataProviderService { +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction.DataTransactionListener +import org.opendaylight.controller.md.sal.common.api.TransactionStatus +import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification +import org.opendaylight.controller.md.sal.common.api.data.DataReader +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration +import org.opendaylight.yangtools.concepts.ListenerRegistration +import static extension org.opendaylight.controller.sal.binding.impl.util.MapUtils.*; +import java.util.Collection +import java.util.Map.Entry +import java.util.HashSet +import java.util.Set +import com.google.common.collect.Multimap +import static com.google.common.base.Preconditions.*; +import java.util.List +import java.util.LinkedList +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider +import com.google.common.collect.HashMultimap +import java.util.concurrent.ExecutorService +import java.util.concurrent.Callable +import org.opendaylight.yangtools.yang.common.RpcResult +import org.opendaylight.controller.sal.common.util.Rpcs +import java.util.Collections +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction +import java.util.ArrayList +import org.opendaylight.controller.sal.common.util.RpcErrors + +class DataBrokerImpl extends DeprecatedDataAPISupport implements DataProviderService { + + @Property + var ExecutorService executor; + + Multimap configReaders = HashMultimap.create(); + Multimap operationalReaders = HashMultimap.create(); + Multimap listeners = HashMultimap.create(); + Multimap commitHandlers = HashMultimap.create(); override beginTransaction() { + return new DataTransactionImpl(this); } - override commit(DataStoreIdentifier store) { - throw new UnsupportedOperationException("Deprecated") + override readConfigurationData(InstanceIdentifier path) { + val readers = configReaders.getAllChildren(path); + return readers.readConfiguration(path); } - override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) { - throw new UnsupportedOperationException("Deprecated") + override readOperationalData(InstanceIdentifier path) { + val readers = operationalReaders.getAllChildren(path); + return readers.readOperational(path); } - override getCandidateData(DataStoreIdentifier store, Class rootType) { - throw new UnsupportedOperationException("Deprecated") + override registerCommitHandler(InstanceIdentifier path, + DataCommitHandler, DataObject> commitHandler) { + val registration = new DataCommitHandlerRegistration(path,commitHandler,this); + commitHandlers.put(path,registration) + return registration; } - override T getCandidateData(DataStoreIdentifier store, T filter) { - throw new UnsupportedOperationException("Deprecated") + override registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { + val reg = new DataChangeListenerRegistration(path, listener, this); + listeners.put(path, reg); + return reg; } - override getConfigurationData(InstanceIdentifier data) { - throw new UnsupportedOperationException("Deprecated") + override registerDataReader(InstanceIdentifier path, + DataReader, DataObject> provider) { + val ret = new DataReaderRegistration(provider, this); + ret.paths.add(path); + configReaders.put(path, ret); + operationalReaders.put(path, ret); + return ret; } - override getData(DataStoreIdentifier store, Class rootType) { - throw new UnsupportedOperationException("Deprecated") + protected def removeReader(DataReaderRegistration reader) { + for (path : reader.paths) { + operationalReaders.remove(path, reader); + configReaders.remove(path, reader); + } } - override T getData(DataStoreIdentifier store, T filter) { - throw new UnsupportedOperationException("Deprecated") + protected def removeListener(DataChangeListenerRegistration registration) { + listeners.remove(registration.path, registration); } - override getData(InstanceIdentifier path) { - return readOperationalData(path); + protected def removeCommitHandler(DataCommitHandlerRegistration registration) { + commitHandlers.remove(registration.path, registration); } - override readConfigurationData(InstanceIdentifier path) { + protected def DataObject readConfiguration( + Collection> entries, + InstanceIdentifier path) { + + val List partialResults = new LinkedList(); + for (entry : entries) { + partialResults.add(entry.value.instance.readConfigurationData(path)) + } + return merge(path, partialResults); } - override readOperationalData(InstanceIdentifier path) { + protected def DataObject readOperational( + Collection> entries, + InstanceIdentifier path) { + + val List partialResults = new LinkedList(); + for (entry : entries) { + partialResults.add(entry.value.instance.readOperationalData(path)) + } + return merge(path, partialResults); } - override registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + protected def DataObject merge(InstanceIdentifier identifier, List objects) { + + // FIXME: implement real merge + if (objects.size > 0) { + return objects.get(0); + } + } + + protected def getActiveCommitHandlers() { + + return commitHandlers.entries.map[ value.instance].toSet } - override registerCommitHandler(InstanceIdentifier path, - DataCommitHandler, DataObject> commitHandler) { + protected def commit(DataTransactionImpl transaction) { + checkNotNull(transaction); + transaction.changeStatus(TransactionStatus.SUBMITED); + val task = new TwoPhaseCommit(transaction, this); + return executor.submit(task); } - override registerDataChangeListener(InstanceIdentifier path, DataChangeListener listener) { +} + +package class DataReaderRegistration extends // +AbstractObjectRegistration, DataObject>> { + + DataBrokerImpl dataBroker; + + @Property + val Set> paths; + + new(DataReader, DataObject> instance, DataBrokerImpl broker) { + super(instance) + dataBroker = broker; + _paths = new HashSet(); } - override unregisterChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + override protected removeRegistration() { + dataBroker.removeReader(this); } } + +package class DataChangeListenerRegistration extends AbstractObjectRegistration implements ListenerRegistration { + + DataBrokerImpl dataBroker; + + @Property + val InstanceIdentifier path; + + new(InstanceIdentifier path, DataChangeListener instance, DataBrokerImpl broker) { + super(instance) + dataBroker = broker; + _path = path; + } + + override protected removeRegistration() { + dataBroker.removeListener(this); + dataBroker = null; + } + +} + +package class DataCommitHandlerRegistration // +extends AbstractObjectRegistration, DataObject>> { + + DataBrokerImpl dataBroker; + + @Property + val InstanceIdentifier path; + + new(InstanceIdentifier path, DataCommitHandler, DataObject> instance, + DataBrokerImpl broker) { + super(instance) + dataBroker = broker; + _path = path; + } + + override protected removeRegistration() { + dataBroker.removeCommitHandler(this); + dataBroker = null; + } + +} + +package class TwoPhaseCommit implements Callable> { + + val DataTransactionImpl transaction; + val DataBrokerImpl dataBroker; + + new(DataTransactionImpl transaction, DataBrokerImpl broker) { + this.transaction = transaction; + this.dataBroker = broker; + } + + override call() throws Exception { + + val Iterable, DataObject>> commitHandlers = dataBroker.activeCommitHandlers; + + // requesting commits + val List, DataObject>> handlerTransactions = new ArrayList(); + try { + for (handler : commitHandlers) { + handlerTransactions.add(handler.requestCommit(transaction)); + } + } catch (Exception e) { + return rollback(handlerTransactions,e); + } + val List> results = new ArrayList(); + try { + for (subtransaction : handlerTransactions) { + results.add(subtransaction.finish()); + } + } catch (Exception e) { + return rollback(handlerTransactions,e); + } + + return Rpcs.getRpcResult(true, TransactionStatus.COMMITED, Collections.emptySet()); + } + + def rollback(List, DataObject>> transactions,Exception e) { + for (transaction : transactions) { + transaction.rollback() + } + // FIXME return encoutered error. + return Rpcs.getRpcResult(false, TransactionStatus.FAILED, Collections.emptySet()); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java new file mode 100644 index 0000000000..9cb9caf7c1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DataTransactionImpl.java @@ -0,0 +1,100 @@ +package org.opendaylight.controller.sal.binding.impl; + +import java.util.concurrent.Future; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification; +import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class DataTransactionImpl extends AbstractDataModification, DataObject> + implements DataModificationTransaction { + + private final Object identifier; + + private TransactionStatus status; + private ListenerRegistry listeners; + + final DataBrokerImpl broker; + + public DataTransactionImpl(DataBrokerImpl dataBroker) { + identifier = new Object(); + broker = dataBroker; + status = TransactionStatus.NEW; + listeners = new ListenerRegistry<>(); + } + + @Override + public Future> commit() { + return broker.commit(this); + } + + @Override + public DataObject readConfigurationData( + org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { + return broker.readConfigurationData(path); + } + + @Override + public DataObject readOperationalData(InstanceIdentifier path) { + return broker.readOperationalData(path); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((broker == null) ? 0 : broker.hashCode()); + result = prime * result + ((identifier == null) ? 0 : identifier.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; + DataTransactionImpl other = (DataTransactionImpl) obj; + if (broker == null) { + if (other.broker != null) + return false; + } else if (!broker.equals(other.broker)) + return false; + if (identifier == null) { + if (other.identifier != null) + return false; + } else if (!identifier.equals(other.identifier)) + return false; + return true; + } + + @Override + public TransactionStatus getStatus() { + return status; + } + + @Override + public Object getIdentifier() { + return identifier; + } + + @Override + public ListenerRegistration registerListener(DataTransactionListener listener) { + return listeners.register(listener); + } + + public void changeStatus(TransactionStatus status) { + this.status = status; + Iterable> listenersToNotify = listeners.getListeners(); + for (ListenerRegistration listenerRegistration : listenersToNotify) { + listenerRegistration.getInstance().onStatusUpdated(this, status); + } + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend new file mode 100644 index 0000000000..8568dd56ec --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/DeprecatedDataAPISupport.xtend @@ -0,0 +1,59 @@ +package org.opendaylight.controller.sal.binding.impl + +import org.opendaylight.controller.sal.binding.api.data.DataProviderService +import org.opendaylight.controller.sal.common.DataStoreIdentifier +import org.opendaylight.yangtools.yang.binding.DataRoot +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.controller.sal.binding.api.data.DataChangeListener + +abstract class DeprecatedDataAPISupport implements DataProviderService { + + @Deprecated + override commit(DataStoreIdentifier store) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override getCandidateData(DataStoreIdentifier store, Class rootType) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override T getCandidateData(DataStoreIdentifier store, T filter) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override getConfigurationData(InstanceIdentifier data) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override getData(DataStoreIdentifier store, Class rootType) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override T getData(DataStoreIdentifier store, T filter) { + throw new UnsupportedOperationException("Deprecated") + } + + @Deprecated + override getData(InstanceIdentifier path) { + return readOperationalData(path); + } + + override registerChangeListener(InstanceIdentifier path, DataChangeListener changeListener) { + } + + override unregisterChangeListener(InstanceIdentifier path, + DataChangeListener changeListener) { + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/HashMapDataStore.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/HashMapDataStore.xtend new file mode 100644 index 0000000000..2356468f5b --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/HashMapDataStore.xtend @@ -0,0 +1,85 @@ +package org.opendaylight.controller.sal.binding.impl + +import org.opendaylight.controller.md.sal.common.api.data.DataReader +import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.controller.md.sal.common.api.data.DataModification +import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction +import org.opendaylight.yangtools.yang.common.RpcResult +import java.util.Map +import java.util.concurrent.ConcurrentHashMap +import org.opendaylight.controller.sal.common.util.Rpcs +import java.util.Collections + +class HashMapDataStore // +implements // +RuntimeDataProvider, DataCommitHandler, DataObject> { + + val Map,DataObject> configuration = new ConcurrentHashMap(); + val Map,DataObject> operational = new ConcurrentHashMap(); + + + override readConfigurationData(InstanceIdentifier path) { + configuration.get(path); + } + + override readOperationalData(InstanceIdentifier path) { + operational.get(path); + } + + override requestCommit(DataModification, DataObject> modification) { + return new HashMapDataStoreTransaction(modification,this); + } + + def RpcResult rollback(HashMapDataStoreTransaction transaction) { + return Rpcs.getRpcResult(true,null,Collections.emptySet); + } + + def RpcResult finish(HashMapDataStoreTransaction transaction) { + val modification = transaction.modification; + configuration.putAll(modification.updatedConfigurationData); + operational.putAll(modification.updatedOperationalData); + + for(removal : modification.removedConfigurationData) { + configuration.remove(removal); + } + for(removal : modification.removedOperationalData) { + operational.remove(removal); + } + return Rpcs.getRpcResult(true,null,Collections.emptySet); + } + +} + +class HashMapDataStoreTransaction implements // +DataCommitTransaction, DataObject> { + @Property + val DataModification, DataObject> modification + + @Property + val HashMapDataStore datastore; + + + new( + DataModification, DataObject> modify, + HashMapDataStore store + ) { + _modification = modify; + _datastore = store; + } + + override finish() throws IllegalStateException { + datastore.finish(this); + + } + + override getModification() { + this._modification; + } + + override rollback() throws IllegalStateException { + datastore.rollback(this); + } +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend index 1be19c0213..7fd3fd24d8 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/OsgiProviderContext.xtend @@ -44,20 +44,6 @@ class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext return salReg; } - override addMountRpcImplementation(Class type, InstanceIdentifier mount, T implementation) throws IllegalStateException { - checkNotNull(type, "Service type should not be null") - checkNotNull(mount,"Path to the mount should not be null") - checkNotNull(implementation, "Service instance should not be null") - - val properties = new Hashtable(); - properties.salServiceType = SAL_SERVICE_TYPE_PROVIDER - - // Fill requirements - val salReg = broker.registerMountedRpcImplementation(type, implementation, mount, this) - registeredServices.put(type, salReg) - return salReg; - } - override addRoutedRpcImplementation(Class type, T implementation) throws IllegalStateException { checkNotNull(type, "Service type should not be null") checkNotNull(implementation, "Service type should not be null") diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/MapUtils.xtend b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/MapUtils.xtend new file mode 100644 index 0000000000..4ebfd9a002 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/util/MapUtils.xtend @@ -0,0 +1,31 @@ +package org.opendaylight.controller.sal.binding.impl.util + +import java.util.Map.Entry +import org.opendaylight.yangtools.concepts.Path +import java.util.Map +import java.util.Set +import java.util.Collection +import java.util.HashSet +import com.google.common.collect.Multimap + +class MapUtils { + + public static def

, V> Collection> getAllChildren( + Multimap map, P path) { + val ret = new HashSet(); + val entries = map.entries; + + for (entry : entries) { + val currentPath = entry.key; + // If the registered reader processes nested elements + if (path.contains(currentPath)) { + ret.add(entry); + } else if(currentPath.contains(path)) { + // If the registered reader is parent of entry + ret.add(entry); + } + } + + return ret; + } +} 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 38e309f46d..7db90b62fd 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 @@ -11,6 +11,7 @@ import java.util.Set; import org.opendaylight.yangtools.yang.binding.BaseIdentity; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.binding.RpcImplementation; import org.opendaylight.yangtools.yang.binding.RpcService; /** @@ -25,14 +26,14 @@ import org.opendaylight.yangtools.yang.binding.RpcService; * Type of RpcService for which router provides routing information * and route selection. */ -public interface RpcRouter { +public interface RpcRouter extends RpcImplementation{ /** * Returns a type of RpcService which is served by this instance of router. * * @return type of RpcService which is served by this instance of router. */ - Class getRpcServiceType(); + Class getServiceType(); /** @@ -42,7 +43,6 @@ public interface RpcRouter { * @return type of RpcService which is served by this instance of router. */ T getInvocationProxy(); - /** * Returns a routing table for particular route context diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java new file mode 100644 index 0000000000..cda20e5613 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RemoteRpcRouter.java @@ -0,0 +1,17 @@ +package org.opendaylight.controller.sal.binding.spi.remote; + +import org.opendaylight.yangtools.concepts.ListenerRegistration; + +public interface RemoteRpcRouter { + + + + + + + ListenerRegistration registerRouteChangeListener(RouteChangeListener listener); + + + + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RouteChangeListener.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RouteChangeListener.java new file mode 100644 index 0000000000..56cdee9b86 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/spi/remote/RouteChangeListener.java @@ -0,0 +1,13 @@ +package org.opendaylight.controller.sal.binding.spi.remote; + +import java.util.EventListener; + +import org.opendaylight.controller.md.sal.common.api.routing.RouteChange; +import org.opendaylight.yangtools.yang.binding.BaseIdentity; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface RouteChangeListener extends EventListener { + + void onRouteChange(RouteChange, InstanceIdentifier> change); + +} 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 65bc58314f..1a97bd693a 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 @@ -28,6 +28,7 @@ import org.opendaylight.controller.sal.binding.test.mock.FlowDelete; import org.opendaylight.controller.sal.binding.test.mock.FooListener; import org.opendaylight.controller.sal.binding.test.mock.FooService; import org.opendaylight.controller.sal.binding.test.mock.FooUpdate; +import org.opendaylight.controller.sal.binding.test.mock.InheritedContextInput; import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject; import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey; import org.opendaylight.controller.sal.binding.test.mock.SimpleInput; @@ -64,6 +65,9 @@ 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/mock/FooService.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java index 3161e936dc..9de0bb7edc 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/mock/FooService.java @@ -11,6 +11,6 @@ public interface FooService extends RpcService { Future> simple(SimpleInput obj); - Future> inheritedContextInput(InheritedContextInput obj); + Future> inheritedContext(InheritedContextInput obj); } diff --git a/opendaylight/md-sal/sal-binding-it/pom.xml b/opendaylight/md-sal/sal-binding-it/pom.xml index e4afc815bb..20518bdff7 100644 --- a/opendaylight/md-sal/sal-binding-it/pom.xml +++ b/opendaylight/md-sal/sal-binding-it/pom.xml @@ -172,6 +172,12 @@ model-flow-service 1.0-SNAPSHOT provided + + + org.opendaylight.controller.model + model-flow-management + 1.0-SNAPSHOT + provided diff --git a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java index 842b80e98e..a644619aa5 100644 --- a/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java +++ b/opendaylight/md-sal/sal-binding-it/src/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java @@ -23,6 +23,7 @@ public class TestHelper { mavenBundle(YANGTOOLS, "yang-common").versionAsInProject(), // mavenBundle(CONTROLLER, "sal-common").versionAsInProject(), // mavenBundle(CONTROLLER, "sal-common-api").versionAsInProject(), // + mavenBundle(CONTROLLER, "sal-common-impl").versionAsInProject(), // mavenBundle("com.google.guava", "guava").versionAsInProject(), // mavenBundle(YANGTOOLS + ".thirdparty", "xtend-lib-osgi").versionAsInProject() // ); @@ -65,7 +66,7 @@ public class TestHelper { public static Option junitAndMockitoBundles() { return new DefaultCompositeOption( - // Repository required to load harmcrest (OSGi-fied version). + // Repository required to load harmcrest (OSGi-fied version). repository("http://repository.springsource.com/maven/bundles/external").id( "com.springsource.repository.bundles.external"), diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java index 6e772b5a36..083741e0ec 100644 --- a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/AbstractTest.java @@ -59,4 +59,5 @@ public abstract class AbstractTest { // BASE Models baseModelBundles(), flowCapableModelBundles(), junitAndMockitoBundles()); } + } diff --git a/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java new file mode 100644 index 0000000000..d26f2e7aa1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java @@ -0,0 +1,103 @@ +package org.opendaylight.controller.test.sal.binding.it; + +import static org.junit.Assert.*; + +import java.util.concurrent.Future; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer; +import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext; +import org.opendaylight.controller.sal.binding.api.data.DataBrokerService; +import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction; +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.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +public class DataServiceTest extends AbstractTest { + + protected DataBrokerService consumerDataService; + + @Before + public void setUp() throws Exception { + } + + @Test + public void test() throws Exception { + BindingAwareConsumer consumer1 = new BindingAwareConsumer() { + + @Override + public void onSessionInitialized(ConsumerContext session) { + consumerDataService = session.getSALService(DataBrokerService.class); + } + }; + broker.registerConsumer(consumer1, getBundleContext()); + + assertNotNull(consumerDataService); + + + DataModificationTransaction transaction = consumerDataService.beginTransaction(); + assertNotNull(transaction); + + NodeRef node1 = createNodeRef("0"); + DataObject node = consumerDataService.readConfigurationData(node1.getValue()); + assertNull(node); + Node nodeData1 = createNode("0"); + + transaction.putConfigurationData(node1.getValue(), nodeData1); + Future> commitResult = transaction.commit(); + assertNotNull(commitResult); + + RpcResult result = commitResult.get(); + + assertNotNull(result); + assertNotNull(result.getResult()); + assertEquals(TransactionStatus.COMMITED, result.getResult()); + + DataObject readedData = consumerDataService.readConfigurationData(node1.getValue()); + assertNotNull(readedData); + assertEquals(nodeData1, readedData); + + + DataModificationTransaction transaction2 = consumerDataService.beginTransaction(); + assertNotNull(transaction); + + transaction2.removeConfigurationData(node1.getValue()); + + Future> commitResult2 = transaction2.commit(); + assertNotNull(commitResult2); + + RpcResult result2 = commitResult2.get(); + + assertNotNull(result2); + assertNotNull(result2.getResult()); + assertEquals(TransactionStatus.COMMITED, result2.getResult()); + + DataObject readedData2 = consumerDataService.readConfigurationData(node1.getValue()); + assertNull(readedData2); + + + } + + + private static NodeRef createNodeRef(String string) { + NodeKey key = new NodeKey(new NodeId(string)); + InstanceIdentifier path = InstanceIdentifier.builder().node(Nodes.class).node(Node.class, key) + .toInstance(); + + return new NodeRef(path); + } + + private static Node createNode(String string) { + NodeBuilder ret = new NodeBuilder(); + ret.setId(new NodeId(string)); + return ret.build(); + } +} diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataReader.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataReader.java index ff1703f181..7240a506be 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataReader.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataReader.java @@ -10,6 +10,15 @@ package org.opendaylight.controller.md.sal.common.api.data; // FIXME: After 0.6 Release of YANGTools refactor to use Path marker interface for arguments. // import org.opendaylight.yangtools.concepts.Path; +/** + * Reader for reading YANG subtrees based on their path. + * + * Reader is requested to return object at specified path and all it's subnodes + * known to the reader or null if node is not found in this reader. + * + * @param

Path Type + * @param Data Type + */ public interface DataReader

*/,D> { /** diff --git a/opendaylight/md-sal/sal-common-impl/pom.xml b/opendaylight/md-sal/sal-common-impl/pom.xml index 8da8f24655..0c2344a23e 100644 --- a/opendaylight/md-sal/sal-common-impl/pom.xml +++ b/opendaylight/md-sal/sal-common-impl/pom.xml @@ -1,28 +1,47 @@ - 4.0.0 - - org.opendaylight.controller - sal-parent - 1.0-SNAPSHOT - - sal-common-impl - - scm:git:ssh://git.opendaylight.org:29418/controller.git - scm:git:ssh://git.opendaylight.org:29418/controller.git - https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.opendaylight.controller + sal-parent + 1.0-SNAPSHOT + + sal-common-impl + bundle + + scm:git:ssh://git.opendaylight.org:29418/controller.git + scm:git:ssh://git.opendaylight.org:29418/controller.git + https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL + + + + + org.opendaylight.controller + sal-common-api + 1.0-SNAPSHOT + + + com.google.guava + guava + + + org.eclipse.xtend + org.eclipse.xtend.lib + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.md.sal.common.impl + + + + + - - - org.opendaylight.controller - sal-common-api - 1.0-SNAPSHOT - - - com.google.guava - guava - - - bundle diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java index e786b7443b..5d76717ab6 100644 --- a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/AbstractDataModification.java @@ -11,36 +11,34 @@ import org.opendaylight.yangtools.concepts.Path; import static org.opendaylight.controller.md.sal.common.api.TransactionStatus.NEW; -public abstract class AbstractDataModification

, D> implements DataModification { +public abstract class AbstractDataModification

*/, D> implements DataModification { - private final Map configurationUpdate; - private final Map operationalUpdate; + private final Map configurationUpdate; + private final Map operationalUpdate; private final Set

configurationRemove; private final Set

operationalRemove; - + private final Map unmodifiable_configurationUpdate; private final Map unmodifiable_operationalUpdate; private final Set

unmodifiable_configurationRemove; private final Set

unmodifiable_OperationalRemove; - - public AbstractDataModification(Map configurationUpdate, Map operationalUpdate, Set

configurationRemove, Set

operationalRemove) { this.configurationUpdate = configurationUpdate; this.operationalUpdate = operationalUpdate; this.configurationRemove = configurationRemove; this.operationalRemove = operationalRemove; - + unmodifiable_configurationUpdate = Collections.unmodifiableMap(configurationUpdate); unmodifiable_operationalUpdate = Collections.unmodifiableMap(operationalUpdate); unmodifiable_configurationRemove = Collections.unmodifiableSet(configurationRemove); unmodifiable_OperationalRemove = Collections.unmodifiableSet(operationalRemove); } - + public AbstractDataModification() { - this(new HashMap(), new HashMap(), new HashSet

(), new HashSet

()); + this(new HashMap(), new HashMap(), new HashSet

(), new HashSet

()); } @Override @@ -49,21 +47,21 @@ public abstract class AbstractDataModification

, D> implements configurationUpdate.put(path, data); configurationRemove.remove(path); } - + @Override public final void putRuntimeData(P path, D data) { checkMutable(); operationalUpdate.put(path, data); operationalRemove.remove(path); } - + @Override public final void removeRuntimeData(P path) { checkMutable(); operationalUpdate.remove(path); operationalRemove.add(path); } - + @Override public final void removeConfigurationData(P path) { checkMutable(); @@ -72,12 +70,13 @@ public abstract class AbstractDataModification

, D> implements } private final void checkMutable() { - if(!NEW.equals(this.getStatus())) throw new IllegalStateException("Transaction was already submitted"); + if (!NEW.equals(this.getStatus())) + throw new IllegalStateException("Transaction was already submitted"); } @Override public Map getUpdatedConfigurationData() { - + return unmodifiable_configurationUpdate; } @@ -90,7 +89,7 @@ public abstract class AbstractDataModification

, D> implements public Set

getRemovedConfigurationData() { return unmodifiable_configurationRemove; } - + @Override public Set

getRemovedOperationalData() { return unmodifiable_OperationalRemove; diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java new file mode 100644 index 0000000000..d884dc81e0 --- /dev/null +++ b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/ListenerRegistry.java @@ -0,0 +1,55 @@ +package org.opendaylight.controller.md.sal.common.impl; + +import java.util.Collections; +import java.util.EventListener; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import static com.google.common.base.Preconditions.*; + +import org.opendaylight.yangtools.concepts.AbstractObjectRegistration; +import org.opendaylight.yangtools.concepts.ListenerRegistration; + +public class ListenerRegistry { + + final Set> listeners; + final Set> unmodifiableView; + + public ListenerRegistry() { + listeners = new HashSet<>(); + unmodifiableView = Collections.unmodifiableSet(listeners); + } + + public Iterable> getListeners() { + return unmodifiableView; + } + + + public ListenerRegistration register(T listener) { + checkNotNull(listener, "Listener should not be null."); + ListenerRegistrationImpl ret = new ListenerRegistrationImpl(listener); + listeners.add(ret); + return ret; + } + + + @SuppressWarnings("rawtypes") + private void remove(ListenerRegistrationImpl registration) { + listeners.remove(registration); + } + + private class ListenerRegistrationImpl

// + extends AbstractObjectRegistration

// + implements ListenerRegistration

{ + + public ListenerRegistrationImpl(P instance) { + super(instance); + } + + @Override + protected void removeRegistration() { + ListenerRegistry.this.remove(this); + } + } +} diff --git a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java index 6b1b68362a..91146f3c2e 100644 --- a/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java +++ b/opendaylight/md-sal/samples/toaster-consumer/src/main/java/org/opendaylight/controller/sample/toaster/provider/impl/ToastConsumerImpl.java @@ -72,8 +72,6 @@ public class ToastConsumerImpl extends AbstractBindingAwareConsumer implements B this.session = session; NotificationService notificationService = session.getSALService(NotificationService.class); notificationService.addNotificationListener(ToastDone.class, this); - - } @Override diff --git a/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java b/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java index d8031e52f2..0bf589b781 100644 --- a/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java +++ b/opendaylight/md-sal/samples/toaster-it/src/test/java/org/opendaylight/controller/sample/toaster/it/ToasterTest.java @@ -62,7 +62,8 @@ public class ToasterTest { mavenBundle(ODL, "sal-binding-api").versionAsInProject(), // mavenBundle(ODL, "sal-binding-broker-impl").versionAsInProject(), // mavenBundle(ODL, "sal-common").versionAsInProject(), // - mavenBundle(ODL, "sal-common-api").versionAsInProject(), + mavenBundle(ODL, "sal-common-api").versionAsInProject(),// + mavenBundle(ODL, "sal-common-impl").versionAsInProject(), // mavenBundle(ODL, "sal-common-util").versionAsInProject(), // mavenBundle(SAMPLE, "sample-toaster").versionAsInProject(), // mavenBundle(SAMPLE, "sample-toaster-consumer").versionAsInProject(), // -- 2.36.6