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中执行,执行完毕再回到主线程显示结果。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • 前面我们看到,SAP函数调用,Invoke语句的代码是这样的: 我们不用关心与SAP系统的连接,连接都是NCo3....
    Stone0823阅读 1,511评论 0 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,296评论 18 399
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,018评论 11 349
  • 因为可能没什么时间更新,可能解释会比较少数组是为了放一系列的数值的一个集合,他的表现形式类似于 "{数组[0]=1...
    水电梁师傅阅读 198评论 0 0