在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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。