Вы находитесь на странице: 1из 26

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Applies to:
SAP Java Connector 3.0.x For more information, visit the Java homepage.

Summary
SAP has introduced a new programming model for the SAP Java Connector version 3 (in the sequel called: JCo3) compared to version 2.1.x of the SAP Java Connector. Therefore existing Java client applications that use JCo 2.1.x so far need to be adapted accordingly when switching to JCo3. The main differences of JCo3 compared to the former version 2 are that connection handling is now transparently performed by the JCo3 framework and that additional client code is needed to use JCo3 in a multi-threaded Java client application. The two main contributions of this paper are: First, it summarizes the main changes from JCo2 to JCo3 thus providing a short guide for migrating existing applications from JCo2 to JCo3. Second, it elaborates on how to use JCo3 in a multi-threaded environment. This second point obtains special attention, because there are some issues to take care of that are not covered by the official SAP JCo3 documentation. This paper fills this gap. Author: Dr. Dirk Heuzeroth

Company: IBM Germany Research & Development Created on: 8 May 2009

Author Bio
Dr. Dirk Heuzeroth is a SAP-certified SAP NetWeaver 2004 Java Development Consultant. He works for IBM Germany Research & Development as software engineer for IBM Tivoli Workload Scheduler for Applications for SAP.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 1

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Table of Contents
Introduction ......................................................................................................................................................... 3 Migration from JCo2 to JCo3 .............................................................................................................................. 3 Renaming of packages ................................................................................................................................... 3 Change of parameter order ............................................................................................................................. 3 Replacing JCo-classes.................................................................................................................................... 4 Connection management ................................................................................................................................ 4
JCo2 ............................................................................................................................................................................ 4 JCo3 ............................................................................................................................................................................ 5 Stateful connections ................................................................................................................................................... 11

Exceptions ..................................................................................................................................................... 11 Metadata-Model Changes ............................................................................................................................. 11


Separating Metadata Types ....................................................................................................................................... 11 Enhancement of Metadata Objects ............................................................................................................................ 12 Reducing the amount of meta-data-objects in memory.............................................................................................. 12 Consequences ........................................................................................................................................................... 12

Using JCo3 in a multi-threaded environment ................................................................................................... 12 Session References per Thread ................................................................................................................... 12 Stateful Connections ..................................................................................................................................... 18 XMI Logons ................................................................................................................................................... 19 Example Implementation............................................................................................................................... 19 Framework ........................................................................................................................................................ 20 Class Model for Remote Enabled Functions................................................................................................. 20 Class Model for complex tasks based on JCo3-specific session and connection handling ......................... 21 Related Content ................................................................................................................................................ 23 Disclaimer and Liability Notice .......................................................................................................................... 24

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 2

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Introduction
With the SAP Java Connector version 3 (in the sequel called: JCo3) SAP has changed the programming model to connect to an SAP system from a Java client completely. The main difference of JCo3 compared to the former version 2 is that connection handling is now transparently performed by the JCo3 framework so that the application programmer nearly has no control on when a connection is opened or closed. This paper has two purposes: First, it summarizes the main changes from JCo2 to JCo3 thus providing a short guide for migrating existing applications from JCo2 to JCo3. Second, it elaborates on how to use JCo3 in a multi-threaded environment. This second point obtains special attention, because there are some issues to take care of that are not covered by the official SAP JCo3 documentation. This paper fills this gap. Section Migration from JCo2 to JCo3 covers the steps to migrate from JCo2 to JCo3, and section Using JCo3 in a multi-threaded environment describes in detail how to use JCo3 in a multi-threaded environment.

Migration from JCo2 to JCo3


This section describes the steps necessary to migrate a JCo2-based application to a JCo3-based application.

Renaming of packages SAP has renamed the packages com.sap.mw.jco* to com.sap.conn.jco* Therefore the corresponding change has to be performed in the client code using the JCo library.

Change of parameter order SAP has changed the order of the formal parameters of the setValue()-Operations of the JCoRecord and therefore also the JCoParameterList as a subinterface of JCoRecord. In JCo2, the name of the parameter to set has been the second formal parameter of setValue() and the value to set has been the first formal parameter of setValue(). In JCo3 the order has been exchanged, so that the name is the first and the value is the second parameter. Although this change makes much sense from a logical perspective, it is very dangerous in case the value parameter is of type String, because the compiler cannot automatically detect the changed parameter order. Example: In JCo2 the JCoRecord offered a function with the following signature: void setValue(java.lang.String value, java.lang.String name)

The same function is offered in JCo3 with the same signature but with exchanged parameter names and therefore semantics: void setValue(java.lang.String name, java.lang.String value)

When an JCo2-based application contained code like this JCoParameterList inParams = ivFunction.getImportParameterList();

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 3

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

inParams.setValue(value, name); then no compile time error would occur after having exchanged the JCo2 library by the JCo3 library. But of course the runtime behavior of the application would be different. After a correct migration the code should look like this: JCoParameterList inParams = ivFunction.getImportParameterList(); inParams.setValue(name, value);

Replacing JCo-classes In JCo2 the JCo model has been comprised of inner classes of the JCO class, e.g. JCO.Function for a class that represents a function. In JCo3 non-nested interfaces are used to define the JCo model, instead. As a consequence, it is necessary to replace JCO.<class name> by JCo<interface name> in the client application code.

Connection management The handling of connections has changed a lot from JCo2 to JCo3. JCo2 In JCo2 the client application has been responsible to explicitly manage the connections to a client on the SAP system, i.e. the client application had to open the connection and close it, when it is no longer needed. // Create a client connection to a dedicated R/3 system client = JCO.createClient(connectionProperties); // Open the connection client.connect(); // get repository JCO.Repository repository = new JCO.Repository(REPOSITORY_NAME,client); //get function JCO.Function function = repository.getFunctionTemplate(functionName).getFunction(); // execute function client.execute(function); // disconnect client.disconnect();

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 4

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

JCo3 In JCo3 connections are handled transparently by the JCoDestination object: // get the JCo destination JCoDestination destination = JCoDestinationManager.getDestination(destinationName); // get repository JCoRepository repository = destination.getRepository(); // get function JCoFunction function = repository.getFunctionTemplate(functionName).getFunction(); // execute function function.execute(destination); There is no JCo API function to close a connection in JCo3. The JCo3 framework closes the connection automatically. Another important aspect is the way a connection is configured. In JCo2 a properties object specifying the connection properties has to be passed to the JCO.createClient() method. In JCo3 there are two ways to create a destination and specify the corresponding connection properties. Creating a destination from a property file As a first step, the properties of a destination that specify how connections are established to a SAP system have to be set as the properties of a property object. In the second step this property object has to be written to a properties file. The name of this file consists of the name of the destination followed by .jcoDestination, i.e. <name of destination>.jcoDestination To create this destination, the name of the destination and therefore the name of the corresponding properties file has to be passed as an argument to the getDestination() method of the JCoDestinationManager. The main deficiency of this approach is that the password to connect to the SAP system has to be stored in clear text form in the property file. Section Creating a destination from a property object describes the other way to create a JCo destination circumventing this problem. Examples 1. Creating a non-pooled destination: public class JCoClientApp { static final String DESTINATION_NAME = "DESTINATION_WITHOUT_POOL";

static void createDestinationDataFile(String destinationName, Properties connectionProperties) { File destCfg = new File(destinationName+".jcoDestination"); try

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 5

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

{ FileOutputStream fos = new FileOutputStream(destCfg, false); connectionProperties.store(fos, "for tests only !"); fos.close(); } catch (Exception e) { throw new RuntimeException("Unable to create the destination files", e); } }

public static void main(String[] args) { Properties connectionProperties = new Properties(); connectionProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "hostname"); connectionProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "00"); connectionProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "000"); connectionProperties.setProperty(DestinationDataProvider.JCO_USER, "username"); connectionProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "password"); connectionProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");

createDestinationDataFile(DESTINATION_WITHOUT_POOL, connectProperties);

JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_WITHOUT_POOL); ... } }

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 6

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

2. Creating a pooled destination: public class JCoClientApp { static String DESTINATION_NAME = "DESTINATION_WITH_POOL"; static void createDestinationDataFile(String destinationName, Properties connectionProperties) { File destCfg = new File(destinationName+".jcoDestination"); try { FileOutputStream fos = new FileOutputStream(destCfg, false); connectionProperties.store(fos, "for tests only !"); fos.close(); } catch (Exception e) { throw new RuntimeException("Unable to create the destination files", e); } } public static void main(String[] args) { Properties connectionProperties = new Properties(); connectionProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "hostname"); connectionProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "00"); connectionProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "000"); connectionProperties.setProperty(DestinationDataProvider.JCO_USER, "username"); connectionProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "password"); connectionProperties.setProperty(DestinationDataProvider.JCO_LANG, "en"); connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "10"); connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");

createDestinationDataFile(DESTINATION_WITH_POOL, connectProperties);

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 7

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

JCoDestination destination = JCoDestinationManager.getDestination(DESTINATION_WITH_POOL); ... } }

Creating a destination from a property object Since the password has to be stored in clear text in the approach of creating a destination from a property file, it is preferable to create the destination from a property object. This is done by the following steps which are detailed below: 1. Providing a custom implementation of a destination data provider 2. Register the custom destination data provider at the environment 3. Specify destination name and connection properties and pass both to the custom destination data provider 4. Create the destination 1. Providing a custom implementation of a destination data provider: This means to implement a subclass of com.sap.conn.jco.ext.DestinationDataProvider. The following code is an example of such a class: import java.util.Properties; import com.sap.conn.jco.ext.DestinationDataEventListener; import com.sap.conn.jco.ext.DestinationDataProvider; public class SapDestinationDataProvider implements DestinationDataProvider { private DestinationDataEventListener eL; private Properties ABAP_AS_properties; private String destinationName; public void setDestinationName(String destinationName) { this.destinationName = destinationName; } public Properties getDestinationProperties(String destinationName) { if (destinationName.equals(this.destinationName) && ABAP_AS_properties!=null) return ABAP_AS_properties;

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 8

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

return null; //alternatively throw runtime exception //throw new RuntimeException("Destination " + destinationName // } public void setDestinationDataEventListener( DestinationDataEventListener eventListener) { this.eL = eventListener; } public boolean supportsEvents() { return true; } public void changeProperties(Properties properties) { if(properties==null) { eL.deleted(this.destinationName); ABAP_AS_properties = null; } else { if (ABAP_AS_properties!=null && !ABAP_AS_properties.equals(properties)) eL.updated(this.destinationName); ABAP_AS_properties = properties; } } } 2. Register the custom destination data provider at the environment
sapDestinationDataProvider = new SapDestinationDataProvider(); com.sap.conn.jco.ext.Environment.registerDestinationDataProvider(sapDestinationDataProvider);

+ " is not available");

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 9

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

3. Specify destination name and connection properties and pass both to the custom destination data provider: After having registered the custom destination data provider at the environment, the destination name has to be specified and the connection properties have to be defined in a property object. Both have to be passed to the custom destination data provider. sapDestinationDataProvider.setDestinationName(destinationName); Properties connectionProperties = new Properties(); // read properties from a file where the password is encrypted // decrypt password in memory and store it together with the other properties // in the connectionProperties object connectionProperties.put(DestinationDataProvider.JCO_ASHOST, hostNameFromFile); connectionProperties.put(DestinationDataProvider.JCO_CLIENT, clientFromFile); connectionProperties.put(DestinationDataProvider.JCO_USER, userNameFromFile); connectionProperties.put(DestinationDataProvider.JCO_PASSWD, decyrptedPasswordFromMemory); connectionProperties.put(DestinationDataProvider.JCO_LANG, LANG_EN); connectionProperties.put(DestinationDataProvider.JCO_SYSNR, instanceNumberFromFile); connectionProperties.put(DestinationDataProvider.JCO_LCHECK, ENABLE_LCHECK); connectionProperties.put(DestinationDataProvider.JCO_TRACE, jcoTraceFromFile); connectionProperties.put(DestinationDataProvider.JCO_CPIC_TRACE, cpicTraceFromFile);

sapDestinationDataProvider.changeProperties(connectionProperties); 4. Create the destination: After that the destination can be created: destination = JCoDestinationManager.getDestination(destinationName); Now, calls can be issued via the newly created destination which handles connections transparently.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 10

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Using multiple destinations in a client application It is possible to use multiple destinations created from a property object in the same client application. The required steps are 1. Change the destination name in the custom destination data provider 2. Modify the connectionProperties object 3. Pass the modified connectionProperties object to the custom destination data provider 4. Create a new destination // 1. Change the destination name in the custom destination data provider sapDestinationDataProvider.setDestinationName(pooledDestinationName); // 2. Modify the connectionProperties object connectionProperties.put(DestinationDataProvider.JCO_POOL_CAPACITY, maxConnectionsFromFile); // 3. Pass the modified connectionProperties object to // the custom destination data provider sapDestinationDataProvider.changeProperties(connectionProperties); // 4. Create a new destination pooledDestination = JCoDestinationManager.getDestination(pooledDestinationName);

Stateful connections In JCo 2.x all connections have been stateful. In JCo3 all connections are stateless by default. If a stateful connection should be used, i.e. the destination should use the same connection for a sequence of calls, then these calls must be wrapped by: JCoContext.begin(destination); // calls to SAP JCoContext.end(destination);

Exceptions In JCo 2.x all JCo exceptions have been derived from java.lang.RuntimeException and therefore need not be catched. In JCo 3 exceptions are derived from java.lang.Exception so that additional trycatch-blocks or throw clauses are necessary.

Metadata-Model Changes Separating Metadata Types In JCo 2.x there is a common data container parent class for JCo structure and JCo table meta-data. To avoid confusion, JCo 3 has separate parent classes for structure and table meta-data.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 11

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Enhancement of Metadata Objects In JCo 3.x meta-data-objects contain Unicode as well as non-Unicode information, in order to avoid errors when configuring the Repository. Of course the configuration of the repository should be performed cautiously in general, like for example, not to use the same name for different functions in different systems. Reducing the amount of meta-data-objects in memory Only one single object is created for a particular meta-data layout so that all corresponding structures and tables are referenced through this single object. Consequences Some meta-data-operations are no longer possible, like addInfo() on record and list objects The method ParameterList.appendValue() no longer exists It is still possible to create a JCoFuntion and its parameter list JCoParameterLists on the fly It is now possible to lock a meta-data-object after its creation, in order to prevent accidental modifications

Using JCo3 in a multi-threaded environment


In JCo3 the context of a session is connected to a thread of control. This means that for every thread of the client application the following steps are needed to perform a sequence of stateful calls via the same connection. When a function module is called that requires XMI logon, steps 3 and 5 are mandatory, otherwise these steps are optional. Steps 2 and 6 are mandatory to perform a sequence of stateful calls, otherwise these steps are optional: 1. Associate a session reference to each thread (cf. section Session References per Thread) 2. Begin a new JCoContext (cf. section Stateful Connections) 3. Logon via XMI for all required interfaces, e.g. XBP (cf. section

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 12

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

XMI Logons) 4. Perform the sequence of calls to the SAP system 5. Logoff from XMI 6. Close the JCoContext 7. Detach the session reference from the thread Section Example Implementation shows an example implementation of these steps.

Session References per Thread JCo3 needs a separate session for each thread that invokes function modules. In order to create these sessions, a custom session reference provider which is a subclass of SessionReferenceProvider must be created and registered at the JCo3 environment. Examples implementation of a custom session reference provider: import java.util.Collection; import com.sap.conn.jco.ext.JCoSessionReference; import com.sap.conn.jco.ext.SessionException; import com.sap.conn.jco.ext.SessionReferenceProvider; public class SapSessionReferenceProvier implements SessionReferenceProvider { public JCoSessionReference getCurrentSessionReference(String scopeType) { SapSessionReference sessionRef = SapSessionManager.getLocalSessionReference(); if (sessionRef != null) { return sessionRef; } throw new RuntimeException("Unknown thread: " + Thread.currentThread().getId()); } public boolean isSessionAlive(String sessionId) { Collection<SapSessionReference> availableSessions = SapSessionManager.getSessions().values(); for (SapSessionReference ref : availableSessions) { if (ref.getID().equals(sessionId)) { return true; } }

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 13

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

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; } } }

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 14

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Example implementation of a custom session reference: import java.util.concurrent.atomic.AtomicInteger; import com.sap.conn.jco.ext.JCoSessionReference; public class SapSessionReference implements JCoSessionReference { static AtomicInteger atomicIntId = new AtomicInteger(0); private String id = "session-" + String.valueOf(atomicIntId.addAndGet(1)); public void contextFinished() { public void contextStarted() { } public String getID() { return id; } } The data about active sessions and further utility methods needed for stateful connections and login to the XMI interface are encapsulated in a SapSessionManager object (source code is shown below) that is used by the custom session reference provider. This SapSessionManager object contains two attributes that deserve special attention. The first is a hash table (attribute sessions) that maps the current thread to its session reference, such that it is always possible for the JCo3 framework to determine the current session reference for the current thread. The second is a ThreadLocal object that holds the session reference of the current thread. Moreover the SapSessionManager provides methods to associate a session reference with the current thread (startJCoSession) detach a session reference (endJCoSession) logon to the XMI (interfaceLogoff) logoff from XMI (interfaceLogoff) }

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 15

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

The following shows an example implementation of such a session manager: import java.util.Hashtable; import java.util.Properties; import com.sap.conn.jco.JCoDestination; import com.sap.conn.jco.JCoDestinationManager; import com.sap.conn.jco.JCoException; import com.sap.conn.jco.JCoRepository; import com.sap.conn.jco.ext.Environment; public class SapSessionManager { public static final String public static final String EXTCOMPANY_NAME EXTPRODUCT_NAME = "YOURCOMPANY"; = "PRODUCTNAME";

private static Hashtable<Thread, SapSessionReference> sessions = new Hashtable<Thread, SapSessionReference>(); private static ThreadLocal<SapSessionReference> localSessionReference = new ThreadLocal<SapSessionReference>(); /* * @return mapping of threads to SapSessionReference objects */ public static Hashtable<Thread, SapSessionReference> getSessions() { return sessions; } /* * @return local SapSessionReference for the current thread */ public static SapSessionReference getLocalSessionReference() { return localSessionReference.get(); } private JCoDestination ivDestination = null; private SapCpu ivSapCpu = null; public SapSessionManager(SapCpu sapcpu) throws JCoException { String destinationName = sapcpu.getName(); ivSapCpu = sapcpu; Environment.registerSessionReferenceProvider( new SapSessionReferenceProvier());

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 16

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

SapDestinationDataProvider sapDestinationDataProvider = DestinationDataProviderFactory.createDestinationDataProvider(); sapDestinationDataProvider.setDestinationName(destinationName); Properties connectionProperties = ConnectionProperties.createConnectionProperties(sapcpu); sapDestinationDataProvider.changeProperties(connectionProperties); ivDestination = JCoDestinationManager.getDestination(destinationName); } public SapCpu getSapCpu() { return ivSapCpu; } public JCoDestination getDestination() { return ivDestination; } public final JCoRepository getRepository() throws JCoException { return = ivDestination.getRepository(); } public void shutdown() { ivDestination = null; } public void startJCoSession() { SapSessionReference sessionRef = sessions.get(Thread.currentThread()); if (sessionRef == null) { sessionRef = new SapSessionReference(); /* store current thread with its session in set of active sessions */ sessions.put(Thread.currentThread(), sessionRef); } /* Store JCo session reference (SapSessionReference) in current thread */ localSessionReference.set(sessionRef); } public void endJCoSession() { /* remove current thread from set of active sessions */

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 17

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

sessions.remove(Thread.currentThread()); /* Remove JCo session reference (SapSessionReference) from current thread */ localSessionReference.set(null); }

public final boolean interfaceLogin(JCoDestination destination, JCoRepository repository, String sapInterface, String version) { boolean result = false;

// LOGON BAPI_XMI_LOGON logon = new BAPI_XMI_LOGON(destination,repository); logon.setIn_EXTCOMPANY(EXTCOMPANY_NAME); logon.setIn_EXTPRODUCT(EXTPRODUCT_NAME); if(sapInterface!=null && sapInterface.trim().length()!=0) { logon.setIn_INTERFACE(sapInterface); } if(version!=null && version.trim().length()!=0) { logon.setIn_VERSION(version); } logon.execute(); }

public final boolean interfaceLogoff(JCoDestination destination, JCoRepository repository) { return interfaceLogoff(destination,repository,null); } public final boolean interfaceLogoff(JCoDestination destination, JCoRepository repository, String sapInterface) { // LOGOFF BAPI_XMI_LOGOFF logoff = new BAPI_XMI_LOGOFF(destination, repository); if(sapInterface!=null && sapInterface.trim().length()!=0) { logoff.setIn_INTERFACE(sapInterface);

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 18

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

} logoff.execute(); } } In the above code BAPI_XMI_LOGON and BAPI_XMI_LOGOFF are classes of our framework to model SAP BAPI calls via JCo (cf. section

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 19

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Framework). After these steps the custom session reference provider has to be registered at the environment with the following call: Environment.registerSessionReferenceProvider(new SapSessionReferenceProvier()); henever a thread accesses JCo3 functionality, i.e. issues calls to function modules, the JCo3 framework invokes callback methods on the custom session reference provider to determine the currently active session. After having registered the custom session reference provider at the environment, the destination to be used should be created. The simple way to connect to a SAP system is to create a destination using a property file that specifies the connection parameters (cf. section Creating a destination from a property file). The main problem with this approach is that, the password for the connection has to be contained in this property file in clear text. Thus, this approach cannot be used in a production environment. To solve this problem, the destination can also be created using a property object (cf. section Creating a destination from a property object).

Stateful Connections To make a series of calls using the same connection (stateful calls) these calls should be encapsulated between: JCoContext.begin(destination); ... JCoContext.end(destination); The details of this mechanism are described in section Stateful connections. Important note: The context for the destination is valid for the current session until either JCoContext.end() is invoked or the session is ended. Unless a SessionReferenceProvider is implemented in a way that it allows switching threads for sessions, this means that the connection context is valid for the current thread only as implemented by the standard implementation of the SessionReferenceProvider interface.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 20

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

XMI Logons If XMI logons are necessary to execute remote function modules, these logons have to take place after having created the JCo session and the JCo context for the current thread.

Example Implementation // start JCo session for current thread ivSapSessionManager.startJCoSession(); // open stateful connection JCoContext.begin(destination); // generic XMI Login ivSapSessionManager.interfaceLogin(getDestination(), getRepository(), null, null); // XBP 2.0 Login ivSapSessionManager.interfaceLogin(getDestination(), getRepository(), "XBP", "2.0"); // execute calls to SAP // logoff from XMI ivSapSessionManager.interfaceLogoff(getDestination(), getRepository()); // terminate stateful connection JCoContext.end(destination); // end JCo session for current thread ivSapSessionManager.endJCoSession();

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 21

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Framework
This section describes the simple framework we have created to call remote function modules using the SAP JCo3 library. The framework essentially consists of two parts, one part to deal with classes to model SAP remote enabled functions (cf. section Class Model for Remote Enabled Functions). The second part of the framework deal with creating more complex tasks based on a class model for SAP JCo3 specific session and connection handling (cf. section Class Model for complex tasks based on JCo3-specific session and connection handling).

Class Model for Remote Enabled Functions As a basic layer we have one class for each function module we are calling. Each such class is derived from a superclass representing the interface function group that the function module belongs to (cf. Figure 1). As an example the class BAPI_XMI_LOGON models the remote function module BAPI_XMI_LOGON which belongs to the XMI interface function group. Therefore BAPI_XMI_LOGON is derived from the class XMI. All classes representing interface function groups are derived from a common superclass SapInterface which contains the functionality that is common for all interface function module classes.
<<abstract>> SapInterface
public SapInterface(JCoDestination dest, JCoRepository repository) protected abstract void writeInputParameters(JCoParameterList inParams) protected boolean hasReturn() protected boolean hasInputParameters() protected boolean hasOutputParameters() protected void readExportParameters(JCoParameterList outParams) protected void readReturnMessage(JCoParameterList outParams) public final boolean execute() public final boolean execute(JCoDestination destination) protected final JCoTable getTable(String name) protected final JCoStructure getImportStructure(String name) protected final void setMandatoryParameter() protected final void setOptionalParameter()

<<abstract>> XMI
public XMI(JCoDestination dest, JCoRepository repository) protected void readReturnMessage(JCoParameterList outParams)

BAPI_XMI_LOGON
public BAPI_XMI_LOGON(JCoDestination dest, JCoRepository repository) protected boolean hasInputParameters() protected boolean hasOutputParameters() protected void writeInputParameters(JCoParameterList inputParams) protected void readExportParameters(JCoParameterList outputParams) public String getIn_EXTCOMPANY() public void setIn_EXTCOMPANY(String in_EXTCOMPANY) public String getIn_EXTPRODUCT() public void setIn_EXTPRODUCT(String in_EXTPRODUCT) public String getIn_INTERFACE() public void setIn_INTERFACE(String in_INTERFACE) public String getIn_VERSION() public void setIn_VERSION(String in_VERSION) public String getOut_SESSIONID() public void setOut_SESSIONID(String out_SESSIONID)

BAPI_XMI_LOGOFF
public BAPI_XMI_LOGON(JCoDestination dest, JCoRepository repository) protected boolean hasInputParameters() protected boolean hasOutputParameters() protected void writeInputParameters(JCoParameterList inputParams) protected void readExportParameters(JCoParameterList outputParams) public String getIn_INTERFACE() public void setIn_INTERFACE(String in_INTERFACE)

Figure 1: Class Hierarchy for Interface Functions

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 22

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Class Model for complex tasks based on JCo3-specific session and connection handling The main part of the framework to deal with JCo3-specific session and connection handling has already been extensively described in sections Migration from JCo2 to JCo3 and Using JCo3 in a multi-threaded environment of this article. This section shows the class hierarchy (see Figure 2) to use the new JCo3functions in a comfortable way to create complex tasks.
<<abstract>> R3BatchTask
public R3BatchTask(SapSessionManager manager) protected JCoDestination getDestination() protected JCoRepository getRepository() public void run() protected abstract boolean execute(JCoDestination destination, JCoRepository repository)

<<abstract>> ThreadedR3BatchTask
public ThreadedR3BatchTask(SapSessionManager manager) public void run()

<<abstract>> StatefulR3BatchTask
public StatefulR3BatchTask(SapSessionManager manager) public void run()

<<abstract>> ThreadedStatefulR3BatchTask
public ThreadedStatefulR3BatchTask(SapSessionManager manager) public void run()

Figure 2: Class Hierarchy for Complex Tasks The common superclass for all complex tasks is R3BatchTask. This class provides the protected attributes ivSapCpu and ivSapSessionManager. ivSapCpu contains the parameters to connect to a particular SAP system and ivSapSessionManager (cf. section Session References per Thread) references the object to manage connections to the SAP system via the JCo3 framework. Moreover, R3BatchTask defines the abstract template method execute to be defined by subclasses to perform the real work of the task. Tasks directly derive from R3BatchTask when no further infrastructure services are needed. To add infrastructure services for JCo sessions and stateful connections, subclasses of R3BatchTask are defined which overwrite the run template method of R3BatchTask. If a task should run concurrently as a thread, then this task should derive from ThreadedR3BatchTask, which itself is a direct subclass of R3BatchTask, but implements the interface Runnable and creates a JCo3 session at the beginning of the task and releases the session at the end of the task: public abstract class ThreadedR3BatchTask extends R3BatchTask implements Runnable { public ThreadedR3BatchTask(SapSessionManager manager) { super(manager); } public final void run() { ivSapSessionManager.startJCoSession(); super.run(); ivSapSessionManager.endJCoSession(); } }

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 23

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

On the other hand, a complex task may require that all its calls to the SAP system use the same connection. In this case the task should derive from StatefulR3BatchTask, which itself is a direct subclass of R3BatchTask, but ensures stateful JCo3 connections by opening a JCoContext at the beginning and closing the JCoContext at the end of the task: public abstract class StatefulR3BatchTask extends R3BatchTask { public StatefulR3BatchTask(SapSessionManager manager) { super(manager); } /* template method */ public void run() { JCoContext.begin(getDestination()); super.run(); try { JCoContext.end(getDestination()); } catch (JCoException e) { ... } } } Finally, a task may combine the features of concurrent execution in a thread with stateful connection. in this case the task should derive from ThreadedStatefulR3BatchTask, which itself is a direct subclass of StatefulR3BatchTask, because the protocol is important. First, the new JCo session for the thread has to be created and then the stateful connection can be established: public abstract class ThreadedStatefulR3BatchTask extends StatefulR3BatchTask implements Runnable { public ThreadedStatefulR3BatchTask(SapSessionManager manager) { super(manager); } public void run() { ivSapSessionManager.startJCoSession(); super.run(); ivSapSessionManager.endJCoSession(); } } In order to allow for an even more flexible use of the framework, mix-in-classes (realized with generic type parameters) or the chain-of-responsibility pattern could be used to combine the features of concurrent JCo3 sessions and stateful connections. For our purposes, the static type hierarchy depicted in Figure 2 has turned out to be sufficient.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 24

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Related Content
http://service.sap.com/connectors SAP JCo 3.0 documentation SAP JCo Migration Guide For more information, visit the Java homepage.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 25

How to Migrate from SAP JCo2 to SAP JCo3 and use SAP JCo3 in a Multi-Threaded Environment

Disclaimer and Liability Notice


This document may discuss sample coding or other information that does not include SAP official interfaces and therefore is not supported by SAP. Changes made based on this information are not supported and can be overwritten during an upgrade. SAP will not be held liable for any damages caused by using or misusing the information, code or methods suggested in this document, and anyone using these methods does so at his/her own risk. SAP offers no guarantees and assumes no responsibility or liability of any type with respect to the content of this technical article or code sample, including any liability resulting from incompatibility between the content within this document and the materials and services offered by SAP. You agree that you will not hold, or seek to hold, SAP responsible or liable with respect to the content of this document.

SAP COMMUNITY NETWORK 2009 SAP AG

SDN - sdn.sap.com | BPX - bpx.sap.com | BOC - boc.sap.com 26

Вам также может понравиться