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中执行,执行完毕再回到主线程显示结果。
原文链接:http://www.jianshu.com/p/2ce28196483c
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
SAP接口编程 之 JCo3.0系列(04) : 会话管理的更多相关文章
- SAP接口编程 之 JCo3.0系列(01):JCoDestination
SAP接口编程 之 JCo3.0系列(01):JCoDestination 字数2101 阅读103 评论0 喜欢0 JCo3.0是Java语言与ABAP语言双向通讯的中间件.与之前1.0/2.0相比 ...
- SAP接口编程 之 JCo3.0系列(02) : JCo Client Programming
SAP接口编程 之 JCo3.0系列(02) : JCo Client Programming 字数545 阅读52 评论0 喜欢1 JCo3.0调用SAP函数的过程 大致可以总结为以下步骤: 连接至 ...
- SAP接口编程 之 JCo3.0系列(03) : Table参数
Table参数作为export parameter BAPI_COMPANYCODE_GETDETAIL是一个适合演示的函数,没有import paramter参数,调用后COMPANYCODE_GE ...
- SAP接口编程 之 JCo3.0系列(05) : Exception Handling
JCO3.0的Exception,常用的Exception如下: JCoException 继承自java.lang.Exception,是JCo3中Exception的基类. JCoRuntimeE ...
- TCP系列04—连接管理—3、TCP连接的半打开和半关闭
在前面部分我们我们分别介绍了三次握手.四次挥手.同时打开和同时关闭,TCP连接还有两种场景分别是半打开(Half-Open)连接和半关闭(Half-Close)连接.TCP是一个全双工(Full-Du ...
- Spring Boot 2.0系列文章(七):SpringApplication 深入探索
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/04/30/springboot_SpringApplication/ 前言 在 Spring B ...
- LXD 2.0 系列(四):资源控制
LXD 提供了各种资源限制.其中一些与容器本身相关,如内存配额.CPU 限制和 I/O 优先级.而另外一些则与特定设备相关,如 I/O 带宽或磁盘用量限制.-- Stéphane Graber 本文导 ...
- Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- java接口,接口的特性,接口实现多态,面向接口编程
package cn.zy.cellphone; /**接口是一种引用数据类型.使用interface声明接口,形式 * 形式:public interface 接口名称{} * 接口不能拥有构造方法 ...
随机推荐
- Docker CPU 资源限制——CPU分片功能测试
之前的一篇随笔——Docker CPU 资源限制 中介绍了针对COU的某个或某几个核的控制,今天介绍下CPU分片功能,即CPU占比. 测试步骤 1.下载CPU测试image.agileek/cpuse ...
- Android网络传输中必用的两个加密算法:MD5 和 RSA (附java完成测试代码)
MD5和RSA是网络传输中最常用的两个算法,了解这两个算法原理后就能大致知道加密是怎么一回事了.但这两种算法使用环境有差异,刚好互补. 一.MD5算法 首先MD5是不可逆的,只能加密而不能解密.比如明 ...
- 提高PHP性能的实用方法+40个技巧优化您的PHP代码
1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的"函数" ...
- jquery 操作select 语句大全
jquery select操作大全 添加option $("#ID option").each(function(){ ){ $(this).remove(); } }); ...
- angular 控制器之间的通信
1, 利用作用域的继承方式 由于作用域的继承是基于js的原型继承方式,所以这里分为两种情况,当作用域上面的值为基本类型的时候,修改父作用域上面的值会 影响到子作用域,反之,修改子作用域只会影响子作用域 ...
- Pipe(点积叉积的应用POJ1039)
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9723 Accepted: 2964 Description ...
- Poj(2679),SPFA,邻接表(主流写法)
题目链接:http://poj.org/problem?id=3268 题意: 有编号为1-N的牛,它们之间存在一些单向的路径.给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求 ...
- HashMap原理详解
HashMap 概述 HashMap 是基于哈希表的 Map 接口的非同步实现.此实现提供所有可选的映射操作,并允许使用 null 值和 null 键.此类不保证映射的顺序,特别是它不保证该顺序恒久不 ...
- Java总结反射
[案例1]通过一个对象获得完整的包名和类名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package Reflect; /** * 通过一个对象获得完整的包名和类名 ...
- C# 对Xml的常用操作
using System.Xml; //初始化一个xml实例 XmlDocument xml=new XmlDocument(); //导入指定xml文件 xml.Load(path); ...