在odl中怎样实现rpc

opendaylight作为sdn主要开源项目,採用osgi框架。已经得到非常多厂商的支持。氦版本号也公布在即。

以下介绍一下在odl中怎样实现rpc. odl使用yang作为model模型定义文件。yang规范最先被用于netconf,后来restconf在http协议上实现restful。而採用yang定义模型。

实现分2步:1.採用yang定义模型,实现api jar包。2 实现rpc service的实现类,注冊到session中。

2个java的project文件夹结构。


第一步:定义yang文件及其pom.xml

在文件夹xptest\src\main\yang下定义xptest.yang

  module xptest {
    yang-version 1;

    namespace
      "http://startsky.com/ns/xptest";

    prefix xps;

    organization "xpstudio Netconf Central";

    contact
      "xinping <xpzh@sohu.com>";

    description
      "YANG version of the xptest-MIB.";

    revision "2014-10-3" {
      description
        "xptest module in progress.";
    }



    typedef DispString {
      type string {
        length "0 .. 255";
      }
      description
        "YANG version of the SMIv2 DisplayString TEXTUAL-CONVENTION.";
      reference
        "RFC 2579, section 2.";

    }

    container xptester {
    leaf name {
      type string;
    }

    leaf age {
      type uint32;
      default 99;
    }
    leaf homeaddress {
      type string;
    }
    }  // container toaster

    rpc make-order {
      input {
      leaf name {
        type string;
      }
      leaf days {
      type uint32;
      default 1;
      }
      }
      output {
      leaf name {
        type string;
      }
       leaf orderno {
          type uint32;
      }
        }
    }  // make-order

    rpc cancel-order {
        input {
        leaf orderno {
          type uint32;
        }
        }
        output {
           leaf name {
             type string;
           }
          leaf order-status {
             type enumeration {
                enum "success" {
               value 1;
               }
                enum "fail" {
                 value 2;
                }
        }
      }
    }
    }  // cancel-order

  }  // module xptest

定义yang的pom.xml,在xptest下定义pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.opendaylight.controller.samples</groupId>
    <artifactId>sal-samples</artifactId>
    <version>1.2.0-SNAPSHOT</version>
  </parent>
  <artifactId>sample-xptest</artifactId>
  <packaging>bundle</packaging>
  <dependencies>
    <dependency>
      <groupId>org.opendaylight.yangtools</groupId>
      <artifactId>yang-binding</artifactId>
    </dependency>
    <dependency>
      <groupId>org.opendaylight.yangtools</groupId>
      <artifactId>yang-common</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.opendaylight.yangtools</groupId>
        <artifactId>yang-maven-plugin</artifactId>
        <dependencies>
          <dependency>
            <groupId>org.opendaylight.yangtools</groupId>
            <artifactId>maven-sal-api-gen-plugin</artifactId>
            <version>${yangtools.version}</version>
            <type>jar</type>
          </dependency>
        </dependencies>
        <executions>
          <execution>
            <goals>
              <goal>generate-sources</goal>
            </goals>
            <configuration>
              <yangFilesRootDir>src/main/yang</yangFilesRootDir>
              <codeGenerators>
                <generator>
                  <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
                  <outputBaseDir>${salGeneratorPath}</outputBaseDir>
                </generator>
              </codeGenerators>
              <inspectDependencies>true</inspectDependencies>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <scm>
    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
    <tag>HEAD</tag>
    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
  </scm>
</project>

上面yang文件定义了两个rpc。

执行mvn install编译xptest.yang. 会产生一个rpc服务XptestService 接口。当中两个方法相应两个rpc 函数。

第二步:定义rpc的实现文件XpTestProvider及其Activator

该project定义为xpprovider。

rpc实现类XpTestProvider

package org.opendaylight.controller.xptest.impl;


import java.io.File;
import java.util.concurrent.Future;


//import org.opendaylight.controller.xptest.Activator;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderInput;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderOutput;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderOutput.OrderStatus;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.CancelOrderOutputBuilder;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.MakeOrderInput;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.MakeOrderOutput;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.MakeOrderOutputBuilder;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.XptestService;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.google.common.util.concurrent.Futures;


public class XpTestProvider implements XptestService {
  private final static Logger LOG = LoggerFactory.getLogger(XpTestProvider.class);
  @Override
  public Future<RpcResult<CancelOrderOutput>> cancelOrder(
      CancelOrderInput input) {
    // TODO Auto-generated method stub
    RpcResult<CancelOrderOutput> ret=null;
    if(input.getOrderno() >10)
    {
      ret=RpcResultBuilder.<CancelOrderOutput>failed().withError( ErrorType.APPLICATION, "resource-denied",
                  "days > 10,failed!!" ).build();
    }else {
      CancelOrderOutputBuilder builder=new CancelOrderOutputBuilder();
      builder.setName("name"+input.getOrderno());
      builder.setOrderStatus(OrderStatus.Success);
      ret=RpcResultBuilder.<CancelOrderOutput>success(builder.build()).build();
    }


    return Futures.immediateFuture(ret);
  }


  @Override
  public Future<RpcResult<MakeOrderOutput>> makeOrder(MakeOrderInput input) {
    // TODO Auto-generated method stub
    RpcResult<MakeOrderOutput> ret=null;
    LOG.info( "user.dir "+System.getProperty("user.dir"));
    File directory = new File("");//设定为当前目录
    try{
      LOG.info("std: "+directory.getCanonicalPath());//获取标准的路径
      LOG.info("abs: "+directory.getAbsolutePath());//获取绝对路径
    }catch(Exception e)
    {


    }
    if(input.getDays()>10)
    {
      ret=RpcResultBuilder.<MakeOrderOutput>failed().withError( ErrorType.APPLICATION, "resource-denied",
                  "days > 10,failed!!" ).build();
    }else {
      MakeOrderOutputBuilder builder=new MakeOrderOutputBuilder();
      builder.setName(input.getName());
      builder.setOrderno((long) 112233);
      ret=RpcResultBuilder.<MakeOrderOutput>success(builder.build()).build();
    }


    return Futures.immediateFuture(ret);
  }








}
实现插件入口类Activator,顺便实现命令行接口,能够自己定义命令行測试命令。

/**
 * Copyright (c) 2014 Cisco Systems, Inc. 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.controller.xptest;
import org.eclipse.osgi.framework.console.CommandInterpreter;
import org.eclipse.osgi.framework.console.CommandProvider;
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.xptest.impl.XpTestProvider;
import org.opendaylight.yang.gen.v1.http.startsky.com.ns.xptest.rev141003.XptestService;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Forwarding Rules Manager Activator
 *
 * Activator {@link ForwardingRulesManager}.
 * It registers all listeners (DataChangeEvent, ReconcilNotification)
 * in the Session Initialization phase.
 *
 * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
 * *
 */
public class Activator extends AbstractBindingAwareProvider
   implements CommandProvider {

    private final static Logger LOG = LoggerFactory.getLogger(Activator.class);



    @Override
    public void onSessionInitiated(ProviderContext session) {
        LOG.info("FRMActivator initialization.");
        try {
 //           final DataBroker dataBroker = session.getSALService(DataBroker.class);
//            this.manager = new ForwardingRulesManagerImpl(dataBroker, session);
//            this.manager.start();
          XpTestProvider rpcins=new XpTestProvider();
          session.addRpcImplementation(XptestService.class,rpcins);
            LOG.info("FRMActivator initialization successfull.");
        }
        catch (Exception e) {
            LOG.error("Unexpected error by FRM initialization!", e);
            this.stopImpl(null);
        }
    }

    @Override
  protected void startImpl(BundleContext context) {
    // TODO Auto-generated method stub
    super.startImpl(context);
     context.registerService(CommandProvider.class.getName(),
                  this, null);
  }

  @Override
    protected void stopImpl(final BundleContext context) {
    /*    if (manager != null) {
            try {
                manager.close();
            } catch (Exception e) {
                LOG.error("Unexpected error by stopping FRMActivator", e);
            }
            manager = null;
        }*/
       LOG.info("FRMActivator stopped.");
    }
    public void _gettpsbyne(CommandInterpreter ci) {
        ci.println("gettpsbyne:" + ci.nextArgument());
   }

   @Override
   public String getHelp() {
       return "\tgettpsbyne neid– say what you input\n";
   }
  }

xpprovider的pom.xml文件。

<?xml version="1.0" encoding="UTF-8"?

> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>   <parent>     <groupId>org.opendaylight.controller.samples</groupId>     <artifactId>sal-samples</artifactId>     <version>1.2.0-SNAPSHOT</version>   </parent> <artifactId>sample-xptest-provider</artifactId> <packaging>bundle</packaging> <dependencies> <dependency> <groupId>${project.groupId}</groupId> <artifactId>sample-xptest</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>equinoxSDK381</groupId> <artifactId>org.eclipse.osgi</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>config-api</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-api</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-config</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-common-util</artifactId> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> </dependency> <!-- dependencies to use AbstractDataBrokerTest --> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-broker-impl</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-broker-impl</artifactId> <type>test-jar</type> <scope>test</scope> </dependency> <dependency> <artifactId>junit</artifactId> <groupId>junit</groupId> <scope>test</scope> </dependency> <!-- used to mock up classes --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-api</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller.model</groupId> <artifactId>model-flow-service</artifactId> </dependency> <dependency> <groupId>org.opendaylight.yangtools</groupId> <artifactId>yang-common</artifactId> </dependency> <dependency> <groupId>org.opendaylight.controller</groupId> <artifactId>sal-binding-broker-impl</artifactId> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <configuration> <instructions> <Bundle-Activator>org.opendaylight.controller.xptest.Activator</Bundle-Activator> </instructions> </configuration> </plugin> </plugins> </build> <scm> <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection> <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection> <tag>HEAD</tag> <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url> </scm> </project>

执行mvn install 编译,之后把这两个jar包复制到odl的plugins文件夹下,最好执行odl准备。

第三步:进行測试。

执行run.bat,启动odl,在restclient中执行以下測试用例。

能够做restclient的工具有chrome插件postman,firefox的restclient,网上还有个单独jar包restclient.

HTTP Method => POST
URL => http://localhost:8080/restconf/operations/xptest:make-order
Header => Content-Type: application/yang.data+json  
Body =>  
{
  "input" :
  {
     "xptest:name" : "3","xptest:days":3
  }
}

能够看到返回xml数据, response header

  1. Status Code: 200 OK
  2. Content-Type: application/xml
  3. Date: Wed, 08 Oct 2014 12:43:29 GMT
  4. Server: Apache-Coyote/1.1
  5. Transfer-Encoding: chunked
response body

<?

xml version="1.0" encoding="UTF-8" standalone="no"?> <output xmlns="http://startsky.com/ns/xptest"> <name>3</name> <orderno>112233</orderno> </output>



假设header中加accept:application/yang.data+json,将返回json数据。

按上面代码中意图能够构造失败測试用例。

希望本文对odl有兴趣的人,可以给予帮助。

posted on 2017-04-19 21:52  blfbuaa  阅读(587)  评论(0编辑  收藏  举报