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



    文/StoneWM(简书作者)
    原文链接:http://www.jianshu.com/p/2ce28196483c
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 相关阅读:
    conda创建、删除、重命名环境
    jupyter notebook选择conda环境
    conda 创建tensorflow虚拟环境后,无法import tensorflow在jupyter
    labelme2coco
    MacOs 10.14.3 Matlab2018b 解决“找不到已安装的编译器 'Xcode Clang++'。错误使用mex,未找到合适的编译器”问题
    MaskRCNN 奔跑自己的数据
    labelme2coco问题:TypeError: Object of type 'int64' is not JSON serializable
    kill 掉 占据端口的进程
    关于对多层嵌套的json字符串取目标值的问题
    关于Jmeter测试移动端应用时提示非法登录,不是合法的登录设备时的解决办法
  • 原文地址:https://www.cnblogs.com/zfswff/p/5671160.html
Copyright © 2020-2023  润新知