Chapter 5
Usage

5.1 Mapping Remote Function Modules to Java classes

The main task of Hibersap is to map Remote Function Modules (RFMs) which are defined in SAP R/3 to Java classes. To accomplish this, Hibersap provides a set of Java annotations that map Java classes and their fields to the elements of the function module’s interface. This section provides detailed information on the Hibersap annotations and on how data types are converted.

For a complete example of how to define Hibersap classes and mappings, see chapter 2 or checkout the Hibersap examples code from the source code repository.

5.1.1 The annotations

Since Hibersap maps SAP Remote Function Modules to plain Java classes, an application must define one class for each function module that acts as a kind of proxy for the function module. This class is called a BAPI class and has to be annotated with the @Bapi1 annotation2 . The annotation’s value property defines the name of the corresponding function module:

@Bapi(BAPI_SFLIGHT_GETLIST) 
public class FlightListBapi {...}

A function module’s interface usually has a set of parameters which are either of a scalar data type (such as a number, a text or a date) or of a complex data type (in ABAP called structure, a set of parameters of scalar data types). Scalar parameters can be mapped directly to a field of the BAPI class, whereas structures are mapped to complex Java types, i.e. classes with a set of fields. In Hibersap, these classes representing an ABAP structure are annotated with the @BapiStructure annotation. Since Structure class instances need to be created by Hibersap, they must have a default constructor.

@BapiStructure 
public class BapiRet2 {...}

To map parameters of a function module to fields of Java classes, those fields have to be annotated with the @Parameter annotation. Here, Hibersap needs to know the name of the function module’s parameter as well as its type using the annotation’s value and type properties respectively. The Enumeration ParameterType defines the types STRUCTURE and SIMPLE for parameters of a complex or scalar type:

@Export 
@Parameter(value = RETURN, type = ParameterType.STRUCTURE) 
private BapiRet2 returnData;

Since the interface parameters of ABAP functions are divided into import, export and table parameters, Hibersap has to know where to find the corresponding parameters. The @Import, @Export and @Table annotations provide this information. However, since members of complex parameters should always be scalar parameters, we only have to use these annotations on “top-level” parameters, i.e. parameters of the BAPI class. Parameters of Structure classes just need the @Parameter annotation:

@BapiStructure 
public class BapiRet2 { 
    @Parameter(MESSAGE) 
    private String message; 
    ... 
}

ABAP tables are lists of complex parameters. As such they are mapped to a java.util.Collection field. Hibersap again needs to know the name of the ABAP parameter as provided by the @Parameter annotation and its type as provided by the @Table annotation. A special characteristic of table parameters is that they can be used as import parameters as well as export parameters. Tables that import data to the function module are filled by the Java application, Hibersap will use the application-provided Collection to populate the table. Tables that export data from the function module will be read by Hibersap and copied to the corresponding Collection. Hibersap detects the type of the Collection’s element by identifying its generic type, which means that it is crucial to define the Collection with a generic type (the class Flight in the example):

@Bapi(BAPI_SFLIGHT_GETLIST) 
public class FlightListBapi { 
    @Table 
    @Parameter(FLIGHTLIST) 
    private List<Flight> flightList; 
}

The Java field representing a table need not be defined as a concrete implementation. When Hibersap creates a Collection, it creates a java.util.HashSet for fields defined as java.util.Set and a java.util.ArrayList for fields defined as java.util.Collection or java.util.List.

Table 5.1 shows an overview of the Hibersap annotations.


Annotation Description / Parameters
@Bapi Maps a Java class to a Remote Function Module in SAP. value The name of the RFM, e.g. BAPI_FLIGHT_GETLIST
@BapiStructure Maps the Java class to a structure in an RFM’s interface
@Parameter Maps a field to a parameter of the RFM’s interface. value The parameter’s name as defined by the RFM. type The parameter’s type, either ParamType.SIMPLE for a scalar type or ParamType.STRUCTURE for complex types. Default: SIMPLE.
@Import Defines a field annotated with @Parameter to be an import parameter.
@Export Defines a field annotated with @Parameter to be an export parameter.
@Table Defines a field annotated with @Parameter to be a table parameter.
@Convert The parameter’s data type will be converted by the given Converter, i.e. the Java field’s data type may differ from the JCo data type conversion pattern. converter An implementation of org.hibersap.conversion. Converter.
@ThrowExceptionOnError Generate a SapException when the function module returns errors in a RETURN structure or table. returnStructure Contains the path to the BAPI’s return structure or table. The first element should be ’EXPORT’ or ’TABLE’ to indicate if the return structure is defined as an export or table parameter. The last element is the name of the return structure, usually ’RETURN’. errorMessageTypes The message types which Hibersap shall interpret as an error. In these cases an Exception will be thrown. The RETURN structure’s field TYPE is compared to the message types.

Table 5.1: Hibersap annotations: Overview

5.1.2 Type Conversion

The Java type of each simple field is related to the ABAP field’s data type. Hibersap relies on the Java Connector’s conversion scheme as shown in table 5.2.


ABAP type Description Java type
C Character java.lang.String
N Numerical character java.lang.String
D Date java.lang.Date
T Time java.lang.Date
X Byte field byte[]
P Packed number java.lang.BigDecimal
I 4-byte integer int
F Floating point number double
STRING Variable-length character java.lang.String
XSTRING Variable-length byte field byte[]

Table 5.2: SAP Java Connector type conversion

Hibersap allows to convert a parameter’s data type to any Java type and vice versa. For example, ABAP does not have a boolean data type. Usually a boolean in ABAP is represented by a character field of length 1. A parameter is true if it equals to ’X’, false if it is empty. With a Hibersap Converter it is possible to map an ABAP “boolean” parameter to a boolean field in Java.

You can use Hibersap Converters to do any kind of data type conversion. There are a few Converters defined in the package org.hibersap.conversion. However, it is easy to write your own converter by implementing the org.hibersap.conversion.Converter interface:

public interface Converter 
{ 
    /** 
     * Convert the SAP value, as it is returned by the underlying 
     * interfacing technology (e.g. the SAP Java Connector, JCo) 
     * to the Java data type of the corresponding BAPI class field. 
     * Hibersap will call this method after calling the SAP function 
     * and before setting the field in the Java class. 
     * 
     * @param sapValue The object which is returned by the SAP interface 
     * @return The converted value 
     * @throws ConversionException - if the value can not be converted 
     */ 
    Object convertToJava( Object sapValue ) throws ConversionException; 
 
    /** 
     * Convert the Java value of the corresponding BAPI class field to the 
     * data type as it is expected by the underlying interfacing 
     * technology (e.g. the SAP Java Connector, JCo). Hibersap will call 
     * this method before calling the SAP function. 
     * 
     * @param javaValue The value of the BAPI class field 
     * @return The converted value 
     * @throws ConversionException - if the value can not be converted 
     */ 
    Object convertToSap( Object javaValue ) throws ConversionException; 
}
Listing 5.1: The Converter interface

To use a converter, you simply have to annotate the filed in the BAPI or Structure class with Hibersap’s @Convert annotation, specifying the Converter that should be called:

@Import 
@Parameter ( SHOW_DETAILS ) 
@Convert(converter = BooleanConverter.class) 
privatefinal boolean showDetails;
Listing 5.2: Using a converter

5.2 Calling Function Modules

5.2.1 Configure Hibersap and build a SessionManager

Chapter 4 explains in detail how to configure Hibersap. The following code snippet assumes that there is the /META-INF/hibersap.xml configuration file defining a SessionManager named “A12” in the application’s classpath and shows how to build a SessionManager:

AnnotationConfiguration configuration= new AnnotationConfiguration(A12); 
SessionManager sessionManager = configuration.buildSessionManager();
Listing 5.3: Building the SessionManager

The SessionManager should be created only once in an application’s lifetime. It depends on the kind of application how to store the SessionManager instances. E.g. in a web application it may be created and shut down in a ServletContextListener when starting the web application and put into the servlet context, in a stand-alone application it may be created and managed by a utility class with static accessor methods or – more advisable – by a dependency injection container such as Pico Container, Guice or Spring.

5.2.2 Calling a function in SAP

Calling a remote function module in SAP is as easy as opening a new Session via the SessionManager, creating the BAPI class with the required parameters, and calling the Session’s execute() method with the Bapi class as an argument.

Session session = sessionManager.openSession(); 
try 
{ 
    FlightListBapi flightList = new FlightListBapi( DE, Frankfurt, 
                                                    DE, Berlin, 
                                                    null, false, 10 ); 
    session.execute( flightList ); 
    showResult( flightList ); 
} 
finally 
{ 
    session.close(); 
}
Listing 5.4: Executing the BAPI function

After the call to session.execute(), the Bapi class is populated with the SAP function’s return parameters as it is defined in the parameter mappings.

A physical connection to the SAP system is created during the first call to the Session’s execute() method. It is crucial to close the Session after the last call to the execute() method. If Sessions are not closed, the connection pool may get exhausted. Therefore it is strongly recommended to close the Session in a finally block like in the above example. This way, even if one of the method calls in the try block throws a RuntimeException, the Session will still be closed.

If the application keeps sessions open for a long time, connections may also get shut down by the SAP system after some timeout period or the may get broken due to network related reasons. This means that Sessions should have a short lifetime (just like database sessions), usually a Session should be used for a single request or unit of work.

Hibersap Sessions are inexpensive to create, the Java Connector’s connection pool takes care of an efficient connection management (if properly configured), and Hibersap will not akquire a SAP-connection before it is needed. Thus, Sessions should be used once and then discarded.

5.3 Transaction Management

SAP R/3 allows external callers of its function modules to control logical units of work (transactions). Calling applications may call a number of function modules and commit or rollback all changes made during the function calls. This can be done by calling special BAPIs named “BAPI_TRANSACTION_COMMIT” and “BAPI_TRANSACTION_ROLLBACK”.3

Using Hibersap, it is very easy to start and end transactions, you do not have to map and call these BAPIs yourself. Depending on the chosen interfacing technology, you can either handle your transactions manually (JCo and JCA) or use Container Managed Transactions (JCA only).

5.3.1 Manual transaction handling

The Hibersap Session has a method beginTransaction() which must be called when starting the transaction. beginTransaction() returns a Transaction object on which you can later call the methods commit() or rollback() to tell SAP to commit or rollback all changes made during the transaction.

Session session = sessionManager.openSession(); 
Transaction transaction = null; 
try 
{ 
    transaction = session.beginTransaction(); 
    session.execute( bapiClass1 ); 
    ... 
    session.execute( bapiClassN ); 
        transaction.commit(); 
} 
catch (Exception e) 
{ 
    if (transaction != null) 
        transaction.rollback(); 
} 
finally 
{ 
    session.close(); 
}
Listing 5.5: Manual transaction handling

5.3.2 Container Managed Transactions

Applications running in an application server that use EJBs and a Java EE compatible Resource Adapter, may profit of the app server’s capability of automatically handle transactions. In this case, the application code does not have to take care of starting, committing and rolling back transactions.

See section 5.5 for a detailed discussion on Container Managed Transactions.

5.4 Authentication

5.4.1 Using a central User

The most common way to interact with a SAP system in enterprise applications is to use a central SAP user that is shared by all users of the application. Using this kind of authentication is a matter of configuration. When using Hibersap with JCo, the user credentials are defined in the Hibersap configuration. When using Hibersap with JCA, the credentials are usually defined in the resource adapter.

5.4.2 Per-session authentication

If the application has to provide user credentials, e.g. when each application user log on to the SAP system using his own SAP account, you can specify logon credentials for each Hibersap session you create.

When obtaining a Session from the SessionManager, the method openSession(Credentials) must be used. The authentication information is specified in the Credentials object.

Credentials credentials = new Credentials() 
    .setUser(atuttle) 
    .setPassword(myPassw0rd) 
    .setLanguage(EN); 
Session session = sessionManager.openSession( credentials ); 
session.execute( bapiClass ); 
...
Listing 5.6: Component-managed authentication

The attributes defined in the Credentials object are simply passed on to SAP. Table 5.3 lists the possible fields including the corresponding JCo parameter as defined in interface DestinationDataProvider of the SAP Java Connector version 3.


Credentials field Description JCo parameter
user SAP logon user JCO_USER
aliasUser SAP logon user alias, can be used instead of logon user JCO_ALIAS_USER
client SAP client JCO_CLIENT
language Logon language ISO code JCO_LANG
password Logon password JCO_PASSWD
ssoTicket SAP Cookie Version 2 as logon ticket for SSO based authentication JCO_MYSAPSSO2
x509Certificate X509 certificate for certificate based authentication JCO_X509CERT

Table 5.3: SAP Java Connector type conversion

5.4.3 Single sign-on

A special case of per-session authentication is the use of single sign-on. In a SAP environment it is common to use SAP Logon Tickets issued by SAP systems. In a web application / portal scenario the ticket is stored in a cookie named MYSAPSSO2 in the HTTP user session. After obtaining this ticket it has to be passed to the Hibersap session by setting the ssoTicket field of the Credentials object like described in the previous section 5.4.2.

5.5 Java EE application server integration

If developing applications which run inside a Java EE application server and make use of Enterprise Java Beans (EJB), it is strongly recommended using Hibersap in combination with a JCA compatible resource adapter. A resource adapter offers some important features which will be treated in this section.

5.5.1 Transaction Management

The application server’s transaction manager is used to handle transactions. In combination with EJBs and Container Managed Transactions (CMT), the code does not need to care about transaction demarcation, because the container sets the transaction boundaries implicitly. This simplifies development and reduces the probability of errors. If using CMT, all the function calls to SAP which take place during an EJB method call are running in one transaction. If the EJB method returns normally, the transaction manager commits the transaction. In case of an error, the transaction is automatically rolled back. Error here means that a RuntimeException is thrown or an application exception configured with the rollback=true attribute. (Note that Hibersap only throws runtime exceptions.)

Unfortunately, SAP R/3 does not provide the two-phase commit protocol (2PC) which is necessary for a resource to participate in a distributed transaction. The effect is that resource adapters for SAP R/3 support only local transactions, which is no problem if there is only one resource (the SAP R/3 system) enlisting in a transaction. If there are multiple resources participating in one distributed transaction (e.g. a SAP R/3 system, a database and/or a JMS system), the transaction manager starts a distributed transaction which requires 2PC aware resources as its participants. The good news is that some application servers (e.g. JBoss Application Server, Bea Weblogic or SAP WebAS) support a strategy called Last Resource Commit Optimization which makes it possible for a single non-2PC-aware resource to enlist in a distributed transaction. This is transparent for the programmer.

5.5.2 Security Management

With a resource adapter there are two methods to authenticate with the SAP R/3 system, container-managed and component-managed authentication. Using the former, the credentials (user name and password) are configured centrally in the resource adapter and the container uses these to automatically sign in whenever connecting to the SAP system. With component-managed authentication, an application passes credentials each time a connection is obtained from the resource adapter. This method is used when each user of the application signs in using its own SAP user, e.g. by entering the SAP user name and password in the application or when using single sign-on with logon tickets. Hibersap supports both authentication methods.

Container-managed authentication is simply a matter of configuration. The Resource Adapter will use the provided username/password combination (e.g. a central, technical SAP user).

Using component-managed authentication, the application has to provide authentication information itself. This may be e.g. a username/password combination entered by the application user, or a single sign-on login ticket obtained from the HTTP session. Section 5.4.2 shows how to use different authentication information on a per-session basis, section 5.4.3 shows how to use single sign-on tickets.

5.5.3 Configuration

Another advantage of using a resource adapter over using JCo directly is that a resource adapter can be deployed and configured independent of the applications that use it. Thus it is not necessary to reconfigure and redeploy all applications that connect to a SAP system whenever connection parameters (e.g. the SAP system’s host name) change. Instead, only the resource adapter has to be reconfigured. Since the configuration of the resource adapter specifies all the necessary properties to access the SAP system, the Hibersap configuration only needs to specify the resource adapter’s JNDI name that is used to look up the adapter’s connection factory.