在SAP接口編程之 NCo3.0系列(06) : 會話管理 這篇文章中根盒,對會話管理的相關(guān)知識點已經(jīng)說得很詳細(xì)了阳懂,請參考×罂現(xiàn)在用JCo3.0來實現(xiàn)音婶。
1. JCoContext
如果SAP中多個函數(shù)需要在一個session中運行,需要JCoContext
來提供保證倒谷。如果在同一個線程中蛛蒙,大體模式這樣:
JCoContext.begin(sapDestination);
fm1.execute(sapDestination);
fm2.execute(sapDestination);
JCoContext.end(destination);
begin()和end()之間的函數(shù)execute之后,SAP不會釋放連接渤愁,確保同一個session之中牵祟。
第二種情況:如果不同的函數(shù)不在同一個線程中,需要由開發(fā)人員實現(xiàn)SessionReferenceProvider
接口抖格,在類中提供session id诺苹。邏輯跟nco3.0也是一樣的。JCo3.0提供了一個示例代碼雹拄,但是搞的太復(fù)雜收奔,我弄了一個簡單的,方便理解滓玖。
2. SAP函數(shù)
我們要使用的函數(shù)是從標(biāo)準(zhǔn)系統(tǒng)函數(shù)INCREMENT_COUNTER
坪哄,GET_COUNTER
拷貝而來的。在SAP系統(tǒng)中INCREMENT_COUNTER
势篡,GET_COUNTER
在同一個function group中翩肌,共享一個變量count(計數(shù)器),每次運行INCREMENT_COUNTER
, count就會加一禁悠,GET_COUNTER
函數(shù)
可以獲得這個count念祭。因為這兩個函數(shù)不能被遠(yuǎn)程調(diào)用,所以我們將這兩個函數(shù)拷貝出另外兩個函數(shù)ZINCREMENT_COUNTER和ZGET_COUNTER绷蹲。
3. 同一線程中執(zhí)行函數(shù)
首先我們把兩個函數(shù)定義在一個類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);
}
}
然后編寫測試類進(jìn)行測試:
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);
}
}
代碼很直觀棒卷,就不多說了顾孽。函數(shù)執(zhí)行前祝钢,counter的值為0比规,運行函數(shù)5次之后,counter的值為5拦英。如果我們注釋掉JCoContext.begin(destination);
和JCoContext.end(destination);
蜒什,可以對比出不同的效果。
4. 不同線程中執(zhí)行函數(shù)
如果在不同的線程中執(zhí)行不同的函數(shù)疤估,需要開發(fā)者提供session id灾常。我準(zhǔn)備將兩個函數(shù)放在不同的線程中:
- 在JVM的主線程中調(diào)用
ZGET_COUNTER
,查看counter的結(jié)果铃拇。 - 在另外一個線程中運行
ZINCREMENT_COUNTER
钞瀑,兩個線程通過JCoContext,保持在同一個session ID下慷荔。
4.1 實現(xiàn)JCoSessionReference接口
JCoSessionRefence
實現(xiàn)類的主要作用是提供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 實現(xiàn)SessionReferenceProvider接口
在SessionReferenceProvider
接口的實現(xiàn)類中雕什,改寫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
接口的實現(xiàn)類磷雇,這樣JCoDestination
就有狀態(tài)管理功能了偿警。
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 在單獨線程中執(zhí)行ZINCREMENT_COUNTER
定義WorkingThread, 從Thread類繼承,在這個線程中執(zhí)行函數(shù)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用于標(biāo)識該線程是否結(jié)束螟蒸。線程本身結(jié)束,是run()方法運行完畢崩掘。
4.5 測試多線程函數(shù)調(diào)用
好了尿庐,最后來測試在多線程中函數(shù)調(diào)用:
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);
}
}
與前面同一個線程中代碼的主要區(qū)別是:
定義一個WorkingThread類的實例,然后啟動線程:
WorkingThread workingThread = new WorkingThread(destination, false);
workingThread.start();
然后通過Thread.sleep()
, 將線程切換到workingThread中執(zhí)行呢堰,執(zhí)行完畢再回到主線程顯示結(jié)果抄瑟。