From: Devin Avery Date: Wed, 2 Jul 2014 11:30:34 +0000 (+0000) Subject: Merge changes I8598d0bd,I560c2072 X-Git-Tag: release/helium~564 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=d04e0863b86415749a8437241c57df0d32a3b133;hp=5c2c22d99e522ccdc164287757fd2defa62a9f9c Merge changes I8598d0bd,I560c2072 * changes: Bug 488: Removed BundleContext usage for registering to DOM Components. Bug 488: Removed BundleContext from InMemoryDataBroker. --- diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java index 6eda364af0..33546b1e2a 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/gofactory/AbsModuleGeneratedObjectFactory.java @@ -286,7 +286,7 @@ public class AbsModuleGeneratedObjectFactory { format("private final %s oldModule;\n", abstractFQN.getTypeName())+ format("private final %s oldInstance;\n", AutoCloseable.class.getCanonicalName())+ format("private %s instance;\n", AutoCloseable.class.getCanonicalName())+ - format("private final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+ + format("protected final %s dependencyResolver;\n", DependencyResolver.class.getCanonicalName())+ format("private final %s identifier;\n", ModuleIdentifier.class.getCanonicalName())+ "@Override\n"+ format("public %s getIdentifier() {\n", ModuleIdentifier.class.getCanonicalName())+ diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingTransactionChain.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingTransactionChain.java new file mode 100644 index 0000000000..eac65ad677 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/BindingTransactionChain.java @@ -0,0 +1,18 @@ +package org.opendaylight.controller.md.sal.binding.api; + +import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +public interface BindingTransactionChain extends TransactionChain, DataObject> { + + @Override + ReadOnlyTransaction newReadOnlyTransaction(); + + @Override + ReadWriteTransaction newReadWriteTransaction(); + + @Override + WriteTransaction newWriteOnlyTransaction(); + +} diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java index 0b3658a6a6..b60d8ff1be 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.md.sal.binding.api; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainFactory; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -19,7 +20,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; *

* For more information on usage, please see the documentation in {@link AsyncDataBroker}. */ -public interface DataBroker extends AsyncDataBroker, DataObject, DataChangeListener>, BindingService { +public interface DataBroker extends AsyncDataBroker, DataObject, DataChangeListener>, BindingService, TransactionChainFactory, DataObject> { @Override ReadOnlyTransaction newReadOnlyTransaction(); 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 453ff44911..a41186dae1 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 @@ -156,11 +156,26 @@ public interface BindingAwareBroker { void unregisterFunctionality(ProviderFunctionality functionality); } + /** + * Represents an RPC implementation registration. Users should call the + * {@link ObjectRegistration#close close} method when the registration is no longer needed. + * + * @param the implemented RPC service interface + */ public interface RpcRegistration extends ObjectRegistration { + /** + * Returns the implemented RPC service interface. + */ Class getServiceType(); } + /** + * Represents a routed RPC implementation registration. Users should call the + * {@link RoutedRegistration#close close} method when the registration is no longer needed. + * + * @param the implemented RPC service interface + */ public interface RoutedRpcRegistration extends RpcRegistration, RoutedRegistration, InstanceIdentifier, T> { 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 index 7da0a48517..615acd3195 100644 --- 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 @@ -10,16 +10,60 @@ 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 + * Provides access to registered Remote Procedure Call (RPC) service implementations. The RPCs are + * defined in YANG models. + *

+ * RPC implementations are registered using the {@link RpcProviderRegistry}. * */ public interface RpcConsumerRegistry extends BindingAwareService { /** - * Returns a session specific instance (implementation) of requested - * YANG module implementation / service provided by consumer. + * Returns an implementation of a requested RPC service. * - * @return Session specific implementation of service + *

+ * The returned instance is not an actual implementation of the RPC service + * interface, but a proxy implementation of the interface that forwards to + * an actual implementation, if any. + *

+ * + * The following describes the behavior of the proxy when invoking RPC methods: + *

+ * + * The returned proxy is automatically updated with the most recent + * registered implementation. + *

+ * The generated RPC method APIs require implementors to return a {@link java.util.concurrent.Future Future} + * instance that wraps the {@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult}. Since + * RPC methods may be implemented asynchronously, callers should avoid blocking on the + * {@link java.util.concurrent.Future Future} result. Instead, it is recommended to use + * {@link com.google.common.util.concurrent.JdkFutureAdapters#listenInPoolThread(java.util.concurrent.Future)} + * or {@link com.google.common.util.concurrent.JdkFutureAdapters#listenInPoolThread(java.util.concurrent.Future, java.util.concurrent.Executor)} + * to listen for Rpc Result. This will asynchronously listen for future result in executor and + * will not block current thread. + * + *

+     *   final Future> future = someRpcService.someRpc( ... );
+     *   Futures.addCallback(JdkFutureAdapters.listenInThreadPool(future), new FutureCallback>() {
+     *
+     *       public void onSuccess(RpcResult result) {
+     *          // process result ...
+     *       }
+     *
+     *       public void onFailure(Throwable t) {
+     *          // RPC failed
+     *       }
+     *   );
+     * 
+ * @param serviceInterface the interface of the RPC Service. Typically this is an interface generated + * from a YANG model. + * @return the proxy for the requested RPC service. This method never returns null. */ - T getRpcService(Class module); + T getRpcService(Class serviceInterface); } 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 index cdf55844b3..22db985ba9 100644 --- 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 @@ -15,39 +15,256 @@ 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. + * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are + * defined in YANG models. + *

+ * There are 2 types of RPCs: + *

    + *
  • Global
  • + *
  • Routed
  • + *
* - * @author ttkacik + *

Global RPC

+ *

+ * An RPC is global if there is intended to be only 1 registered implementation. A global RPC is not + * explicitly declared as such, essentially any RPC that is not defined to be routed is considered global. + *

+ * Global RPCs are registered using the + * {@link #addRpcImplementation(Class, RpcService)} method. * + *

Routed RPC

+ *

+ * MD-SAL supports routing of RPC between multiple implementations where the appropriate + * implementation is selected at run time based on the content of the RPC message as described in + * YANG model. + *

+ * RPC routing is based on: + *

    + *
  • Route identifier - + * An {@link org.opendaylight.yangtools.yang.binding.InstanceIdentifier InstanceIdentifier} value + * which is part of the RPC input. This value is used to select the correct + * implementation at run time.
  • + *
  • Context Type - A YANG-defined construct which constrains the subset of + * valid route identifiers for a particular RPC.
  • + *
+ * + *

Context type

+ *

+ * A context type is modeled in YANG using a combination of a YANG identity + * and Opendaylight specific extensions from yang-ext module. These extensions are: + *

    + *
  • context-instance - This is used in the data tree part of a YANG model to + * define a context type that associates nodes with a specified context identity. + * Instance identifiers that reference these nodes are valid route identifiers for RPCs that + * reference this context type.
  • + *
  • context-reference - This is used in RPC input to mark a leaf of type + * instance-identifier as a reference to the particular context type defined by the + * specified context identity. The value of this + * leaf is used by the RPC broker at run time to route the RPC request to the correct implementation. + * Note that context-reference may only be used on leaf elements of type + * instance-identifier or a type derived from instance-identifier.
  • + *
+ * + * + *

Routed RPC example

+ *

+ *

1. Defining a Context Type
+ *

+ * The following snippet declares a simple YANG identity named example-context: + * + *

+ * module example {
+ *     ...
+ *     identity example-context {
+ *          description "Identity used to define an example-context type";
+ *     }
+ *     ...
+ * }
+ * 
+ *

+ * We then use the declared identity to define a context type by using it in combination + * with the context-instance YANG extension. We'll associate the context type + * with a list element in the data tree. This defines the set of nodes whose instance + * identifiers are valid for the example-context context type. + *

+ * The following YANG snippet imports the yang-ext module and defines the list + * element named item inside a container named foo: + * + *

+ * module foo {
+ *     ...
+ *     import yang-ext {prefix ext;}
+ *     ...
+ *     container foo {
+ *          list item {
+ *              key "id";
+ *              leaf id {type string;}
+ *              ext:context-instance "example-context";
+ *          }
+ *     }
+ *     ...
+ * }
+ * 
+ *

+ * The statement ext:context-instance "example-context"; inside the list element + * declares that any instance identifier referencing item in the data + * tree is valid for example-context. For example, the following instance + * identifier: + *

+ *     InstanceIdentifier.create(Foo.class).child(Item.class,new ItemKey("Foo"))
+ * 
+ * is valid for example-context. However the following: + *
+ *     InstanceIdentifier.create(Example.class)
+ * 
+ * is not valid. + *

+ * So using an identity in combination with context-instance we + * have effectively defined a context type that can be referenced in a YANG RPC input. + * + *

2. Defining an RPC to use the Context Type
+ *

+ * To define an RPC to be routed based on the context type we need to add an input leaf element + * that references the context type which will hold an instance identifier value to be + * used to route the RPC. + *

+ * The following snippet defines an RPC named show-item with 2 leaf elements + * as input: item of type instance-identifier and description: + * + *

+ * module foo {
+ *      ...
+ *      import yang-ext {prefix ext;}
+ *      ...
+ *      rpc show-item {
+ *          input {
+ *              leaf item {
+ *                  type instance-identifier;
+ *                  ext:context-reference example-context;
+ *              }
+ *              leaf description {
+ *                  type "string";
+ *              }
+ *          }
+ *      }
+ * }
+ * 
+ *

+ * We mark the item leaf with a context-reference statement that + * references the example-context context type. RPC calls will then be routed + * based on the instance identifier value contained in item. Only instance + * identifiers that point to a foo/item node are valid as input. + *

+ * The generated RPC Service interface for the module is: + * + *

+ * interface FooService implements RpcService {
+ *      Future<RpcResult<Void>> showItem(ShowItemInput input);
+ * }
+ * 
+ *

+ * For constructing the RPC input, there are generated classes ShowItemInput and ShowItemInputBuilder. + * + *

3. Registering a routed RPC implementation
+ *

+ * To register a routed implementation for the show-item RPC, we must use the + * {@link #addRoutedRpcImplementation(Class, RpcService)} method. This + * will return a {@link RoutedRpcRegistration} instance which can then be used to register / + * unregister routed paths associated with the registered implementation. + *

+ * The following snippet registers myImpl as the RPC implementation for an + * item with key "foo": + *

+ * // Create the instance identifier path for item "foo"
+ * InstanceIdentifier path = InstanceIdentifier.create(Foo.class).child(Item.class, new ItemKey("foo"));
+ *
+ * // Register myImpl as the implementation for the FooService RPC interface
+ * RoutedRpcRegistration reg = rpcRegistry.addRoutedRpcImplementation(FooService.class, myImpl);
+ *
+ * // Now register for the context type and specific path ID. The context type is specified by the
+ * // YANG-generated class for the example-context identity.
+ * reg.registerPath(ExampleContext.class, path);
+ * 
+ *

+ * It is also possible to register the same implementation for multiple paths: + * + *

+ * InstanceIdentifier one = InstanceIdentifier.create(Foo.class).child(Item.class, new ItemKey("One"));
+ * InstanceIdentifier two = InstanceIdentifier.create(Foo.class).child(Item.class, new ItemKey("Two"));
+ *
+ * RoutedRpcRegistration reg = rpcRegistry.addRoutedRpcImplementation(FooService.class, myImpl);
+ * reg.registerPath(ExampleContext.class, one);
+ * reg.registerPath(ExampleContext.class, two);
+ * 
+ * + *

+ * When another client invokes the showItem(ShowItemInput) method on the proxy instance + * retrieved via {@link RpcConsumerRegistry#getRpcService(Class)}, the proxy will inspect the + * arguments in ShowItemInput, extract the InstanceIdentifier value of the item leaf and select + * the implementation whose registered path matches the InstanceIdentifier value of the item leaf. + * + *

Notes for RPC Implementations

+ * + *

RpcResult

+ *

+ * The generated interfaces require implementors to return + * {@link java.util.concurrent.Future Future}<{@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult}<{RpcName}Output>> instances. + * + * Implementations should do processing of RPC calls asynchronously and update the + * returned {@link java.util.concurrent.Future Future} instance when processing is complete. + * However using {@link com.google.common.util.concurrent.Futures#immediateFuture(Object) Futures.immediateFuture} + * is valid only if the result is immediately available and asynchronous processing is unnecessary and + * would only introduce additional complexity. + * + *

+ * The {@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult} is a generic + * wrapper for the RPC output payload, if any, and also allows for attaching error or + * warning information (possibly along with the payload) should the RPC processing partially + * or completely fail. This is intended to provide additional human readable information + * for users of the API and to transfer warning / error information across the system + * so it may be visible via other external APIs such as Restconf. + *

+ * It is recommended to use the {@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult} + * for conveying appropriate error information + * on failure rather than purposely throwing unchecked exceptions if at all possible. + * While unchecked exceptions will fail the returned {@link java.util.concurrent.Future Future}, + * using the intended RpcResult to convey the error information is more user-friendly. */ public interface RpcProviderRegistry extends // RpcConsumerRegistry, // RouteChangePublisher> { /** - * Registers a global RpcService implementation. + * Registers a global implementation of the provided RPC service interface. + * All methods of the interface are required to be implemented. + * + * @param serviceInterface the YANG-generated interface of the RPC Service for which to register. + * @param implementation "the implementation of the RPC service interface. + * @return an RpcRegistration instance that should be used to unregister the RPC implementation + * when no longer needed by calling {@link RpcRegistration#close()}. * - * @param type - * @param implementation - * @return + * @throws IllegalStateException + * if the supplied RPC interface is a routed RPC type. */ - RpcRegistration addRpcImplementation(Class type, T implementation) + RpcRegistration addRpcImplementation(Class serviceInterface, T implementation) throws IllegalStateException; /** + * Registers an implementation of the given routed RPC service interface. + *

+ * See the {@link RpcProviderRegistry class} documentation for information and example on + * how to use routed RPCs. * - * Register a 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 class - * @param implementation - * Implementation of RpcService - * @return Registration object for routed Rpc which could be used to unregister + * @param serviceInterface the YANG-generated interface of the RPC Service for which to register. + * @param implementation the implementation instance to register. + * @return a RoutedRpcRegistration instance which can be used to register paths for the RPC + * implementation via invoking {@link RoutedRpcRegistration#registerPath(....). + * {@link RoutedRpcRegistration#close()} should be called to unregister the implementation + * and all previously registered paths when no longer needed. * * @throws IllegalStateException + * if the supplied RPC interface is not a routed RPC type. */ - RoutedRpcRegistration addRoutedRpcImplementation(Class type, T implementation) + RoutedRpcRegistration addRoutedRpcImplementation(Class serviceInterface, + 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 d0225768b4..d30ca6beaf 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 @@ -21,7 +21,9 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; * * * @see DataProviderService + * @deprecated Replaced by newer better documented version {@link org.opendaylight.controller.md.sal.binding.api.DataBroker} */ +@Deprecated public interface DataBrokerService extends // BindingAwareService, // DataModificationTransactionFactory, DataObject>, // @@ -31,16 +33,26 @@ public interface DataBrokerService extends // * Creates a data modification transaction. * * @return new blank data modification transaction. + * @deprecated Replaced by more specific transaction types. Please use + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadOnlyTransaction(), + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadWriteTransaction() + * or + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newWriteOnlyTransaction(). */ + @Deprecated @Override DataModificationTransaction beginTransaction(); /** * 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)- + * inject state into providers. E.g. Flow configuration) + * + * + * @deprecated Please use {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadOnlyTransaction()} * */ + @Deprecated @Override public DataObject readConfigurationData(InstanceIdentifier path); @@ -49,7 +61,9 @@ public interface DataBrokerService extends // * (Store which is populated by providers, which is usually used to * capture state of providers. E.g. Topology) * + * @deprecated Please use {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadOnlyTransaction()} */ + @Deprecated @Override public DataObject readOperationalData(InstanceIdentifier path); @@ -58,7 +72,10 @@ public interface DataBrokerService extends // * * Callback is invoked each time data in subtree changes. * + * @deprecated Please use {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#registerDataChangeListener(org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType, InstanceIdentifier, org.opendaylight.controller.md.sal.binding.api.DataChangeListener, org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope)} + * which provides more fine-grained registration options. */ + @Deprecated @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/DataChangeListener.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataChangeListener.java index 6373cfbf4a..e26cbcef29 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataChangeListener.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataChangeListener.java @@ -11,6 +11,12 @@ import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +/** + * + * @deprecated Replaced by {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener} + * + */ +@Deprecated public interface DataChangeListener extends org.opendaylight.controller.md.sal.common.api.data.DataChangeListener, DataObject> { 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 5fafabbd1b..0c250fdbee 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 @@ -17,6 +17,18 @@ import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; +/** + * + * + * @deprecated Replaced by more specific transaction types. Please use + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadOnlyTransaction(), + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadWriteTransaction() + * or + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newWriteOnlyTransaction(). + * + * + */ +@Deprecated public interface DataModificationTransaction extends DataModification, DataObject> { /** * Returns an unique identifier for transaction 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 b496d1dfb4..5aa3b99b30 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 @@ -16,7 +16,10 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * DataProviderService is common access point for {@link org.opendaylight.controller.sal.binding.api.BindingAwareProvider} providers * to access data trees described by the YANG model. + * + * @deprecated Replaced by {@link org.opendaylight.controller.md.sal.common.api.data.AsyncConfigurationCommitCoordinator} service. */ +@Deprecated public interface DataProviderService extends DataBrokerService, DataProvisionService, DataObject> { /** * Registers a data reader for particular subtree of overal YANG data tree. @@ -27,6 +30,8 @@ public interface DataProviderService extends DataBrokerService, DataProvisionSer * @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. + * @deprecated Data Reader contract is removed from capabilities of MD-SAL and is replaced by replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore contract. */ + @Deprecated 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/DataRefresher.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java index 3334f2a037..c0c8f4f211 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/DataRefresher.java @@ -13,8 +13,9 @@ import org.opendaylight.controller.sal.binding.api.BindingAwareProvider; * Trigger for refreshing of the data exposed by the {@link Provider} * * - * + * @deprecated Unused, not supported. Replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore. */ +@Deprecated public interface DataRefresher extends BindingAwareProvider.ProviderFunctionality { /** 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 85a2b82ee0..273f20f01d 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 @@ -15,9 +15,11 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; /** * Utility interface which does type capture for BindingAware DataReader. * - * @author + * + * @deprecated Removed, replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore. * */ +@Deprecated 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/data/SynchronizedTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/SynchronizedTransaction.java index da6d46d499..fc0d3964ea 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/SynchronizedTransaction.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/sal/binding/api/data/SynchronizedTransaction.java @@ -25,12 +25,19 @@ import com.google.common.base.Preconditions; * * To get instance of synchronized wrapper use {@link #from(DataModificationTransaction)} * + * @deprecated Replaced by more specific transaction types. Please use + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadOnlyTransaction(), + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newReadWriteTransaction() + * or + * {@link org.opendaylight.controller.md.sal.binding.api.DataBroker#newWriteOnlyTransaction(). + * */ +@Deprecated public final class SynchronizedTransaction implements DataModificationTransaction,Delegator { private final DataModificationTransaction delegate; - private SynchronizedTransaction(DataModificationTransaction delegate) { + private SynchronizedTransaction(final DataModificationTransaction delegate) { this.delegate = delegate; } @@ -40,7 +47,7 @@ public final class SynchronizedTransaction implements DataModificationTransactio * @param transaction Transaction for which synchronized wrapper should be created. * @return Synchronized wrapper over transaction. */ - public static final SynchronizedTransaction from(DataModificationTransaction transaction) { + public static final SynchronizedTransaction from(final DataModificationTransaction transaction) { Preconditions.checkArgument(transaction != null, "Transaction must not be null."); if (transaction instanceof SynchronizedTransaction) { return (SynchronizedTransaction) transaction; @@ -59,7 +66,7 @@ public final class SynchronizedTransaction implements DataModificationTransactio } @Override - public synchronized DataObject readOperationalData(InstanceIdentifier path) { + public synchronized DataObject readOperationalData(final InstanceIdentifier path) { return delegate.readOperationalData(path); } @@ -79,7 +86,7 @@ public final class SynchronizedTransaction implements DataModificationTransactio } @Override - public synchronized DataObject readConfigurationData(InstanceIdentifier path) { + public synchronized DataObject readConfigurationData(final InstanceIdentifier path) { return delegate.readConfigurationData(path); } @@ -89,12 +96,12 @@ public final class SynchronizedTransaction implements DataModificationTransactio } @Override - public synchronized void putOperationalData(InstanceIdentifier path, DataObject data) { + public synchronized void putOperationalData(final InstanceIdentifier path, final DataObject data) { delegate.putOperationalData(path, data); } @Override - public synchronized void putConfigurationData(InstanceIdentifier path, DataObject data) { + public synchronized void putConfigurationData(final InstanceIdentifier path, final DataObject data) { delegate.putConfigurationData(path, data); } @@ -104,12 +111,12 @@ public final class SynchronizedTransaction implements DataModificationTransactio } @Override - public synchronized void removeOperationalData(InstanceIdentifier path) { + public synchronized void removeOperationalData(final InstanceIdentifier path) { delegate.removeOperationalData(path); } @Override - public synchronized void removeConfigurationData(InstanceIdentifier path) { + public synchronized void removeConfigurationData(final InstanceIdentifier path) { delegate.removeConfigurationData(path); } @@ -129,7 +136,7 @@ public final class SynchronizedTransaction implements DataModificationTransactio } @Override - public synchronized ListenerRegistration registerListener(DataTransactionListener listener) { + public synchronized ListenerRegistration registerListener(final DataTransactionListener listener) { return delegate.registerListener(listener); } @@ -152,7 +159,7 @@ public final class SynchronizedTransaction implements DataModificationTransactio } @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj) { return true; } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java index f24809de45..b109f89ff6 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java @@ -7,7 +7,9 @@ */ package org.opendaylight.controller.md.sal.binding.impl; +import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -40,6 +42,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.Objects; import com.google.common.base.Optional; +import com.google.common.collect.Iterables; public abstract class AbstractForwardedDataBroker implements Delegator, DomForwardedBroker, SchemaContextListener, AutoCloseable { @@ -97,8 +100,8 @@ public abstract class AbstractForwardedDataBroker implements Delegator, DataObject> toBinding( final Map> normalized) { Map, DataObject> newMap = new HashMap<>(); - for (Map.Entry> entry : normalized - .entrySet()) { + + for (Map.Entry> entry : sortedEntries(normalized)) { try { Optional, DataObject>> potential = getCodec().toBinding( entry); @@ -113,6 +116,21 @@ public abstract class AbstractForwardedDataBroker implements Delegator Iterable> sortedEntries(final Map map) { + ArrayList> entries = new ArrayList<>(map.entrySet()); + Collections.sort(entries, new Comparator>() { + + @Override + public int compare(final Entry left, + final Entry right) { + int leftSize = Iterables.size(left.getKey().getPathArguments()); + int rightSize = Iterables.size(right.getKey().getPathArguments()); + return Integer.compare(leftSize, rightSize); + } + }); + return entries; + } + protected Set> toBinding( final Set normalized) { Set> hashSet = new HashSet<>(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java index 3fac0dc93a..e5e1e300c1 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedTransaction.java @@ -7,220 +7,55 @@ */ package org.opendaylight.controller.md.sal.binding.impl; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; -import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; -import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.yangtools.concepts.Delegator; +import org.opendaylight.yangtools.concepts.Identifiable; import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; -import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import com.google.common.base.Function; import com.google.common.base.Optional; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.google.common.base.Preconditions; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -public class AbstractForwardedTransaction>> - implements Delegator { - private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedTransaction.class); +abstract class AbstractForwardedTransaction>> + implements Delegator, Identifiable { + private final T delegate; - private final static CacheBuilder CACHE_BUILDER = CacheBuilder.newBuilder() - .expireAfterWrite(10, TimeUnit.MILLISECONDS).maximumSize(100); private final BindingToNormalizedNodeCodec codec; - private final EnumMap, DataObject>> cacheMap; - protected AbstractForwardedTransaction(final T delegate, final BindingToNormalizedNodeCodec codec) { - super(); - this.delegate = delegate; - this.codec = codec; + public AbstractForwardedTransaction(final T delegateTx, final BindingToNormalizedNodeCodec codec) { + this.delegate = Preconditions.checkNotNull(delegateTx, "Delegate must not be null"); + this.codec = Preconditions.checkNotNull(codec, "Codec must not be null"); + } - this.cacheMap = new EnumMap<>(LogicalDatastoreType.class); - cacheMap.put(LogicalDatastoreType.OPERATIONAL, CACHE_BUILDER., DataObject> build()); - cacheMap.put(LogicalDatastoreType.CONFIGURATION, CACHE_BUILDER., DataObject> build()); + @Override + public final Object getIdentifier() { + return delegate.getIdentifier(); } @Override - public T getDelegate() { + public final T getDelegate() { return delegate; } - protected final BindingToNormalizedNodeCodec getCodec() { - return codec; - } - - protected ListenableFuture> transformFuture(final LogicalDatastoreType store, - final InstanceIdentifier path, final ListenableFuture>> future) { - return Futures.transform(future, new Function>, Optional>() { - @Nullable - @Override - public Optional apply(@Nullable final Optional> normalizedNode) { - if (normalizedNode.isPresent()) { - final DataObject dataObject; - try { - dataObject = codec.toBinding(path, normalizedNode.get()); - } catch (DeserializationException e) { - LOG.warn("Failed to create dataobject from node {}", normalizedNode.get(), e); - throw new IllegalStateException("Failed to create dataobject", e); - } - - if (dataObject != null) { - updateCache(store, path, dataObject); - return Optional.of(dataObject); - } - } - return Optional.absent(); - } - }); - } - - protected void doPut(final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType store, - final InstanceIdentifier path, final DataObject data) { - invalidateCache(store, path); - final Entry> normalized = codec - .toNormalizedNode(path, data); - writeTransaction.put(store, normalized.getKey(), normalized.getValue()); - } - - protected void doPutWithEnsureParents(final DOMDataReadWriteTransaction writeTransaction, - final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { - invalidateCache(store, path); - final Entry> normalized = codec - .toNormalizedNode(path, data); - - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey(); - ensureParentsByMerge(writeTransaction, store, normalizedPath, path); - LOG.debug("Tx: {} : Putting data {}", getDelegate().getIdentifier(), normalizedPath); - writeTransaction.put(store, normalizedPath, normalized.getValue()); - } - - protected void doMergeWithEnsureParents(final DOMDataReadWriteTransaction writeTransaction, - final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { - invalidateCache(store, path); - final Entry> normalized = codec - .toNormalizedNode(path, data); - - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey(); - ensureParentsByMerge(writeTransaction, store, normalizedPath, path); - LOG.debug("Tx: {} : Merge data {}",getDelegate().getIdentifier(),normalizedPath); - writeTransaction.merge(store, normalizedPath, normalized.getValue()); + @SuppressWarnings("unchecked") + protected final >> S getDelegateChecked(final Class txType) { + Preconditions.checkState(txType.isInstance(delegate)); + return (S) delegate; } - private void ensureParentsByMerge(final DOMDataReadWriteTransaction writeTransaction, - final LogicalDatastoreType store, - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath, - final InstanceIdentifier path) { - List currentArguments = new ArrayList<>(); - DataNormalizationOperation currentOp = codec.getDataNormalizer().getRootOperation(); - Iterator iterator = normalizedPath.getPath().iterator(); - while (iterator.hasNext()) { - PathArgument currentArg = iterator.next(); - try { - currentOp = currentOp.getChild(currentArg); - } catch (DataNormalizationException e) { - throw new IllegalArgumentException(String.format("Invalid child encountered in path %s", path), e); - } - currentArguments.add(currentArg); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier currentPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier( - currentArguments); - - final Optional> d; - try { - d = writeTransaction.read(store, currentPath).get(); - } catch (InterruptedException | ExecutionException e) { - LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e); - throw new IllegalStateException("Failed to read pre-existing data", e); - } - - if (!d.isPresent() && iterator.hasNext()) { - writeTransaction.merge(store, currentPath, currentOp.createDefault(currentArg)); - } - } - } - - protected void doMerge(final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType store, - final InstanceIdentifier path, final DataObject data) { - invalidateCache(store, path); - final Entry> normalized = codec - .toNormalizedNode(path, data); - writeTransaction.merge(store, normalized.getKey(), normalized.getValue()); - } - - protected void doDelete(final DOMDataWriteTransaction writeTransaction, final LogicalDatastoreType store, - final InstanceIdentifier path) { - invalidateCache(store, path); - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = codec.toNormalized(path); - writeTransaction.delete(store, normalized); - } - - protected ListenableFuture> doCommit(final DOMDataWriteTransaction writeTransaction) { - return writeTransaction.commit(); - } - - protected boolean doCancel(final DOMDataWriteTransaction writeTransaction) { - return writeTransaction.cancel(); - } - - protected ListenableFuture> doRead(final DOMDataReadTransaction readTransaction, - final LogicalDatastoreType store, final InstanceIdentifier path) { - final DataObject dataObject = getFromCache(store, path); - if (dataObject == null) { - final ListenableFuture>> future = readTransaction.read(store, - codec.toNormalized(path)); - return transformFuture(store, path, future); - } else { - return Futures.immediateFuture(Optional.of(dataObject)); - } - } - - private DataObject getFromCache(final LogicalDatastoreType store, final InstanceIdentifier path) { - Cache, DataObject> cache = cacheMap.get(store); - if (cache != null) { - return cache.getIfPresent(path); - } - return null; - } - - private void updateCache(final LogicalDatastoreType store, final InstanceIdentifier path, - final DataObject dataObject) { - // Check if cache exists. If not create one. - Cache, DataObject> cache = cacheMap.get(store); - if (cache == null) { - cache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(1, TimeUnit.MINUTES).build(); - - } - - cache.put(path, dataObject); + protected final BindingToNormalizedNodeCodec getCodec() { + return codec; } - private void invalidateCache(final LogicalDatastoreType store, final InstanceIdentifier path) { - // FIXME: Optimization: invalidate only parents and children of path - Cache, DataObject> cache = cacheMap.get(store); - cache.invalidateAll(); - LOG.trace("Cache invalidated"); + protected final ListenableFuture> doRead(final DOMDataReadTransaction readTx, + final LogicalDatastoreType store, final org.opendaylight.yangtools.yang.binding.InstanceIdentifier path) { + return Futures.transform(readTx.read(store, codec.toNormalized(path)), codec.deserializeFunction(path)); } - } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java new file mode 100644 index 0000000000..3988bc6960 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.ExecutionException; + +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; + +public class AbstractReadWriteTransaction extends AbstractWriteTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractReadWriteTransaction.class); + + public AbstractReadWriteTransaction(final DOMDataReadWriteTransaction delegate, final BindingToNormalizedNodeCodec codec) { + super(delegate, codec); + } + + protected final void doPutWithEnsureParents(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { + final Entry> normalized = getCodec() + .toNormalizedNode(path, data); + + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey(); + ensureParentsByMerge(store, normalizedPath, path); + LOG.debug("Tx: {} : Putting data {}", getDelegate().getIdentifier(), normalizedPath); + doPut(store, path, data); + } + + protected final void doMergeWithEnsureParents(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { + final Entry> normalized = getCodec() + .toNormalizedNode(path, data); + + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey(); + ensureParentsByMerge(store, normalizedPath, path); + LOG.debug("Tx: {} : Merge data {}", getDelegate().getIdentifier(), normalizedPath); + doMerge(store, path, data); + } + + private final void ensureParentsByMerge(final LogicalDatastoreType store, + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath, + final InstanceIdentifier path) { + List currentArguments = new ArrayList<>(); + DataNormalizationOperation currentOp = getCodec().getDataNormalizer().getRootOperation(); + Iterator iterator = normalizedPath.getPathArguments().iterator(); + while (iterator.hasNext()) { + PathArgument currentArg = iterator.next(); + try { + currentOp = currentOp.getChild(currentArg); + } catch (DataNormalizationException e) { + throw new IllegalArgumentException(String.format("Invalid child encountered in path %s", path), e); + } + currentArguments.add(currentArg); + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier currentPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create( + currentArguments); + + final Optional> d; + try { + d = getDelegate().read(store, currentPath).get(); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Failed to read pre-existing data from store {} path {}", store, currentPath, e); + throw new IllegalStateException("Failed to read pre-existing data", e); + } + + if (!d.isPresent() && iterator.hasNext()) { + getDelegate().merge(store, currentPath, currentOp.createDefault(currentArg)); + } + } + } + + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java new file mode 100644 index 0000000000..5ce66874b1 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl; + +import java.util.Map.Entry; + +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.util.concurrent.ListenableFuture; + +/** + * + * Abstract Base Transaction for transactions which are backed by + * {@link DOMDataWriteTransaction} + */ +public class AbstractWriteTransaction extends + AbstractForwardedTransaction { + + private static final Logger LOG = LoggerFactory.getLogger(AbstractWriteTransaction.class); + + protected AbstractWriteTransaction(final T delegate, + final BindingToNormalizedNodeCodec codec) { + super(delegate, codec); + } + + protected final void doPut(final LogicalDatastoreType store, + final InstanceIdentifier path, final DataObject data) { + final Entry> normalized = getCodec() + .toNormalizedNode(path, data); + getDelegate().put(store, normalized.getKey(), normalized.getValue()); + } + + protected final void doMerge(final LogicalDatastoreType store, + final InstanceIdentifier path, final DataObject data) { + final Entry> normalized = getCodec() + .toNormalizedNode(path, data); + getDelegate().merge(store, normalized.getKey(), normalized.getValue()); + } + + protected final void doDelete(final LogicalDatastoreType store, + final InstanceIdentifier path) { + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized = getCodec().toNormalized(path); + getDelegate().delete(store, normalized); + } + + protected final ListenableFuture> doCommit() { + return getDelegate().commit(); + } + + protected final boolean doCancel() { + return getDelegate().cancel(); + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java new file mode 100644 index 0000000000..e71404dfa4 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadTransactionImpl.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl; + +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.ListenableFuture; + +class BindingDataReadTransactionImpl extends AbstractForwardedTransaction implements + ReadOnlyTransaction { + + protected BindingDataReadTransactionImpl(final DOMDataReadOnlyTransaction delegate, + final BindingToNormalizedNodeCodec codec) { + super(delegate, codec); + } + + @Override + public ListenableFuture> read(final LogicalDatastoreType store, + final InstanceIdentifier path) { + return doRead(getDelegate(),store, path); + } + + @Override + public void close() { + getDelegate().close(); + } + +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java new file mode 100644 index 0000000000..5a89cc70b8 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataReadWriteTransactionImpl.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl; + +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.ListenableFuture; + +class BindingDataReadWriteTransactionImpl extends + BindingDataWriteTransactionImpl implements ReadWriteTransaction { + + protected BindingDataReadWriteTransactionImpl(final DOMDataReadWriteTransaction delegate, + final BindingToNormalizedNodeCodec codec) { + super(delegate, codec); + } + + @Override + public ListenableFuture> read(final LogicalDatastoreType store, + final InstanceIdentifier path) { + return doRead(getDelegate(), store, path); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java new file mode 100644 index 0000000000..a62319be22 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl; + +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.TransactionStatus; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.yangtools.yang.binding.DataObject; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; + +import com.google.common.util.concurrent.ListenableFuture; + +class BindingDataWriteTransactionImpl extends + AbstractWriteTransaction implements WriteTransaction { + + protected BindingDataWriteTransactionImpl(final T delegateTx, final BindingToNormalizedNodeCodec codec) { + super(delegateTx, codec); + } + + + + @Override + public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { + doPut(store, path, data); + } + + @Override + public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { + doMerge(store, path, data); + } + + @Override + public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) { + doDelete( store, path); + } + + @Override + public ListenableFuture> commit() { + return doCommit(); + } + + @Override + public boolean cancel() { + return doCancel(); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java index f1be5c6922..003f57cd72 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java @@ -14,6 +14,8 @@ import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; +import javax.annotation.Nullable; + import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer; @@ -42,7 +44,9 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Function; import com.google.common.base.Optional; +import com.google.common.base.Preconditions; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; @@ -75,7 +79,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { public Entry> toNormalizedNode( final InstanceIdentifier bindingPath, final DataObject bindingObject) { - return toNormalizedNode(toEntry(bindingPath, bindingObject)); + return toNormalizedNode(toBindingEntry(bindingPath, bindingObject)); } @@ -87,17 +91,16 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { .toNormalized(legacyEntry); LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding, legacyEntry, normalizedEntry); - if (Augmentation.class.isAssignableFrom(binding.getKey().getTargetType())) { + if (isAugmentation(binding.getKey().getTargetType())) { for (DataContainerChild child : ((DataContainerNode) normalizedEntry .getValue()).getValue()) { if (child instanceof AugmentationNode) { ImmutableList childArgs = ImmutableList. builder() - .addAll(normalizedEntry.getKey().getPath()).add(child.getIdentifier()).build(); - org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier( + .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build(); + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create( childArgs); - return new SimpleEntry>( - childPath, child); + return toDOMEntry(childPath, child); } } @@ -119,7 +122,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) throws DeserializationException { - PathArgument lastArgument = Iterables.getLast(normalized.getPath()); + PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments()); // Used instance-identifier codec do not support serialization of last // path // argument if it is AugmentationIdentifier (behaviour expected by old @@ -143,7 +146,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { } int normalizedCount = getAugmentationCount(normalized); - AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPath()); + AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPathArguments()); // Here we employ small trick - Binding-aware Codec injects an pointer // to augmentation class @@ -152,7 +155,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { LOG.trace("Looking for candidates to match {}", normalized); for (QName child : lastArgument.getPossibleChildNames()) { org.opendaylight.yangtools.yang.data.api.InstanceIdentifier childPath = new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier( - ImmutableList. builder().addAll(normalized.getPath()).add(new NodeIdentifier(child)) + ImmutableList. builder().addAll(normalized.getPathArguments()).add(new NodeIdentifier(child)) .build()); try { if (isNotRepresentable(childPath)) { @@ -218,19 +221,26 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) throws DataNormalizationException { DataNormalizationOperation current = legacyToNormalized.getRootOperation(); - for (PathArgument arg : normalized.getPath()) { + for (PathArgument arg : normalized.getPathArguments()) { current = current.getChild(arg); } return current; } - private static final Entry, DataObject> toEntry( + private static final Entry, DataObject> toBindingEntry( final org.opendaylight.yangtools.yang.binding.InstanceIdentifier key, final DataObject value) { return new SimpleEntry, DataObject>( key, value); } + private static final Entry> toDOMEntry( + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key, + final NormalizedNode value) { + return new SimpleEntry>( + key, value); + } + public DataObject toBinding(final InstanceIdentifier path, final NormalizedNode normalizedNode) throws DeserializationException { CompositeNode legacy = null; @@ -262,7 +272,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { if (bindingData == null) { LOG.warn("Failed to deserialize {} to Binding format. Binding path is: {}", normalized, bindingPath); } - return Optional.of(toEntry(bindingPath, bindingData)); + return Optional.of(toBindingEntry(bindingPath, bindingData)); } else { return Optional.absent(); } @@ -304,15 +314,15 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalized) { int position = 0; int foundPosition = -1; - for (PathArgument arg : normalized.getPath()) { + for (PathArgument arg : normalized.getPathArguments()) { position++; if (arg instanceof AugmentationIdentifier) { foundPosition = position; } } if (foundPosition > 0) { - return new org.opendaylight.yangtools.yang.data.api.InstanceIdentifier(normalized.getPath().subList(0, - foundPosition)); + Iterable shortened = Iterables.limit(normalized.getPathArguments(), foundPosition); + return org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create(shortened); } return null; } @@ -404,7 +414,7 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { } private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier processed) { - return Iterables.getLast(processed.getPath()) instanceof AugmentationIdentifier; + return Iterables.getLast(processed.getPathArguments()) instanceof AugmentationIdentifier; } private static int getAugmentationCount(final InstanceIdentifier potential) { @@ -420,11 +430,46 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener { private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier potential) { int count = 0; - for(PathArgument arg : potential.getPath()) { + for(PathArgument arg : potential.getPathArguments()) { if(arg instanceof AugmentationIdentifier) { count++; } } return count; } + + public Function>, Optional> deserializeFunction(final InstanceIdentifier path) { + return new DeserializeFunction(this, path); + } + + private static class DeserializeFunction implements Function>, Optional> { + + private final BindingToNormalizedNodeCodec codec; + private final InstanceIdentifier path; + + public DeserializeFunction(final BindingToNormalizedNodeCodec codec, final InstanceIdentifier path) { + super(); + this.codec = Preconditions.checkNotNull(codec, "Codec must not be null"); + this.path = Preconditions.checkNotNull(path, "Path must not be null"); + } + + @Nullable + @Override + public Optional apply(@Nullable final Optional> normalizedNode) { + if (normalizedNode.isPresent()) { + final DataObject dataObject; + try { + dataObject = codec.toBinding(path, normalizedNode.get()); + } catch (DeserializationException e) { + LOG.warn("Failed to create dataobject from node {}", normalizedNode.get(), e); + throw new IllegalStateException("Failed to create dataobject", e); + } + + if (dataObject != null) { + return Optional.of(dataObject); + } + } + return Optional.absent(); + } + } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java new file mode 100644 index 0000000000..2d8e51cff9 --- /dev/null +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingTranslatedTransactionChain.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.md.sal.binding.impl; + +import java.util.Map; +import java.util.WeakHashMap; + +import javax.annotation.concurrent.GuardedBy; + +import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; +import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChain; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; +import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; +import org.opendaylight.yangtools.concepts.Delegator; + +import com.google.common.base.Preconditions; + +class BindingTranslatedTransactionChain implements BindingTransactionChain, Delegator { + + private final DOMTransactionChain delegate; + + @GuardedBy("this") + private final Map, AsyncTransaction> delegateTxToBindingTx = new WeakHashMap<>(); + private final BindingToNormalizedNodeCodec codec; + + public BindingTranslatedTransactionChain(final DOMDataBroker chainFactory, + final BindingToNormalizedNodeCodec codec, final TransactionChainListener listener) { + Preconditions.checkNotNull(chainFactory, "DOM Transaction chain factory must not be null"); + this.delegate = chainFactory.createTransactionChain(new ListenerInvoker(listener)); + this.codec = codec; + } + + @Override + public DOMTransactionChain getDelegate() { + return delegate; + } + + @Override + public ReadOnlyTransaction newReadOnlyTransaction() { + DOMDataReadOnlyTransaction delegateTx = delegate.newReadOnlyTransaction(); + ReadOnlyTransaction bindingTx = new BindingDataReadTransactionImpl(delegateTx, codec); + putDelegateToBinding(delegateTx, bindingTx); + return bindingTx; + } + + @Override + public ReadWriteTransaction newReadWriteTransaction() { + DOMDataReadWriteTransaction delegateTx = delegate.newReadWriteTransaction(); + ReadWriteTransaction bindingTx = new BindingDataReadWriteTransactionImpl(delegateTx, codec); + putDelegateToBinding(delegateTx, bindingTx); + return bindingTx; + } + + @Override + public WriteTransaction newWriteOnlyTransaction() { + DOMDataWriteTransaction delegateTx = delegate.newWriteOnlyTransaction(); + WriteTransaction bindingTx = new BindingDataWriteTransactionImpl<>(delegateTx, codec); + putDelegateToBinding(delegateTx, bindingTx); + return bindingTx; + } + + @Override + public void close() { + delegate.close(); + } + + private synchronized void putDelegateToBinding(final AsyncTransaction domTx, + final AsyncTransaction bindingTx) { + final Object previous = delegateTxToBindingTx.put(domTx, bindingTx); + Preconditions.checkState(previous == null, "DOM Transaction %s has already associated binding transation %s",domTx,previous); + } + + private synchronized AsyncTransaction getBindingTransaction(final AsyncTransaction transaction) { + return delegateTxToBindingTx.get(transaction); + } + + private final class ListenerInvoker implements TransactionChainListener { + + private final TransactionChainListener listener; + + public ListenerInvoker(final TransactionChainListener listener) { + this.listener = Preconditions.checkNotNull(listener, "Listener must not be null."); + } + + @Override + public void onTransactionChainFailed(final TransactionChain chain, + final AsyncTransaction transaction, final Throwable cause) { + Preconditions.checkState(delegate.equals(chain), + "Illegal state - listener for %s was invoked for incorrect chain %s.", delegate, chain); + AsyncTransaction bindingTx = getBindingTransaction(transaction); + listener.onTransactionChainFailed(chain, bindingTx, cause); + } + + @Override + public void onTransactionChainSuccessful(final TransactionChain chain) { + Preconditions.checkState(delegate.equals(chain), + "Illegal state - listener for %s was invoked for incorrect chain %s.", delegate, chain); + listener.onTransactionChainSuccessful(BindingTranslatedTransactionChain.this); + } + } + +} diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java index 49d04d04b3..1c6447a4e7 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java @@ -186,7 +186,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat } private class ForwardedBackwardsCompatibleTransacion extends - AbstractForwardedTransaction implements DataModificationTransaction { + AbstractReadWriteTransaction implements DataModificationTransaction { private final ListenerRegistry listeners = ListenerRegistry.create(); private final Map, DataObject> updated = new HashMap<>(); @@ -214,9 +214,9 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat public void putOperationalData(final InstanceIdentifier path, final DataObject data) { boolean previouslyRemoved = posponedRemovedOperational.remove(path); if(previouslyRemoved) { - doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data); + doPutWithEnsureParents(LogicalDatastoreType.OPERATIONAL, path, data); } else { - doMergeWithEnsureParents(getDelegate(), LogicalDatastoreType.OPERATIONAL, path, data); + doMergeWithEnsureParents(LogicalDatastoreType.OPERATIONAL, path, data); } } @@ -232,9 +232,9 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat } updated.put(path, data); if(previouslyRemoved) { - doPutWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data); + doPutWithEnsureParents(LogicalDatastoreType.CONFIGURATION, path, data); } else { - doMergeWithEnsureParents(getDelegate(), LogicalDatastoreType.CONFIGURATION, path, data); + doMergeWithEnsureParents(LogicalDatastoreType.CONFIGURATION, path, data); } } @@ -308,11 +308,6 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat } } - @Override - public Object getIdentifier() { - return getDelegate().getIdentifier(); - } - private void changeStatus(final TransactionStatus status) { LOG.trace("Transaction {} changed status to {}", getIdentifier(), status); this.status = status; @@ -330,11 +325,11 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat public ListenableFuture> commit() { for(InstanceIdentifier path : posponedRemovedConfiguration) { - doDelete(getDelegate(), LogicalDatastoreType.CONFIGURATION, path); + doDelete(LogicalDatastoreType.CONFIGURATION, path); } for(InstanceIdentifier path : posponedRemovedOperational) { - doDelete(getDelegate(), LogicalDatastoreType.OPERATIONAL, path); + doDelete(LogicalDatastoreType.OPERATIONAL, path); } changeStatus(TransactionStatus.SUBMITED); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java index 5b008ad4bc..6359b60684 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java @@ -8,27 +8,16 @@ package org.opendaylight.controller.md.sal.binding.impl; +import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; -import org.opendaylight.controller.md.sal.common.api.TransactionStatus; -import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction; -import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.controller.sal.core.api.model.SchemaService; -import org.opendaylight.yangtools.yang.binding.DataObject; -import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; -import org.opendaylight.yangtools.yang.common.RpcResult; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; - /** * The DataBrokerImpl simply defers to the DOMDataBroker for all its operations. * All transactions and listener registrations are wrapped by the DataBrokerImpl @@ -37,9 +26,7 @@ import com.google.common.util.concurrent.ListenableFuture; * Besides this the DataBrokerImpl and it's collaborators also cache data that * is already transformed from the binding independent to binding aware format * - * TODO : All references in this class to CompositeNode should be switched to - * NormalizedNode once the MappingService is updated - * + */ public class ForwardedBindingDataBroker extends AbstractForwardedDataBroker implements DataBroker { @@ -60,90 +47,11 @@ public class ForwardedBindingDataBroker extends AbstractForwardedDataBroker impl @Override public WriteTransaction newWriteOnlyTransaction() { - return new BindingDataWriteTransactionImpl(getDelegate().newWriteOnlyTransaction(),getCodec()); - } - - private abstract class AbstractBindingTransaction>> - extends AbstractForwardedTransaction implements AsyncTransaction, DataObject> { - - protected AbstractBindingTransaction(final T delegate, final BindingToNormalizedNodeCodec codec) { - super(delegate, codec); - } - - @Override - public Object getIdentifier() { - return getDelegate().getIdentifier(); - } - - } - - - private class BindingDataReadTransactionImpl extends AbstractBindingTransaction implements - ReadOnlyTransaction { - - protected BindingDataReadTransactionImpl(final DOMDataReadOnlyTransaction delegate, - final BindingToNormalizedNodeCodec codec) { - super(delegate, codec); - } - - @Override - public ListenableFuture> read(final LogicalDatastoreType store, - final InstanceIdentifier path) { - return doRead(getDelegate(), store, path); - } - - @Override - public void close() { - getDelegate().close(); - } + return new BindingDataWriteTransactionImpl<>(getDelegate().newWriteOnlyTransaction(),getCodec()); } - private class BindingDataWriteTransactionImpl extends - AbstractBindingTransaction implements WriteTransaction { - - protected BindingDataWriteTransactionImpl(final T delegate, final BindingToNormalizedNodeCodec codec) { - super(delegate, codec); - - } - - @Override - public boolean cancel() { - return doCancel(getDelegate()); - } - - @Override - public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { - doPut(getDelegate(), store, path, data); - } - - @Override - public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { - doMerge(getDelegate(), store, path, data); - } - - @Override - public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) { - doDelete(getDelegate(), store, path); - } - - @Override - public ListenableFuture> commit() { - return doCommit(getDelegate()); - } - } - - private class BindingDataReadWriteTransactionImpl extends - BindingDataWriteTransactionImpl implements ReadWriteTransaction { - - protected BindingDataReadWriteTransactionImpl(final DOMDataReadWriteTransaction delegate, - final BindingToNormalizedNodeCodec codec) { - super(delegate, codec); - } - - @Override - public ListenableFuture> read(final LogicalDatastoreType store, - final InstanceIdentifier path) { - return doRead(getDelegate(), store, path); - } + @Override + public BindingTransactionChain createTransactionChain(final TransactionChainListener listener) { + return new BindingTranslatedTransactionChain(getDelegate(), getCodec(), listener); } } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java index 15d1daa1bb..5e5ea0c138 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java @@ -10,6 +10,15 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.Immutable; import org.opendaylight.yangtools.concepts.Path; +/** + * + * + * + * @param

+ * @param + * @deprecated Replaced by {@link AsyncDataChangeEvent} + */ +@Deprecated public interface DataChangeEvent

,D> extends DataChange, Immutable { /** diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeListener.java index 669baa8d9e..21006173f2 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeListener.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeListener.java @@ -10,7 +10,12 @@ package org.opendaylight.controller.md.sal.common.api.data; import java.util.EventListener; import org.opendaylight.yangtools.concepts.Path; - +/** + * + * + * @deprecated Replaced by {@link AsyncDataChangeEvent} + */ +@Deprecated public interface DataChangeListener

, D> extends EventListener { /** * Note that this method may be invoked from a shared thread pool, so diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java index 0c4c6d179f..222dba8eaf 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangePublisher.java @@ -10,6 +10,11 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Path; +/** + * + * @deprecated Replaced by {@link AsyncDataBroker} + */ +@Deprecated public interface DataChangePublisher

, D, L extends DataChangeListener> { ListenerRegistration registerDataChangeListener(P path, L listener); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java index 22e95197bb..a9f02a8ee5 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandler.java @@ -79,7 +79,9 @@ import org.opendaylight.yangtools.yang.common.RpcResult; * * @param

Class representing a path * @param Superclass from which all data objects are derived from. + * @deprecated Replaced by {@link AsyncConfigurationCommitHandler} */ +@Deprecated public interface DataCommitHandler

, D> { diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java index 86f1f9b138..224751c37d 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataCommitHandlerRegistration.java @@ -10,6 +10,16 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.concepts.Registration; +/** + * + * + * @deprecated THis was intended as Registration object, normal use of {@link org.opendaylight.yangtools.concepts.ObjectRegistration} + * is suffiecient, since {@link #getPath()} was implementation leak. + * + * @param

+ * @param + */ +@Deprecated public interface DataCommitHandlerRegistration

,D> extends Registration>{ P getPath(); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java index 22c5fa0c1d..630078dced 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModification.java @@ -12,7 +12,11 @@ import java.util.concurrent.Future; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.yang.common.RpcResult; - +/** + * + * @deprecated Replaced by {@link AsyncWriteTransaction} + */ +@Deprecated public interface DataModification

, D> extends DataChange, DataReader { /** * Returns transaction identifier diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModificationTransactionFactory.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModificationTransactionFactory.java index 34f6fe970d..6a370b8cd1 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModificationTransactionFactory.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataModificationTransactionFactory.java @@ -8,7 +8,11 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.Path; - +/** + * + * @deprecated Replaced by {@link AsyncDataTransactionFactory} + */ +@Deprecated public interface DataModificationTransactionFactory

,D> { DataModification beginTransaction(); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvider.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvider.java index dae9a1144b..fdeda2800b 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvider.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvider.java @@ -9,6 +9,12 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.Path; +/** + * + * + * @deprecated Replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore contract. + */ +@Deprecated public interface DataProvider

, D> extends DataReader { } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java index da7efebdfe..bd80a53893 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataProvisionService.java @@ -12,7 +12,12 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.concepts.Registration; - +/** + * + * + * @deprecated replaced by {@link AsyncDataBroker} and {@link AsyncConfigurationCommitCoordinator} + */ +@Deprecated public interface DataProvisionService

, D> { public Registration> registerCommitHandler(P path, DataCommitHandler commitHandler); 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 14731d688c..2f657b8e50 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 @@ -17,7 +17,9 @@ import org.opendaylight.yangtools.concepts.Path; * * @param

Path Type * @param Data Type + * @deprecated Replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore contract. */ +@Deprecated public interface DataReader

,D> { /** diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java index 3520ba1819..5688dd0988 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataStore.java @@ -9,6 +9,11 @@ package org.opendaylight.controller.md.sal.common.api.data; import org.opendaylight.yangtools.concepts.Path; +/** + * + * @deprecated Replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore Contract. + */ +@Deprecated public interface DataStore

, D> extends // DataReader, // DataModificationTransactionFactory { diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChange.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChange.java index 5f84ec579d..0c04b936b6 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChange.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChange.java @@ -9,9 +9,36 @@ package org.opendaylight.controller.md.sal.common.api.routing; import java.util.Map; import java.util.Set; - +/** + * Event representing change in RPC routing table. + * + * + * @param Type, which is used to represent Routing context. + * @param

Type of data tree path, which is used to identify route. + */ public interface RouteChange { + /** + * + * Returns a map of removed routes in associated routing contexts. + *

+ * This map represents routes, which were withdrawn from broker local + * routing table and broker may need to forward RPC to other broker + * in order to process RPC request. + * + * @return Map of contexts and removed routes + */ Map> getRemovals(); + /** + * + * Returns a map of announced routes in associated routing contexts. + * + * This map represents routes, which were announced by broker + * and are present in broker's local routing table. This routes + * are processed by implementations which are registered + * to originating broker. + * + * @return Map of contexts and announced routes + */ Map> getAnnouncements(); } diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java index 62206013f8..b3b6fe6ee9 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RouteChangeListener.java @@ -8,8 +8,23 @@ package org.opendaylight.controller.md.sal.common.api.routing; import java.util.EventListener; - +/** + * + * Listener which is interested in receiving RouteChangeEvents + * for its local broker. + *

+ * Listener is registerd via {@link RouteChangePublisher#registerRouteChangeListener(RouteChangeListener)} + * + * + * @param Type, which is used to represent Routing context. + * @param

Type of data tree path, which is used to identify route. + */ public interface RouteChangeListener extends EventListener { + /** + * Callback which is invoked if there is an rpc routing table change. + * + * @param change Event representing change in local RPC routing table. + */ void onRouteChange(RouteChange change); } 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 7bf61fab0b..dc6b6dd3b7 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 @@ -9,6 +9,12 @@ package org.opendaylight.controller.md.sal.common.api.routing; import org.opendaylight.yangtools.concepts.ListenerRegistration; +/** + * Publishes changes in local RPC routing table to registered listener. + * + * @param Type, which is used to represent Routing context. + * @param

Type of data tree path, which is used to identify route. + */ public interface RouteChangePublisher { > ListenerRegistration registerRouteChangeListener(L listener); diff --git a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutedRegistration.java b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutedRegistration.java index 6ce7b5a5c7..6fe8d69217 100644 --- a/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutedRegistration.java +++ b/opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/routing/RoutedRegistration.java @@ -10,9 +10,31 @@ package org.opendaylight.controller.md.sal.common.api.routing; import org.opendaylight.yangtools.concepts.Path; import org.opendaylight.yangtools.concepts.Registration; +/** + * Base interface for a routed RPC RPC implementation registration. + * + * @param the context type used for routing + * @param

the path identifier type + * @param the RPC implementation type + */ public interface RoutedRegistration, S> extends Registration { + /** + * Registers the RPC implementation associated with this registration for the given path + * identifier and context. + * + * @param context the context used for routing RPCs to this implementation. + * @param path the path identifier for which to register. + */ void registerPath(C context, P path); + + /** + * Unregisters the RPC implementation associated with this registration for the given path + * identifier and context. + * + * @param context the context used for routing RPCs to this implementation. + * @param path the path identifier for which to unregister. + */ void unregisterPath(C context, P path); @Override diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java new file mode 100644 index 0000000000..ba09d04025 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DataChangeListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore; + +import akka.actor.Props; +import akka.actor.UntypedActor; +import akka.japi.Creator; + +public class DataChangeListener extends UntypedActor { + @Override public void onReceive(Object message) throws Exception { + throw new UnsupportedOperationException("onReceive"); + } + + public static Props props() { + return Props.create(new Creator() { + @Override + public DataChangeListener create() throws Exception { + return new DataChangeListener(); + } + + }); + + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java index c87f1abb21..f64c6f1a86 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/DistributedDataStore.java @@ -10,6 +10,10 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; import akka.actor.ActorSystem; +import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener; +import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; +import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.controller.sal.core.spi.data.DOMStore; @@ -20,39 +24,72 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.model.api.SchemaContext; +import org.opendaylight.yangtools.yang.model.api.SchemaContextListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * */ -public class DistributedDataStore implements DOMStore { - private final ActorRef shardManager; - - public DistributedDataStore(ActorSystem actorSystem, String type) { - shardManager = actorSystem.actorOf(ShardManager.props(type)); - } - - @Override - public >> ListenerRegistration registerChangeListener(InstanceIdentifier path, L listener, AsyncDataBroker.DataChangeScope scope) { - return new ListenerRegistrationProxy(); - } - - @Override - public DOMStoreTransactionChain createTransactionChain() { - return new TransactionChainProxy(); - } - - @Override - public DOMStoreReadTransaction newReadOnlyTransaction() { - return new TransactionProxy(); - } - - @Override - public DOMStoreWriteTransaction newWriteOnlyTransaction() { - return new TransactionProxy(); - } - - @Override - public DOMStoreReadWriteTransaction newReadWriteTransaction() { - return new TransactionProxy(); - } +public class DistributedDataStore implements DOMStore, SchemaContextListener { + + private static final Logger + LOG = LoggerFactory.getLogger(DistributedDataStore.class); + + + private final String type; + private final ActorContext actorContext; + + public DistributedDataStore(ActorSystem actorSystem, String type) { + this(new ActorContext(actorSystem, actorSystem.actorOf(ShardManager.props(type))), type); + } + + public DistributedDataStore(ActorContext actorContext, String type) { + this.type = type; + this.actorContext = actorContext; + } + + + @Override + public >> ListenerRegistration registerChangeListener( + InstanceIdentifier path, L listener, + AsyncDataBroker.DataChangeScope scope) { + + ActorRef dataChangeListenerActor = actorContext.getActorSystem().actorOf(DataChangeListener.props()); + + Object result = actorContext.executeShardOperation(Shard.DEFAULT_NAME, + new RegisterChangeListener(path, dataChangeListenerActor.path(), + AsyncDataBroker.DataChangeScope.BASE), + ActorContext.ASK_DURATION); + + RegisterChangeListenerReply reply = (RegisterChangeListenerReply) result; + return new ListenerRegistrationProxy(reply.getListenerRegistrationPath()); + } + + + + @Override + public DOMStoreTransactionChain createTransactionChain() { + return new TransactionChainProxy(actorContext); + } + + @Override + public DOMStoreReadTransaction newReadOnlyTransaction() { + return new TransactionProxy(actorContext, TransactionProxy.TransactionType.READ_ONLY); + } + + @Override + public DOMStoreWriteTransaction newWriteOnlyTransaction() { + return new TransactionProxy(actorContext, TransactionProxy.TransactionType.WRITE_ONLY); + } + + @Override + public DOMStoreReadWriteTransaction newReadWriteTransaction() { + return new TransactionProxy(actorContext, TransactionProxy.TransactionType.READ_WRITE); + } + + @Override public void onGlobalContextUpdated(SchemaContext schemaContext) { + actorContext.getShardManager().tell(new UpdateSchemaContext(schemaContext), null); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerProxy.java new file mode 100644 index 0000000000..7c38ee5acb --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerProxy.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore; + +import akka.actor.ActorSelection; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; + +public class ListenerProxy implements AsyncDataChangeListener>{ + private final ActorSelection listenerRegistrationActor; + + public ListenerProxy(ActorSelection listenerRegistrationActor) { + this.listenerRegistrationActor = listenerRegistrationActor; + } + + @Override public void onDataChanged( + AsyncDataChangeEvent> change) { + throw new UnsupportedOperationException("onDataChanged"); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java index c2fc8c0277..a548a885eb 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ListenerRegistrationProxy.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorPath; import org.opendaylight.yangtools.concepts.ListenerRegistration; /** @@ -17,6 +18,13 @@ import org.opendaylight.yangtools.concepts.ListenerRegistration; * The ListenerRegistrationProxy talks to a remote ListenerRegistration actor. */ public class ListenerRegistrationProxy implements ListenerRegistration { + private final ActorPath listenerRegistrationPath; + + public ListenerRegistrationProxy(ActorPath listenerRegistrationPath) { + + this.listenerRegistrationPath = listenerRegistrationPath; + } + @Override public Object getInstance() { throw new UnsupportedOperationException("getInstance"); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java index d75edc7922..5b4f7ef898 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.cluster.datastore; import akka.actor.ActorRef; +import akka.actor.ActorSelection; import akka.actor.Props; import akka.event.Logging; import akka.event.LoggingAdapter; @@ -46,89 +47,112 @@ import java.util.concurrent.Executors; */ public class Shard extends UntypedProcessor { - public static final String DEFAULT_NAME = "default"; + public static final String DEFAULT_NAME = "default"; - private final ListeningExecutorService storeExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2)); + private final ListeningExecutorService storeExecutor = + MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2)); - private final InMemoryDOMDataStore store; + private final InMemoryDOMDataStore store; - private final Map modificationToCohort = new HashMap<>(); + private final Map + modificationToCohort = new HashMap<>(); - private final LoggingAdapter log = Logging.getLogger(getContext().system(), this); + private final LoggingAdapter log = + Logging.getLogger(getContext().system(), this); - private Shard(String name){ - store = new InMemoryDOMDataStore(name, storeExecutor); - } - - public static Props props(final String name) { - return Props.create(new Creator() { + private Shard(String name) { + store = new InMemoryDOMDataStore(name, storeExecutor); + } - @Override - public Shard create() throws Exception { - return new Shard(name); - } + public static Props props(final String name) { + return Props.create(new Creator() { - }); - } + @Override + public Shard create() throws Exception { + return new Shard(name); + } - @Override - public void onReceive(Object message) throws Exception { - if (message instanceof CreateTransactionChain) { - createTransactionChain(); - } else if (message instanceof RegisterChangeListener) { - registerChangeListener((RegisterChangeListener) message); - } else if (message instanceof UpdateSchemaContext) { - updateSchemaContext((UpdateSchemaContext) message); - } else if (message instanceof ForwardedCommitTransaction ) { - handleForwardedCommit((ForwardedCommitTransaction) message); - } else if (message instanceof Persistent){ - commit((Persistent) message); + }); } - } - - private void commit(Persistent message) { - Modification modification = (Modification) message.payload(); - DOMStoreThreePhaseCommitCohort cohort = modificationToCohort.remove(modification); - if(cohort == null){ - log.error("Could not find cohort for modification : " + modification); - return; + + @Override + public void onReceive(Object message) throws Exception { + if (message instanceof CreateTransactionChain) { + createTransactionChain(); + } else if (message instanceof RegisterChangeListener) { + registerChangeListener((RegisterChangeListener) message); + } else if (message instanceof UpdateSchemaContext) { + updateSchemaContext((UpdateSchemaContext) message); + } else if (message instanceof ForwardedCommitTransaction) { + handleForwardedCommit((ForwardedCommitTransaction) message); + } else if (message instanceof Persistent) { + commit((Persistent) message); + } } - final ListenableFuture future = cohort.commit(); - final ActorRef sender = getSender(); - final ActorRef self = getSelf(); - future.addListener(new Runnable() { - @Override - public void run() { - try { - future.get(); - sender.tell(new CommitTransactionReply(), self); - } catch (InterruptedException | ExecutionException e) { - log.error(e, "An exception happened when committing"); + + private void commit(Persistent message) { + Modification modification = (Modification) message.payload(); + DOMStoreThreePhaseCommitCohort cohort = + modificationToCohort.remove(modification); + if (cohort == null) { + log.error( + "Could not find cohort for modification : " + modification); + return; } - } - }, getContext().dispatcher()); - } - - private void handleForwardedCommit(ForwardedCommitTransaction message) { - log.info("received forwarded transaction"); - modificationToCohort.put(message.getModification(), message.getCohort()); - getSelf().forward(Persistent.create(message.getModification()), getContext()); - } - - private void updateSchemaContext(UpdateSchemaContext message) { - store.onGlobalContextUpdated(message.getSchemaContext()); - } - - private void registerChangeListener(RegisterChangeListener registerChangeListener) { - org.opendaylight.yangtools.concepts.ListenerRegistration>> registration = - store.registerChangeListener(registerChangeListener.getPath(), registerChangeListener.getListener(), registerChangeListener.getScope()); - ActorRef listenerRegistration = getContext().actorOf(ListenerRegistration.props(registration)); - getSender().tell(new RegisterChangeListenerReply(listenerRegistration.path()), getSelf()); - } - - private void createTransactionChain() { - DOMStoreTransactionChain chain = store.createTransactionChain(); - ActorRef transactionChain = getContext().actorOf(ShardTransactionChain.props(chain)); - getSender().tell(new CreateTransactionChainReply(transactionChain.path()), getSelf()); - } + final ListenableFuture future = cohort.commit(); + final ActorRef sender = getSender(); + final ActorRef self = getSelf(); + future.addListener(new Runnable() { + @Override + public void run() { + try { + future.get(); + sender.tell(new CommitTransactionReply(), self); + } catch (InterruptedException | ExecutionException e) { + log.error(e, "An exception happened when committing"); + } + } + }, getContext().dispatcher()); + } + + private void handleForwardedCommit(ForwardedCommitTransaction message) { + log.info("received forwarded transaction"); + modificationToCohort + .put(message.getModification(), message.getCohort()); + getSelf().forward(Persistent.create(message.getModification()), + getContext()); + } + + private void updateSchemaContext(UpdateSchemaContext message) { + store.onGlobalContextUpdated(message.getSchemaContext()); + } + + private void registerChangeListener( + RegisterChangeListener registerChangeListener) { + + ActorSelection listenerRegistrationActor = getContext() + .system().actorSelection(registerChangeListener.getDataChangeListenerPath()); + + AsyncDataChangeListener> + listener = new ListenerProxy(listenerRegistrationActor); + + org.opendaylight.yangtools.concepts.ListenerRegistration>> + registration = + store.registerChangeListener(registerChangeListener.getPath(), + listener, registerChangeListener.getScope()); + ActorRef listenerRegistration = + getContext().actorOf(ListenerRegistration.props(registration)); + getSender() + .tell(new RegisterChangeListenerReply(listenerRegistration.path()), + getSelf()); + } + + private void createTransactionChain() { + DOMStoreTransactionChain chain = store.createTransactionChain(); + ActorRef transactionChain = + getContext().actorOf(ShardTransactionChain.props(chain)); + getSender() + .tell(new CreateTransactionChainReply(transactionChain.path()), + getSelf()); + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java index 8d8527a240..4e2369d375 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java @@ -19,6 +19,7 @@ import akka.japi.Creator; import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; import org.opendaylight.controller.cluster.datastore.messages.PrimaryNotFound; +import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext; import java.util.HashMap; import java.util.List; @@ -92,6 +93,9 @@ public class ShardManager extends UntypedActor { } else { getSender().tell(new PrimaryNotFound(shardName), getSelf()); } + } else if(message instanceof UpdateSchemaContext){ + // FIXME : Notify all local shards of a context change + getContext().system().actorSelection(defaultShardPath).forward(message, getContext()); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java new file mode 100644 index 0000000000..197b3b70ce --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortProxy.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore; + +import akka.actor.ActorPath; +import com.google.common.util.concurrent.ListenableFuture; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; + +import java.util.Collections; +import java.util.List; + +/** + * ThreePhaseCommitCohortProxy represents a set of remote cohort proxies + */ +public class ThreePhaseCommitCohortProxy implements + DOMStoreThreePhaseCommitCohort{ + + private final List cohortPaths; + + public ThreePhaseCommitCohortProxy(List cohortPaths) { + + this.cohortPaths = cohortPaths; + } + + @Override public ListenableFuture canCommit() { + throw new UnsupportedOperationException("canCommit"); + } + + @Override public ListenableFuture preCommit() { + throw new UnsupportedOperationException("preCommit"); + } + + @Override public ListenableFuture abort() { + throw new UnsupportedOperationException("abort"); + } + + @Override public ListenableFuture commit() { + throw new UnsupportedOperationException("commit"); + } + + public List getCohortPaths() { + return Collections.unmodifiableList(this.cohortPaths); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java index 1ee0d89e61..837ffc1b51 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionChainProxy.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.cluster.datastore; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain; @@ -17,23 +18,32 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction; * TransactionChainProxy acts as a proxy for a DOMStoreTransactionChain created on a remote shard */ public class TransactionChainProxy implements DOMStoreTransactionChain{ + private final ActorContext actorContext; + + public TransactionChainProxy(ActorContext actorContext) { + this.actorContext = actorContext; + } + @Override public DOMStoreReadTransaction newReadOnlyTransaction() { - throw new UnsupportedOperationException("newReadOnlyTransaction"); + return new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); } @Override public DOMStoreReadWriteTransaction newReadWriteTransaction() { - throw new UnsupportedOperationException("newReadWriteTransaction"); + return new TransactionProxy(actorContext, + TransactionProxy.TransactionType.WRITE_ONLY); } @Override public DOMStoreWriteTransaction newWriteOnlyTransaction() { - throw new UnsupportedOperationException("newWriteOnlyTransaction"); + return new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_WRITE); } @Override public void close() { - throw new UnsupportedOperationException("close"); + throw new UnsupportedOperationException("close - not sure what to do here?"); } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java index 609dea0b36..32bb7d0951 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/TransactionProxy.java @@ -8,57 +8,161 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorPath; +import akka.actor.ActorSelection; import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListenableFutureTask; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.DeleteData; +import org.opendaylight.controller.cluster.datastore.messages.MergeData; +import org.opendaylight.controller.cluster.datastore.messages.ReadData; +import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.WriteData; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction; import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicLong; + /** * TransactionProxy acts as a proxy for one or more transactions that were created on a remote shard - * + *

* Creating a transaction on the consumer side will create one instance of a transaction proxy. If during * the transaction reads and writes are done on data that belongs to different shards then a separate transaction will * be created on each of those shards by the TransactionProxy - * + *

+ *

* The TransactionProxy does not make any guarantees about atomicity or order in which the transactions on the various * shards will be executed. - * + *

*/ public class TransactionProxy implements DOMStoreReadWriteTransaction { + + public enum TransactionType { + READ_ONLY, + WRITE_ONLY, + READ_WRITE + } + + private static final AtomicLong counter = new AtomicLong(); + + private final TransactionType readOnly; + private final ActorContext actorContext; + private final Map remoteTransactionPaths = new HashMap<>(); + private final String identifier; + + public TransactionProxy( + ActorContext actorContext, + TransactionType readOnly) { + + this.identifier = "transaction-" + counter.getAndIncrement(); + this.readOnly = readOnly; + this.actorContext = actorContext; + + Object response = actorContext.executeShardOperation(Shard.DEFAULT_NAME, new CreateTransaction(), ActorContext.ASK_DURATION); + if(response instanceof CreateTransactionReply){ + CreateTransactionReply reply = (CreateTransactionReply) response; + remoteTransactionPaths.put(Shard.DEFAULT_NAME, actorContext.actorSelection(reply.getTransactionPath())); + } + } + @Override - public ListenableFuture>> read(InstanceIdentifier path) { - throw new UnsupportedOperationException("read"); + public ListenableFuture>> read(final InstanceIdentifier path) { + final ActorSelection remoteTransaction = remoteTransactionFromIdentifier(path); + + Callable>> call = new Callable() { + + @Override public Optional> call() throws Exception { + Object response = actorContext + .executeRemoteOperation(remoteTransaction, new ReadData(path), + ActorContext.ASK_DURATION); + if(response instanceof ReadDataReply){ + ReadDataReply reply = (ReadDataReply) response; + //FIXME : A cast should not be required here ??? + return (Optional>) Optional.of(reply.getNormalizedNode()); + } + + return Optional.absent(); + } + }; + + ListenableFutureTask>> + future = ListenableFutureTask.create(call); + + //FIXME : Use a thread pool here + Executors.newSingleThreadExecutor().submit(future); + + return future; } @Override public void write(InstanceIdentifier path, NormalizedNode data) { - throw new UnsupportedOperationException("write"); + final ActorSelection remoteTransaction = remoteTransactionFromIdentifier(path); + remoteTransaction.tell(new WriteData(path, data), null); } @Override public void merge(InstanceIdentifier path, NormalizedNode data) { - throw new UnsupportedOperationException("merge"); + final ActorSelection remoteTransaction = remoteTransactionFromIdentifier(path); + remoteTransaction.tell(new MergeData(path, data), null); } @Override public void delete(InstanceIdentifier path) { - throw new UnsupportedOperationException("delete"); + final ActorSelection remoteTransaction = remoteTransactionFromIdentifier(path); + remoteTransaction.tell(new DeleteData(path), null); } @Override public DOMStoreThreePhaseCommitCohort ready() { - throw new UnsupportedOperationException("ready"); + List cohortPaths = new ArrayList<>(); + + for(ActorSelection remoteTransaction : remoteTransactionPaths.values()) { + Object result = actorContext.executeRemoteOperation(remoteTransaction, + new ReadyTransaction(), + ActorContext.ASK_DURATION + ); + + if(result instanceof ReadyTransactionReply){ + ReadyTransactionReply reply = (ReadyTransactionReply) result; + cohortPaths.add(reply.getCohortPath()); + } + } + + return new ThreePhaseCommitCohortProxy(cohortPaths); } @Override public Object getIdentifier() { - throw new UnsupportedOperationException("getIdentifier"); + return this.identifier; } @Override public void close() { - throw new UnsupportedOperationException("close"); + for(ActorSelection remoteTransaction : remoteTransactionPaths.values()) { + remoteTransaction.tell(new CloseTransaction(), null); + } + } + + private ActorSelection remoteTransactionFromIdentifier(InstanceIdentifier path){ + String shardName = shardNameFromIdentifier(path); + return remoteTransactionPaths.get(shardName); + } + + private String shardNameFromIdentifier(InstanceIdentifier path){ + return Shard.DEFAULT_NAME; } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java index 0123a70147..7c9e4f0665 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/RegisterChangeListener.java @@ -8,32 +8,34 @@ package org.opendaylight.controller.cluster.datastore.messages; +import akka.actor.ActorPath; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; -import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; public class RegisterChangeListener { - private final InstanceIdentifier path; - private final AsyncDataChangeListener> listener; - private final AsyncDataBroker.DataChangeScope scope; + private final InstanceIdentifier path; + private final ActorPath dataChangeListenerPath; + private final AsyncDataBroker.DataChangeScope scope; - public RegisterChangeListener(InstanceIdentifier path, AsyncDataChangeListener> listener, AsyncDataBroker.DataChangeScope scope) { - this.path = path; - this.listener = listener; - this.scope = scope; - } + public RegisterChangeListener(InstanceIdentifier path, + ActorPath dataChangeListenerPath, + AsyncDataBroker.DataChangeScope scope) { + this.path = path; + this.dataChangeListenerPath = dataChangeListenerPath; + this.scope = scope; + } - public InstanceIdentifier getPath() { - return path; - } + public InstanceIdentifier getPath() { + return path; + } - public AsyncDataChangeListener> getListener() { - return listener; - } - public AsyncDataBroker.DataChangeScope getScope() { - return scope; - } + public AsyncDataBroker.DataChangeScope getScope() { + return scope; + } + + public ActorPath getDataChangeListenerPath() { + return dataChangeListenerPath; + } } diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java new file mode 100644 index 0000000000..ba4d4de6bf --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/ActorContext.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore.utils; + +import akka.actor.ActorPath; +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import akka.util.Timeout; +import org.opendaylight.controller.cluster.datastore.messages.FindPrimary; +import org.opendaylight.controller.cluster.datastore.messages.PrimaryFound; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; +import scala.concurrent.duration.FiniteDuration; + +import java.util.concurrent.TimeUnit; + +import static akka.pattern.Patterns.ask; + +/** + * The ActorContext class contains utility methods which could be used by + * non-actors (like DistributedDataStore) to work with actors a little more + * easily. An ActorContext can be freely passed around to local object instances + * but should not be passed to actors especially remote actors + */ +public class ActorContext { + private static final Logger + LOG = LoggerFactory.getLogger(ActorContext.class); + + public static final FiniteDuration ASK_DURATION = Duration.create(5, TimeUnit.SECONDS); + public static final Duration AWAIT_DURATION = Duration.create(5, TimeUnit.SECONDS); + + private final ActorSystem actorSystem; + private final ActorRef shardManager; + + public ActorContext(ActorSystem actorSystem, ActorRef shardManager){ + this.actorSystem = actorSystem; + this.shardManager = shardManager; + } + + public ActorSystem getActorSystem() { + return actorSystem; + } + + public ActorRef getShardManager() { + return shardManager; + } + + public ActorSelection actorSelection(String actorPath){ + return actorSystem.actorSelection(actorPath); + } + + public ActorSelection actorSelection(ActorPath actorPath){ + return actorSystem.actorSelection(actorPath); + } + + + /** + * Finds the primary for a given shard + * + * @param shardName + * @return + */ + public ActorSelection findPrimary(String shardName) { + Object result = executeLocalOperation(shardManager, + new FindPrimary(shardName), ASK_DURATION); + + if(result instanceof PrimaryFound){ + PrimaryFound found = (PrimaryFound) result; + + LOG.error("Primary found {}", found.getPrimaryPath()); + + return actorSystem.actorSelection(found.getPrimaryPath()); + } + throw new RuntimeException("primary was not found"); + } + + /** + * Executes an operation on a local actor and wait for it's response + * @param actor + * @param message + * @param duration + * @return The response of the operation + */ + public Object executeLocalOperation(ActorRef actor, Object message, + FiniteDuration duration){ + Future future = + ask(actor, message, new Timeout(duration)); + + try { + return Await.result(future, AWAIT_DURATION); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Execute an operation on a remote actor and wait for it's response + * @param actor + * @param message + * @param duration + * @return + */ + public Object executeRemoteOperation(ActorSelection actor, Object message, + FiniteDuration duration){ + Future future = + ask(actor, message, new Timeout(duration)); + + try { + return Await.result(future, AWAIT_DURATION); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * Execute an operation on the primary for a given shard + *

+ * This method first finds the primary for a given shard ,then sends + * the message to the remote shard and waits for a response + *

+ * @param shardName + * @param message + * @param duration + * @throws java.lang.RuntimeException when a primary is not found or if the message to the remote shard fails or times out + * + * @return + */ + public Object executeShardOperation(String shardName, Object message, FiniteDuration duration){ + ActorSelection primary = findPrimary(shardName); + + return executeRemoteOperation(primary, message, duration); + } + +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java index 45492fd714..3a74a4ca76 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/DistributedDataStoreTest.java @@ -1,6 +1,13 @@ package org.opendaylight.controller.cluster.datastore; +import akka.actor.ActorRef; +import akka.actor.Props; import junit.framework.Assert; +import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply; +import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor; +import org.opendaylight.controller.cluster.datastore.utils.MockActorContext; +import org.opendaylight.controller.md.cluster.datastore.model.TestModel; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener; @@ -15,10 +22,24 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; public class DistributedDataStoreTest extends AbstractActorTest{ private DistributedDataStore distributedDataStore; + private MockActorContext mockActorContext; + private ActorRef doNothingActorRef; @org.junit.Before public void setUp() throws Exception { - distributedDataStore = new DistributedDataStore(getSystem(), "config"); + final Props props = Props.create(DoNothingActor.class); + + doNothingActorRef = getSystem().actorOf(props); + + mockActorContext = new MockActorContext(getSystem(), doNothingActorRef); + distributedDataStore = new DistributedDataStore(mockActorContext, "config"); + distributedDataStore.onGlobalContextUpdated( + TestModel.createTestContext()); + + // Make CreateTransactionReply as the default response. Will need to be + // tuned if a specific test requires some other response + mockActorContext.setExecuteShardOperationResponse( + new CreateTransactionReply(doNothingActorRef.path())); } @org.junit.After @@ -28,8 +49,9 @@ public class DistributedDataStoreTest extends AbstractActorTest{ @org.junit.Test public void testRegisterChangeListener() throws Exception { + mockActorContext.setExecuteShardOperationResponse(new RegisterChangeListenerReply(doNothingActorRef.path())); ListenerRegistration registration = - distributedDataStore.registerChangeListener(InstanceIdentifier.builder().build(), new AsyncDataChangeListener>() { + distributedDataStore.registerChangeListener(TestModel.TEST_PATH, new AsyncDataChangeListener>() { @Override public void onDataChanged(AsyncDataChangeEvent> change) { throw new UnsupportedOperationException("onDataChanged"); diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java index a9d8042ce2..48365fa1a0 100644 --- a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java @@ -63,7 +63,7 @@ public class ShardTest extends AbstractActorTest{ subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef()); - subject.tell(new RegisterChangeListener(InstanceIdentifier.builder().build(), noOpDataChangeListener() , AsyncDataBroker.DataChangeScope.BASE), getRef()); + subject.tell(new RegisterChangeListener(TestModel.TEST_PATH, getRef().path() , AsyncDataBroker.DataChangeScope.BASE), getRef()); final String out = new ExpectMsg("match hint") { // do not put code outside this method, will run afterwards @@ -97,4 +97,4 @@ public class ShardTest extends AbstractActorTest{ } }; } -} \ No newline at end of file +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java new file mode 100644 index 0000000000..6d057a4dbe --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/TransactionProxyTest.java @@ -0,0 +1,225 @@ +package org.opendaylight.controller.cluster.datastore; + +import akka.actor.ActorRef; +import akka.actor.Props; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.ListenableFuture; +import junit.framework.Assert; +import org.junit.Test; +import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction; +import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.DeleteData; +import org.opendaylight.controller.cluster.datastore.messages.MergeData; +import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply; +import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply; +import org.opendaylight.controller.cluster.datastore.messages.WriteData; +import org.opendaylight.controller.cluster.datastore.utils.ActorContext; +import org.opendaylight.controller.cluster.datastore.utils.DoNothingActor; +import org.opendaylight.controller.cluster.datastore.utils.MessageCollectorActor; +import org.opendaylight.controller.cluster.datastore.utils.MockActorContext; +import org.opendaylight.controller.md.cluster.datastore.model.TestModel; +import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort; +import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; + +import java.util.List; + +public class TransactionProxyTest extends AbstractActorTest { + + @Test + public void testRead() throws Exception { + final Props props = Props.create(DoNothingActor.class); + final ActorRef actorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse(new CreateTransactionReply(actorRef.path())); + actorContext.setExecuteRemoteOperationResponse("message"); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + + ListenableFuture>> read = + transactionProxy.read(TestModel.TEST_PATH); + + Optional> normalizedNodeOptional = read.get(); + + Assert.assertFalse(normalizedNodeOptional.isPresent()); + + actorContext.setExecuteRemoteOperationResponse(new ReadDataReply( + ImmutableNodes.containerNode(TestModel.TEST_QNAME))); + + read = transactionProxy.read(TestModel.TEST_PATH); + + normalizedNodeOptional = read.get(); + + Assert.assertTrue(normalizedNodeOptional.isPresent()); + } + + @Test + public void testWrite() throws Exception { + final Props props = Props.create(MessageCollectorActor.class); + final ActorRef actorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse(new CreateTransactionReply(actorRef.path())); + actorContext.setExecuteRemoteOperationResponse("message"); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + transactionProxy.write(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.NAME_QNAME)); + + ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class))); + Object messages = testContext + .executeLocalOperation(actorRef, "messages", + ActorContext.ASK_DURATION); + + Assert.assertNotNull(messages); + + Assert.assertTrue(messages instanceof List); + + List listMessages = (List) messages; + + Assert.assertEquals(1, listMessages.size()); + + Assert.assertTrue(listMessages.get(0) instanceof WriteData); + } + + @Test + public void testMerge() throws Exception { + final Props props = Props.create(MessageCollectorActor.class); + final ActorRef actorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse(new CreateTransactionReply(actorRef.path())); + actorContext.setExecuteRemoteOperationResponse("message"); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + transactionProxy.merge(TestModel.TEST_PATH, + ImmutableNodes.containerNode(TestModel.NAME_QNAME)); + + ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class))); + Object messages = testContext + .executeLocalOperation(actorRef, "messages", + ActorContext.ASK_DURATION); + + Assert.assertNotNull(messages); + + Assert.assertTrue(messages instanceof List); + + List listMessages = (List) messages; + + Assert.assertEquals(1, listMessages.size()); + + Assert.assertTrue(listMessages.get(0) instanceof MergeData); + } + + @Test + public void testDelete() throws Exception { + final Props props = Props.create(MessageCollectorActor.class); + final ActorRef actorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse(new CreateTransactionReply(actorRef.path())); + actorContext.setExecuteRemoteOperationResponse("message"); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + transactionProxy.delete(TestModel.TEST_PATH); + + ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class))); + Object messages = testContext + .executeLocalOperation(actorRef, "messages", + ActorContext.ASK_DURATION); + + Assert.assertNotNull(messages); + + Assert.assertTrue(messages instanceof List); + + List listMessages = (List) messages; + + Assert.assertEquals(1, listMessages.size()); + + Assert.assertTrue(listMessages.get(0) instanceof DeleteData); + } + + @Test + public void testReady() throws Exception { + final Props props = Props.create(DoNothingActor.class); + final ActorRef doNothingActorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse(new CreateTransactionReply(doNothingActorRef.path())); + actorContext.setExecuteRemoteOperationResponse(new ReadyTransactionReply(doNothingActorRef.path())); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + + DOMStoreThreePhaseCommitCohort ready = transactionProxy.ready(); + + Assert.assertTrue(ready instanceof ThreePhaseCommitCohortProxy); + + ThreePhaseCommitCohortProxy proxy = (ThreePhaseCommitCohortProxy) ready; + + Assert.assertTrue("No cohort paths returned", proxy.getCohortPaths().size() > 0); + + } + + @Test + public void testGetIdentifier(){ + final Props props = Props.create(DoNothingActor.class); + final ActorRef doNothingActorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse( + new CreateTransactionReply(doNothingActorRef.path())); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + Assert.assertNotNull(transactionProxy.getIdentifier()); + } + + @Test + public void testClose(){ + final Props props = Props.create(MessageCollectorActor.class); + final ActorRef actorRef = getSystem().actorOf(props); + + final MockActorContext actorContext = new MockActorContext(this.getSystem()); + actorContext.setExecuteShardOperationResponse(new CreateTransactionReply(actorRef.path())); + actorContext.setExecuteRemoteOperationResponse("message"); + + TransactionProxy transactionProxy = + new TransactionProxy(actorContext, + TransactionProxy.TransactionType.READ_ONLY); + + transactionProxy.close(); + + ActorContext testContext = new ActorContext(getSystem(), getSystem().actorOf(Props.create(DoNothingActor.class))); + Object messages = testContext + .executeLocalOperation(actorRef, "messages", + ActorContext.ASK_DURATION); + + Assert.assertNotNull(messages); + + Assert.assertTrue(messages instanceof List); + + List listMessages = (List) messages; + + Assert.assertEquals(1, listMessages.size()); + + Assert.assertTrue(listMessages.get(0) instanceof CloseTransaction); + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/DoNothingActor.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/DoNothingActor.java new file mode 100644 index 0000000000..819cfd08c7 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/DoNothingActor.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore.utils; + +import akka.actor.UntypedActor; + +public class DoNothingActor extends UntypedActor { + + @Override public void onReceive(Object message) throws Exception { + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MessageCollectorActor.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MessageCollectorActor.java new file mode 100644 index 0000000000..f75aa5445b --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MessageCollectorActor.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore.utils; + +import akka.actor.UntypedActor; + +import java.util.ArrayList; +import java.util.List; + +/** + * MessageCollectorActor collects messages as it receives them. It can send + * those collected messages to any sender which sends it the "messages" message + *

+ * This class would be useful as a mock to test whether messages were sent + * to a remote actor or not. + *

+ */ +public class MessageCollectorActor extends UntypedActor { + private List messages = new ArrayList<>(); + + @Override public void onReceive(Object message) throws Exception { + if(message instanceof String){ + if("messages".equals(message)){ + getSender().tell(messages, getSelf()); + } + } else { + messages.add(message); + } + } +} diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java new file mode 100644 index 0000000000..fe62516098 --- /dev/null +++ b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/utils/MockActorContext.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.cluster.datastore.utils; + + +import akka.actor.ActorRef; +import akka.actor.ActorSelection; +import akka.actor.ActorSystem; +import scala.concurrent.duration.FiniteDuration; + +public class MockActorContext extends ActorContext { + + private Object executeShardOperationResponse; + private Object executeRemoteOperationResponse; + private Object executeLocalOperationResponse; + + public MockActorContext(ActorSystem actorSystem) { + super(actorSystem, null); + } + + public MockActorContext(ActorSystem actorSystem, ActorRef shardManager) { + super(actorSystem, shardManager); + } + + + @Override public Object executeShardOperation(String shardName, + Object message, FiniteDuration duration) { + return executeShardOperationResponse; + } + + @Override public Object executeRemoteOperation(ActorSelection actor, + Object message, FiniteDuration duration) { + return executeRemoteOperationResponse; + } + + @Override public ActorSelection findPrimary(String shardName) { + return null; + } + + public void setExecuteShardOperationResponse(Object response){ + executeShardOperationResponse = response; + } + + public void setExecuteRemoteOperationResponse(Object response){ + executeRemoteOperationResponse = response; + } + + public void setExecuteLocalOperationResponse( + Object executeLocalOperationResponse) { + this.executeLocalOperationResponse = executeLocalOperationResponse; + } + + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java index 266b6976af..9c7deaf406 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataBrokerService.java @@ -21,8 +21,10 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; * * * @see DataProviderService + * @deprecated Replaced by {@link org.opendaylight.controller.md.sal.dom.api.DOMDataBroker} * */ +@Deprecated public interface DataBrokerService extends BrokerService, // DataReader, // @@ -36,5 +38,6 @@ public interface DataBrokerService extends @Override public CompositeNode readOperationalData(InstanceIdentifier path); + @Override DataModificationTransaction beginTransaction(); } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataChangeListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataChangeListener.java index 944ccc5b33..2bf949d208 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataChangeListener.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataChangeListener.java @@ -11,6 +11,11 @@ import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +/** + * + * @deprecated Replaced by {@link org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener} + */ +@Deprecated public interface DataChangeListener extends org.opendaylight.controller.md.sal.common.api.data.DataChangeListener { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java index 9706bbacdb..82e62255c3 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataModificationTransaction.java @@ -17,7 +17,17 @@ import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -public interface DataModificationTransaction extends DataModification{ +/** + * + * @deprecated Replaced by more specific + * {@link org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction} + * , + * {@link org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction} + * or {@link org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction} + * + */ +@Deprecated +public interface DataModificationTransaction extends DataModification { /** * Returns transaction identifier @@ -34,8 +44,8 @@ public interface DataModificationTransaction extends DataModification> commit(); @@ -43,6 +53,6 @@ public interface DataModificationTransaction extends DataModification registerListener(DataTransactionListener listener); public interface DataTransactionListener extends EventListener { - void onStatusUpdated(DataModificationTransaction transaction,TransactionStatus status); + void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status); } } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java index 0538660fd7..0810fa3e98 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataProviderService.java @@ -8,13 +8,19 @@ package org.opendaylight.controller.sal.core.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.common.DataStoreIdentifier; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.yangtools.concepts.Registration; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; -import org.opendaylight.controller.md.sal.common.api.data.DataReader;; +/** + * + * @deprecated Replaced by {@link org.opendaylight.controller.md.sal.dom.api.DOMDataBroker} + * + */ +@Deprecated public interface DataProviderService extends DataBrokerService, // DataProvisionService diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java index 58ffb38365..56d2e87c2c 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java @@ -12,6 +12,12 @@ import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; +/** + * + * @deprecated Replaced by org.opendaylight.controller.sal.core.spi.data.DOMStore. + * + */ +@Deprecated public interface DataStore extends // DataReader, DataCommitHandler { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java index 286770b048..e4e6e2f26d 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataValidator.java @@ -28,7 +28,10 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode; * {@link DataProviderService#addValidator(DataStoreIdentifier, DataValidator)} * * + * @deprecated Replaced by {@link org.opendaylight.controller.md.sal.common.api.data.AsyncConfigurationCommitHandler} + * **/ +@Deprecated public interface DataValidator extends Provider.ProviderFunctionality { /** diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java index 9318af529b..30dc1161bf 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java @@ -226,7 +226,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader { BitsTypeDefinition.Bit mockBit1 = mock( BitsTypeDefinition.Bit.class ); when( mockBit1.getName() ).thenReturn( "first" ); BitsTypeDefinition.Bit mockBit2 = mock( BitsTypeDefinition.Bit.class ); - when( mockBit1.getName() ).thenReturn( "second" ); + when( mockBit2.getName() ).thenReturn( "second" ); List bitList = Lists.newArrayList( mockBit1, mockBit2 ); List> types = Lists.>newArrayList(