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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值