首页 > 代码库 > 在odl中如何实现rpc

在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的工程目录结构。


第一步:定义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.1-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

该工程定义为xpprovider。

rpc实现类XpTestProvider

package org.opendaylight.controller.xptest.impl;

import java.util.concurrent.Future;

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 com.google.common.util.concurrent.Futures;

public class XpTestProvider implements XptestService {

  @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;
    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.1-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>

第三步:进行测试。

运行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数据,如何header中加accept:application/yang.data+json,将返回json数据。

按上面代码中意图可以构造失败测试用例。

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

在odl中如何实现rpc