1 Developing apps on the OpenDaylight controller
2 ==============================================
4 This section provides the information required to develop apps on
5 an OpenDaylight controller. Apps can be developed either within the
6 controller using a Model-Driven SAL (MD-SAL) archetype or via an
7 external app using the RESTCONF API to communicate with the controller.
12 This section starts app development within an OpenDaylight controller.
14 Perform the following steps to develop an app:
16 1. Create a local repository for the code using a simple build process.
18 2. Start the OpenDaylight controller.
20 3. Test a simple remote procedure call (RPC) that was created based on
21 the principle of *hello world*.
26 The following are the prerequisites for app creation:
28 - A development environment with the following setup and working correctly
31 - Maven 3.8.3 or later
33 - Java 11-compliant JDK
35 - An appropriate Maven settings.xml file. One way to get the
36 default OpenDaylight settings.xml file is:
40 cp -n ~/.m2/settings.xml{,.orig}
41 wget -q -O - https://raw.githubusercontent.com/opendaylight/odlparent/master/settings.xml > ~/.m2/settings.xml
45 For Linux or Mac OS X development operating systems, the default local
46 repository is ~/.m2/repository. For other platforms, the default local
47 repository location varies.
49 Building an Example module
50 --------------------------
52 Perform the following steps to develop an app:
54 1. Create an *Example* project using Maven and an archetype called the
55 *opendaylight-startup-archetype*. For first time downloads, this project
56 will take some time to pull all the code from the remote repository.
60 mvn archetype:generate -DarchetypeGroupId=org.opendaylight.archetypes \
61 -DarchetypeArtifactId=opendaylight-startup-archetype \
62 -DarchetypeCatalog=remote -DarchetypeVersion=<VERSION>
64 The correct VERSION depends on desired Simultaneous Release:
66 .. list-table:: Archetype versions
70 * - OpenDaylight Simultaneous Release
71 - ``opendaylight-startup-archetype`` version
73 * - Magnesium Development
76 * - Aluminium Development
79 2. Update the properties values. Ensure that the values for the ``groupId`` and
80 the ``artifactId`` are in lower case.
84 Define value for property 'groupId': org.opendaylight.example
85 Define value for property 'artifactId': example
86 [INFO] Using property: version = 0.1.0-SNAPSHOT
87 Define value for property 'package' org.opendaylight.example: :
88 Define value for property 'classPrefix' Example: :
89 Define value for property 'copyright': Copyright (c) 2021 Yoyodyne, Inc.
90 [INFO] Using property: copyrightYear = 2021
92 3. Accept the default value of ``classPrefix``, that is:
93 ``(${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)})``.
94 The ``classPrefix`` creates a Java Class Prefix by capitalizing the first
95 character of the ``artifactId``.
99 This will create a directory with the name given to ``artifactId``
100 in the above dialog, with the following contents.
115 4. Build the *example* project.
119 Build time varies depending on the development machine specification.
120 Ensure that you are in the project’s root directory (example/,) and then
121 issue the the following build command.
127 5. Initialize the *example* project.
131 cd karaf/target/assembly/bin
135 6. Wait for the Karaf CLI to appear. Wait for OpenDaylight to fully load
136 all components. This can take a minute or two after the prompt appears.
137 Check the CPU on the dev machine, specifically the Java process to see
142 opendaylight-user@root>
144 7. Verify if the “example” module is built and search for the log entry
145 that includes the entry *ExampleProvider Session Initiated*.
149 log:display | grep Example
151 8. Enter the following command to shutdown OpenDaylight through the console:
157 Defining a simple HelloWorld RPC
158 --------------------------------
160 1. Build a *hello* example from the Maven archetype *opendaylight-startup-archetype*,
161 same as what was done in the previous steps.
163 2. View the entry point to understand the origins of the log line. The
164 entry point starts in the ``./impl`` project:
168 impl/src/main/java/org/opendaylight/hello/impl/HelloProvider.java
170 3. Add any new content that you are doing in your implementation by
171 using the ``HelloProvider.init`` method. It is analogous to an Activator.
176 * Method called when the blueprint container is created.
179 LOG.info("HelloProvider Session Initiated");
182 Add a simple HelloWorld RPC API
183 -------------------------------
185 1. Navigate to ``api/src/main/yang``.
189 cd api/src/main/yang/
191 2. Edit the ``hello.yang`` file. In the following example, we are adding
192 the code in a YANG module to define the *hello-world* RPC:
198 namespace "urn:opendaylight:params:xml:ns:yang:hello";
201 revision "2021-03-21" {
202 description "Initial revision of hello model";
219 3. Return to the ``hello/api`` directory. Do the following to build the API:
226 Implement the HelloWorld RPC API
227 --------------------------------
229 1. Define the HelloService that was invoked through the *hello-world* API.
233 cd ../impl/src/main/java/org/opendaylight/hello/impl/
235 The ``HelloProvider.java`` file is in the current directory. Register the
236 RPC that you created in the *hello.yang* file in the
237 ``HelloProvider.java`` file. You can either edit the ``HelloProvider.java``
238 to match what is below or simply replace it with the code below.
243 * Copyright © 2021 Copyright (c) 2021 Yoyodyne, Inc. and others. All rights reserved.
245 * This program and the accompanying materials are made available under the
246 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
247 * and is available at http://www.eclipse.org/legal/epl-v10.html
249 package org.opendaylight.hello.impl;
251 import com.google.common.util.concurrent.ListenableFuture;
252 import org.opendaylight.mdsal.binding.api.DataBroker;
253 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev210321.HelloService;
254 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev210321.HelloWorldInput;
255 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev210321.HelloWorldOutput;
256 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev210321.HelloWorldOutputBuilder;
257 import org.opendaylight.yangtools.yang.common.RpcResult;
258 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
259 import org.slf4j.Logger;
260 import org.slf4j.LoggerFactory;
262 public class HelloProvider implements HelloService {
264 private static final Logger LOG = LoggerFactory.getLogger(HelloProvider.class);
266 private final DataBroker dataBroker;
268 public HelloProvider(final DataBroker dataBroker) {
269 this.dataBroker = dataBroker;
273 public ListenableFuture<RpcResult<HelloWorldOutput>> helloWorld(HelloWorldInput input) {
274 HelloWorldOutputBuilder helloBuilder = new HelloWorldOutputBuilder();
275 helloBuilder.setGreeting("Hello " + input.getName());
276 return RpcResultBuilder.success(helloBuilder.build()).buildFuture();
280 * Method called when the blueprint container is created.
283 LOG.info("HelloProvider Session Initiated");
287 * Method called when the blueprint container is destroyed.
289 public void close() {
290 LOG.info("HelloProvider Closed");
294 2. Update Blueprint XML file.
298 cd ../../../../../resources/OSGI-INF/blueprint/
300 You can either edit the ``impl-blueprint.xml`` to match what is below
301 or simply replace it with the XML below.
305 <?xml version="1.0" encoding="UTF-8"?>
306 <!-- vi: set et smarttab sw=4 tabstop=4: -->
308 Copyright © 2021 Copyright (c) 2021 Yoyodyne, Inc. and others. All rights reserved.
310 This program and the accompanying materials are made available under the
311 terms of the Eclipse Public License v1.0 which accompanies this distribution,
312 and is available at http://www.eclipse.org/legal/epl-v10.html
314 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
315 xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
316 odl:use-default-for-reference-types="true">
318 <reference id="dataBroker"
319 interface="org.opendaylight.mdsal.binding.api.DataBroker"
320 odl:type="default" />
323 class="org.opendaylight.hello.impl.HelloProvider"
324 init-method="init" destroy-method="close">
325 <argument ref="dataBroker" />
328 <odl:rpc-implementation ref="provider"/>
332 3. Optionally, users can build the Java classes that will register
333 the new RPC. This is useful to test the edits that were made to
334 ``HelloProvider.java``.
341 4. Return to the top level directory
347 5. Build the entire *hello* again. This will pickup the new changes,
348 and then build them into the project:
354 Execute the *hello* project for the first time
355 ----------------------------------------------
361 cd karaf/target/assembly/bin
364 2. Wait for the project to load completely. Then view the log to see the
365 loaded *Hello* Module:
369 log:display | grep Hello
371 Test the *hello-world* RPC via REST
372 -----------------------------------
374 There are a lot of ways to test a RPC. The following are a few examples.
376 1. Using the API Explorer through HTTP
378 2. Using a browser REST client
380 Using the API Explorer through HTTP
381 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
383 1. Navigate to `apidoc
384 UI <http://localhost:8181/apidoc/explorer/index.html>`__ with your
389 In the URL link for *apidoc UI*, change *localhost* to the IP/Host
390 name to reflect your development machine’s network address.
392 2. Enter the username and password.
393 By default the credentials are *admin/admin*.
405 POST /rests/operations/hello:hello-world
407 5. Click on the **Try it out** button.
409 6. Provide the required request input.
420 7. Select **application/json** for *Media type* in the *Responses* section.
422 8. Click the **Execute** button.
424 9. In the response body you should see
430 "greeting": "Hello Your Name"
435 Using a browser REST client
436 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
438 Next, use a browser to POST a REST client request.
439 For example, use the following information in the Firefox plugin:
441 *RESTClient* `https://github.com/chao/RESTClient <https://github.com/chao/RESTClient>`_
445 POST: http://localhost:8181/rests/operations/hello:hello-world
451 Accept: application/json
452 Content-Type: application/json
453 Authorization: Basic admin admin
465 In the response body you should see:
471 "greeting": "Hello Your Name"
478 If you get a response code 500 while attempting to
479 ``POST /rests/operations/hello:hello-world``, check the file:
480 ``impl/src/main/resources/OSGI-INF/blueprint/impl-blueprint.xml``
481 and make sure the following element is specified for ``<blueprint>``.
485 <odl:rpc-implementation ref="provider"/>