______________________________________________________________________________________________

PIC
The easy way to connect Java with SAP

______________________________________________________________________________________________

Version 1.1.0

Copyright ©2008-2012 akquinet tech@spree GmbH

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

Contents
1 Introduction to Hibersap
2 Quick Start
3 Installation
4 Configuration
5 Usage

Contents

1 Introduction to Hibersap
2 Quick Start
 2.1 Installation
 2.2 The first Hibersap application
  2.2.1 The function module
  2.2.2 The BAPI class
  2.2.3 Structure classes
  2.2.4 Configuration
  2.2.5 Calling a function module
3 Installation
 3.1 The Hibersap libraries
 3.2 Third party libraries
  3.2.1 Hibersap dependencies
  3.2.2 The SAP Java Connector (JCo)
  3.2.3 The Cuckoo Resource Adapter for SAP
  3.2.4 Using other JCA compatible Resource Adapters
 3.3 Building Hibersap applications with Maven
4 Configuration
 4.1 XML file configuration
 4.2 Programmatic configuration
5 Usage
 5.1 Mapping Remote Function Modules to Java classes
  5.1.1 The Annotations
  5.1.2 Data Type Conversion
  5.1.3 Using Custom Converters
 5.2 Calling Function Modules
  5.2.1 Configure Hibersap and build a SessionManager
  5.2.2 Calling a function in SAP
 5.3 Transaction Management
  5.3.1 Manual transaction handling
  5.3.2 Automatic transaction handling
 5.4 Authentication
  5.4.1 Using a configured User
  5.4.2 Per-session authentication
  5.4.3 Single sign-on
 5.5 Java EE application server integration
  5.5.1 Transaction Management
  5.5.2 Security Management
  5.5.3 Configuration
  5.5.4 Hibersap EJB tools
 5.6 Bean Validation

Chapter 1
Introduction to Hibersap

Hibersap helps developers of Java applications to call business logic in SAP backends. It defines a set of Java annotations to map SAP function modules to Java classes as well as a small, clean API to execute these function modules and handle transaction and security aspects. Hibersap’s programming model is quite similar to those of modern O/R mappers, significantly speeding up the development of SAP interfaces and making it much more fun to write the integration code.

Under the hood, Hibersap either uses the SAP Java Connector (JCo) or a JCA compatible resource adapter to communicate with the SAP backend. While retaining the benefits of JCo and JCA like transactions, security, connection pooling, etc., developers can focus on writing business logic because the need for boilerplate code is largely reduced.

Hibersap can either be configured programmatically or by providing an XML file. Switching between JCo and JCA is a sole matter of configuration, the program code remains the same. This makes it possible to execute integration tests via JCo while using a resource adapter in the production environment.

Regarding data type conversion from ABAP to Java types, Hibersap per default uses the conversion as is done by JCo resp. JCA. Custom converters may be used to implement special conversion logic. Hibersap will then call the conversion code on-the-fly, before and after calling the function module in SAP.

Hibersap may be configured to use Bean Validation (JSR 303) to validate field values according to the standard Bean Validation annotations.

If the function module defines a standard Return structure or table, Hibersap is able to automatically detect an error state and throw a SapException which includes the information returned by SAP.

For Java EE applications it is recommended to use a resource adapter since it integrated seamlessly with Java EE containers. Using the Hibersap EJB tools makes it very easy to call SAP from EJB methods including such nice features like Container Managed Transactions and Container Managed Security. In a managed environment calls to SAP functions may even be part of distrubited transactions.

For advanced use cases, there are two types of interceptors that work on different levels of the call stack.


In chapter 2 you’ll find out how easy it is to use Hibersap.

Chapter 2
Quick Start

2.1 Installation

<?xml version=”1.0” encoding=”UTF-8”?> 
<project xmlns=”http://maven.apache.org/POM/4.0.0” 
         xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance 
         xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd> 
    <modelVersion>4.0.0</modelVersion> 
    <groupId>com.mycomp</groupId> 
    <artifactId>hibersap-example</artifactId> 
    <version>1.0</version> 
    <repositories> 
        <repository> 
            <id>repository.hibersap</id> 
            <name>Hibersap Repository for Maven</name> 
            <url> 
              http://hibersap.svn.sourceforge.net/viewvc/hibersap/m2repo 
            </url> 
        </repository> 
    </repositories> 
    <dependencies> 
        <dependency> 
            <groupId>org.hibersap</groupId> 
            <artifactId>hibersap-core</artifactId> 
            <version>1.1.0</version> 
        </dependency> 
        <dependency> 
            <groupId>org.hibersap</groupId> 
            <artifactId>hibersap-jco</artifactId> 
            <version>1.1.0</version> 
        </dependency> 
        <dependency> 
            <groupId>com.sap</groupId> 
            <artifactId>sap-jco</artifactId> 
            <version>3.0.8</version> 
        </dependency> 
    </dependencies> 
</project>
Listing 2.1: The Maven pom.xml

If you don’t want to use Maven to build the application, you can look up the dependencies of hibersap-core and hibersap-jco on Hibersap’s project site, under ”Dependency Convergence”: http://hibersap.org

2.2 The first Hibersap application

We are going to write a small example application that will call the SAP function BAPI_SFLIGHT_GETLIST. This function is part of a demo application in SAP that implements a simplified flight-booking system.

2.2.1 The function module

This is the function module’s interface in SAP:

FUNCTION BAPI_SFLIGHT_GETLIST. 
  IMPORTING 
     VALUE(FROMCOUNTRYKEY) LIKE  BAPISFDETA-COUNTRYFR 
     VALUE(FROMCITY)       LIKE  BAPISFDETA-CITYFROM 
     VALUE(TOCOUNTRYKEY)   LIKE  BAPISFDETA-COUNTRYTO 
     VALUE(TOCITY)         LIKE  BAPISFDETA-CITYTO 
     VALUE(AIRLINECARRIER) LIKE  BAPISFDETA-CARRID DEFAULT SPACE 
     VALUE(AFTERNOON)      LIKE  BAPI_AUX-AFTERNOON DEFAULT SPACE 
     VALUE(MAXREAD)        LIKE  BAPI_AUX-MAXREAD DEFAULT 0 
  EXPORTING 
     VALUE(RETURN)         LIKE  BAPIRET2 STRUCTURE  BAPIRET2 
  TABLES 
     FLIGHTLIST            STRUCTURE  BAPISFLIST
Listing 2.2: The ABAP Function

This function module takes some parameters that represent search criteria to look up flights in SAP’s database. The matching flights are returned in the FLIGHTLIST table, which contains information such as the airline carrier id, a flight connection code and departure/destination data. The RETURN structure may be filled by SAP with extra messages like errors, warnings, etc.

In this function, the import parameters are simple types, whereas the export and table parameter are complex data types (ABAP structures). The RETURN parameter is of type BAPIRET2, which is a standard structure that can be found in many function modules’ interfaces and that is not specific to this BAPI. See table 2.1.


Component name Type Description
TYPE Character Message type: S Success, E Error, W Warning,
I Info, A Abort
ID Character Messages, message class
NUMBER Numeric character Messages, message number
MESSAGE Character Message text
LOG_NO Character Application log: log number
LOG_MSG_NO Numeric character Application log: Internal message serial number
MESSAGE_V1 Character Messages, message variables
MESSAGE_V2 Character Messages, message variables
MESSAGE_V3 Character Messages, message variables
MESSAGE_V4 Character Messages, message variables
PARAMETER Character Parameter name
ROW 4-byte integer Lines in parameter
FIELD Character Field in parameter
SYSTEM Character Logical system from which message originates

Table 2.1: Structure BAPIRET2

The FLIGHTLIST table’s lines are of type BAPISFLIST which contains the following fields, as shown in table 2.2.


Component name Type Description
CARRID Character Airline carrier ID
CONNID Numerical character Flight connection code
FLDATE Date Flight date
AIRPFROM Character Airport of departure
AIRPTO Character Destination airport
DEPTIME Time Departure time
SEATSMAX 4-byte integer Maximum capacity
SEATSOCC 4-byte integer Occupied seats

Table 2.2: Structure BAPISFLIST

2.2.2 The BAPI class

To call a function module from a Java application using Hibersap, we will write a BAPI class that acts as an adapter to JCo. The BAPI class is a simple Java class with a number of fields representing the BAPI’s import, export and table parameters. In case the BAPI parameter being a scalar parameter, the Java field itself is of a primitive Java type. In the case of a structure parameter, the Java field’s type has to be a complex type, too. A table parameter maps to an Array or a Collection of a complex type.

All setup related to the function module’s interface is done via Java annotations. A BAPI class is defined using the Hibersap class annotation @Bapi, which has a name argument specifying the name of the SAP function module we want to call. (All Hibersap annotations can be found in the package org.hibersap.annotations.)

package org.hibersap.examples.flightlist; 
 
import java.util.List; 
import org.hibersap.*; 
 
@Bapi(BAPI_SFLIGHT_GETLIST) 
public class FlightListBapi 
{ 
  ... 
}
Listing 2.3: The BAPI class

The Java fields that will be mapped to the function module’s parameters are annotated with the @Import, @Export or @Table annotations to tell Hibersap which kind of parameter it should handle. Additionally, we have to specify the function module’s field name to which it relates, using the @Parameter annotation. The @Parameter’s second argument, type, tells Hibersap if the parameter has a simple or a complex structure type. The enumeration ParameterType defines possible values, the default type for element type being SIMPLE. In most cases we have to specify a parameter’s name only. Since table parameters always represent a table of complex types, any parameter type argument will be ignored by Hibersap.

@Import 
@Parameter(FROMCOUNTRYKEY) 
private final String fromCountryKey; 
 
@Import 
@Parameter(FROMCITY) 
private final String fromCity; 
 
@Import 
@Parameter(TOCOUNTRYKEY) 
private final String toCountryKey; 
 
@Import 
@Parameter(TOCITY) 
private final String toCity; 
 
@Import 
@Parameter(AIRLINECARRIER) 
private final String airlineCarrier; 
 
@Import 
@Parameter(AFTERNOON) 
@Convert(converter = BooleanConverter.class) 
private final boolean afternoon; 
 
@Import 
@Parameter(MAXREAD) 
private final int maxRead; 
 
@Export 
@Parameter(value=RETURN, type = ParameterType.STRUCTURE) 
private BapiRet2 returnData; 
 
@Table 
@Parameter(FLIGHTLIST) 
private List<Flight> flightList;
Listing 2.4: The BAPI fields

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

The @Convert annotation on the field afternoon in the listing above tells Hibersap to use a Converter of type BooleanConverter to convert the parameter AFTERNOON which is a character field of length 1 to a Java boolean value. See section 5.1 on how to implement custom Converters.

To conclude the example, we write a constructor which takes all the import parameters as arguments, initializing the corresponding fields.

public FlightListBapi( String fromCountryKey, 
                       String fromCity, 
                       String toCountryKey, 
                       String toCity, 
                       String airlineCarrier, 
                       boolean afternoon, 
                       int maxRead ) 
{ 
    this.fromCountryKey = fromCountryKey; 
    this.fromCity = fromCity; 
    this.toCountryKey = toCountryKey; 
    this.toCity = toCity; 
    this.airlineCarrier = airlineCarrier; 
    this.afternoon = afternoon; 
    this.maxRead = maxRead; 
}
Listing 2.5: The constructor

Finally, we should add a getter method for each field. Hibersap itself does not need setter methods, because all fields are set using reflection. We could of course add additional fields and methods if needed.

public boolean getAfternoon() 
{ 
    return this.afternoon; 
} 
...
Listing 2.6: The getter methods

______________________________________________________________________________________________

Note — There is one constraint in the current version of Hibersap you should take into account: The mapping between SAP parameters and Java classes works as expected only if the SAP function module complies to the BAPI standard, this means:

______________________________________________________________________________________________

2.2.3 Structure classes

There are two more classes we have to write: One for the complex export parameter RETURN, which is named BapiRet2, after the SAP data type. It is another annotated simple Java class with fields related to some of the function module’s parameter. To keep the example simple, we do not map all the fields of the RETURN parameter.

package org.hibersap.bapi; 
 
import org.hibersap.annotations.*; 
 
@BapiStructure 
public class BapiRet2 
{ 
    @Parameter(TYPE) 
    @Convert(converter = CharConverter.class) 
    private char type; 
 
    @Parameter(ID) 
    private String id; 
 
    @Parameter(NUMBER) 
    private String number; 
 
    @Parameter(MESSAGE) 
    private String message; 
 
    public char getType() 
    { 
        return this.type; 
    } 
 
    public String getId() 
    { 
        return this.id; 
    } 
 
    public String getNumber() 
    { 
        return this.number; 
    } 
 
    public String getMessage() 
    { 
        return this.message; 
    } 
}
Listing 2.7: The BapiRet2 class

The class is annotated with @BapiStructure to tell Hibersap that it maps to a complex parameter on the SAP side. Each particular field is annotated with the already known @Parameter annotation that defines the name of the corresponding structure field. The BapiRet2 class is already part of Hibersap, since this structure is used by a lot of SAP function modules. This means, you don’t have to implement it.

The second class we need to implement is a Java class that Hibersap will map to each row in the table parameter FLIGHTLIST, which in our example is simply called Flight. The table FLIGHTLIST will be filled by SAP with the flight information matching our request.

package org.hibersap.examples.flightlist; 
 
import java.util.Date; 
import org.hibersap.*; 
 
@BapiStructure 
public class Flight 
{ 
    @Parameter(CARRID) 
    private String carrierId; 
 
    @Parameter(CONNID) 
    private String connectionId; 
 
    @Parameter(AIRPFROM) 
    private String airportFrom; 
 
    @Parameter(AIRPTO) 
    private String airportTo; 
 
    @Parameter(FLDATE) 
    private Date flightDate; 
 
    @Parameter(DEPTIME) 
    private Date departureTime; 
 
    @Parameter(SEATSMAX) 
    private int seatsMax; 
 
    @Parameter(SEATSOCC) 
    private int seatsOccupied; 
 
    public String getAirportFrom() 
    { 
        return this.airportFrom; 
    } 
 
    public String getAirportTo() 
    { 
        return this.airportTo; 
    } 
 
    public String getCarrierId() 
    { 
        return this.carrierId; 
    } 
 
    public String getConnectionId() 
    { 
        return this.connectionId; 
    } 
 
    public Date getDepartureTime() 
    { 
        return DateUtil.joinDateAndTime( flightDate, departureTime ); 
    } 
 
    public Date getFlightDate() 
    { 
        return flightDate; 
    } 
 
    public int getSeatsMax() 
    { 
        return this.seatsMax; 
    } 
 
    public int getSeatsOccupied() 
    { 
        return this.seatsOccupied; 
    } 
}
Listing 2.8: The Flight class

Please note that the method getDepartureTime() does not simply return the field departureTime but calls a utility method DateUtil.joinDateAndTime(). This is done here because ABAP – unlike Java – does not have a data type that contains date and time. In ABAP such a timestamp is separated into two fields, one of type Date, the other of type Time. Therefore the Java Connector returns a java.util.Date for the SAP date field containing the date fraction (date at 00:00:00,000) and another java.util.Date for the time field containing the time fraction (i.e. Jan. 1st, 1970 plus time). The utility method joins those two dates into one.

2.2.4 Configuration

To configure Hibersap, we need to specify some information for the Hibersap framework, plus properties for the Java Connector. To accomplish this, we create an XML file named hibersap.xml in $project_home/src/main/resources/META-INF. Hibersap will look for this file in the classpath under “/META-INF/hibersap.xml”.

In the example we use a minimal set of JCo properties to be able to connect to the back-end SAP system. All valid JCo properties are specified in the JCo library interface com.sap.conn. jco.ext.DestinationDataProvider (see javadoc provided with JCo).

<?xml version=1.0 encoding=UTF-8?> 
<hibersap xmlns=urn:hibersap:hibersap-configuration:1.0> 
  <session-manager name=A12> 
    <context>org.hibersap.execution.jco.JCoContext</context> 
 
    <properties> 
      <property name=jco.client.client value=800 /> 
      <property name=jco.client.user value=sapuser /> 
      <property name=jco.client.passwd value=password /> 
      <property name=jco.client.lang value=en /> 
      <property name=jco.client.ashost value=10.20.80.76 /> 
      <property name=jco.client.sysnr value=00 /> 
      <property name=jco.destination.pool_capacity value=1 /> 
    </properties> 
 
    <annotatedClasses> 
      <class>org.hibersap.examples.flightlist.FlightListBapi</class> 
    </annotatedClasses> 
  </session-manager> 
</hibersap>
Listing 2.9: hibersap.xml

2.2.5 Calling a function module

Hibersap’s API is quite similar to Hibernate. There is the notion of a SessionManager which should be created only once in an application, because it is rather expensive to create. One SessionManager is needed for each SAP system which is used by the application.

The SessionManager is responsible for creating Sessions. A Session represents a connection to the SAP system. The first time we call a function module on a Session, Hibersap gets a connection from the underlying connection pool. When closing a session, the connection is returned to the pool. Therefore you have to take care always to close the session, preferably in a finally block, else the connection pool may get exhausted sooner or later.

The following function configures a Hibersap SessionManager. First, an instance of type AnnotationConfiguration has to be created for the named SessionManager, as specified in hibersap.xml. Finally, we build the SessionManager. In a real application this should be done once, reusing the SessionManager throughout the application’s lifetime.

public SessionManager createSessionManager() 
{ 
    AnnotationConfiguration configuration 
        = new AnnotationConfiguration(A12); 
    return configuration.buildSessionManager(); 
}
Listing 2.10: Creating the SessionManager

Now it is time to call the function module in SAP. After creating the SessionManager and opening a new Session, we create an instance of our BAPI Class, passing all parameters needed to execute the function as constructor arguments. Then we simply call the execute() method on the Session, passing the BAPI class, which actually performs the call to SAP. Now the flightListBapi object is enriched with all the values returned by the function module and which we have mapped to Java fields in our BAPI Class.

public void showFlightList() 
{ 
    SessionManager sessionManager = createSessionManager(); 
 
    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 2.11: Executing the function

To see the result of the function call, we simply print the BAPI class’ fields to the console in the showResult() method:

private void showResult( FlightListBapi flightList ) 
{ 
    System.out.println( AirlineId:  + flightList.getFromCountryKey() ); 
    System.out.println( FromCity:  + flightList.getFromCity() ); 
    System.out.println( ToCountryKey:  + flightList.getToCountryKey() ); 
    System.out.println( ToCity:  + flightList.getToCity() ); 
    System.out.println( AirlineCarrier:  + flightList 
                                             .getAirlineCarrier() ); 
    System.out.println( Afternoon:  + flightList.getAfternoon() ); 
    System.out.println( MaxRead:  + flightList.getMaxRead() ); 
 
    System.out.println( \nFlightData ); 
    List<Flight> flights = flightList.getFlightList(); 
    for ( Flight flight : flights ) 
    { 
        System.out.print( \t + flight.getAirportFrom() ); 
        System.out.print( \t + flight.getAirportTo() ); 
        System.out.print( \t + flight.getCarrierId() ); 
        System.out.print( \t + flight.getConnectionId() ); 
        System.out.print( \t + flight.getSeatsMax() ); 
        System.out.print( \t + flight.getSeatsOccupied() ); 
        System.out.println( \t + flight.getDepartureTime() ); 
    } 
 
    System.out.println( \nReturn ); 
    BapiRet2 returnStruct = flightList.getReturnData(); 
    System.out.println( \tMessage:  + returnStruct.getMessage() ); 
    System.out.println( \tNumber:  + returnStruct.getNumber() ); 
    System.out.println( \tType:  + returnStruct.getType() ); 
    System.out.println( \tId:  + returnStruct.getId() ); 
}
Listing 2.12: Printing the results

Finally, create a main method that calls the showFlightList() method. Build the project with maven on the command-line using “mvn compile” and run the main class, or run it directly from your IDE.

In the example, we are looking for all flights from Frankfurt to Berlin. The result should look like follows, in this example, there were two flights found.

AirlineId: DE 
FromCity: Frankfurt 
ToCountryKey: DE 
ToCity: Berlin 
AirlineCarrier: 
Afternoon: false 
MaxRead: 10 
 
FlightData 
        FRA  SXF  LH  2402  220  191  Thu Dec 30 10:30:00 CET 2010 
        FRA  SXF  LH  2402  220  207  Fri Dec 31 10:30:00 CET 2010 
 
Return 
        Message: 
        Number: 000 
        Type: S 
        Id:

If there were no flights found, the return field will contain the following data returned by SAP:

Return 
        Message: No corresponding flights found 
        Number: 150 
        Type: E 
        Id: BC_BOR

To see further examples, you may check out the complete hibersap project from the subversion source code repository. See the information provided at the Hibersap project site http://hibersap.org. There you will also find examples of using Hibersap in a Java EE application server with a JCA resource adapter.

Chapter 3
Installation

3.1 The Hibersap libraries

The Hibersap framework is divided into the following libraries:

When using Hibersap in conjunction with a JCA compatible resource adapter, both the hibersap-core and the hibersap-jca jars must be on the application’s classpath. When using Hibersap with the SAP Java Connector (JCo), the hibersap-core and the hibersap-jco libraries are needed.

When using Hibersap with EJBs, you may consider using the EJB tools provided by the hibersap-ejb module. The EJB tools provide an EJB3 interceptor which takes care of opening and closing sessions as well as injecting them into your EJBs at a special injection point denoted by a @HibersapSession annotation. See section 5.5.4 for more information.

3.2 Third party libraries

Hibersap has a few dependencies on third-party libraries, such as apache-commons or JAXB, which you need to add to your application’s classpath. The easiest way to achieve this is to build your projects with Maven, see section 3.3.

Depending on which interfacing technology is actually used, you also need the SAP Java Connector (JCo) or a JCA compatible resource adapter.

3.2.1 Hibersap dependencies

If not using Maven, please see the page ”Dependency Convergence” on the Hibersap project site (http://hibersap.org) to get a current list of libraries used by Hibersap and add these to your application’s classpath. When using Maven, it will download the dependencies automatically.

3.2.2 The SAP Java Connector (JCo)

The SAP JCo library is provided by SAP to their customers and comes with its own license. Thus it can not be provided by public Maven repositories or download sites. Please check the following URL for more information and downloads: http://service.sap.com/connectors. You need to have a user and password for this URL, which is free for SAP customers. Valuable help regarding SAP technologies can also be found on the SAP Community Network (SCN): http://scn.sap.com.

After downloading SAP Java Connector 3.0, extract the sapjco3.jar and the sapjco3 native library. The native library must be on your application’s library path. You may copy it to a global library path, to a special directory such as C:/WINDOWS/SYSTEM32 on Windows systems or to the execution directory of the application (e.g. the bin folder of your application server or the folder from which you run your application). Additionally, the JCo jar file must be on the application’s classpath.

You may set the Java library path programmatically within your application by calling

System.setProperty(java.library.path, /the/actual/path);

or by passing it to the Java runtime when executing your Java application using

-Djava.library.path=/the/actual/path

3.2.3 The Cuckoo Resource Adapter for SAP

If you are using Hibersap with a resource adapter in a managed environment, the preferred choice is the Cuckoo Resource Adapter for SAP. The project’s web site can be found under http://sourceforge.net/p/cuckoo-ra.

For your application, you need to deploy the resource adapter to your application server. Since it uses the SAP Java Connector internally, the previous section also applies to this scenario, i.e. the SAP JCo has to be installed for use within the application server.

3.2.4 Using other JCA compatible Resource Adapters

Being the only open source resource adapters for SAP, Hibersap was tested with Cuckoo as well as the SAP BAPI JCA Adapter (see http://sourceforge.net/projects/sapbapijcaadapt/). Nevertheless, you are welcome to use Hibersap with other resource adapters and we would be glad to get your feedback. Note that a resource adapter must implement the JCA Common Client Interface (CCI) to be supported by Hibersap.

Integrating another Resource Adapter in combination with application-managed authentication includes writing a Resource Adapter specific implementation of the interface org.hibersap. execution.jca.cci.ConnectionSpecFactory. This is due to a limitation in the JCA specification which specifies the javax.resource.cci.ConnectionSpec as an empty interface, letting it up to the vendor-specific implementation to define which properties it contains. Hibersap’s aim to support different resource adapters means that there must be a layer on top of the ConnectionSpec interface which makes it possible to adapt to different JCA implementations without having explicit dependencies to each of them. Hibersap implements ConnectionSpecFactories for Cuckoo as well as the SAP BAPI JCA Adapter that use reflection for setting and getting the ConnectionSpec’s parameters in order to reduce (compile-time) dependencies to the actual resource adapter.

However, an implementation of the ConnectionSpecFactory is not needed if the application uses container-managed authentication, because in this case there is no need to use a ConnectionSpec.

3.3 Building Hibersap applications with Maven

If you are building your application with Maven, you need to specify the Hibersap repository for your module. Adding the following part to the repositories section of your pom.xml gives your project access to the libraries you need when using Hibersap.

<repositories> 
    <repository> 
        <id>repository.hibersap</id> 
        <name>Hibersap Repository for Maven</name> 
        <url> 
            https://svn.code.sf.net/p/hibersap/code/m2repo/ 
        </url> 
    </repository> 
    ... 
</repositories>
Listing 3.1: Maven repository for Hibersap

This is how you can specify the dependencies to the Hibersap libraries in your pom.xml. Depending on which interfacing technology you use, you generally need to depend from either hibersap-core and hibersap-jco or from hibersap-core and hibersap-jca.

<dependency> 
    <groupId>org.hibersap</groupId> 
    <artifactId>hibersap-core</artifactId> 
    <version>1.1.0</version> 
    <type>jar</type> 
</dependency>
Listing 3.2: hibersap-core
<dependency> 
    <groupId>org.hibersap</groupId> 
    <artifactId>hibersap-jco</artifactId> 
    <version>1.1.0</version> 
    <type>jar</type> 
</dependency>
Listing 3.3: hibersap-jco
<dependency> 
    <groupId>org.hibersap</groupId> 
    <artifactId>hibersap-jca</artifactId> 
    <version>1.1.0</version> 
    <type>jar</type> 
</dependency>
Listing 3.4: hibersap-jca

Due to Maven’s dependency management capabilities, all transient dependencies are automatically resolved so that there is no need to specify any of the above mentioned third-party libraries. However, since the SAP JCo and the SAP BAPI JCA Adapter can not be found in a (public) Maven repository due to its commercial license model, you have to manually add these libraries to your local or enterprise repository.

The latest version of the SAP Java Connector can be downloaded from the SAP Service Marketplace at http://service.sap.com/connectors. There you will find different distribution packages for the supported platforms. To install the JCo jar to your local Maven repository, unpack the downloaded zip file (e.g. version 3.0.8) and issue the following command from your console.

mvn install:install-file -DgroupId=com.sap -DartifactId=sap-jco -Dversion=3.0.8 -Dpackaging=jar -Dfile=sapjco.jar
Listing 3.5: Installation of sap-jco.jar to local Maven repository

After installing the JCo library to your local repository or alternatively deploying it to your project’s or company’s repository, you can include the JCo lib in your project by declaring the following dependency.

<dependency> 
    <groupId>com.sap</groupId> 
    <artifactId>sap-jco</artifactId> 
    <version>3.0.8</version> 
</dependency>
Listing 3.6: Installation of sap-jco.jar to local Maven repository

The other important file from the JCo distribution is the JCo native library which you must put into your application’s library path.

Chapter 4
Configuration

Hibersap configuration consists of a set of properties. There are two possibilities to configure Hibersap:

While bootstrapping, Hibersap first tries to configure itself looking for the /META-INF/hibersap.xml file in the classpath. When creating a SessionManager, configuration can be set or overwritten using programmatic configuration.

Using an XML file is usually the preferred way to configure Hibersap.

4.1 XML file configuration

The format of the XML configuration file is inspired by JPA’s persistence.xml. If you have to access different SAP systems, you can define more than one SessionManager by multiplying the session-manager XML element.

Listing 4.1 shows the XML configuration when using JCo. Note that you may use the Hibersap XML schema definition as shown in the hibersap element to get validation and autocompletion in your IDE or XML editor.

<?xml version=1.0 encoding=UTF-8?> 
<hibersap xmlns=http://hibersap.org/xml/ns/hibersap-config 
          xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance 
          xsi:schemaLocation=http://hibersap.org/xml/ns/hibersap-config http://hibersap.sourceforge.net/xml/hibersap_1_1.xsd> 
  <session-manager name=A12> 
    <context>org.hibersap.execution.jco.JCoContext</context> 
    <properties> 
      <property name=jco.client.client value=800 /> 
      <property name=jco.client.user value=sapuser /> 
      <property name=jco.client.passwd value=password /> 
      <property name=jco.client.lang value=en /> 
      <property name=jco.client.ashost value=10.20.80.76 /> 
      <property name=jco.client.sysnr value=00 /> 
    </properties> 
    <annotated-classes> 
      <annotated-class>org.hibersap.examples.flightlist.FlightListBapi</annotated-class> 
      <annotated-class>org.hibersap.examples.flightdetail.FlightDetailBapi</annotated-class> 
    </annotated-classes> 
  </session-manager> 
</hibersap>
Listing 4.1: hibersap.xml for use with JCo

Listing 4.2 shows the XML configuration when using a JCA compatible resource adapter.

<?xml version=1.0 encoding=UTF-8?> 
<hibersap> 
  <session-manager name=A12> 
    <context>org.hibersap.execution.jca.JCAContext</context> 
    <jca-connection-factory>java:/eis/sap/A12</jca-connection-factory> 
    <jca-connectionspec-factory> 
      org.hibersap.execution.jca.cci.SapBapiJcaAdapterConnectionSpecFactory 
    </jca-connectionspec-factory> 
    <annotated-classes> 
      <annotated-class>org.hibersap.examples.flightlist.FlightListBapi</annotated-class> 
      <annotated-class>org.hibersap.examples.flightdetail.FlightDetailBapi</annotated-class> 
    </annotated-classes> 
  </session-manager> 
</hibersap>
Listing 4.2: hibersap.xml for use with JCA

Following is a complete list of Hibersap’s configuration parameters.

Configuration Parameters________________________________________________________________

context
The fully qualified class name of the Context class. This class must implement org.hibersap.session.Context and acts as a facade to the interfacing technology that is actually used. Existing implementations are org.hibersap.execution.jco.JCoContext for the SAP Java Connector (JCo) or org.hibersap.execution.jca.JCAContext for a JCA compatible Resource Adapter. (Default: JCoContext.)
jca-connection-factory
The JNDI name of the JCA Connection Factory. This parameter has to be specified if the application uses a JCA compatible resource adapter. The resource adapter has to be deployed on the application server independently from Hibersap and the application, defining a JNDI name for each configured ConnectionFactory. Hibersap will use this name to look up the resource adapter’s ConnectionFactory.
jca-connectionspec-factory
The fully qualified class name of the ConnectionSpecFactory implementation used to get a ConnectionSpec object. A ConnectionSpec is is used to provide data such as a user name and password for the current session. The existing implementations are CuckooJcaAdapterConnectionSpecFactory and SapBapiJcaAdapterConnectionSpecFactory. Others may be added by implementing org.hibersap.execution.jca.cci.ConnectionSpecFactory interface.
properties
Zero or more additional properties. These depend on the interfacing technology in use. For the SAP JCo, all the JCo-specific properties must be defined here. See javadoc for the class com.sap.conn.jco.ext.DestinationDataProvider of the JCo distribution to get a complete list of possible properties. For use with JCA, this element is not needed.
annotated-classes
All annotated BAPI classes which are used with the SessionManager must be listed here.
validation-mode
Specifies if Bean Validation (JSR-303) shall be used. Possible values are NONE to deactivate Bean Validation, AUTO to activate Bean Validation only if a provider is available on the classpath, and CALLBACK to make sure Bean Validation is used. With CALLBACK, Hibersap will throw an exception if no Bean Validation provider is present at runtime.
bapi-interceptor-classes
A list of the interceptor classes. These must implement org.hibersap.interceptor.BapiInterceptor and are called before and after a SAP function module gets executed. Each interceptor must be defined with the fully qualified class name in a seperate bapi-interceptor-class element.
execution-interceptor-classes
A list of the interceptor classes. These must implement org.hibersap.interceptor.ExecutionInterceptor and are called before and after a SAP function module gets executed. Each interceptor must be defined with the fully qualified class name in a seperate execution-interceptor-class element.
________________________________________________________________________________________

To build a SessionManager using the hibersap.xml file, you simply have to create an object of class org.hibersap.configuration.AnnotationConfiguration, specifying the SessionManager name as an argument. Note that there is also a default constructor for AnnotationConfiguration which can be used if there is only one configured SessionManager. Hibersap will issue a warning when there are more than one SessionManagers configured, but the no-args constructor is used.

AnnotationConfiguration configuration= new AnnotationConfiguration(A12); 
SessionManager sessionManager = configuration.buildSessionManager();

4.2 Programmatic configuration

After creating a Configuration object which will be used to build the SessionManager, configuration can be set or overwritten programmatically.

The information from the XML file is internally converted into a Java data structure reflecting the structure of the XML document. All configuration classes have Java Bean style accessor methods (get.. and set..) for their fields.

For programmatic configuration you have to change or create SessionManagerConfig for each SessionManager you want to use. You can use method chaining to build the object. The following example creates a SessionManagerConfig object that is equivalent to the one created internally by the hibersap.xml example in listing 4.1.

SessionManagerConfig cfg = new SessionManagerConfig( A12 ) 
    .setContext( JCoContext.class.getName() ) 
    .setProperty( jco.client.client, 800 ) 
    .setProperty( jco.client.user, sapuser ) 
    .setProperty( jco.client.passwd, password ) 
    .setProperty( jco.client.lang, en ) 
    .setProperty( jco.client.ashost, 10.20.80.76 ) 
    .setProperty( jco.client.sysnr, 00 ) 
    .addAnnotatedClass( FlightListBapi.class ) 
    .addAnnotatedClass( FlightDetailBapi.class ); 
 
AnnotationConfiguration configuration = new AnnotationConfiguration(cfg); 
SessionManager sessionManager = configuration.buildSessionManager();
Listing 4.3: Programmatic configuration

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. 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, the 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. fields 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 an Array or 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 Array or Collection to populate the table. Tables that export data from the function module will be read by Hibersap and copied to the corresponding Array or Collection. Hibersap detects the type of its elements by the array type if it is declared as an Array, or by its generic type if it is declared as a Collection. When using a Collection, it is crucial to declare it with a generic type (the class Flight in the example), otherwise Hibersap will throw an error because it cannot determine the element type:

@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 instantiates 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.

List 5.1.1 shows an overview of the Hibersap annotations.

Annotations overview_____________________________________________________________________

@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
Tells Hibersap to throw 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, path elements are separated by a forward slash (’/’). The first element should be ’EXPORT’ or ’TABLE’ to indicate if the return structure is defined as an export or table parameter. The second element is the name of the return structure, usually ’RETURN’. Default: ”EXPORT/RETURN”
errorMessageTypes The ABAP 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. Default: ”E”, ”A”.
______________________________________________________________________________________________________________________

5.1.2 Data Type Conversion

The Java type of each simple field is related to the ABAP field’s data type. When using Hibersap with JCo, it relies on the Java Connector’s conversion scheme as shown in table 5.1.


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.1: SAP Java Connector type conversion

When using Hibersap with JCA, it relies on the data types returned by the Resource Adapter. Most Resource Adapters for SAP use JCo, so the above type conversion scheme will be applicable here, too.

5.1.3 Using Custom Converters

Custom converters allow for converting a parameter’s data type to any Java type and vice versa. A common example for a custom converter is one that converts boolean values. ABAP does not have a boolean data type, a boolean in ABAP is usually 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 
{ 
  public interface Converter<J, S> extends Serializable 
  { 
    /** 
     * 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 
     */ 
    J convertToJava( S 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 
     */ 
    S convertToSap( J javaValue ) throws ConversionException; 
  } 
}
Listing 5.1: The Converter interface

To use a converter, you simply annotate the field 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

You can use converters not only with simple parameters, but also with structure and table parameters. In case of a structure parameter, the object passed to Converter.convertToJava() will be a Map with the structure parameter names as keys and the parameter values as map values. Converter.convertToSap() must return a Map like this.

When using a converter with a table parameter, the object passed to Converter.convertToJava() be a List of Maps where each Map has the structure parameter name and values as keys/values. Converter.convertToSap() must return a List of Maps of the same structure.

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 closed in a ServletContextListener when starting and stopping the web application, putting into the servlet context. In an EJB application this may be done using a Singleton EJB and its life-cycle methods, in a stand-alone application the SessionManager might be managed by a dependency injection framework.

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 an instance of the BAPI class with the required parameters and passing it to the Session’s execute() method.

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 object is populated with the SAP function’s return parameters as defined in the parameter mappings.

A physical connection to the SAP system is created during the first call to a 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 (managed by JCo or the Resource adapter) 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.

Keep in mind that, if the application keeps sessions open for a long time, connections may also be shut down by the SAP system after some timeout period or there is some possibility that they 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 or Resource Adapter’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). An application may call a number of function modules and commit or rollback all changes made during the function calls. This is done by calling special function modules 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 function modules 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

In Java EE applications that make use of EJBs and Bean Managed Transactions (BMT) it is also necessary to explicitly start, commit and rollback transactions like in the code example.

5.3.2 Automatic transaction handling

Applications running in an application server that use EJBs and a Java EE compatible Resource Adapter can profit from the application server’s capability to automatically handle transactions. This is called Container Managed Transactions (CMT).

In case of using CMT, 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 configured 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 provided through Hibersap configuration, namely the JCo properties defined for a SessionManager. When using Hibersap with JCA, the credentials are usually defined in the resource adapter configuration.

5.4.2 Per-session authentication

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

In this case, when obtaining a Session from the SessionManager, the method
openSession(org.hibersap.session.Credentials) must be used. The authentication information is specified in the Credentials object.

Credentials credentials = new Credentials() 
    .setUser(archibald_tuttle) 
    .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.2 lists the available attributes of the Credentials class 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.client.user
aliasUser SAP logon user alias, can be used instead of logon user jco.client.alias_user
client SAP client jco.client.client
language Logon language ISO code jco.client.lang
password Logon password jco.client.passwd
ssoTicket SAP Cookie Version 2 as logon ticket for SSO based authentication jco.client.mysapsso2
x509Certificate X509 certificate for certificate based authentication jco.client.x509cert

Table 5.2: SAP Java Connector type conversion

Using this method together with JCo, Hibersap will internally create a custom JCo destination setting the specified credential attributes. Note that in this case, every user needs to have the proper permissions in SAP to use the function modules that are called via Hibersap.

In addition to calling the function modules itself, JCo makes calls to the SAP system to obtain meta data on function modules, the so-called repository calls. Those calls depend on different sets of permissions which the specific user might or might not have. Therefore, JCo uses a configured user to do repository calls instead of the current user supplied with the Hibersap Credentials object when creating custom destinations. This user may either be configured via the JCo parameter jco.client.user, or with a seperate user for repository calls using the parameter jco.destination.repository.user. The latter is recommended for applications which make use of per-session authentication, for this makes sure the functions are always called with the session user and the repository calls are done by the repository user. In this case, the property jco.client.user should not be set.

When using Hibersap with JCA, the configuration should be done accordingly, but is resource adapter specific. The Cuckoo Resource Adapter defines almost all possible JCo properties and passes them on to the Java Connector.

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 can 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

When 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. In this context, error means that a RuntimeException is thrown or an application exception configured with the rollback=true attribute. (Note that Hibersap only throws runtime exceptions.)

In EJB3, container managed transaction is the default transaction management demarcation. It can be exlicitly declared using the @TransactionManagement annotation with a transaction management type of CONTAINER or BEAN. The transaction semantics are further defined by the @TransactionAttribute annotation on the EJB class or the EJB methods, where TransactionAttributeType.REQUIRED is a sensible default value.

Distributed Transactions

In an application it might be necessary or wanted to access SAP and other resources like a database and/or a JMS message queue in one unit of work, making sure either every resource is committed in case of success, or every resource is rolled back in case of an error. To accomplish this, Java EE supports distributed transactions through the JTA transaction manager.

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, the transaction manager starts a distributed transaction which requires 2PC aware resources as its participants. The good news is that almost all of the modern application servers (including JBoss Application Server, Glassfish, Bea Weblogic or SAP WebAS) support a strategy called Last Resource Commit Optimization which makes it possible for a single non-2PC-aware resource (in our case SAP) to enlist in a distributed transaction. This is transparent for the programmer. However, as soon as there are two non-2PC-resources enlisting in the distributed transaction, the transaction manager will throw an error.

5.5.2 Security Management

With a resource adapter there are two different methods to authenticate with the SAP R/3 system, container managed and component managed authentication. Hibersap supports both authentication methods.

With component managed authentication, an application passes credentials each time a connection is obtained from the resource adapter. This method may be used when each user of the application signs in using its own SAP user, e.g. by entering the user name and password in the application or when using single sign-on with logon tickets. In JCA, the credentials are passed with a javax.resource.cci.ConnectionSpec instance. Internally, Hibersap will create this instance and fills it with information passed with the Credentials object when a new Session is opened (the code is the same as in 5.4.2 Per-session authentication):

Credentials credentials = new Credentials() 
    .setUser(archibald_tuttle) 
    .setPassword(myPassw0rd); 
Session session = sessionManager.openSession( credentials ); 
session.execute( bapiClass ); 
...
Listing 5.7: Component managed authentication

With container managed authentication the sing-on information is either obtained from a JAAS login module or – in the simplest case – a central user and password is taken from the resource adapter’s configuration. Using a login module, the sign-on information is passed by the container to the resource adapter with a javax.security.auth.Security object. Login module configuration is container specific.

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 independently 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 JNDI name that is used to look up the resource adapter’s connection factory.

5.5.4 Hibersap EJB tools

If using Hibersap in a Java EE environment with Enterprise Java Beans, consider using the Hibersap EJB tools. The EJB tools help in automatically creating Hibersap Sessions, injecting them into your EJBs and closing them.

The following code implements a Stateless Session EJB with a business method to search for Customers in SAP. The EJB’s business methods are intercepted with the HibersapSessionInterceptor. It has a field named ”session” which is annotated with @HibersapSession to tell the interceptor which SessionManager to use in order to open the Session. The annotation’s value parameter specifies a JNDI name to which the SessionManager is bound.

@Stateless 
@Interceptors( HibersapSessionInterceptor.class ) 
public class CustomerServiceBean implements CustomerService 
{ 
    @HibersapSession( java:global/eis/hibersap/A12 ) 
    private Session session; 
 
    public CustomerSearch search( String nameSearchPattern ) 
    { 
        CustomerSearch customerSearch = new CustomerSearch( nameSearchPattern ); 
        session.execute( customerSearch ); 
        return customerSearch; 
    } 
}

The CustomerSearch is a Hibersap BAPI class. As can be seen, the programmer can directly use the injected Hibersap session to call functions in the SAP backend. There is no need to close the Session, this is done by the interceptor. The example uses container managed transactions and the method is called with transaction attribute REQUIRED (the default). This makes sure the SAP call is transactional and will be committed or rolled back by the transaction manager.

The interceptor adds each created Hibersap session to the EJB’s session context to make sure that subsequent calls to other EJBs use the same session. When the HibersapSessionInterceptor is executed, it first checks if there is a session of the specified session manager already in the session context. If yes, it uses the existing session, if not, a new session is created.

On returning from the business method for which the session was opened, the interceptor will close the session, thus making sure the underlying JCA connection will be returned to the connection pool.

To make the example complete we need a way to create a SessionManager and bind it to JNDI. The following code implements a singleton EJB which is created when the application gets deployed. The container will automatically call the lifecycle method rebindSessionManager() which is annotated with @PostConstruct when the EJB is started. The method creates a session manager from a hibersap.xml configuration file and binds it to JNDI. When the application gets undeployed, the method unbindSessionManager() is called which unbinds the session manager from JNDI. To actually binding and unbinding the session manager to and from JNDI, the helper methods in class JndiUtil are used which is a part of the hibersap-ejb module.

@Singleton 
@Startup 
public class HibersapBootstrapBean 
{ 
    public static final String JNDI_NAME = java:jboss/eis/hibersap/NSP; 
 
    @PostConstruct 
    public void rebindSessionManager() 
    { 
        SessionManager sessionManager = new AnnotationConfiguration(A12).buildSessionManager(); 
        JndiUtil.rebindSessionManager( sessionManager, JNDI_NAME ); 
    } 
 
    @PreDestroy 
    public void unbindSessionManager() 
    { 
        JndiUtil.unbindSessionManager( JNDI_NAME ) 
    } 
}

When using Maven, add the hibersap-ejb module to your application by defining the following dependency:

<dependency> 
    <groupId>org.hibersap</groupId> 
    <artifactId>hibersap-ejb</artifactId> 
    <version>1.1.0</version> 
</dependency>

5.6 Bean Validation

Java Bean Validation (JSR 303) is a Java EE standard which defines an API and metadata model (in the form of Java annotations) to validate Java Beans and their attributes. If a Bean Validation provider is on the classpath of your application, Hibersap will validate the BAPI and Structure classes each time before a function gets executed.

To configure Bean Validation for your Hibersap application you may specify the SessionManager’s validation element in the hibersap.xml configuration file:

<hibersap> 
  <session-manager name=A12> 
    ... 
    <validation>AUTO</validation> 
    ... 
  </session-manager> 
</hibersap>

If using programmatic configuration, just set the validationMode property of the SessionManagerConfig:

sessionManagerConfig.setValidationMode( ValidationMode.AUTO );

The validation element may contain any of the values defined in org.hibersap.configuration.xml.ValidationMode:

Bean Validation configuration values____________________________________________________

AUTO
Use Bean Validation if a provider is found on the classpath (Default).
CALLBACK
Force the use of Bean Validation. Hibersap will throw an Exception if no provider is found on the classpath.
NONE
Do not use Bean Validation, even if a provider is present.
______________________________________________________________________________________________________________________