1 Developing Apps on the OpenDaylight controller
2 ==============================================
4 This section provides information that is required to develop apps on
5 the OpenDaylight controller.
7 You can either develop apps within the controller using the model-driven
8 SAL (MD-SAL) archetype or develop external apps and use the RESTCONF to
9 communicate with the controller.
14 This section enables you to get started with app development within the
15 OpenDaylight controller. In this example, you perform the following
16 steps to develop an app.
18 1. Create a local repository for the code using a simple build process.
20 2. Start the OpenDaylight controller.
22 3. Test a simple remote procedure call (RPC) which you have created
23 based on the principle of *hello world*.
28 This example requires the following.
30 - A development environment with following set up and working correctly
33 - Maven 3.5.2 or later
35 - Java 11-compliant JDK
37 - An appropriate Maven settings.xml file. A simple way to get the
38 default OpenDaylight settings.xml file is:
42 cp -n ~/.m2/settings.xml{,.orig} ; wget -q -O - https://raw.githubusercontent.com/opendaylight/odlparent/master/settings.xml > ~/.m2/settings.xml
46 If you are using Linux or Mac OS X as your development OS, your
47 local repository is ~/.m2/repository. For other platforms the local
48 repository location will vary.
50 Building an example module
51 --------------------------
53 To develop an app perform the following steps.
55 1. Create an *Example* project using Maven and an archetype called the
56 *opendaylight-startup-archetype*. If you are downloading this project
57 for the first time, then it will take sometime to pull all the code
58 from the remote repository.
62 mvn archetype:generate -DarchetypeGroupId=org.opendaylight.archetypes -DarchetypeArtifactId=opendaylight-startup-archetype \
63 -DarchetypeCatalog=remote -DarchetypeVersion=<VERSION>
65 The correct VERSION depends on desired Simultaneous Release:
67 .. list-table:: Archetype versions
71 * - OpenDaylight Simultaneous Release
72 - opendaylight-startup-archetype version
74 * - Magnesium Development
77 2. Update the properties values as follows. Ensure that the values for
78 the *groupId* and the *artifactId* are in lower case.
82 Define value for property 'groupId': : org.opendaylight.example
83 Define value for property 'artifactId': : example
84 Define value for property 'version': 1.0-SNAPSHOT: : 1.3.0-SNAPSHOT
85 Define value for property 'package': org.opendaylight.example: :
86 Define value for property 'classPrefix': ${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)}
87 Define value for property 'copyright': : Copyright (c) 2020 Yoyodyne, Inc.
89 3. Accept the default value of classPrefix that is,
90 ``(${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)})``.
91 The classPrefix creates a Java Class Prefix by capitalizing the first
92 character of the artifactId.
96 This will create a directory with the name given to artifactId in the above dialog, with
97 the following contents.
113 4. Build the *example* project.
117 Depending on your development machine’s specification this might
118 take a little while. Ensure that you are in the project’s root
119 directory, ``example/``, and then issue the build command, shown
126 5. Start the *example* project for the first time.
130 cd karaf/target/assembly/bin
134 6. Wait for the karaf cli that appears as follows. Wait for OpenDaylight
135 to fully load all the components. This can take a minute or two after
136 the prompt appears. Check the CPU on your dev machine, specifically
137 the Java process to see when it calms down.
141 opendaylight-user@root>
143 7. Verify if the “example” module is built and search for the log entry
144 which includes the entry *ExampleProvider Session Initiated*.
148 log:display | grep Example
150 8. Shutdown OpenDaylight through the console by using the following
157 Defining a Simple Hello World RPC
158 ---------------------------------
160 1. | Build a *hello* example from the Maven archetype *opendaylight-startup-archetype*,
163 2. Now view the entry point to understand where the log line came from. The
164 entry point is in the impl project:
168 impl/src/main/java/org/opendaylight/hello/impl/HelloProvider.java
170 3. Add any new things that you are doing in your implementation by
171 using the ``HelloProvider.init`` method. It's analogous to
177 * Method called when the blueprint container is created.
180 LOG.info("HelloProvider Session Initiated");
183 Add a simple HelloWorld RPC API
184 -------------------------------
186 1. Navigate to the file.
190 api/src/main/yang/hello.yang
192 2. Edit this file as follows. In the following example, we are adding
193 the code in a YANG module to define the *hello-world* RPC:
199 namespace "urn:opendaylight:params:xml:ns:yang:hello";
201 revision "2019-11-27" {
202 description "Initial revision of hello model";
218 3. Return to the hello/api directory and build your API as follows.
225 Implement the HelloWorld RPC API
226 --------------------------------
228 1. Define the HelloService, which is invoked through the *hello-world*
233 cd ../impl/src/main/java/org/opendaylight/hello/impl/
235 2. Create a new file called ``HelloWorldImpl.java`` and add in the code
240 package org.opendaylight.hello.impl;
242 import com.google.common.util.concurrent.ListenableFuture;
243 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev191127.HelloService;
244 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev191127.HelloWorldInput;
245 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev191127.HelloWorldOutput;
246 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev191127.HelloWorldOutputBuilder;
247 import org.opendaylight.yangtools.yang.common.RpcResult;
248 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
250 public class HelloWorldImpl implements HelloService {
252 public ListenableFuture<RpcResult<HelloWorldOutput>> helloWorld(HelloWorldInput input) {
253 HelloWorldOutputBuilder helloBuilder = new HelloWorldOutputBuilder();
254 helloBuilder.setGreeting("Hello " + input.getName());
255 return RpcResultBuilder.success(helloBuilder.build()).buildFuture();
259 3. The ``HelloProvider.java`` file is in the current directory. Register the
260 RPC that you created in the *hello.yang* file in the
261 ``HelloProvider.java`` file. You can either edit the ``HelloProvider.java``
262 to match what is below or you can simple replace it with the code
268 * Copyright(c) Yoyodyne, Inc. and others. All rights reserved.
270 * This program and the accompanying materials are made available under the
271 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
272 * and is available at http://www.eclipse.org/legal/epl-v10.html
274 package org.opendaylight.hello.impl;
276 import org.opendaylight.mdsal.binding.api.DataBroker;
277 import org.opendaylight.mdsal.binding.api.RpcProviderService;
278 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev191127.HelloService;
279 import org.opendaylight.yangtools.concepts.ObjectRegistration;
280 import org.slf4j.Logger;
281 import org.slf4j.LoggerFactory;
283 public class HelloProvider {
285 private static final Logger LOG = LoggerFactory.getLogger(HelloProvider.class);
287 private final DataBroker dataBroker;
288 private ObjectRegistration<HelloService> helloService;
289 private RpcProviderService rpcProviderService;
291 public HelloProvider(final DataBroker dataBroker, final RpcProviderService rpcProviderService) {
292 this.dataBroker = dataBroker;
293 this.rpcProviderService = rpcProviderService;
297 * Method called when the blueprint container is created.
300 LOG.info("HelloProvider Session Initiated");
301 helloService = rpcProviderService.registerRpcImplementation(HelloService.class, new HelloWorldImpl());
305 * Method called when the blueprint container is destroyed.
307 public void close() {
308 LOG.info("HelloProvider Closed");
309 if (helloService != null) {
310 helloService.close();
315 4. Optionally, you can also build the Java classes which will register
316 the new RPC. This is useful to test the edits you have made to
317 HelloProvider.java and HelloWorldImpl.java.
321 cd ../../../../../../../
324 5. Return to the top level directory
330 6. Build the entire *hello* again, which will pickup the changes you
331 have made and build them into your project:
337 Execute the *hello* project for the first time
338 ----------------------------------------------
344 cd ../karaf/target/assembly/bin
347 2. Wait for the project to load completely. Then view the log to see the
348 loaded *Hello* Module:
352 log:display | grep Hello
354 Test the *hello-world* RPC via REST
355 -----------------------------------
357 There are a lot of ways to test your RPC. Following are some examples.
359 1. Using the API Explorer through HTTP
361 2. Using a browser REST client
363 Using the API Explorer through HTTP
364 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
366 1. | Navigate to `apidoc
367 UI <http://localhost:8181/apidoc/explorer/index.html>`__ with your
369 | NOTE: In the URL mentioned above, Change *localhost* to the IP/Host
370 name to reflect your development machine’s network address.
382 POST /operations/hello:hello-world
384 4. Provide the required value.
388 {"hello:input": { "name":"Your Name"}}
392 6. Enter the username and password.
393 By default the credentials are *admin/admin*.
395 7. In the response body you should see.
401 "greeting": "Hello Your Name"
405 Using a browser REST client
406 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
408 | For example, use the following information in the Firefox plugin
410 `https://github.com/chao/RESTClient <https://github.com/chao/RESTClient>`_
414 POST: http://localhost:8181/restconf/operations/hello:hello-world
420 Accept: application/json
421 Content-Type: application/json
422 Authorization: Basic admin admin
433 In the response body you should see:
439 "greeting": "Hello Your Name"
446 If you get a response code 501 while attempting to POST
447 /operations/hello:hello-world, check the file: HelloProvider.java and
448 make sure the helloService member is being set. By not invoking
449 "session.addRpcImplementation()" the REST API will be unable to map
450 /operations/hello:hello-world url to HelloWorldImpl.