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 <[email protected]>";
//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<RpcResult<java.lang.Void>> cancelToast() {
LOG.info("cancelToast");
return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
}
@Override
public Future<RpcResult<java.lang.Void>> makeToast(MakeToastInput input) {
LOG.info("makeToast:{}",input);
return Futures.immediateFuture(RpcResultBuilder.<Void> 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<ToasterService> 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<ToasterService> 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<Void>{
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<Future<?>> currentMakeToastTask = new AtomicReference<>();
private final ExecutorService executor = Executors.newFixedThreadPool(1);
private DataBroker broker;
public ToasterServiceImpl(DataBroker broker) {
this.broker = broker;
}
@Override
public Future<RpcResult<java.lang.Void>> cancelToast() {
LOG.info("cancelToast");
return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
}
@Override
public Future<RpcResult<java.lang.Void>> makeToast(final MakeToastInput input) {
LOG.info("makeToast: {}",input);
final InstanceIdentifier<Toaster> TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
final ReadWriteTransaction tx = broker.newReadWriteTransaction();
ListenableFuture<Optional<Toaster>> readFuture =
tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID );
//將Optional<Toaster>類型的ListenableFuture轉換成Void的ListenableFuture
final ListenableFuture<Void> commitFuture =
Futures.transform( readFuture, new AsyncFunction<Optional<Toaster>,Void>() {
@Override
public ListenableFuture<Void> apply(
final Optional<Toaster> 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<Void>() {
@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.<Void> 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<ToasterService> rpcReg = null;
private ListenerRegistration<DataChangeListener> 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<Future<?>> currentMakeToastTask = new AtomicReference<>();
final InstanceIdentifier<Toaster> 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<RpcResult<java.lang.Void>> cancelToast() {
LOG.info("cancelToast");
return Futures.immediateFuture(RpcResultBuilder.<Void> success().build());
}
@Override
public Future<RpcResult<java.lang.Void>> makeToast(final MakeToastInput input) {
LOG.info("makeToast: {}",input);
final InstanceIdentifier<Toaster> TOASTER_IID = InstanceIdentifier.builder(Toaster.class).build();
final ReadWriteTransaction tx = broker.newReadWriteTransaction();
ListenableFuture<Optional<Toaster>> readFuture =
tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID );
//將Optional<Toaster>類型的ListenableFuture轉換成Void的ListenableFuture
final ListenableFuture<Void> commitFuture =
Futures.transform( readFuture, new AsyncFunction<Optional<Toaster>,Void>() {
@Override
public ListenableFuture<Void> apply(
final Optional<Toaster> 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<Void>() {
@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.<Void> success().build());
}
@Override
public void onDataChanged( final AsyncDataChangeEvent<InstanceIdentifier<?>, 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={}}
opendaylight(Li)下toaster APP的簡單實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章
開發第一個OpenDaylight中的OSGI bundle
pantingting_
2020-02-21 20:50:01
OpenDaylight集羣功能驗證實驗一
pantingting_
2020-02-21 20:50:01
OpenDaylight集羣功能驗證性實驗二_可靠性驗證
pantingting_
2020-07-06 20:26:55
SDN-OpenDaylight(Solium版本)應用開發入門HelloWorld
lady_killer9
2020-04-25 08:31:48
Opendaylight Carbon(碳)版本安裝
又起风了
2019-10-25 14:53:49
opendaylight 安裝報錯 Non-resolvable parent POM for org.opendaylight.sfc:sfc-parent
又起风了
2019-10-25 14:53:49
最普及的開源SDN控制器OpenDaylight發佈Neon版本慶祝成立六週年
Donald Liu
2019-03-27 23:48:06
通過opendaylight源碼解讀控制器與openflow交換機建立過程
nn_li
2018-09-05 01:00:23
OpenDaylight簡介和安裝
AshinCode
2018-09-04 19:30:09
opendaylight(Li) l2switch 源代碼分析(2)--parent
TODD911
2018-09-04 09:24:48
opendaylight(Li) l2switch 源代碼分析(1)--代碼的整體結構和整體pom.xml
TODD911
2018-09-04 09:24:48
opendalight(Li) northbound APP 開發
TODD911
2018-09-04 09:24:48