Show TOC

Background documentationStatefulCalls Locate this document in the navigation structure

 

The following example describes the processing of stateful RFC function modules.

To distinguish more clearly between stateful and stateless calls, simple repository queries are executed here with the function modules INCREMENT_COUNTER and GET_COUNTER. In the case of stateful calls, the counter value increases by 1 with every query, however in the case of stateless calls, the value remains at 1 because a new context is opened with every query.

To execute the example you first need to create the remote-capable function modules Z_INCREMENT_COUNTER and Z_GET_COUNTER in AS ABAP. These function modules act as the wrapper for the non-remote-capable function modules INCREMENT_COUNTER and GET_COUNTER:

Syntax Syntax

Wrapper of INCREMENT_COUNTER and GET_COUNTER

  1.      * remote enabled function Z_INCREMENT_COUNTER wrapping the  
  2. INCREMENT_COUNTER
  3.        
  4.            FUNCTION Z_INCREMENT_COUNTER.
  5.            CALL FUNCTION 'INCREMENT_COUNTER'.
  6.            ENDFUNCTION.
  7.        
  8.    * remote enabled function Z_GET_COUNTER wrapping the GET_COUNTER 
  9.        
  10.            FUNCTION Z_GET_COUNTER.
  11.            CALL FUNCTION 'GET_COUNTER'
  12.                IMPORTING
  13.                   GET_VALUE = GET_VALUE
  14.            .
  15.            ENDFUNCTION.
  16.        
  17.     * with GET_VALUE TYPE  I as export parameter and report ZJCO_STATEFUL_COUNTER
  18.                   REPORT  ZJCO_STATEFUL_COUNTER.
  19.            PARAMETER dest TYPE RFCDEST.
  20.  
  21.            DATA value TYPE i.
  22.            DATA loops TYPE i VALUE 5.
  23.  
  24.            DO loops TIMES.
  25.                CALL FUNCTION 'Z_INCREMENT_COUNTER' DESTINATION dest.
  26.            ENDDO.
  27.  
  28.            CALL FUNCTION 'Z_GET_COUNTER' DESTINATION dest
  29.                IMPORTING
  30.                   GET_VALUE       = value
  31.            .
  32.  
  33.            IF value <> loops.
  34.              write: / 'Error expecting ', loops, ', but get ', value, ' as counter value'.
  35.            ELSE.
  36.              write: / 'success'.
  37.            ENDIF.
  38.        
End of the code.

The actual calls are processed in the next step:

Syntax Syntax

Stateful Calls (JCo Server)

  1. import java.io.File;
  2. import java.io.FileOutputStream;
  3. import java.util.Hashtable;
  4. import java.util.Map;
  5. import java.util.Properties;
  6. import com.sap.conn.jco.JCoException;
  7. import com.sap.conn.jco.JCoFunction;
  8. import com.sap.conn.jco.ext.DestinationDataProvider;
  9. import com.sap.conn.jco.ext.ServerDataProvider;
  10. import com.sap.conn.jco.server.JCoServer;
  11. import com.sap.conn.jco.server.JCoServerContext;
  12. import com.sap.conn.jco.server.JCoServerFactory;
  13. import com.sap.conn.jco.server.JCoServerFunctionHandler;
  14. import com.sap.conn.jco.server.JCoServerFunctionHandlerFactory;
  15. public class StatefulServerExample
  16. {
  17.     static String SERVER = "SERVER";
  18.     static String ABAP_AS_WITHOUT_POOL = "ABAP_AS_WITHOUT_POOL";
  19.     static
  20.     {
  21.         Properties connectProperties = new Properties();
  22.         connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "binmain");
  23.         connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR,  "53");
  24.         connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "000");
  25.         connectProperties.setProperty(DestinationDataProvider.JCO_USER,   "JCOTEST");
  26.         connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "JCOTEST");
  27.         connectProperties.setProperty(DestinationDataProvider.JCO_LANG,   "en");
  28.         createDataFile(ABAP_AS_WITHOUT_POOL, "jcoDestination", connectProperties);
  29.         
  30.         Properties servertProperties = new Properties();
  31.         servertProperties.setProperty(ServerDataProvider.JCO_GWHOST, "binmain");
  32.         servertProperties.setProperty(ServerDataProvider.JCO_GWSERV, "sapgw53");
  33.         servertProperties.setProperty(ServerDataProvider.JCO_PROGID, "JCO_SERVER");
  34.         servertProperties.setProperty(ServerDataProvider.JCO_REP_DEST, ABAP_AS_WITHOUT_POOL);
  35.         servertProperties.setProperty(ServerDataProvider.JCO_CONNECTION_COUNT, "2");
  36.         createDataFile(SERVER, "jcoServer", servertProperties);
  37.     }
  38.     
  39.     static void createDataFile(String name, String suffix, Properties properties)
  40.     {
  41.         File cfg = new File(name+"."+suffix);
  42.         if(!cfg.exists())
  43.         {
  44.             try
  45.             {
  46.                 FileOutputStream fos = new FileOutputStream(cfg, false);
  47.                 properties.store(fos, "for tests only !");
  48.                 fos.close();
  49.             }
  50.             catch (Exception e)
  51.             {
  52.                 throw new RuntimeException("Unable to create the destination file " + cfg.getName(), e);
  53.             }
  54.         }
  55.     }
  56.     
  57.     
  58.     static class MyFunctionHandlerFactory implements JCoServerFunctionHandlerFactory
  59.     {
  60.         class SessionContext
  61.         {
  62.             Hashtable<String, Object> cachedSessionData = new Hashtable<String, Object>();
  63.         }
  64.         
  65.         private Map<String, SessionContext> statefulSessions = 
  66.             new Hashtable<String, SessionContext>();
  67.         private ZGetCounterFunctionHandler zGetCounterFunctionHandler = 
  68.             new ZGetCounterFunctionHandler();
  69.         private ZIncrementCounterFunctionHandler zIncrementCounterFunctionHandler = 
  70.             new ZIncrementCounterFunctionHandler();
  71.         
  72.         public JCoServerFunctionHandler getCallHandler(JCoServerContext serverCtx, String functionName)
  73.         {
  74.             JCoServerFunctionHandler handler = null;
  75.             
  76.             if(functionName.equals("Z_INCREMENT_COUNTER"))
  77.                 handler = zIncrementCounterFunctionHandler;
  78.             else if(functionName.equals("Z_GET_COUNTER"))
  79.                 handler = zGetCounterFunctionHandler;
  80.             
  81.             if(handler instanceof StatefulFunctionModule)
  82.             {
  83.                 SessionContext cachedSession;
  84.                 if(!serverCtx.isStatefulSession())
  85.                 {
  86.                     serverCtx.setStateful(true);
  87.                     cachedSession = new SessionContext();
  88.                     statefulSessions.put(serverCtx.getSessionID(), cachedSession);
  89.                 }
  90.                 else
  91.                 {
  92.                     cachedSession = statefulSessions.get(serverCtx.getSessionID());
  93.                     if(cachedSession == null)
  94.                         throw new RuntimeException("Unable to find the session context for session id " + serverCtx.getSessionID());
  95.                 }
  96.                 ((StatefulFunctionModule)handler).setSessionData(cachedSession.cachedSessionData);
  97.                 return handler;
  98.             }
  99.             
  100.             //null leads to a system failure on the ABAP side 
  101.             return null;
  102.         }
  103.         public void sessionClosed(JCoServerContext serverCtx, String message, boolean error)
  104.         {
  105.             System.out.println("Session " + serverCtx.getSessionID() + " was closed " + (error?message:"by SAP system"));
  106.             statefulSessions.remove(serverCtx.getSessionID());
  107.         }
  108.     }
  109.     static abstract class StatefulFunctionModule implements JCoServerFunctionHandler
  110.     {
  111.         Hashtable<String, Object> sessionData;
  112.         public void setSessionData(Hashtable<String, Object> sessionData)
  113.         {
  114.             this.sessionData = sessionData;
  115.         }
  116.     }
  117.     
  118.     
  119.     static class ZGetCounterFunctionHandler extends StatefulFunctionModule
  120.     {
  121.         public void handleRequest(JCoServerContext serverCtx, JCoFunction function)
  122.         {
  123.             System.out.println("ZGetCounterFunctionHandler: return counter");
  124.             Integer counter = (Integer)sessionData.get("COUNTER");
  125.             if(counter == null)
  126.                 function.getExportParameterList().setValue("GET_VALUE", 0);
  127.             else
  128.                 function.getExportParameterList().setValue("GET_VALUE", counter.intValue());
  129.         }
  130.         
  131.     }
  132.     static class ZIncrementCounterFunctionHandler extends StatefulFunctionModule
  133.     {
  134.         public void handleRequest(JCoServerContext serverCtx, JCoFunction function)
  135.         {
  136.             System.out.println("ZIncrementCounterFunctionHandler: increase counter");
  137.             Integer counter = (Integer)sessionData.get("COUNTER");
  138.             if(counter == null)
  139.                 sessionData.put("COUNTER", new Integer(1));
  140.             else
  141.                 sessionData.put("COUNTER", new Integer(counter.intValue()+1));
  142.         }
  143.     }
  144.     
  145.     public static void main(String[] args)
  146.     {
  147.         JCoServer server;
  148.         try
  149.         {
  150.             server = JCoServerFactory.getServer(SERVER);
  151.         }
  152.         catch(JCoException ex)
  153.         {
  154.             throw new RuntimeException("Unable to create the server " + SERVER + ", because of " + ex.getMessage(), ex);
  155.         }
  156.         
  157.         server.setCallHandlerFactory(new MyFunctionHandlerFactory());
  158.         
  159.         server.start();
  160.         System.out.println("The program can be stopped using <ctrl>+<c>");
  161.     }
  162. }
End of the code.