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 8-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=1.0.0-SNAPSHOT
65 To find the correct <Archetype-Version> for an OpenDaylight release, search https://nexus.opendaylight.org;
66 e.g. ``https://nexus.opendaylight.org/#nexus-search;gav~org.opendaylight.archetypes~~~~``.
68 2. Update the properties values as follows. Ensure that the values for the groupId and
69 the artifactId are in lower case.
73 Define value for property 'groupId': : org.opendaylight.example
74 Define value for property 'artifactId': : example
75 Define value for property 'version': 1.0-SNAPSHOT: : 1.0.0-SNAPSHOT
76 Define value for property 'package': org.opendaylight.example: :
77 Define value for property 'classPrefix': ${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)}
78 Define value for property 'copyright': : Copyright (c) 2015 Yoyodyne, Inc.
80 3. Accept the default value of classPrefix that is,
81 ``(${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)})``.
82 The classPrefix creates a Java Class Prefix by capitalizing the first
83 character of the artifactId.
87 In this scenario, the classPrefix used is "Example". Create a
88 top-level directory for the archetype.
102 4. Build the *example* project.
106 Depending on your development machine’s specification this might
107 take a little while. Ensure that you are in the project’s root
108 directory, example/, and then issue the build command, shown
115 5. Start the *example* project for the first time.
119 cd karaf/target/assembly/bin
123 6. Wait for the karaf cli that appears as follows. Wait for OpenDaylight
124 to fully load all the components. This can take a minute or two after
125 the prompt appears. Check the CPU on your dev machine, specifically
126 the Java process to see when it calms down.
130 opendaylight-user@root>
132 7. Verify if the “example” module is built and search for the log entry
133 which includes the entry *ExampleProvider Session Initiated*.
137 log:display | grep Example
139 8. Shutdown OpenDaylight through the console by using the following
146 Defining a Simple Hello World RPC
147 ---------------------------------
149 1. | Build a *hello* example from the Maven archetype *opendaylight-startup-archetype*,
152 2. Now view the entry point to understand where the log line came from. The
153 entry point is in the impl project:
157 impl/src/main/java/org/opendaylight/hello/impl/HelloProvider.java
159 3. Add any new things that you are doing in your implementation by
160 using the HelloProvider.onSessionInitiate method. It's analogous to
166 public void onSessionInitiated(ProviderContext session) {
167 LOG.info("HelloProvider Session Initiated");
170 Add a simple HelloWorld RPC API
171 -------------------------------
173 1. Navigate to the file.
178 api/src/main/yang/hello.yang
180 2. Edit this file as follows. In the following example, we are adding
181 the code in a YANG module to define the *hello-world* RPC:
187 namespace "urn:opendaylight:params:xml:ns:yang:hello";
189 revision "2015-01-05" {
190 description "Initial revision of hello model";
206 3. Return to the hello/api directory and build your API as follows.
213 Implement the HelloWorld RPC API
214 --------------------------------
216 1. Define the HelloService, which is invoked through the *hello-world*
221 cd ../impl/src/main/java/org/opendaylight/hello/impl/
223 2. Create a new file called HelloWorldImpl.java and add in the code
228 package org.opendaylight.hello.impl;
230 import java.util.concurrent.Future;
231 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloService;
232 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldInput;
233 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldOutput;
234 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldOutputBuilder;
235 import org.opendaylight.yangtools.yang.common.RpcResult;
236 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
238 public class HelloWorldImpl implements HelloService {
241 public Future<RpcResult<HelloWorldOutput>> helloWorld(HelloWorldInput input) {
242 HelloWorldOutputBuilder helloBuilder = new HelloWorldOutputBuilder();
243 helloBuilder.setGreating("Hello " + input.getName());
244 return RpcResultBuilder.success(helloBuilder.build()).buildFuture();
248 3. The HelloProvider.java file is in the current directory. Register the
249 RPC that you created in the *hello.yang* file in the
250 HelloProvider.java file. You can either edit the HelloProvider.java
251 to match what is below or you can simple replace it with the code
257 * Copyright(c) Yoyodyne, Inc. and others. All rights reserved.
259 * This program and the accompanying materials are made available under the
260 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
261 * and is available at http://www.eclipse.org/legal/epl-v10.html
263 package org.opendaylight.hello.impl;
265 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
266 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
267 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
268 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloService;
269 import org.slf4j.Logger;
270 import org.slf4j.LoggerFactory;
272 public class HelloProvider implements BindingAwareProvider, AutoCloseable {
274 private static final Logger LOG = LoggerFactory.getLogger(HelloProvider.class);
275 private RpcRegistration<HelloService> helloService;
278 public void onSessionInitiated(ProviderContext session) {
279 LOG.info("HelloProvider Session Initiated");
280 helloService = session.addRpcImplementation(HelloService.class, new HelloWorldImpl());
284 public void close() throws Exception {
285 LOG.info("HelloProvider Closed");
286 if (helloService != null) {
287 helloService.close();
292 4. Optionally, you can also build the Java classes which will register
293 the new RPC. This is useful to test the edits you have made to
294 HelloProvider.java and HelloWorldImpl.java.
298 cd ../../../../../../../
301 5. Return to the top level directory
307 6. Build the entire *hello* again, which will pickup the changes you
308 have made and build them into your project:
314 Execute the *hello* project for the first time
315 ----------------------------------------------
321 cd ../karaf/target/assembly/bin
324 2. Wait for the project to load completely. Then view the log to see the
325 loaded *Hello* Module:
329 log:display | grep Hello
331 Test the *hello-world* RPC via REST
332 -----------------------------------
334 There are a lot of ways to test your RPC. Following are some examples.
336 1. Using the API Explorer through HTTP
338 2. Using a browser REST client
340 Using the API Explorer through HTTP
341 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
343 1. | Navigate to `apidoc
344 UI <http://localhost:8181/apidoc/explorer/index.html>`__ with your
346 | NOTE: In the URL mentioned above, Change *localhost* to the IP/Host
347 name to reflect your development machine’s network address.
359 POST /operations/hello:hello-world
361 4. Provide the required value.
365 {"hello:input": { "name":"Your Name"}}
369 6. Enter the username and password, by default the credentials are
372 7. In the response body you should see.
378 "greating": "Hello Your Name"
382 Using a browser REST client
383 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
385 | For example, use the following information in the Firefox plugin
387 [`https://github.com/chao/RESTClient} <https://github.com/chao/RESTClient}>`__
391 POST: http://192.168.1.43:8181/restconf/operations/hello:hello-world
411 If you get a response code 501 while attempting to POST
412 /operations/hello:hello-world, check the file: HelloProvider.java and
413 make sure the helloService member is being set. By not invoking
414 "session.addRpcImplementation()" the REST API will be unable to map
415 /operations/hello:hello-world url to HelloWorldImpl.