SAP接口编程 之 JCo3.0系列(04) : 会话管理

SAP接口编程之 NCo3.0系列(06) : 会话管理 这篇文章中,对会话管理的相关知识点已经说得很详细了,请参考。现在用JCo3.0来实现。

1. JCoContext

如果SAP中多个函数需要在一个session中运行,需要JCoContext来提供保证。如果在同一个线程中,大体模式这样:

JCoContext.begin(sapDestination);

fm1.execute(sapDestination);
fm2.execute(sapDestination);

JCoContext.end(destination);

begin()和end()之间的函数execute之后,SAP不会释放连接,确保同一个session之中。

第二种情况:如果不同的函数不在同一个线程中,需要由开发人员实现SessionReferenceProvider接口,在类中提供session id。逻辑跟nco3.0也是一样的。JCo3.0提供了一个示例代码,但是搞的太复杂,我弄了一个简单的,方便理解。

2. SAP函数

我们要使用的函数是从标准系统函数INCREMENT_COUNTER
GET_COUNTER拷贝而来的。在SAP系统中INCREMENT_COUNTER
GET_COUNTER在同一个function group中,共享一个变量count(计数器),每次运行INCREMENT_COUNTER
, count就会加一,GET_COUNTER函数
可以获得这个count。因为这两个函数不能被远程调用,所以我们将这两个函数拷贝出另外两个函数ZINCREMENT_COUNTER和ZGET_COUNTER。

3. 同一线程中执行函数

首先我们把两个函数定义在一个类RfcFunctions中:

package jco3.demo6;

import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoFunction;

public class RfcFunctions
{
    public static int runGetCounter(JCoDestination dest) throws JCoException
    {
        JCoFunction counterFM = dest.getRepository().getFunction("ZGET_COUNTER");
        counterFM.execute(dest);
        int counter = (int) counterFM.getExportParameterList().getValue("GET_VALUE");

        return counter;
    }

    public static void runIncrement(JCoDestination dest) throws JCoException
    {
        JCoFunction increment = dest.getRepository().getFunction("ZINCREMENT_COUNTER");
        increment.execute(dest);
    }
}

然后编写测试类进行测试:

package jco3.demo6;

import com.sap.conn.jco.JCoContext;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;

public class TestSessionSameThread
{
    public static void main(String[] args) throws JCoException, InterruptedException
    {
        // get JCoDestination object instance
        JCoDestination destination = JCoDestinationManager.getDestination("ECC");

        // make sure the two functions will be executed in the same session
        JCoContext.begin(destination);

        // Before increment
        System.out.println("Before execution of ZINCREMENT_COUNTER:");
        System.out.println("Counter:" + RfcFunctions.runGetCounter(destination));

        // Run incrementCounter five times
        for(int i = 0; i < 5; i++){
            RfcFunctions.runIncrement(destination);
            System.out.println("Add:" + (i + 1));
        }

        // After increment
        System.out.println("After execution of ZINCREMENT_COUNTER:");
        System.out.println("Counter:" + RfcFunctions.runGetCounter(destination));    

        // release the connection
        JCoContext.end(destination);
    }
}

代码很直观,就不多说了。函数执行前,counter的值为0,运行函数5次之后,counter的值为5。如果我们注释掉JCoContext.begin(destination);JCoContext.end(destination);,可以对比出不同的效果。

4. 不同线程中执行函数

如果在不同的线程中执行不同的函数,需要开发者提供session id。我准备将两个函数放在不同的线程中:

  • 在JVM的主线程中调用ZGET_COUNTER,查看counter的结果。
  • 在另外一个线程中运行ZINCREMENT_COUNTER,两个线程通过JCoContext,保持在同一个session ID下。

4.1 实现JCoSessionReference接口

JCoSessionRefence实现类的主要作用是提供session ID:

package jco3.session;

import java.util.concurrent.atomic.AtomicInteger;
import com.sap.conn.jco.ext.JCoSessionReference;

public class JCoSessionRefenceImpl implements JCoSessionReference
{
    private AtomicInteger atomInt = new AtomicInteger(0);
    private String id = "session"+String.valueOf(atomInt.addAndGet(1));

    public void contextFinished()
    {
    }

    public void contextStarted()
    {
    }

    @Override
    public String getID()
    {
        /**
         * We need to override getID() method
         */

        return id;
    }
}

4.2 实现SessionReferenceProvider接口

SessionReferenceProvider接口的实现类中,改写getCurrentSessionReference()方法,获取上面定义的JCoSessionRefence,从而获得session ID。其他方法保持不动。

package jco3.session;

import com.sap.conn.jco.ext.JCoSessionReference;
import com.sap.conn.jco.ext.SessionException;
import com.sap.conn.jco.ext.SessionReferenceProvider;

public class SessionReferencProviderImpl implements SessionReferenceProvider
{

    @Override
    public JCoSessionReference getCurrentSessionReference(String scopeType)
    {
        /**
         *  We need to override getCurrentSessionReference() method
         */

        JCoSessionRefenceImpl sessionRef = new JCoSessionRefenceImpl();
        return sessionRef;
    }

    @Override
    public boolean isSessionAlive(String sessionID)
    {
        return false;
    }

    public void jcoServerSessionContinued(String sessionID) throws SessionException
    {
    }

    public void jcoServerSessionFinished(String sessionID)
    {
    }

    public void jcoServerSessionPassivated(String sessionID) throws SessionException
    {
    }

    public JCoSessionReference jcoServerSessionStarted() throws SessionException
    {
        return null;
    }
}

4.3 注册 SessionReferenceProvider接口

注册SessionReferenceProvider接口的实现类,这样JCoDestination就有状态管理功能了。

package jco3.session;

import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.ext.Environment;
import com.sap.conn.jco.ext.SessionReferenceProvider;

public class DestinationProvider
{
    public static JCoDestination getDestination() throws JCoException
    {
        // create an instance of SessionReferenceProvider
        // and register in environment
        SessionReferenceProvider provider = new SessionReferencProviderImpl();
        Environment.registerSessionReferenceProvider(provider);

        JCoDestination destination = JCoDestinationManager.getDestination("ECC");

        return destination;
    }
}

4.4 在单独线程中执行ZINCREMENT_COUNTER

定义WorkingThread, 从Thread类继承,在这个线程中执行函数ZINCREMENT_COUNTER 5次。

package jco3.demo6;

import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoException;

public class WorkingThread extends Thread
{
    private boolean doneSignal;
    private JCoDestination destination;

    // constructor
    public WorkingThread(JCoDestination destination, boolean doneSignal)
    {
        this.destination = destination;
        this.doneSignal = doneSignal;
    }

    public boolean hasDone()
    {
        return doneSignal;
    }

    @Override
    public void run()
    {
        /**
         * run method of runIncrement() for five times
         */

        for (int i = 0; i < 5; i++){
            try {
                RfcFunctions.runIncrement(this.destination);
                System.out.println("Run " + (i+1) + " times.");
            } catch (JCoException e) {
                e.printStackTrace();
            }
        }

        this.doneSignal = true;
    }
}

doneSignal用于标识该线程是否结束。线程本身结束,是run()方法运行完毕。

4.5 测试多线程函数调用

好了,最后来测试在多线程中函数调用:

package jco3.demo6;

import com.sap.conn.jco.JCoContext;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoException;
import jco3.session.DestinationProvider;

public class TestSAPSessionMultiThread
{
    public static void main(String[] args) throws JCoException, InterruptedException
    {
        /**
         * Run ZINCREMENT_COUNTER & ZGET_COUNTER functions in
         * different threads in a stateful way.
         *
         * The SAP will keep a session id which was created in
         * JCoSessionReferenceImpl class
         * and used in SessionReferenceProviderImpl class.
         *
         * Before using, SessionReferenceProviderImpl class should be
         * registered using Environment.registerSessionReferenceProvider() method.
         */

        // get JCoDestination object instance
        JCoDestination destination = DestinationProvider.getDestination();

        // make sure the two functions will be executed in the same session
        JCoContext.begin(destination);

        // Before increment
        System.out.println("Before execution of ZINCREMENT_COUNTER:");
        System.out.println("Counter:" + RfcFunctions.runGetCounter(destination));

        // start a new Thread in which function ZINCREMENT_COUNTER
        // will be executed for five times
        WorkingThread workingThread = new WorkingThread(destination, false);
        workingThread.start();

        // wait and switch thread
        Thread.sleep(1000);

        // After increment
        if (workingThread.hasDone() == true){
            System.out.println("After execution of ZINCREMENT_COUNTER:");
            System.out.println("Counter:" + RfcFunctions.runGetCounter(destination));
        }

        // release the connection
        JCoContext.end(destination);
    }
}

与前面同一个线程中代码的主要区别是:
定义一个WorkingThread类的实例,然后启动线程:

WorkingThread workingThread = new WorkingThread(destination, false);
workingThread.start();

然后通过Thread.sleep(), 将线程切换到workingThread中执行,执行完毕再回到主线程显示结果。

文/StoneWM(简书作者)
原文链接:http://www.jianshu.com/p/2ce28196483c
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

时间: 2024-08-10 21:22:47

SAP接口编程 之 JCo3.0系列(04) : 会话管理的相关文章

SAP接口编程 之 JCo3.0系列(03) : Table参数

Table参数作为export parameter BAPI_COMPANYCODE_GETDETAIL是一个适合演示的函数,没有import paramter参数,调用后COMPANYCODE_GETDETAIL 表参数返回SAP系统中所有公司代码的清单.只包括公司代码ID和公司代码名称两个字段. JCo中,与表参数相关的两个接口是JCoTable和JCoRecordMetaDta, JCoTable就是RFM中tabl参数,而JCoRecordMetaDta是JCoTable或JCoStru

SAP接口编程 之 JCo3.0系列(05) : Exception Handling

JCO3.0的Exception,常用的Exception如下: JCoException 继承自java.lang.Exception,是JCo3中Exception的基类. JCoRuntimeException 继承自java.lang.RuntimeException,是JCo3中Runtime的基类. 参考文档 以下是JCo3比较有价值的参考文档 JCo3.0在线帮助http://help.sap.com/saphelp_nwce711/helpdata/en/46/fb807cc7b

SAP接口编程之 NCo3.0之RfcDestination(转)

转载地址:http://www.jianshu.com/p/5a5b4de5e1f1 http://www.jianshu.com/u/fd37d4449963 进入新的系列:.net connector 3.0,简称Nco3.0.Nco3.0是SAP针对.net平台提供的编程接口,由nco1.0/nco2.0演变而来.如果使用.net平台编程,推荐使用nco3.0,3.0和之前1.0/2.0比较,不管是API还是架构,都重新设计过,也借鉴了Jco3.0的设计,所以相对来说比较成熟,给程序员提供

Qt系列04 布局管理

本节介绍Qt常用布局管理,QSplitter类.QDockWidget类和QStackedWidget类. QSplitter类 #include "widget.h" #include <QApplication> #include <QSplitter> #include <QLineEdit> int main(int argc, char *argv[]) { QApplication a(argc, argv); QSplitter *sp

LXD 2.0 系列(四):资源控制

LXD 提供了各种资源限制.其中一些与容器本身相关,如内存配额.CPU 限制和 I/O 优先级.而另外一些则与特定设备相关,如 I/O 带宽或磁盘用量限制.-- Stéphane Graber 本文导航 -可用资源限制03% -磁盘08% -CPU12% -内存21% -网络 I/O26% -块 I/O29% -它怎么工作?39% -应用这些限制43% -CPU47% -内存58% -磁盘和块 I/O63% -网络 I/O71% -获取当前资源使用率81% -总结92% -更多信息94% 编译自

面向接口编程

系列——MEF实现设计上的“松耦合”(终结篇:面向接口编程) 序:忙碌多事的八月带着些许的倦意早已步入尾声,金秋九月承载着抗战胜利70周年的喜庆扑面而来.没来得及任何准备,似乎也不需要任何准备,因为生活不需要太多将来时.每天忙着上班.加班.白加班,忘了去愤,忘了去算计所谓的价值.天津爆炸事故时刻警示着我们生命的无常,逝者安息,活着的人生活还得继续,珍惜生命,远离伤害.武汉,这座炙热的城市,虽值金秋,却依然经受着“秋老虎”的烘烤,马路上蒸腾的热气迎面袭来,全身毛孔张开,汗流不止,在这般高温下,似乎

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要  和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数

Spring4.0系列9-websocket简单应用

http://wiselyman.iteye.com/blog/2003336 ******************************************* Spring4.0系列1-新特性 Spring4.0系列2-环境搭建 Spring4.0系列[email protected] Spring4.0系列4-Meta Annotation(元注解) Spring4.0系列[email protected] Spring4.0系列6-Generic Qualifier(泛型限定) Sp

android客户端应用(native app)适配测试自动化 东海陈光剑 2014年5月5日 0:39:04

未命名 android客户端应用(native app)适配测试自动化 东海陈光剑 2014年5月5日 0:39:04 http://10.125.1.58:88/report.html?run_stamp=20140428054354&min=3&sec=214 <!doctype html><html><head>    <meta charset="UTF-8">    <title>适配测试报告<