Introducing Hibersap – Part 1: A simple application

This is the first post in a new series about our open source framework Hibersap. You can use Hibersap in your Java applications to implement interfaces to SAP systems. Under the hood, Hibersap uses the SAP Java Connector version 3 or a JCA compatible resource adapter to connect to SAP. It makes use of Java annotations to map Java classes and fields to ABAP function modules and their parameters and offers a Hibernate-like API to remotely execute those function modules.

In this post we will develop a small sample application that shows Hibersap’s basic concepts. The following posts in this series will successively demonstrate other concepts like transactions, data type conversion, using resource adapters or testing Hibersap applications.

Preparations

  • Have a SAP ABAP system for testing purposes up and running. If you do not have access to one, you may download and install a trial/developer version from http://www.sdn.sap.com/irj/scn/nw-downloads.
  • Make sure Maven2 is installed on your computer.
  • Download SAP Java Connector 3 (http://service.sap.com/connectors) and extract the sapjco3.jar and the sapjco3 native library.
  • Install sapjco3 jar to your local Maven repository from the commandline: “mvn install:install -file -DgroupId=com.sap -DartifactId=sap-jco -Dversion=3.0.3 -Dpackaging=jar -Dfile= sapjco3.jar” (assuming you have version 3.0.3, otherwise change the version number to the actual value).
  • Create a Maven project with the repositories and dependencies elements as described in the listings below.
  • Put the JCo native library into your library path or into the folder your application will be started from (e. g. the root folder of your IDE project that contains your main class).
  • Put the Java classes that are described in this chapter into the folder $project_home/src/main/java.
  • If you prefer not to write your own code, you may use the example project. You will find more information at the end of this post.

pom.xml – Defining the Hibersap Maven repository:

<repositories>
  <repository>
    <id>repository.hibersap</id>
    <name>Hibersap Repository for Maven</name>
    <url>http://hibersap.svn.sourceforge.net/viewvc/hibersap/m2repo
    </url>
  </repository>
</repositories>

pom.xml – Hibersap dependencies:

<dependencies>
  <dependency>
    <groupId>org.hibersap</groupId>
    <artifactId>hibersap-core</artifactId>
    <version>1.0</version>
  </dependency>
  <dependency>
    <groupId>org.hibersap</groupId>
    <artifactId>hibersap-jco</artifactId>
    <version>1.0</version>
  </dependency>
  <dependency>
    <groupId>com.sap</groupId>
    <artifactId>sap-jco</artifactId>
    <version>[3.0,4.0)</version>
  </dependency>
</dependencies>

The ABAP function module

We are going to write a small example application that will call the SAP function BAPI_FLCUST_GETLIST which returns a list of customers. This function is part of a demo application in SAP that offers a simplified flight-booking system. (If not already done, it might be necessary to initialize the application in order to create some test and configuration data. To do this, execute the program SAPBC_DATA_GENERATOR in transaction SE38.)

This is the function module’s interface in SAP:

FUNCTION BAPI_FLCUST_GETLIST.
  IMPORTING
     VALUE(CUSTOMER_NAME) LIKE  BAPISCUDAT-CUSTNAME OPTIONAL
     VALUE(WEB_USER) LIKE  BAPISCUAUX-WEBUSER OPTIONAL
     VALUE(MAX_ROWS) LIKE  BAPISCUAUX-BAPIMAXROW OPTIONAL
  TABLES
      CUSTOMER_RANGE STRUCTURE  BAPISCUCRA OPTIONAL
      EXTENSION_IN STRUCTURE  BAPIPAREX OPTIONAL
      CUSTOMER_LIST STRUCTURE  BAPISCUDAT OPTIONAL
      EXTENSION_OUT STRUCTURE  BAPIPAREX OPTIONAL
      RETURN STRUCTURE  BAPIRET2 OPTIONAL

This function module has import parameters that represent search criteria to look up flight customers in SAP’s database. The matching customers are returned in the CUSTOMER_LIST table, which contains information such as the customer name and address. The RETURN structure may be filled by SAP with extra messages like errors, warnings, etc.

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

To keep the example simple we will only make use of the import parameters CUSTOMER_NAME and MAX_ROWS and the table parameters CUSTOMER_LIST and RETURN. The CUSTOMER_NAME may contain a name pattern with wildcards (‘*’ for any number of characters, ‘+’ for exactly one character), while MAX_ROWS limits the number of returned customers to the specified value. Each CUSTOMER_LIST table entry contains the following fields:

Table 1: The ABAP structure of the CUSTOMER_LIST table
Field Name Type Description
CUSTOMERID Numeric character Customer Number
CUSTNAME Character Customer name
FORM Character Form of address
STREET Character Street
POSTCODE Character Postal Code
CITY Character City
COUNTR_ISO Character ISO country code
PHONE Character Telephone number of flight customer
EMAIL Character Customer e-mail address

Additionally, we will use the following fields of the RETURN table:

Table 2: The ABAP structure of the RETURN table
Field 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

The BAPI class

To call a function module from a Java application using Hibersap, we have to write a Java class that acts as an adapter to JCo. The BAPI class is a plain 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 simple 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 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 an 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.model;

import org.hibersap.annotations.*;

@Bapi("BAPI_FLCUST_GETLIST")
public class GetCustomerList
{
  ...
}

The fields that are mapped to the function module’s parameters are annotated with either the @Import, @Export, or @Table annotations. Additionally, we have to specify the function module’s field name to which it relates, using the @Parameter annotation.

@Import
@Parameter("MAXROWS")
private int maxRows;

@Import
@Parameter("CUSTOMER_NAME")
private String namePattern;

@Table
@Parameter("RETURN")
private List<BapiRet2> returnValues = new ArrayList<BapiRet2>();

@Table
@Parameter("CUSTOMER_LIST")
private List<Customer> customers = new ArrayList<Customer>();

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 which works correctly in most cases. (In cases where it doesn’t, Hibersap offers the use of Converters which are introduced in a following part of this blog series.)

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

public GetCustomerList(int maxRows, String namePattern)
{
    this.maxRows = maxRows;
    this.namePattern = namePattern;
}

Finally, we should add a getter method for the customer list and the list of return values. 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 List<BapiRet2> getReturnValues()
{
    return returnValues;
}

public List<Customer> getCustomers()
{
    return customers;
}

The structure classes

In the above code, there are two classes that are yet unknown. The ABAP structure BAPIRET2 is used in many ABAP function modules. Therefore Hibersap already provides an implementation in package org.hibersap.bapi. The class Customer is rather application specific, thus we will implement it on our own.

Each Structure class has to be annotated with @BapiStructure to tell Hibersap that it maps to a complex parameter in a BAPI. Each particular field is annotated with the already known @Parameter annotation that defines the name of the corresponding structure field. Our implementation of the Customer consists of the individual fields as well as a getter method for each field.

@BapiStructure
public class Customer
{
    @Parameter("CUSTOMERID")
    private String number;

    @Parameter("CUSTNAME")
    private String name;

    @Parameter("FORM")
    private String formOfAddress;

    @Parameter("COUNTR_ISO")
    private String countryCode;

    @Parameter("CITY")
    private String city;

    @Parameter("POSTCODE")
    private String postalCode;

    @Parameter("STREET")
    private String street;

    @Parameter("PHONE")
    private String telephoneNumber;

    @Parameter("EMAIL")
    private String email;

    public String getNumber()
    {
        return number;
    }

    // add getters for the other fields
}

Configuration

To configure Hibersap, we specify some information needed by Hibersap, 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 expects the configuration file to be in the classpath under “/META-INF/hibersap.xml”).

In the example, we use a minimum set of JCo properties 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). The example assumes that SAP runs on the local machine, the system number is ’00’ and that we connect to client ‘001’ with user ‘sapuser’ and password ‘password’. If you connect to your own SAP system, you have to adapt these properties to your specific environment.

<?xml version="1.0" encoding="UTF-8"?>
<hibersap xmlns="urn:hibersap:hibersap-configuration:1.0">
  <session-manager name="NSP">
    <context>org.hibersap.execution.jco.JCoContext</context>
    <properties>
      <property name="jco.client.client" value="001" />
      <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="127.0.0.1" />
      <property name="jco.client.sysnr" value="00" />
      <property name="jco.destination.pool_capacity" value="1" />
    </properties>
    <annotatedClasses>
      <class>org.hibersap.examples.model.GetCustomerList</class>
    </annotatedClasses>
  </session-manager>
</hibersap>

Calling the ABAP function

In Hibersap, a 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 (that is managed by JCo). When closing a session, the connection is returned to the pool. Therefore you have to take care to always close the session, preferably in a finally block, otherwise the connection pool may get exhausted sooner or later.

The following code configures the Hibersap SessionManager named “NSP”. Note that the name has to match the one defined in the name attribute of the session-manager element in hibersap.xml. In a real application the creation of the SessionManager should be done once, reusing the SessionManager throughout the application’s lifetime, because it is rather expensive to create.

public SessionManager createSessionManager()
{
    AnnotationConfiguration configuration = new AnnotationConfiguration( "NSP" );
    return configuration.buildSessionManager();
}

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 bapi object is enriched with all the values which the function module returned and which we have mapped in our BAPI Class.

public void showCustomerList()
{
    SessionManager sessionManager = createSessionManager();

    Session session = sessionManager.openSession();
    try
    {
        GetCustomerList bapi = new GetCustomerList( 50, "M*" );
        session.execute( bapi );
        printCustomerData( bapi );
    }
    finally
    {
        session.close();
    }
}

To see the result of the function call, we simply print the table fields to the console in the printCustomerData() method:

private void printCustomerData( GetCustomerList bapi )
{
    System.out.println( "Customers:" );
    List<Customer> customers = bapi.getCustomers();
    for ( Customer customer : customers )
    {
        System.out.print( customer.getNumber() );
        System.out.print( "\t" + customer.getName() );
		[...]
        System.out.println( "\t" + customer.getEmail() );
    }

    System.out.println( "Return:" );
    List<BapiRet2> returnValues = bapi.getReturnValues();
    for ( BapiRet2 value : returnValues )
    {
        System.out.print( value.getMessage() );
        System.out.print( "\t" + value.getNumber() );
        System.out.print( "\t" + value.getType() );
        System.out.println( "\t" + value.getId() );
    }
}

Finally, we create a main method that calls showCustomerList(), build the project with maven on the command-line using “mvn compile” and run the main class.

Example project

There is an example web application which you can check out from the Hibersap Subversion repository using the following URL:

https://hibersap.svn.sourceforge.net/svnroot/hibersap/tags/hibersap-example-webapp-1.0

See the README.txt on instructions how to set up the project (basically this means setting up the SAP Java Connector), build and run the application with Maven. Then you can use your web browser to find and display flight customers from SAP.

With each of the following posts we will iteratively extend the application.

Conclusion

In this post we showed how to elegantly and efficiently implement SAP interfaces with Hibersap. Making use of Java Annotations and a Hibernate-/JPA-like API, Hibersap fits well into the range of state-of-the-art Java EE technologies that make writing enterprise applications much more fun, compared to the rather verbose and technical API of the SAP Java Connector.

For more information see the Hibersap web site (http://hibersap.org), in particular the Reference Documentation if you like to take a deeper look into the functionality provided by the framework.

If you like Hibersap, please do not hesitate to get involved with the project. Hibersap is open source software and relies on community feedback for improvement. Hibersap is hosted on Sourceforge.net. On its project site (http://sf.net/projects/hibersap) you have the possibility to open tracker items for feature requests or errors, to take part in forum discussions if you are searching for help or want to give any kind of feedback or to subscribe to the mailing lists to get the latest announcements or to discuss the development of Hibersap applications.

5 thoughts on “Introducing Hibersap – Part 1: A simple application

  1. Hi Ozgur,

    what we do for this use-case is to implement a Java EE application that acts as proxy between SAP and the android application. The app on the phone uses a simple REST -API to communicate with the JEE-app. The JEE app then uses Hibersap to contact SAP.

    Best regards,

    Torsten

  2. Can i use this framework to develop Android applications?
    (i don’t know, is There a JCO release for Android cpu)

    1. Hi Ozgur,

      as far as I know, there unfortunately is no JCo-Release for Android platforms.

      JCo uses native libraries for the communication layer (RFC) and according to SAP the following platforms are supported (see SAP note 1077727 for details):

      Windows x86 32bit, Windows x64 64bit, Windows Itanium 64bit,
      Linux x86 32bit, Linux x86 64bit, Linux Itanium 64bit, Linux zSeries 64bit, Linux PowerPC 64bit,
      AIX 64bit, HP-UX PA-RISC, HP-UX Itanium, Solaris SPARC 64bit, Solaris x64,
      Apple MAC OS Intel 32bit, Apple MAC OS Intel 64bit, z/OS 64bit, IBM i 64bit.

      Carsten

Comments are closed.