/* * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sal.binding.api; import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration; import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration; import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.binding.RpcService; /** * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are * defined in YANG models. *
* There are 2 types of RPCs: *
* 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. * *
* 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: *
* 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:
*
identity
.
* Instance identifiers that reference these nodes are valid route identifiers for RPCs that
* reference this context 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
.*
* 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.
*
*
* 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. * *
* 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.
*
*
* 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
* See the {@link RpcProviderRegistry class} documentation for information and example on
* how to use routed RPCs.
*
* @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.
*/