[hide] html
This tutorial is aimed at a developer who would like a quick start to OpenDaylight Development. It will create a local repository for the code and guide you through a simple build process. Once the tutorial is complete you will be able to start OpenDaylight and the test a simple RPC. The test RPC will be one you have created, based on the principle of 'hello world'.java
Ideally you will have already have a working knowledge of Maven 3.2.1 (at time of writing), Java 1.8.0_60 (at time of writing) and how to set up an environment with the correct paths/variables on your development machine. The GettingStarted: Eclipse automated set up is a convenient way to get started.git
During this tutorial you will use the Maven Archetype framework, which provides a template approach to downloading projects. For more details please read http://maven.apache.org/guides/introduction/introduction-to-archetypes.html .github
Once you have setup your development machine with Maven and Java, you will need to update your Maven settings.xml. If you are using GettingStarted: Eclipse, then this is automatically set up for you. Otherwise, do this by editing your settings.xml file. (You should view this file to get a better understanding as to what it is for, which is to define the repositories for this project.)web
IMPORTANT: If you already have previously downloaded OpenDaylight for another project it is recommended that you remove an existing repository before you start this project. If you are simply rebuilding the projects below, having previously run this tutorial, then you don't need to delete your local repository. (If you are using Linux on as your development machine, you will find your local repository in ~/.m2/repository. Other platforms may vary.)apache
Let's begin by creating a simple 'Example' project using Maven and an archetype called 'opendaylight-startup-archetype'.json
If this is the first time you are downloading this project then it will take a while to pull all the code from the remote repository.api
NOTE: If it is failing below, remove ~/.m2 directory. Also make sure you have the OpenDaylight setting.xml file as described above.session
If you are using the GettingStarted: Eclipse fully automated set up, then you can now use menu File > New > Project > Maven > Maven Project, Next; Advanced: Name template: [groupId].[artifactId], and then check [X] Include snapshot archetypes, and choose Artifact Id opendaylight-startup-archetype. (Note that opendaylight-eclipse-setup already has a catalog with the required archetypeRepository from ODL.)app
Otherwise, create your project with the archetype by typing:
mvn archetype:generate -DarchetypeGroupId=org.opendaylight.controller -DarchetypeArtifactId=opendaylight-startup-archetype \ -DarchetypeRepository=http://nexus.opendaylight.org/content/repositories/<Snapshot-Type>/ \ -DarchetypeCatalog=http://nexus.opendaylight.org/content/repositories/<Snapshot-Type>/archetype-catalog.xml \ -DarchetypeVersion=<Archetype-Version>
You need to enter the proper <Archetype-Version> and <Snapshot-Type> that depends on the ODL release you want to work in. for example:
Note each version of the archetype generates version numbers in pom.xml dependencies for its intended ODL revision.
Respond to the prompts (Please note that groupid and artifactid need to be all lower case):
Define value for property 'groupId': : org.opendaylight.example Define value for property 'artifactId': : example Define value for property 'package': org.opendaylight.example: : Define value for property 'classPrefix': ${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)} Define value for property 'copyright': : Yoyodyne, Inc.
In particular, accept the default value of classPrefix (${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)}) which creates a Java Class Prefix by capitalizing the first character of the artifactId ( so in this example the classPrefix will be Example). If you want to change any of the defaults, say 'N' at the last question; which will give you the opportunity to change them.
The archetype will have create a top level directory:
${artifactId}/
in our example:
example/
Enter the directory:
cd example/
and look around:
api/ artifacts/ features/ impl/ karaf/ pom.xml
Let's build the project for the first time. Depending on your development machine's specification this might take a little while. Ensure that you are in the project's root directory, example/, and then issue the build command, shown below.
mvn clean install
Once the project has built you will have created an Opendaylight distribution. Change to the directory and have a look.
cd karaf/target/assembly/bin ls
Once you are ready start the 'example' project using the following command.
./karaf
Wait for the karaf cli:
opendaylight-user@root>
IMPORTANT: Wait for OpenDaylight to fully load all the components which can take a minute or two after the prompt appears. (check the CPU on your dev machine, specifically the Java process, to see when it calms down.
During the build process a module called 'Example' was built, which you can now verify on the console by checking out the log:
log:display | grep Example
Look for the log entry which includes the entry 'ExampleProvider Session Initiated'.
To shutdown OpenDaylight via the console issue the command below.
shutdown -f
In part 2 creates a new project, again using the Maven archetype 'opendaylight-startup-archetype', but this time creating a 'hello' project.
It would be beneficial to have a working knowledge of Java development, since Part 2 of this wiki explains at how to augment the 'hello' project to build the example API.
If you have already done the 'example' project the time to pull the archetype is greatly reduced, since you now have a local repository in ~/.m2/repository (in Linux other systems may vary for location). If you have deleted the local repository, Maven will re-fetch it.
mvn archetype:generate -DarchetypeGroupId=org.opendaylight.controller -DarchetypeArtifactId=opendaylight-startup-archetype \ -DarchetypeRepository=http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/ \ -DarchetypeCatalog=http://nexus.opendaylight.org/content/repositories/opendaylight.snapshot/archetype-catalog.xml
Respond to the prompts:
Define value for property 'groupId': : org.opendaylight.hello Define value for property 'artifactId': : hello Define value for property 'version': 1.0-SNAPSHOT Define value for property 'package': org.opendaylight.hello: : Define value for property 'classPrefix': hello Define value for property 'copyright': : Yoyodyne, Inc.
cd hello/ ls -1 api artifacts features impl karaf pom.xml
mvn clean install
Run karaf:
cd karaf/target/assembly/bin and then execute ./karaf
Wait for the karaf cli:
opendaylight-user@root>
IMPORTANT: Remember to wait for OpenDaylight to fully load. (check Java process CPU has calmed down).
Verify the 'hello' module has loaded by checking out the log:
log:display | grep Hello
Shutdown karaf
shutdown -f
Return to the top of the directory structure:
cd ../../../../
The entry point is in the impl project:
impl/src/main/java/org/opendaylight/hello/impl/HelloProvider.java
In the HelloProvider.init method:
public void init() { LOG.info("HelloProvider Session Initiated"); }
This is the method you would add any new things you are doing in your implementation. It is analogous to an Activator.
Edit
api/src/main/yang/hello.yang
Edit this file to look as below. You will see that we are adding the code in a YANG module to define the 'hello-world' RPC:
module hello { yang-version 1; namespace "urn:opendaylight:params:xml:ns:yang:hello"; prefix "hello"; revision "2015-01-05" { description "Initial revision of hello model"; } rpc hello-world { input { leaf name { type string; } } output { leaf greeting { type string; } } } }
If you are using the GettingStarted: Eclipse set up, then you can now use right-click on the project, and use the context menu Run As > Maven generate-sources. Otherwise, return to the hello/api directory and build your api:
cd ../../../ mvn clean install
We now need to define the HelloService, which will be called via the 'hello-world' API.
cd ../impl/src/main/java/org/opendaylight/hello/impl/
Create a new file called HelloWorldImpl.java and add in the code below.
package org.opendaylight.hello.impl; import java.util.concurrent.Future; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloService; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldInput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldOutput; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.hello.rev150105.HelloWorldOutputBuilder; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; public class HelloWorldImpl implements HelloService { @Override public Future<RpcResult<HelloWorldOutput>> helloWorld(HelloWorldInput input) { HelloWorldOutputBuilder helloBuilder = new HelloWorldOutputBuilder(); helloBuilder.setGreeting("Hello " + input.getName()); return RpcResultBuilder.success(helloBuilder.build()).buildFuture(); } }
In order to register our RPC with MD-SAL, we first need to create the reference to the RPC Registry. This is done in a couple of steps. First, we need to add the RPC Registry reference to the impl-blueprint.xml file in src/main/resources/org/opendaylight/blueprint as follows:
<?xml version="1.0" encoding="UTF-8"?> <!-- vi: set et smarttab sw=4 tabstop=4: --> <!-- Copyright © 2016 Cisco Systems and others. All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html --> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0" odl:use-default-for-reference-types="true"> <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker" odl:type="default" /> <reference id="rpcRegistry" interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry"/>''' <bean id="provider" class="org.opendaylight.spark.impl.HelloProvider" init-method="init" destroy-method="close"> <argument ref="dataBroker" /> <argument ref="rpcRegistry" /> </bean> </blueprint>
Next, we add the reference to the RPC registry to the HelloProvider class and allow its injection into the class through the HelloProvider's constructor:
/* * Copyright © 2016 Cisco Systems and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.hello.impl; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HelloProvider { private static final Logger LOG = LoggerFactory.getLogger(HelloProvider.class); private final DataBroker dataBroker; private final RpcProviderRegistry rpcProviderRegistry; public HelloProvider(final DataBroker dataBroker, RpcProviderRegistry rpcProviderRegistry) { this.dataBroker = dataBroker; this.rpcProviderRegistry = rpcProviderRegistry; } /** * Method called when the blueprint container is created. */ public void init() { LOG.info("HelloProvider Session Initiated"); } /** * Method called when the blueprint container is destroyed. */ public void close() { LOG.info("HelloProvider Closed"); } }
Finally, in the HelloProvider's init() function (called when the blueprint container is created) we register the HelloService RPC with MD-SAL as follows:
.... private RpcRegistration<HelloService> serviceRegistration; ... /** * Method called when the blueprint container is created. */ public void init() { serviceRegistration = rpcProviderRegistry.addRpcImplementation(HelloService.class, new HelloWorldImpl()); LOG.info("HelloProvider Session Initiated"); } /** * Method called when the blueprint container is destroyed. */ public void close() { serviceRegistration.close(); LOG.info("HelloProvider Closed"); }
The next step is optional, however you can build just the java classes which will register the new RPC. This is useful to test the edits you have made to HelloProvider.java and HelloWorldImpl.java
cd ../../../../../../../ mvn clean install
Return to the top level directory
cd ../
Now build the entire 'hello' again, which will pickup the changes you have made and build them into your project:
mvn clean install
Run karaf:
cd ../karaf/target/assembly/bin ./karaf
As before, wait for the project to completely load. Then view the log to see the loaded 'Hello' Module:
log:display | grep Hello
There are a lot of ways to test your RPC. The ones listed below are some examples.
Go to the RestConf API Documentation UI (Swagger/Open API Initiative (OAI)-based) with your web browser. You will be prompted for a username and password, by default they are admin/admin.
NOTE - in the above URL you might need to change 'localhost' to the IP/Host name to reflect your development machine's network address.
Click on
hello(2015-01-05)
and then click on
POST /operations/hello:hello-world
and provide value:
{"hello:input": { "name":"Your Name"}}
and click the button
Try it out
In the response body you should see.
{ "output": { "greeting": "Hello Your Name" } }
For example the Firefox plugin 'RESTClient' [1] or the Chrome app 'Postman' [2]
POST: http://localhost:8181/restconf/operations/hello:hello-world
Header: Content-Type: application/json
Body: {"input": { "name": "Giles" } }
If while attempting to POST /operations/hello:hello-world you get a response code 501 check the file: HelloProvider.java and make sure the helloService member is being set. By not invoking "session.addRpcImplementation()" the REST api will be unable to map the /restconf/operations/hello:hello-world URL to the HelloWorldImpl Java class.
Check out the other tutorials!