3e05f17238415f3f31f8aae3cba2c91561471176
[controller.git] / opendaylight / md-sal / sal-binding-api / src / main / java / org / opendaylight / controller / sal / binding / api / RpcProviderRegistry.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.sal.binding.api;
9
10 import org.opendaylight.controller.md.sal.common.api.routing.RouteChangePublisher;
11 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
12 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
13 import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
14 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
15 import org.opendaylight.yangtools.yang.binding.RpcService;
16
17 /**
18  * Provides a registry for Remote Procedure Call (RPC) service implementations. The RPCs are
19  * defined in YANG models.
20  *
21  * <p>
22  * There are 2 types of RPCs:
23  * <ul>
24  * <li>Global</li>
25  * <li>Routed</li>
26  * </ul>
27  *
28  * <h2>Global RPC</h2>
29  *
30  * <p>
31  * An RPC is global if there is intended to be only 1 registered implementation. A global RPC is not
32  * explicitly declared as such, essentially any RPC that is not defined to be routed is considered global.
33  *
34  * <p>
35  * Global RPCs are registered using the
36  * {@link #addRpcImplementation(Class, RpcService)} method.
37  *
38  * <h2>Routed RPC</h2>
39  *
40  * <p>
41  * MD-SAL supports routing of RPC between multiple implementations where the appropriate
42  * implementation is selected at run time based on the content of the RPC message as described in
43  * YANG model.
44  *
45  * <p>
46  * RPC routing is based on:
47  * <ul>
48  * <li><b>Route identifier</b> -
49  * An {@link org.opendaylight.yangtools.yang.binding.InstanceIdentifier InstanceIdentifier} value
50  * which is part of the RPC input. This value is used to select the correct
51  * implementation at run time.</li>
52  * <li><b>Context Type</b> - A YANG-defined construct which constrains the subset of
53  * valid route identifiers for a particular RPC.</li>
54  * </ul>
55  *
56  * <h3>Context type</h3>
57  *
58  * <p>
59  * A context type is modeled in YANG using a combination of a YANG <code>identity</code>
60  * and Opendaylight specific extensions from <code>yang-ext</code> module. These extensions are:
61  * <ul>
62  * <li><b>context-instance</b> - This is used in the data tree part of a YANG model to
63  * define a context type that associates nodes with a specified context <code>identity</code>.
64  * Instance identifiers that reference these nodes are valid route identifiers for RPCs that
65  * reference this context type.</li>
66  * <li><b>context-reference</b> - This is used in RPC input to mark a leaf of type
67  * <code>instance-identifier</code> as a reference to the particular context type defined by the
68  * specified context <code>identity</code>. The value of this
69  * leaf is used by the RPC broker at run time to route the RPC request to the correct implementation.
70  * Note that <code>context-reference</code> may only be used on leaf elements of type
71  * <code>instance-identifier</code> or a type derived from <code>instance-identifier</code>.</li>
72  * </ul>
73  *
74  * <p><br>
75  * <h4>1. Defining a Context Type</h4>
76  *
77  * <p>
78  * The following snippet declares a simple YANG <code>identity</code> named <code>example-context</code>:
79  *
80  * {@code
81  * module example {
82  *     ...
83  *     identity example-context {
84  *          description "Identity used to define an example-context type";
85  *     }
86  *     ...
87  * }
88  * }
89  *
90  * <p>
91  * We then use the declared identity to define a context type by using it in combination
92  * with the <code>context-instance</code> YANG extension. We'll associate the context type
93  * with a list element in the data tree. This defines the set of nodes whose instance
94  * identifiers are valid for the <code>example-context</code> context type.
95  *
96  * <p>
97  * The following YANG snippet imports the <code>yang-ext</code> module and defines the list
98  * element named <code>item</code> inside a container named <code>foo</code>:
99  *
100  * {@code
101  * module foo {
102  *     ...
103  *     import yang-ext {prefix ext;}
104  *     ...
105  *     container foo {
106  *          list item {
107  *              key "id";
108  *              leaf id {type string;}
109  *              ext:context-instance "example-context";
110  *          }
111  *     }
112  *     ...
113  * }
114  * }
115  *
116  * <p>
117  * The statement <code>ext:context-instance "example-context";</code> inside the list element
118  * declares that any instance identifier referencing <code>item</code> in the data
119  * tree is valid for <code>example-context</code>. For example, the following instance
120  * identifier:
121  * <pre>
122  *     InstanceIdentifier.create(Foo.class).child(Item.class,new ItemKey("Foo"))
123  * </pre>
124  * is valid for <code>example-context</code>. However the following:
125  * <pre>
126  *     InstanceIdentifier.create(Example.class)
127  * </pre>
128  * is not valid.
129  *
130  * <p>
131  * So using an <code>identity</code> in combination with <code>context-instance</code> we
132  * have effectively defined a context type that can be referenced in a YANG RPC input.
133  *
134  * <p>
135  * <h5>2. Defining an RPC to use the Context Type</h5>
136  *
137  * <p>
138  * To define an RPC to be routed based on the context type we need to add an input leaf element
139  * that references the context type which will hold an instance identifier value to be
140  * used to route the RPC.
141  *
142  * <p>
143  * The following snippet defines an RPC named <code>show-item</code> with 2 leaf elements
144  * as input: <code>item</code> of type <code>instance-identifier</code> and <code>description</code>:
145  *
146  * <pre>
147  * module foo {
148  *      ...
149  *      import yang-ext {prefix ext;}
150  *      ...
151  *      rpc show-item {
152  *          input {
153  *              leaf item {
154  *                  type instance-identifier;
155  *                  ext:context-reference example-context;
156  *              }
157  *              leaf description {
158  *                  type "string";
159  *              }
160  *          }
161  *      }
162  * }
163  * </pre>
164  *
165  * <p>
166  * We mark the <code>item</code> leaf with a <code>context-reference</code> statement that
167  * references the <code>example-context</code> context type. RPC calls will then be routed
168  * based on the instance identifier value contained in <code>item</code>. Only instance
169  * identifiers that point to a <code>foo/item</code> node are valid as input.
170  *
171  * <p>
172  * The generated RPC Service interface for the module is:
173  *
174  * <pre>
175  * interface FooService implements RpcService {
176  *      Future&lt;RpcResult&lt;Void&gt;&gt; showItem(ShowItemInput input);
177  * }
178  * </pre>
179  *
180  * <p>
181  * For constructing the RPC input, there are generated classes ShowItemInput and ShowItemInputBuilder.
182  *
183  * <h5>3. Registering a routed RPC implementation</h5>
184  *
185  * <p>
186  * To register a routed implementation for the <code>show-item</code> RPC, we must use the
187  * {@link #addRoutedRpcImplementation(Class, RpcService)} method. This
188  * will return a {@link RoutedRpcRegistration} instance which can then be used to register /
189  * unregister routed paths associated with the registered implementation.
190  *
191  * <p>
192  * The following snippet registers <code>myImpl</code> as the RPC implementation for an
193  * <code>item</code> with key <code>"foo"</code>:
194  * <pre>
195  * // Create the instance identifier path for item "foo"
196  * InstanceIdentifier path = InstanceIdentifier.create(Foo.class).child(Item.class, new ItemKey(&quot;foo&quot;));
197  *
198  * // Register myImpl as the implementation for the FooService RPC interface
199  * RoutedRpcRegistration reg = rpcRegistry.addRoutedRpcImplementation(FooService.class, myImpl);
200  *
201  * // Now register for the context type and specific path ID. The context type is specified by the
202  * // YANG-generated class for the example-context identity.
203  * reg.registerPath(ExampleContext.class, path);
204  * </pre>
205  *
206  * <p>
207  * It is also possible to register the same implementation for multiple paths:
208  *
209  * <pre>
210  * InstanceIdentifier one = InstanceIdentifier.create(Foo.class).child(Item.class, new ItemKey(&quot;One&quot;));
211  * InstanceIdentifier two = InstanceIdentifier.create(Foo.class).child(Item.class, new ItemKey(&quot;Two&quot;));
212  *
213  * RoutedRpcRegistration reg = rpcRegistry.addRoutedRpcImplementation(FooService.class, myImpl);
214  * reg.registerPath(ExampleContext.class, one);
215  * reg.registerPath(ExampleContext.class, two);
216  * </pre>
217  *
218  * <p>
219  * When another client invokes the <code>showItem(ShowItemInput)</code> method on the proxy instance
220  * retrieved via {@link RpcConsumerRegistry#getRpcService(Class)}, the proxy will inspect the
221  * arguments in ShowItemInput, extract the InstanceIdentifier value of the <code>item</code> leaf and select
222  * the implementation whose registered path matches the InstanceIdentifier value of the <code>item</code> leaf.
223  *
224  * <p><br>
225  * <h2>Notes for RPC Implementations</h2>
226  *
227  * <p>
228  * <h3>RpcResult</h3>
229  *
230  * <p>
231  * The generated interfaces require implementors to return
232  *  {@link java.util.concurrent.Future Future}&lt;{@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult}
233  *  &lt;{RpcName}Output&gt;&gt; instances.
234  *
235  * <p>
236  * Implementations should do processing of RPC calls asynchronously and update the
237  * returned {@link java.util.concurrent.Future Future} instance when processing is complete.
238  * However using {@link com.google.common.util.concurrent.Futures#immediateFuture(Object) Futures.immediateFuture}
239  * is valid only if the result is immediately available and asynchronous processing is unnecessary and
240  * would only introduce additional complexity.
241  *
242  * <p>
243  * The {@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult} is a generic
244  * wrapper for the RPC output payload, if any, and also allows for attaching error or
245  * warning information (possibly along with the payload) should the RPC processing partially
246  * or completely fail. This is intended to provide additional human readable information
247  * for users of the API and to transfer warning / error information across the system
248  * so it may be visible via other external APIs such as Restconf.
249  *
250  * <p>
251  * It is recommended to use the {@link org.opendaylight.yangtools.yang.common.RpcResult RpcResult}
252  * for conveying appropriate error information
253  * on failure rather than purposely throwing unchecked exceptions if at all possible.
254  * While unchecked exceptions will fail the returned {@link java.util.concurrent.Future Future},
255  * using the intended RpcResult to convey the error information is more user-friendly.
256  *
257  * @deprecated Use {@link org.opendaylight.mdsal.binding.api.RpcProviderService} instead
258  */
259 @Deprecated
260 public interface RpcProviderRegistry extends RpcConsumerRegistry,
261         RouteChangePublisher<RpcContextIdentifier, InstanceIdentifier<?>> {
262     /**
263      * Registers a global implementation of the provided RPC service interface.
264      * All methods of the interface are required to be implemented.
265      *
266      * @param serviceInterface the YANG-generated interface of the RPC Service for which to register.
267      * @param implementation "the implementation of the RPC service interface.
268      * @return an RpcRegistration instance that should be used to unregister the RPC implementation
269      *         when no longer needed by calling {@link RpcRegistration#close()}.
270      *
271      * @throws IllegalStateException
272      *             if the supplied RPC interface is a routed RPC type.
273      */
274     <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> serviceInterface, T implementation)
275             throws IllegalStateException;
276
277     /**
278      * Registers an implementation of the given routed RPC service interface.
279      *
280      * <p>
281      * See the {@link RpcProviderRegistry class} documentation for information and example on how to use routed RPCs.
282      *
283      * @param serviceInterface the YANG-generated interface of the RPC Service for which to register.
284      * @param implementation the implementation instance to register.
285      * @return a RoutedRpcRegistration instance which can be used to register paths for the RPC
286      *         implementation via invoking RoutedRpcRegistration#registerPath(Class, InstanceIdentifer).
287      *         {@link RoutedRpcRegistration#close()} should be called to unregister the implementation
288      *         and all previously registered paths when no longer needed.
289      * @throws IllegalStateException if the supplied RPC interface is not a routed RPC type.
290      */
291     <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> serviceInterface,
292             T implementation) throws IllegalStateException;
293 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.