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
Wrapper of INCREMENT_COUNTER and GET_COUNTER
* remote enabled function Z_INCREMENT_COUNTER wrapping the
INCREMENT_COUNTER
FUNCTION Z_INCREMENT_COUNTER.
CALL FUNCTION 'INCREMENT_COUNTER'.
ENDFUNCTION.
* remote enabled function Z_GET_COUNTER wrapping the GET_COUNTER
FUNCTION Z_GET_COUNTER.
CALL FUNCTION 'GET_COUNTER'
IMPORTING
GET_VALUE = GET_VALUE
.
ENDFUNCTION.
* with GET_VALUE TYPE I as export parameter and report ZJCO_STATEFUL_COUNTER
REPORT ZJCO_STATEFUL_COUNTER.
PARAMETER dest TYPE RFCDEST.
DATA value TYPE i.
DATA loops TYPE i VALUE 5.
DO loops TIMES.
CALL FUNCTION 'Z_INCREMENT_COUNTER' DESTINATION dest.
ENDDO.
CALL FUNCTION 'Z_GET_COUNTER' DESTINATION dest
IMPORTING
GET_VALUE = value
.
IF value <> loops.
write: / 'Error expecting ', loops, ', but get ', value, ' as counter value'.
ELSE.
write: / 'success'.
ENDIF.
The actual calls are processed in the next step:
Syntax
Stateful Calls (JCo Server)
import java.io.File;
import java.io.FileOutputStream;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.ext.DestinationDataProvider;
import com.sap.conn.jco.ext.ServerDataProvider;
import com.sap.conn.jco.server.JCoServer;
import com.sap.conn.jco.server.JCoServerContext;
import com.sap.conn.jco.server.JCoServerFactory;
import com.sap.conn.jco.server.JCoServerFunctionHandler;
import com.sap.conn.jco.server.JCoServerFunctionHandlerFactory;
public class StatefulServerExample
{
static String SERVER = "SERVER";
static String ABAP_AS_WITHOUT_POOL = "ABAP_AS_WITHOUT_POOL";
static
{
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "binmain");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "53");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "000");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "JCOTEST");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "JCOTEST");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");
createDataFile(ABAP_AS_WITHOUT_POOL, "jcoDestination", connectProperties);
Properties servertProperties = new Properties();
servertProperties.setProperty(ServerDataProvider.JCO_GWHOST, "binmain");
servertProperties.setProperty(ServerDataProvider.JCO_GWSERV, "sapgw53");
servertProperties.setProperty(ServerDataProvider.JCO_PROGID, "JCO_SERVER");
servertProperties.setProperty(ServerDataProvider.JCO_REP_DEST, ABAP_AS_WITHOUT_POOL);
servertProperties.setProperty(ServerDataProvider.JCO_CONNECTION_COUNT, "2");
createDataFile(SERVER, "jcoServer", servertProperties);
}
static void createDataFile(String name, String suffix, Properties properties)
{
File cfg = new File(name+"."+suffix);
if(!cfg.exists())
{
try
{
FileOutputStream fos = new FileOutputStream(cfg, false);
properties.store(fos, "for tests only !");
fos.close();
}
catch (Exception e)
{
throw new RuntimeException("Unable to create the destination file " + cfg.getName(), e);
}
}
}
static class MyFunctionHandlerFactory implements JCoServerFunctionHandlerFactory
{
class SessionContext
{
Hashtable<String, Object> cachedSessionData = new Hashtable<String, Object>();
}
private Map<String, SessionContext> statefulSessions =
new Hashtable<String, SessionContext>();
private ZGetCounterFunctionHandler zGetCounterFunctionHandler =
new ZGetCounterFunctionHandler();
private ZIncrementCounterFunctionHandler zIncrementCounterFunctionHandler =
new ZIncrementCounterFunctionHandler();
public JCoServerFunctionHandler getCallHandler(JCoServerContext serverCtx, String functionName)
{
JCoServerFunctionHandler handler = null;
if(functionName.equals("Z_INCREMENT_COUNTER"))
handler = zIncrementCounterFunctionHandler;
else if(functionName.equals("Z_GET_COUNTER"))
handler = zGetCounterFunctionHandler;
if(handler instanceof StatefulFunctionModule)
{
SessionContext cachedSession;
if(!serverCtx.isStatefulSession())
{
serverCtx.setStateful(true);
cachedSession = new SessionContext();
statefulSessions.put(serverCtx.getSessionID(), cachedSession);
}
else
{
cachedSession = statefulSessions.get(serverCtx.getSessionID());
if(cachedSession == null)
throw new RuntimeException("Unable to find the session context for session id " + serverCtx.getSessionID());
}
((StatefulFunctionModule)handler).setSessionData(cachedSession.cachedSessionData);
return handler;
}
//null leads to a system failure on the ABAP side
return null;
}
public void sessionClosed(JCoServerContext serverCtx, String message, boolean error)
{
System.out.println("Session " + serverCtx.getSessionID() + " was closed " + (error?message:"by SAP system"));
statefulSessions.remove(serverCtx.getSessionID());
}
}
static abstract class StatefulFunctionModule implements JCoServerFunctionHandler
{
Hashtable<String, Object> sessionData;
public void setSessionData(Hashtable<String, Object> sessionData)
{
this.sessionData = sessionData;
}
}
static class ZGetCounterFunctionHandler extends StatefulFunctionModule
{
public void handleRequest(JCoServerContext serverCtx, JCoFunction function)
{
System.out.println("ZGetCounterFunctionHandler: return counter");
Integer counter = (Integer)sessionData.get("COUNTER");
if(counter == null)
function.getExportParameterList().setValue("GET_VALUE", 0);
else
function.getExportParameterList().setValue("GET_VALUE", counter.intValue());
}
}
static class ZIncrementCounterFunctionHandler extends StatefulFunctionModule
{
public void handleRequest(JCoServerContext serverCtx, JCoFunction function)
{
System.out.println("ZIncrementCounterFunctionHandler: increase counter");
Integer counter = (Integer)sessionData.get("COUNTER");
if(counter == null)
sessionData.put("COUNTER", new Integer(1));
else
sessionData.put("COUNTER", new Integer(counter.intValue()+1));
}
}
public static void main(String[] args)
{
JCoServer server;
try
{
server = JCoServerFactory.getServer(SERVER);
}
catch(JCoException ex)
{
throw new RuntimeException("Unable to create the server " + SERVER + ", because of " + ex.getMessage(), ex);
}
server.setCallHandlerFactory(new MyFunctionHandlerFactory());
server.start();
System.out.println("The program can be stopped using <ctrl>+<c>");
}
}