<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
-
+
<groupId>org.opendaylight.toolkit</groupId>
<artifactId>md-sal-app-simple</artifactId>
<version>1.0-SNAPSHOT</version>
<?xml version="1.0" encoding="UTF-8"?>
-<archetype-descriptor xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
+<archetype-descriptor xsi:schemaLocation="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0 http://maven.apache.org/xsd/archetype-descriptor-1.0.0.xsd"
name="md-sal-apps"
xmlns="http://maven.apache.org/plugins/maven-archetype-plugin/archetype-descriptor/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
-
+
<requiredProperties>
<requiredProperty key="appName">
<defaultValue>task</defaultValue>
public class ConsumerActivator {
-
+
}
*
*/
public class CodeGenerator {
-
+
private static String basePackage = "${package}";
-
+
/**
* This method expects two arguments application name and fields for application,
* which it will receive from command line, while generating the project.
* If user does not specify those fields, a default value will be picked up.
- * arg[1] should be a valid JSON, otherwise, ParseException will be thrown.
- * Second argument should be a valid string
+ * arg[1] should be a valid JSON, otherwise, ParseException will be thrown.
+ * Second argument should be a valid string
* @param args
* @throws Exception
*/
- public static void main(String[] args) throws Exception {
+ public static void main(String[] args) throws Exception {
//TODO : Do some preconditions check
JSONParser parser = new JSONParser();
Object obj = parser.parse(args[1]);
processWebViewTemplate(args[0], fieldKeys, ve);
processInitialConfig(args[0], ve);
}
-
-
+
+
private static void processModelYangTemplate(String appName, Set fieldKeys, VelocityEngine ve, JSONObject jsonObject)
throws Exception{
/* next, get the Template */
CodeGeneratorUtil.writeFile(path, context, template);
}
-
+
private static void processWebViewTemplate(String appName, Set fieldKeys, VelocityEngine ve) throws Exception{
/* next, get the Template */
Template template = ve.getTemplate( "view.vm" );
*
*/
public class CodeGeneratorUtil {
-
+
public static void writeFile(String path, VelocityContext context, Template template) throws Exception {
File file = new File(path);
File parent = file.getParentFile();
template.merge( context, bw );
bw.close();
}
-
+
public static String capitalizeFirstLetter(String original){
if(original.length() == 0)
return original;
package ${package}.generate;
public class Field {
-
+
private String name;
-
+
private String type;
public Field(String name, String type) {
package ${package}.generate;
public class ProviderField {
-
+
private String name;
-
+
private String method;
public ProviderField(String name, String method) {
import org.slf4j.LoggerFactory;
/**
- * This is a auto generated class which calls provider service to create an entry in
+ * This is a auto generated class which calls provider service to create an entry in
* data store
* @author harmansingh
*
*/
public class ${capitalApp}ConsumerImpl implements ${capitalApp}ConsumerService {
-
+
private static final Logger log = LoggerFactory.getLogger(${capitalApp}ConsumerImpl.class);
-
+
${capitalApp}Service service;
Random rand = new Random();
-
+
public ${capitalApp}ConsumerImpl(${capitalApp}Service service) {
this.service = service;
}
-
+
public void createEntry(Map<String, String> data) {
if(data == null || data.isEmpty()) {
log.debug("empty input data");
fieldBuilder.setValue(data.get(key));
fields.add(fieldBuilder.build());
}
-
+
SaveEntryInputBuilder inputbuilder = new SaveEntryInputBuilder();
inputbuilder.setEntryId(String.valueOf(rand.nextInt(1000000000)));
inputbuilder.setEntryField(fields);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
- }
+ }
}
public ${capitalApp}ConsumerImpl() {
}
-
+
private final Map<Class<? extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${capitalApp}ConsumerImpl>>, Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${capitalApp}ConsumerImpl>> augmentation = new HashMap<>();
public ${capitalApp}ConsumerImplBuilder() {
- }
-
+ }
+
public RpcRegistry getRpcRegistry() {
return _rpcRegistry;
}
-
+
@SuppressWarnings("unchecked")
public <E extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${capitalApp}ConsumerImpl>> E getAugmentation(Class<E> augmentationType) {
if (augmentationType == null) {
}
public ${capitalApp}ConsumerImplBuilder setRpcRegistry(RpcRegistry value) {
-
+
this._rpcRegistry = value;
return this;
}
-
+
public ${capitalApp}ConsumerImplBuilder addAugmentation(Class<? extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${capitalApp}ConsumerImpl>> augmentationType, Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${capitalApp}ConsumerImpl> augmentation) {
this.augmentation.put(augmentationType, augmentation);
return this;
public RpcRegistry getRpcRegistry() {
return _rpcRegistry;
}
-
+
@SuppressWarnings("unchecked")
@Override
public <E extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${capitalApp}ConsumerImpl>> E getAugmentation(Class<E> augmentationType) {
}
return true;
}
-
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder("${capitalApp}ConsumerImpl [");
boolean first = true;
-
+
if (_rpcRegistry != null) {
if (first) {
first = false;
private final Map<Class<? extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${lowerApp}.consumer.impl.RpcRegistry>>, Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${lowerApp}.consumer.impl.RpcRegistry>> augmentation = new HashMap<>();
public RpcRegistryBuilder() {
- }
-
+ }
+
public RpcRegistryBuilder(org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceRef arg) {
this._name = arg.getName();
this._type = arg.getType();
public Object getName() {
return _name;
}
-
+
public Class<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceType> getType() {
return _type;
}
-
+
@SuppressWarnings("unchecked")
public <E extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${lowerApp}.consumer.impl.RpcRegistry>> E getAugmentation(Class<E> augmentationType) {
if (augmentationType == null) {
}
public RpcRegistryBuilder setName(Object value) {
-
+
this._name = value;
return this;
}
-
+
public RpcRegistryBuilder setType(Class<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceType> value) {
-
+
this._type = value;
return this;
}
-
+
public RpcRegistryBuilder addAugmentation(Class<? extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${lowerApp}.consumer.impl.RpcRegistry>> augmentationType, Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${lowerApp}.consumer.impl.RpcRegistry> augmentation) {
this.augmentation.put(augmentationType, augmentation);
return this;
public Object getName() {
return _name;
}
-
+
@Override
public Class<? extends org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceType> getType() {
return _type;
}
-
+
@SuppressWarnings("unchecked")
@Override
public <E extends Augmentation<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.${lowerApp}.consumer.impl.rev140523.modules.module.configuration.${lowerApp}.consumer.impl.RpcRegistry>> E getAugmentation(Class<E> augmentationType) {
}
return true;
}
-
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder("RpcRegistry [");
boolean first = true;
-
+
if (_name != null) {
if (first) {
first = false;
private final String namespace = "urn:opendaylight:params:xml:ns:yang:controller:config:${app}-consumer:impl";
private final String revision = "2014-05-23";
private final String resourcePath = "/META-INF/yang/${app}-consumer-impl.yang";
-
+
private final Set<YangModuleInfo> importedModules;
public static YangModuleInfo getInstance() {
// Resource leak, but there is nothing we can do
}
}
-
+
@Override
public String getName() {
return name;
}
-
+
@Override
public String getRevision() {
return revision;
}
-
+
@Override
public String getNamespace() {
return namespace;
}
-
+
@Override
public InputStream getModuleSourceStream() throws IOException {
InputStream stream = $YangModuleInfoImpl.class.getResourceAsStream(resourcePath);
}
return stream;
}
-
+
@Override
public Set<YangModuleInfo> getImportedModules() {
return importedModules;
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(this.getClass().getCanonicalName());
* @author harmansingh
*
*/
-
+
public class ${capitalApp}Provider implements ${capitalApp}Service, AutoCloseable {
private static final Logger log = LoggerFactory.getLogger(${capitalApp}Provider.class);
-
+
private DataBrokerService dataService;
-
+
private final ExecutorService executor;
-
+
public DataBrokerService getDataService() {
return dataService;
}
public ${capitalApp}Provider() {
executor = Executors.newFixedThreadPool(1);
}
-
+
/**
* This is an example to show how yang based RPC can be used to perform an operation.
- * Here this is saving data in data store. This code also gives insight into how we can
+ * Here this is saving data in data store. This code also gives insight into how we can
* insert data into data store
* @param input
* @return
*/
-
+
@Override
public Future<RpcResult<Void>> saveEntry(SaveEntryInput input) {
log.debug("Saving the entry");
EntryBuilder entryBuilder = new EntryBuilder();
entryBuilder.setKey(new EntryKey(new EntryId(input.getEntryId())));
List<EntryField> entryFields = input.getEntryField();
-
+
for(EntryField field : entryFields) {
String key = field.getKey();
String value = field.getValue();
}
switch(key) {
#foreach( $field in $fields )
- case "$field.name" :
+ case "$field.name" :
entryBuilder.${field.method}(value);
break;
#end
public void close() throws Exception {
executor.shutdown();
}
-
+
private class SaveEntry implements Callable<RpcResult<Void>> {
Entry entry;
@Override
public RpcResult<Void> call() throws InterruptedException {
- // Each entry will be identifiable by a unique key, we have to create that identifier
+ // Each entry will be identifiable by a unique key, we have to create that identifier
InstanceIdentifier.InstanceIdentifierBuilder<Entry> entryIdBuilder =
InstanceIdentifier.<${capitalApp}>builder(${capitalApp}.class)
.child(Entry.class, entry.getKey());
return Rpcs.<Void> getRpcResult(true, null, Collections.<RpcError> emptySet());
}
}
-
+
}
\ No newline at end of file
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
- <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+ <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
#end
</tr>
</thead>
- <tbody>
+ <tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
-
+
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery.ajax({
url: window.location.origin +"/restconf/operational/${app}:${app}",
dataType: "json",
- success: function(data) {
- jQuery.each(data.${app}.entry,
- function(){
+ success: function(data) {
+ jQuery.each(data.${app}.entry,
+ function(){
var rowEntry = "<tr><td>" +
this['entry-id']+"</td>"
#foreach( $field in $fields )
+ "<td>" + this.${field} + "</td>"
#end
-
+
+"</tr>";
console.log(rowEntry);
jQuery(".table tbody").append(rowEntry);
jQuery("form").on( "submit", function( event ) {
event.preventDefault();
var entryId = Math.random()*100000000000000000;
- var formData = '{"input":{"entryField":['
+ var formData = '{"input":{"entryField":['
#foreach( $field in $fields )
+ '{"key":"${field}", "value":"'+ jQuery("input[name='${field}']").val()+ '"}'
- #if($velocityCount != $fields.size())
+ #if($velocityCount != $fields.size())
+','
#end
#end
jQuery.ajax({
url: window.location.origin +"/restconf/operations/${app}:saveEntry",
type: "POST",
- headers: {
+ headers: {
'Accept': 'application/json',
- 'Content-Type': 'application/json'
+ 'Content-Type': 'application/json'
},
data: formData,
dataType: "json",
- success: function(data) {
+ success: function(data) {
location.reload(true);
},
error : function(){ console.log("Error");}
});
-
+
});
</script>
-
+
</body>
</html>
\ No newline at end of file
prefix $app;
import ietf-inet-types { prefix "inet"; revision-date 2010-09-24; }
-
+
organization "Netconf Central";
contact
description
"MD-SAL sample app";
}
-
+
typedef entry-id {
type inet:uri;
description "An identifier for app entry.";
}
-
+
container $app {
description
"Top-level container for all application database objects.";
#end
}
}
-
+
rpc saveEntry {
description " Method to add a new entry into datastore.";
input {
type string;
description "name of the field";
}
-
+
leaf value {
type string;
description "value of the field";
}
}
-
+
leaf entryId {
type string;
description "entry Identifier";
}
}
}
-
+
}
\ No newline at end of file
</plugins>
<pluginManagement>
<plugins>
- <!--This plugin's configuration is used to store Eclipse
+ <!--This plugin's configuration is used to store Eclipse
m2e settings only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
prefix task;
import ietf-inet-types { prefix "inet"; revision-date 2010-09-24; }
-
+
organization "Netconf Central";
contact
description
"MD-SAL sample app";
}
-
+
typedef entry-id {
type inet:uri;
description "An identifier for app entry.";
}
-
+
container task {
description
"Top-level container for all application database objects.";
}
}
}
-
+
rpc saveEntry {
description " Method to add a new entry into datastore.";
input {
type string;
description "name of the field";
}
-
+
leaf value {
type string;
description "value of the field";
}
}
-
+
leaf entryId {
type string;
description "entry Identifier";
}
}
}
-
+
}
\ No newline at end of file
<groupId>${groupId}</groupId>
<artifactId>${artifactId}</artifactId>
<version>${version}</version>
-
+
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
<salGeneratorPath>src/main/yang-gen-sal</salGeneratorPath>
<config.version>0.2.5-SNAPSHOT</config.version>
</properties>
-
+
<scm>
<connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
<developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
<url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
<tag>HEAD</tag>
</scm>
-
+
<pluginRepositories>
<!-- OpenDayLight Repo Mirror -->
<pluginRepository>
</releases>
</repository>
</repositories>
-
+
<distributionManagement>
<!-- OpenDayLight Released artifact -->
<repository>
</distributionManagement>
<build>
-
+
<pluginManagement>
<plugins>
<plugin>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
-
+
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
-
+
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
@Controller
@RequestMapping("/")
public class SampleAppController {
-
+
@RequestMapping(value="/view", method = RequestMethod.GET)
public String viewList(){
return "view";
}
-
+
}
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
-
+
<context:component-scan base-package="org.opendaylight.controller.app.web" />
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/img/**" location="/img/" />
<mvc:annotation-driven />
-
+
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>.jsp</value>
</property>
</bean>
-
+
</beans>
\ No newline at end of file
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>MD-SAL Application</display-name>
-
+
<servlet>
<servlet-name>md-sal-app</servlet-name>
<servlet-class>
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-
+
<servlet-mapping>
<servlet-name>md-sal-app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
-
-
+
+
</web-app>