OS:
ubuntu 14.04 64bit
一、安装jdk
准备资材:
jdk-8u72-linux-x64.tar.gz
(之前使用了jdk7,compile时报“java/util/function/consumer”找不到)
1.解压jdk
进入/usr/local目录后,解压文件
#cd /usr/local
#tar xzvf /home/todd/jdk-8u72-linux-x64.tar.gz
2.添加环境变量
# vi /etc/profile
文件的最后增加以下内容:
export JAVA_HOME=/usr/local/jdk1.8.0_72
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
3.立刻使环境变量生效
# source /etc/profile
二、安装maven
准备资材:
apache-maven-3.3.3-bin.tar.gz
1.解压maven
进入/usr/local目录后,解压文件
#cd /usr/local
#tar xzvf /home/todd/apache-maven-3.3.3-bin.tar.gz.gz
2.添加环境变量
# vi /etc/profile
文件的最后增加以下内容:
export M2_HOME=/usr/local/apache-maven-3.3.3
export PATH=$PATH:$M2_HOME/bin
3.立刻使环境变量生效
# source /etc/profile
4.使用opendaylight的settings.xml配置文件(ODL没有使用maven的仓库,而是维护自己的仓库)
#cp -n ~/.m2/settings.xml{,.orig} ; \wget -q -O - https://raw.githubusercontent.com/opendaylight/odlparent/stable/lithium/settings.xml > ~/.m2/settings.xml
三、创建opendaylight项目
1.执行以下命令创建项目结构
#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
......
Define value for property 'groupId': : org.opendaylight.toaster
Define value for property 'artifactId': : toaster
[INFO] Using property: version = 1.0.0-SNAPSHOT
Define value for property 'package': org.opendaylight.toaster: :
Mar 28, 2016 11:01:50 PM org.apache.velocity.runtime.log.JdkLogChute log
INFO: FileResourceLoader : adding path '.'
Define value for property 'classPrefix': Toaster: :
Define value for property 'copyright': : CopyLeft(c)
[INFO] Using property: copyrightYear = 2015
Confirm properties configuration:
groupId: org.opendaylight.toaster
artifactId: toaster
version: 1.0.0-SNAPSHOT
package: org.opendaylight.toaster
classPrefix: ${artifactId.substring(0,1).toUpperCase()}${artifactId.substring(1)}
copyright: CopyLeft(c)
copyrightYear: 2015
Y: : y
......
出现以下内容,表示执行成功:
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: opendaylight-startup-archetype:1.0.0-SNAPSHOT
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: org.opendaylight.toaster
[INFO] Parameter: artifactId, Value: toaster
[INFO] Parameter: version, Value: 0.1.0-SNAPSHOT
[INFO] Parameter: package, Value: org.opendaylight.toaster
[INFO] Parameter: packageInPathFormat, Value: org/opendaylight/toaster
[INFO] Parameter: classPrefix, Value: Toaster
[INFO] Parameter: package, Value: org.opendaylight.toaster
[INFO] Parameter: version, Value: 0.1.0-SNAPSHOT
[INFO] Parameter: copyright, Value: CopyLeft(c)
[INFO] Parameter: groupId, Value: org.opendaylight.toaster
[INFO] Parameter: artifactId, Value: toaster
[WARNING] Don't override file /home/todd/opendaylight/toaster/pom.xml
[INFO] project created from Archetype in dir: /home/todd/opendaylight/toaster
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 14:10 min
[INFO] Finished at: 2016-02-02T22:57:51+08:00
[INFO] Final Memory: 19M/175M
[INFO] ------------------------------------------------------------------------
在当前目录下创建了如下目录结构:
toaster/
->api/
->artifacts/
->features/
->impl/
->karaf/
->pom.xml
api:使用yang定义java API,REST API等
artifacts:负责将api,impl等模块打包陈artifact。
feature:描述当前项目feature的依赖关系。
impl:项目功能实现的feature,包含了代码和配置文件。
2.编译运行
# mvn clean install -DskipTests
#cd karaf/target/assembly/bin
#./karaf
opendaylight-user@root>feature:list | grep toaster
odl-toaster | 1.3.1-SNAPSHOT | | odl-mdsal-1.3.1-SNAPSHOT | OpenDaylight :: Toaster
odl-toaster-api | 1.0.0-SNAPSHOT | x | odl-toaster-1.0.0-SNAPSHOT | OpenDaylight :: toaster :: api
odl-toaster | 1.0.0-SNAPSHOT | x | odl-toaster-1.0.0-SNAPSHOT | OpenDaylight :: toaster
odl-toaster-rest | 1.0.0-SNAPSHOT | x | odl-toaster-1.0.0-SNAPSHOT | OpenDaylight :: toaster :: REST
odl-toaster-ui | 1.0.0-SNAPSHOT | x | odl-toaster-1.0.0-SNAPSHOT | OpenDaylight :: toaster :: UI
toaster已经安装
四、定义Toaster YANG 数据模型
1.编辑toaster/api/src/main/yang/toaster.yang文件,定义toaster的基本属性YANG:
module toaster {
yang-version 1;
namespace "urn:opendaylight:params:xml:ns:yang:toaster";
prefix "toaster";
//Defines the organization which defined / owns this .yang file.
organization "Netconf Central";
//defines the primary contact of this yang file.
contact
"Andy Bierman
";
//provides a description of this .yang file.
description
"YANG version of the TOASTER-MIB.";
revision "2015-01-05" {
description "Initial revision of toaster model";
}
//declares a base identity, in this case a base type for different types of toast.
identity toast-type {
description
"Base for all bread types supported by the toaster. New bread types not listed here nay be added in the future.";
}
//the below identity section is used to define globally unique identities
//Note - removed a number of different types of bread to shorten the text length.
identity white-bread {
base toast-type; //logically extending the declared toast-type above.
description "White bread."; //free text description of this type.
}
identity wheat-bread {
base toast-type;
description "Wheat bread.";
}
identity wonder-bread {
base toast-type;
description "Wonder bread.";
}
//defines a new "Type" string type which limits the length
typedef DisplayString {
type string {
length "0 .. 255";
}
description
"YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
reference
"RFC 2579, section 2.";
}
// This definition is the top-level configuration "item" that defines a toaster. The "presence" flag connotes there
// can only be one instance of a toaster which, if present, indicates the service is available.
container toaster {
presence
"Indicates the toaster service is available";
description
"Top-level container for all toaster database objects.";
//Note in these three attributes that config = false. This indicates that they are operational attributes.
leaf toasterManufacturer {
type DisplayString;
config false;
mandatory true;
description
"The name of the toaster's manufacturer. For instance, Microsoft Toaster.";
}
leaf toasterModelNumber {
type DisplayString;
config false;
mandatory true;
description
"The name of the toaster's model. For instance, Radiant Automatic.";
}
leaf toasterStatus {
type enumeration {
enum "up" {
value 1;
description
"The toaster knob position is up. No toast is being made now.";
}
enum "down" {
value 2;
description
"The toaster knob position is down. Toast is being made now.";
}
}
config false;
mandatory true;
description
"This variable indicates the current state of the toaster.";
}
leaf darknessFactor {
type uint32;
config true;
default 1000;
description "The darkness factor";
}
}
rpc make-toast{
input{
leaf toasterDoneness {
type uint32 {
range "1 .. 10";
}
default '5';
}
leaf toasterToastType {
type identityref {
base toast-type;
}
default 'wheat-bread';
}
}
}
rpc cancel-toast {
}
notification toastDone{
leaf toastStatus{
type uint32;
}
}
}
2.编译运行
# mvn clean install -DskipTests
#cd karaf/target/assembly/bin
#./karaf
opendaylight-user@root>
3.使用curl命令来进行RESTCONF调用,查看configure中的数据:
另外打开一个终端,进行数据的写入:
#curl -H 'Content-type:application/json' -X PUT -d '{"toaster":{"darknessFactor":500}}' --verbose -u admin:admin http://localhost:8181/restconf/config/toaster:toaster
查看刚才写入的数据:
#curl --verbose -u admin:admin http://localhost:8181/restconf/config/toaster:toaster
......
{"toaster":{"darknessFactor":500}}
关于darknessFactor,虽然在yang中定义了default值为1000,但是如果部执行数据的写入,而直接查看数据信息,却无法获取
这个默认值,可能是opendaylight的一个bug吧。
五、实现自定义RPC(make-toaster和cancel-toaster)
1.在ToasterProvider.java同目录下定义ToasterServiceImpl.java,实现make-toaster和cancel-toaster方法,
如果觉得使用文本编辑器写代码麻烦,可以执行mvn eclipse:eclipse转换成eclipse工程,然后导入到eclipse
后敲,还要注意一点,java文件必须要在以“/*”开头,不然编译的时候会提示错误。
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import java.util.concurrent.Future;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.MakeToastInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.util.concurrent.Futures;
public class ToasterServiceImpl implements ToasterService {
private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceImpl.class);
@Override
public Future> cancelToast() {
LOG.info("cancelToast");
return Futures.immediateFuture(RpcResultBuilder. success().build());
}
@Override
public Future> makeToast(MakeToastInput input) {
LOG.info("makeToast:{}",input);
return Futures.immediateFuture(RpcResultBuilder. success().build());
}
}
2.修改ToasterProvider.java将ToasterServiceImpl注册到MD-SAL:
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ToasterProvider implements BindingAwareProvider, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(ToasterProvider.class);
private RpcRegistration rpcReg = null;
@Override
public void onSessionInitiated(ProviderContext session) {
LOG.info("ToasterProvider Session Initiated");
rpcReg = session.addRpcImplementation(ToasterService.class, new ToasterServiceImpl());
}
@Override
public void close() throws Exception {
if(rpcReg != null){
rpcReg.close();
}
LOG.info("ToasterProvider Closed");
}
}
3.编译运行
#mvn clean install -DskipTests
#cd karaf/target/assembly/bin
#./karaf
opendaylight-user@root>
4.打开log显示
opendaylight-user@root>log:tail
5.执行一下RPC请求:
#curl -H 'Content-type:application/json' -X POST -d '{"input":{"toaster:toasterDoneness":"10","toaster:toasterToastType":"wheat-bread"}}' --verbose -u admin:admin http://localhost:8181/restconf/operations/toaster:make-toast
请求应该返回200 OK
同时,opendaylight的界面出现如下log:
2016-04-01 23:57:19,473 | INFO | qtp227610208-75 | ToasterServiceImpl | 154 - org.opendaylight.toaster.impl - 1.0.0.SNAPSHOT | makeToast: MakeToastInput{getToasterDoneness=10, getToasterToastType=class org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.WheatBread, augmentations={}}
六、读取dataStore中的数据,执行make toaster,
1.修改ToasterProvider.java的内容如下:
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ToasterProvider implements BindingAwareProvider, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(ToasterProvider.class);
private RpcRegistration rpcReg = null;
@Override
public void onSessionInitiated(ProviderContext session) {
//从session中获取broker
DataBroker broker = session.getSALService(DataBroker.class);
//将broker交给实现者
ToasterServiceImpl service = new ToasterServiceImpl(broker);
rpcReg = session.addRpcImplementation(ToasterService.class, service);
LOG.info("ToasterProvider Session Initiated");
}
@Override
public void clos3.编译运行
#mvn clean install -DskipTests
#cd karaf/target/assembly/bin
#./karaf
opendaylight-user@root>
2.在修改ToasterProvider.java同一目录下创建MakeToastTask.java,用于执行make toaster任务,文件内容如下:
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import java.util.concurrent.Callable;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.MakeToastInput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MakeToastTask implements Callable{
private static final Logger LOG = LoggerFactory.getLogger(MakeToastTask.class);
private final MakeToastInput toastRequest;
public MakeToastTask(MakeToastInput toastRequest){
this.toastRequest = toastRequest;
}
public Void call(){
try{
LOG.info("makeToast start,Doneness:"+toastRequest.getToasterDoneness()+",Type:"+toastRequest.getToasterToastType());
Thread.sleep(10000);
LOG.info("makeToast end.....");
}catch (InterruptedException e){
LOG.info("interrupted while making the toast");
}
return null;
}
}
3.修改ToasterServiceImpl.java文件的内容如下:
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.MakeToastInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.Toaster;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.Toaster.ToasterStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterService;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
public class ToasterServiceImpl implements ToasterService {
private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceImpl.class);
private final AtomicReference> currentMakeToastTask = new AtomicReference<>();
private final ExecutorService executor = Executors.newFixedThreadPool(1);
private DataBroker broker;
public ToasterServiceImpl(DataBroker broker) {
this.broker = broker;
}
@Override
public Future> cancelToast() {
LOG.info("cancelToast");
return Futures.immediateFuture(RpcResultBuilder. success().build());
}
@Override
public Future> makeToast(final MakeToastInput input) {
LOG.info("makeToast: {}",input);
final InstanceIdentifier TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
final ReadWriteTransaction tx = broker.newReadWriteTransaction();
ListenableFuture> readFuture =
tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID );
//将Optional类型的ListenableFuture转换成Void的ListenableFuture
final ListenableFuture commitFuture =
Futures.transform( readFuture, new AsyncFunction,Void>() {
@Override
public ListenableFuture apply(
final Optional toasterData ) throws Exception {
//获取toaster的tasterStatus
ToasterStatus toasterStatus = ToasterStatus.Down;
if( toasterData.isPresent() ) {
toasterStatus = toasterData.get().getToasterStatus();
}
//判断当前的状态是不是Up
if( toasterStatus == ToasterStatus.Up ) {
//如果是Up状态,则抛出异常
LOG.info("the toaster is already using,please wait a moment!");
return Futures.immediateFailedCheckedFuture(
new TransactionCommitFailedException( "", RpcResultBuilder.newWarning( ErrorType.APPLICATION, "in-use",
"Toaster is busy", null, null, null ) ) );
} else{
//如果是down状态,则修改成Up状态
tx.put( LogicalDatastoreType.OPERATIONAL, TOASTER_IID,
new ToasterBuilder().setToasterStatus( ToasterStatus.Up ).build());
return tx.submit();
}
}
} );
//添加callback函数
Futures.addCallback( commitFuture, new FutureCallback() {
@Override
public void onSuccess( final Void result ) {
// 如果更新data store成功则执行makeToast
currentMakeToastTask.set( executor.submit(new MakeToastTask(input)));
}
@Override
public void onFailure( final Throwable ex ) {
LOG.debug( "Failed to commit Toaster status", ex );
}
}
);
return Futures.immediateFuture(RpcResultBuilder. success().build());
}
}
4.编译运行
#mvn clean install -DskipTests
#cd karaf/target/assembly/bin
#./karaf
opendaylight-user@root>
5.打开log显示
opendaylight-user@root>log:tail
6.打开终端,执行make toast请求:
#curl -H 'Content-type:application/json' -X POST -d '{"input":{"toaster:toasterDoneness":"10","toaster:toasterToastType":"wheat-bread"}}' --verbose -u admin:admin http://localhost:8181/restconf/operations/toaster:make-toast
在log中会显示如下信息:
2016-04-04 16:09:21,899 | INFO | pool-30-thread-1 | MakeToastTask | 154 - org.opendaylight.toaster.impl - 1.0.0.SNAPSHOT | makeToast start,Doneness:10,Type:class org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.WheatBread
2016-04-04 16:09:31,901 | INFO | pool-30-thread-1 | MakeToastTask | 154 - org.opendaylight.toaster.impl - 1.0.0.SNAPSHOT | makeToast end.....
7.再次执行make toast请求:
在log中会显示如下信息:(因为md-sal的data store中的toasterStatus一直为up)
2016-04-04 16:12:09,851 | INFO | tp1594748046-332 | ToasterServiceImpl | 154 - org.opendaylight.toaster.impl - 1.0.0.SNAPSHOT | makeToast: MakeToastInput{getToasterDoneness=10, getToasterToastType=class org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.WheatBread, augmentations={}}
2016-04-04 16:12:09,853 | INFO | tp1594748046-332 | ToasterServiceImpl | 154 - org.opendaylight.toaster.impl - 1.0.0.SNAPSHOT | the toaster is already using,please wait a moment!
七、data change事件,toasterStatus改变时APP能获取到
1.在ToasterProvider.java文件进行如下修改:
在onSessionInitiated方法中注册dataChange。
在close方法中增加对dataChangeListenerRegistration的close。
代码如下:
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterService;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ToasterProvider implements BindingAwareProvider, AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(ToasterProvider.class);
private RpcRegistration rpcReg = null;
private ListenerRegistration dataChangeListenerRegistration = null;
@Override
public void onSessionInitiated(ProviderContext session) {
//从session中获取broker
DataBroker broker = session.getSALService(DataBroker.class);
//将broker交给实现者
ToasterServiceImpl service = new ToasterServiceImpl(broker);
//注册rpc 和dataChange
rpcReg = session.addRpcImplementation(ToasterService.class, service);
dataChangeListenerRegistration = broker
.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, service.TOASTER_IID,
service, DataChangeScope.SUBTREE);
LOG.info("ToasterProvider Session Initiated");
}
@Override
public void close() throws Exception {
if(rpcReg != null){
rpcReg.close();
}
if(dataChangeListenerRegistration != null){
dataChangeListenerRegistration.close();
}
LOG.info("ToasterProvider Closed");
}
}
2.在ToasterServiceImpl.java中实现DataChangeListener接口的onDataChanged方法:
/*
* Copyright © 2015 CopyLeft(c) 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.toaster.impl;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
import org.opendaylight.controller.md.sal.binding.api.DataBroker;
import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.MakeToastInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.Toaster;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.Toaster.ToasterStatus;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.toaster.rev150105.ToasterService;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
public class ToasterServiceImpl implements ToasterService,DataChangeListener {
private static final Logger LOG = LoggerFactory.getLogger(ToasterServiceImpl.class);
private final AtomicReference> currentMakeToastTask = new AtomicReference<>();
final InstanceIdentifier TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
private final ExecutorService executor = Executors.newFixedThreadPool(1);
private DataBroker broker;
public ToasterServiceImpl(DataBroker broker) {
this.broker = broker;
}
@Override
public Future> cancelToast() {
LOG.info("cancelToast");
return Futures.immediateFuture(RpcResultBuilder. success().build());
}
@Override
public Future> makeToast(final MakeToastInput input) {
LOG.info("makeToast: {}",input);
final InstanceIdentifier TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
final ReadWriteTransaction tx = broker.newReadWriteTransaction();
ListenableFuture> readFuture =
tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID );
//将Optional类型的ListenableFuture转换成Void的ListenableFuture
final ListenableFuture commitFuture =
Futures.transform( readFuture, new AsyncFunction,Void>() {
@Override
public ListenableFuture apply(
final Optional toasterData ) throws Exception {
//获取toaster的tasterStatus
ToasterStatus toasterStatus = ToasterStatus.Down;
if( toasterData.isPresent() ) {
toasterStatus = toasterData.get().getToasterStatus();
}
//判断当前的状态是不是Up
if( toasterStatus == ToasterStatus.Up ) {
//如果是Up状态,则抛出异常
LOG.info("the toaster is already using,please wait a moment!");
return Futures.immediateFailedCheckedFuture(
new TransactionCommitFailedException( "", RpcResultBuilder.newWarning( ErrorType.APPLICATION, "in-use",
"Toaster is busy", null, null, null ) ) );
} else{
//如果是down状态,则修改成Up状态
tx.put( LogicalDatastoreType.OPERATIONAL, TOASTER_IID,
new ToasterBuilder().setToasterStatus( ToasterStatus.Up ).build());
return tx.submit();
}
}
} );
//添加callback函数
Futures.addCallback( commitFuture, new FutureCallback() {
@Override
public void onSuccess( final Void result ) {
// 如果更新data store成功则执行makeToast
currentMakeToastTask.set( executor.submit(new MakeToastTask(input)));
}
@Override
public void onFailure( final Throwable ex ) {
LOG.debug( "Failed to commit Toaster status", ex );
}
}
);
return Futures.immediateFuture(RpcResultBuilder. success().build());
}
@Override
public void onDataChanged( final AsyncDataChangeEvent, DataObject> change ) {
DataObject dataObject = change.getUpdatedSubtree();
if( dataObject instanceof Toaster )
{
Toaster toaster = (Toaster) dataObject;
LOG.info("onDataChanged - new Toaster config: {}", toaster);
}
}
}
3.编译运行
#mvn clean install -DskipTests
#cd karaf/target/assembly/bin
#./karaf
opendaylight-user@root>
4.打开log显示
opendaylight-user@root>log:tail
5.打开终端,执行make toast请求:
#curl -H 'Content-type:application/json' -X PUT -d '{"toaster":{"darknessFactor":510}}' --verbose -u admin:admin http://localhost:8181/restconf/config/toaster:toaster
#curl -H 'Content-type:application/json' -X PUT -d '{"toaster":{"darknessFactor":511}}' --verbose -u admin:admin http://localhost:8181/restconf/config/toaster:toaster
6.log显示如下信息:
2016-04-04 19:58:48,980 | INFO | n-dispatcher-183 | ToasterServiceImpl | 154 - org.opendaylight.toaster.impl - 1.0.0.SNAPSHOT | onDataChanged - new Toaster config: Toaster{getDarknessFactor=510, augmentations={}}