6ba54d4cd2d07017344bdcafcf9dfb787dc36f58
[docs.git] / manuals / developer-guide / src / main / asciidoc / dlux / dlux-core-dev.adoc
1 == DLUX
2 === Setup and Run
3 ==== Required Technology Stack
4
5 *  AngularJS (JavaScript client-side framework, http://www.angularjs.org )
6
7
8 ==== Run DLUX
9
10 To turn on the DLUX UI, install DLUX core feature via running following command on the Karaf console -
11
12  feature:install odl-dlux-core
13
14 The above command will install odl-restconf and DLUX topology application internally, along with core DLUX components.
15 Once this feature is successfully installed, access the UI at http://localhost:8181/index.html.
16 The default credentials for login are admin/admin.
17
18 All the applications in DLUX are Karaf features. A user can install other dlux applications such as node and yang-ui from Karaf
19 console using commands such as -
20
21 ----
22 $ feature:install odl-dlux-node
23
24 $ feature:install odl-dlux-yangui
25 ----
26
27 === DLUX Modules
28
29 DLUX modules are the individual features such as nodes and topology. Each module has a defined structure and you can find
30 all existing modules at https://github.com/opendaylight/dlux/tree/stable/lithium/modules.
31
32 ==== Module Structure
33
34  * module_folder
35  ** <module_name>.module.js
36  ** <module_name>.controller.js
37  ** <module_name>.services.js
38  ** <module_name>.directives.js
39  ** <module_name>.filter.js
40  ** index.tpl.html
41  ** <a_stylesheet>.css
42
43 ==== Create New Module
44 ===== Define the module
45
46 . Create an empty maven project and create your module folder under src/main/resources.
47 . Create an empty file with pattern <module_name>.module.js.
48 . Next, you need to surround the angular module with a define function. This allows RequireJs to see our module.js files.
49   The first argument is an array which contains all the module's dependencies. The second argument is a callback function,
50   whose body contain the AngularJS code base. The function parameters correspond with the order of dependencies. Each dependency is injected into a parameter, if it is provided.
51 . Finally, you will return the angular module to be able to inject it as a parameter in others modules.
52
53 For each new module, you must have at least these two dependencies :
54
55 * angularAMD : It's a wrapper around AngularJS to provide an AMD (Asynchronous Module Definition) support, which is used by RequireJs. For more information see the https://github.com/amdjs/amdjs-api/blob/master/AMD.md[AMD documentation].
56 * app/core/core.services : This one is mandatory, if you want to add content in the navigation menu, the left bar or the top bar.
57
58 The following are not mandatory, but very often used.
59
60 * angular-ui-router : A library to provide URL routing.
61 * routingConfig : To set the level access to a page.
62
63 Your module.js file might look like this:
64
65  define(['angularAMD','app/routingConfig', 'angular-ui-router','app/core/core.services'], function(ng) {
66     var module = angular.module('app.a_module', ['ui.router.state', 'app.core']);
67     // module configuration
68     module.config(function() {
69         [...]
70     });
71    return module;
72  });
73
74 ===== Set the register function
75 AngularJS allows lazy registration of a module's components such as controller, factory etc. Once you will install your application,
76 DLUX will load your module javascript, but not your angular component during bootstrap phase. You have to register your angular components
77 to make sure they are available at the runtime.
78
79 Here is how to register your module's component for lazy initialization -
80
81  module.config(function($compileProvider, $controllerProvider, $provide) {
82     module.register = {
83       controller : $controllerProvider.register,
84       directive : $compileProvider.directive,
85       factory : $provide.factory,
86       service : $provide.service
87     };
88  });
89
90 ===== Set the route
91 The next step is to set up the route for your module. This part is also done in the configuration method of the module. We have to add *$stateProvider* as a parameter.
92
93  module.config(function($stateProvider) {
94     var access = routingConfig.accessLevels;
95     $stateProvider.state('main.module', {
96       url: 'module',
97       views : {
98         'content' : {
99           templateUrl: 'src/app/module/module.tpl.html',
100           controller: 'ModuleCtrl'
101         }
102       }
103     });
104  });
105
106 ===== Adding element to the navigation menu
107 To be able to add item to the navigation menu, the module requires the *NavHelperProvider* parameter in the configuration method.
108 *addToMenu* method in *NavMenuHelper* helper allows an item  addition to the menu.
109
110  var module = angular.module('app.a_module', ['app.core']);
111  module.config(function(NavMenuHelper) {
112      NavMenuHelper.addToMenu('myFirstModule', {
113          "link" : "#/module/index",
114          "active" : "module",
115          "title" : "My First Module",
116          "icon" : "icon-sitemap",
117          "page" : {
118              "title" : "My First Module",
119              "description" : "My first module"
120          }
121      });
122  });
123
124 The first parameter is an ID that refers to the level of your menu and the second is a object. For now, The ID parameter supports two levels of depth.
125 If your ID looks like 'rootNode.childNode', the helper will look for a node named 'rootNode' and it will append the 'childNode' to it. If the root node doesn't exist, it will create it.
126
127
128 ===== Link the AngularJS module's controller file
129
130 To include the module's controller file, you can use the NavHelperProvider. It contains a method that will load the given file.
131
132  [...]
133     NavHelperProvider.addControllerUrl('<path_to_module_folder>/<module_name>.controller');
134
135 This completes your module.js file.
136
137
138 ==== Create the controller, factory, directive, etc
139
140 Creating the controller and other components is similar to the module.
141
142 * First, add the define method.
143 * Second, add the relative path to the module definition.
144 * Last, create your methods as you usually do it with AngularJS.
145
146 For example -
147
148  define(['<relative_path_to_module>/<module_name>.module'], function(module) {
149     module.register.controller('ModuleCtrl', function($rootScope, $scope) {
150     });
151  });
152
153 === Add new application using DLUX modularity
154 DLUX works as a Karaf based UI platform, where you can create a new Karaf feature of your UI component and install that UI applications in DLUX using blueprint.
155 This page will help you to create and load a new application for DLUX. You don't have to add new module in DLUX repository.
156
157 ==== Add a new OSGi blueprint bundle
158 The OSGi Blueprint Container specification allows us to use dependency injection in our OSGi environment. Each DLUX application module registers itself via blueprint configuration. Each application will have its own blueprint.xml to place its configuration.
159
160 1. Create a maven project to place blueprint configuration. For reference, take a look at topology bundle, present at https://github.com/opendaylight/dlux/tree/stable/lithium/bundles/topology. All the existing DLUX modules' configurations are available under bundles directory of DLUX code.
161
162 2. In pom.xml, you have to add a maven plugin to unpack your module code under generated-resources of this project. For reference, you can check pom.xml of dlux/bundles/topology at https://github.com/opendaylight/dlux/tree/stable/lithium/bundles/topology. Your bundle will eventually get deployed in Karaf as feature, so your bundle should contain all your module code. If you want to combine module and bundle project, that should not be an issue either.
163
164 3. Create a blueprint.xml configuration file under src/main/resources/OSGI-INF/blueprint. Below is the content of the blueprint.xml taken from topology bundles's blueprint.xml. Any new application should create a blueprint.xml in following format -
165
166 ----
167 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
168     <reference id="httpService" availability="mandatory" activation="eager" interface="org.osgi.service.http.HttpService"/>
169     <reference id="loader" availability="mandatory" activation="eager" interface="org.opendaylight.dlux.loader.DluxModuleLoader"/>
170
171     <bean id="bundle" init-method="initialize" destroy-method="clean" class="org.opendaylight.dlux.loader.DluxModule">
172       <property name="httpService" ref="httpService"/>
173       <property name="loader" ref="loader"/>
174       <property name="moduleName" value="topology "/>
175       <property name="url" value="/src/app/topology"/>
176       <property name="directory" value="/topology"/>
177       <property name="requireJs" value="app/topology/topology.module"/>
178       <property name="angularJs" value="app.topology"/>
179       <property name="cssDependencies">
180           <list>
181               <value>http://yui.yahooapis.com/3.18.1/build/cssreset/cssreset-min.css</value>
182               <value>src/app/topology/topology-custom.css</value>
183           </list>
184       </property>
185     </bean>
186 </blueprint>
187 ----
188
189 In above configuration, there are two references with id httpService and loader. These two beans will already be initialized by dlux-core, so any new application can use them. Without these two bean references, a new application will not be able to register.
190
191 Next is the initialization of your application bean, which will be an instance of class org.opendaylight.dlux.loader.DluxModule. There are 5 properties that you should provide in this bean besides the references of httpService and loader. Lets talk about those bean properties in little more detail.
192
193 *moduleName* : Name of your module. This name should be unique in DLUX.
194
195 *url*: This is the url via which RequireJS in DLUX will try to load your module JS/HTML files. Also, this is the url that browser will use to load the static HTML, JS or CSS files. RequireJS in DLUX has a base path of *src*, so all the url should start with /src so RequireJS and the browser can correctly find the files.
196
197 *directory*: In your bundle's pom.xml, you unpack your module code. This is the directory where your actual static files will reside. The above mentioned url is registered with httpService, so when browser makes a call to that url, it will be redirected to the directory mentioned here. In the above example, all the topology files are present under /topology directory and the browser/RequireJS can access those files with uri /src/app/topology.
198
199 *requireJS*: This is the path to your RequireJS module. If you notice closely, you will see the initial path of RequireJS app/topology in the above example matches with the last part of url. This path will be be used by RequireJS. As mentioned above, we have kept *src* as base path in RequireJS, that is the exact reason that url start with /src.
200
201 *angularJS*: name of your AngularJS module.
202
203 *cssDependencies*: If the application has any external/internal css dependencies, then those can be added here. If you create your own css files, just point to those css files here. Use the url path that you mentioned above, so the browser can find your css file.
204
205 OSGi understands blueprint.xml, once you will deploy your bundle in karaf (or you can create a new feature for your application), karaf will read your blueprint.xml and it will try to register your application with dlux. Once successful, if you refresh your dlux UI, you will see your application in left hand navigation bar of dlux.
206
207
208 === Yang Utils
209 Yang Utils are used by UI to perform all CRUD operations. All of these utilities are present in yangutils.services.js file. It has following AngularJS factories -
210
211 .Factories
212 * *arrayUtils* – defines functions for working with arrays.
213 * *pathUtils* – defines functions for working with xpath (paths to APIs and subAPIs). It divides xpath string to array of elements, so this array can be later used for search functions.
214 * *syncFact* – provides synchronization between requests to and from OpenDaylight when it’s needed.
215 * *custFunct* – it is linked with apiConnector.createCustomFunctionalityApis in yangui controller in yangui.controller.js. That function makes it possible to create some custom function called by the click on button in index.tpl.html. All custom functions are stored in array and linked to specific subAPI. When particular subAPI is expanded and clicked, its  inputs (linked root node with its child nodes) are displayed in the bottom part of the page and its buttons with custom functionality are displayed also.
216 * *reqBuilder* – Builds object in JSON format from input fields of the UI page.  *Show Preview* button on Yang UI use this builder. This request is sent to OpenDaylight when button PUT or POST is clicked.
217 * *yinParser* – factory for reading .xml files of yang models and creating object hierarchy. Every statement from yang is represented by a node.
218 * *nodeWrapper* – adds functions to objects in tree hierarchy created with yinParser. These functions provide functionality for every type of node.
219 * *apiConnector* – the main functionality is filling the main structures and linking them. Structure of APIs and subAPIs which is two level array - first level is filled by main APIs, second level is filled by others sub APIs. Second main structure is array of root nodes, which are objects including root node and its children nodes. Linking these two structures is creating links between every subAPI (second level of APIs array) and its root node, which must be displayed like inputs when subAPI is expanded.
220 * *yangUtils* – some top level functions which are used by yangui controller for creating the main structures.