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 the groupId and
78 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.0.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) 2015 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 In this scenario, the classPrefix used is "Example". Create a
97 top-level directory for the archetype.
111 4. Build the *example* project.
115 Depending on your development machine’s specification this might
116 take a little while. Ensure that you are in the project’s root
117 directory, example/, and then issue the build command, shown
124 5. Start the *example* project for the first time.
128 cd karaf/target/assembly/bin
132 6. Wait for the karaf cli that appears as follows. Wait for OpenDaylight
133 to fully load all the components. This can take a minute or two after
134 the prompt appears. Check the CPU on your dev machine, specifically
135 the Java process to see when it calms down.
139 opendaylight-user@root>
141 7. Verify if the “example” module is built and search for the log entry
142 which includes the entry *ExampleProvider Session Initiated*.
146 log:display | grep Example
148 8. Shutdown OpenDaylight through the console by using the following
155 Defining a Simple Hello World RPC
156 ---------------------------------
158 1. | Build a *hello* example from the Maven archetype *opendaylight-startup-archetype*,
161 2. Now view the entry point to understand where the log line came from. The
162 entry point is in the impl project:
166 impl/src/main/java/org/opendaylight/hello/impl/HelloProvider.java
168 3. Add any new things that you are doing in your implementation by
169 using the HelloProvider.onSessionInitiate method. It's analogous to
175 public void onSessionInitiated(ProviderContext session) {
176 LOG.info("HelloProvider Session Initiated");
179 Add a simple HelloWorld RPC API
180 -------------------------------
182 1. Navigate to the file.
187 api/src/main/yang/hello.yang
189 2. Edit this file as follows. In the following example, we are adding
190 the code in a YANG module to define the *hello-world* RPC:
196 namespace "urn:opendaylight:params:xml:ns:yang:hello";
198 revision "2015-01-05" {
199 description "Initial revision of hello model";
215 3. Return to the hello/api directory and build your API as follows.
222 Implement the HelloWorld RPC API
223 --------------------------------
225 1. Define the HelloService, which is invoked through the *hello-world*
230 cd ../impl/src/main/java/org/opendaylight/hello/impl/
232 2. Create a new file called HelloWorldImpl.java and add in the code
237 package org.opendaylight.hello.impl;
239 import com.google.common.util.concurrent.ListenableFuture;
240 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloService;
241 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldInput;
242 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldOutput;
243 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldOutputBuilder;
244 import org.opendaylight.yangtools.yang.common.RpcResult;
245 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
247 public class HelloWorldImpl implements HelloService {
250 public ListenableFuture<RpcResult<HelloWorldOutput>> helloWorld(HelloWorldInput input) {
251 HelloWorldOutputBuilder helloBuilder = new HelloWorldOutputBuilder();
252 helloBuilder.setGreeting("Hello " + input.getName());
253 return RpcResultBuilder.success(helloBuilder.build()).buildFuture();
257 3. The HelloProvider.java file is in the current directory. Register the
258 RPC that you created in the *hello.yang* file in the
259 HelloProvider.java file. You can either edit the HelloProvider.java
260 to match what is below or you can simple replace it with the code
266 * Copyright(c) Yoyodyne, Inc. and others. All rights reserved.
268 * This program and the accompanying materials are made available under the
269 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
270 * and is available at http://www.eclipse.org/legal/epl-v10.html
272 package org.opendaylight.hello.impl;
274 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
275 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
276 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
277 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloService;
278 import org.slf4j.Logger;
279 import org.slf4j.LoggerFactory;
281 public class HelloProvider implements BindingAwareProvider, AutoCloseable {
283 private static final Logger LOG = LoggerFactory.getLogger(HelloProvider.class);
284 private RpcRegistration<HelloService> helloService;
287 public void onSessionInitiated(ProviderContext session) {
288 LOG.info("HelloProvider Session Initiated");
289 helloService = session.addRpcImplementation(HelloService.class, new HelloWorldImpl());
293 public void close() throws Exception {
294 LOG.info("HelloProvider Closed");
295 if (helloService != null) {
296 helloService.close();
301 4. Optionally, you can also build the Java classes which will register
302 the new RPC. This is useful to test the edits you have made to
303 HelloProvider.java and HelloWorldImpl.java.
307 cd ../../../../../../../
310 5. Return to the top level directory
316 6. Build the entire *hello* again, which will pickup the changes you
317 have made and build them into your project:
323 Execute the *hello* project for the first time
324 ----------------------------------------------
330 cd ../karaf/target/assembly/bin
333 2. Wait for the project to load completely. Then view the log to see the
334 loaded *Hello* Module:
338 log:display | grep Hello
340 Test the *hello-world* RPC via REST
341 -----------------------------------
343 There are a lot of ways to test your RPC. Following are some examples.
345 1. Using the API Explorer through HTTP
347 2. Using a browser REST client
349 Using the API Explorer through HTTP
350 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
352 1. | Navigate to `apidoc
353 UI <http://localhost:8181/apidoc/explorer/index.html>`__ with your
355 | NOTE: In the URL mentioned above, Change *localhost* to the IP/Host
356 name to reflect your development machine’s network address.
368 POST /operations/hello:hello-world
370 4. Provide the required value.
374 {"hello:input": { "name":"Your Name"}}
378 6. Enter the username and password, by default the credentials are
381 7. In the response body you should see.
387 "greeting": "Hello Your Name"
391 Using a browser REST client
392 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
394 | For example, use the following information in the Firefox plugin
396 `https://github.com/chao/RESTClient <https://github.com/chao/RESTClient>`_
400 POST: http://192.168.1.43:8181/restconf/operations/hello:hello-world
420 If you get a response code 501 while attempting to POST
421 /operations/hello:hello-world, check the file: HelloProvider.java and
422 make sure the helloService member is being set. By not invoking
423 "session.addRpcImplementation()" the REST API will be unable to map
424 /operations/hello:hello-world url to HelloWorldImpl.