Integrating SAP the
     Java EE way
      JBoss OneDayTalk 2012




Carsten Erker
Remember those
    days...?
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery( "SELECT * FROM customer" );

List<Customer> customers = new ArrayList<Customer>();

while ( rs.next() )
{
    Customer customer = new Customer();
    customer.setId( rs.getString( "ID" ) );
    customer.setFirstName( rs.getString( "FIRST_NAME" ) );
    customer.setLastName( rs.getString( "LAST_NAME" ) );
    ...
    customers.add( customer );
}
...
Who is still doing this?
Nowadays we do
something like this...
@Entity
public class Customer
{
  @Id @GeneratedValue
  private Long id;
  private String firstName;
  private String lastName;
  ...
}
List<Customer> customers = entityManager
   .createQuery( "select c from Customer c" )
   .getResultList();
When calling business
logic in SAP we don‘t
  want to go the old
         way...
Setting the stage...




       Courtesy of Special Collections, University of Houston Libraries. UH Digital Library.
The SAP Java
Connector (JCo)
How it works...
Calls function modules
    in SAP backend
Function modules are a
piece of code written in
         ABAP
They have an interface
 with different types of
parameters to pass data
FUNCTION BAPI_SFLIGHT_GETLIST.
*"-----------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*"     VALUE(FROMCITY) LIKE BAPISFDETA-CITYFROM
*"     VALUE(TOCITY) LIKE BAPISFDETA-CITYTO
*"     VALUE(AIRLINECARRIER) LIKE BAPISFDETA-CARRID
*" EXPORTING
*"     VALUE(RETURN) LIKE BAPIRET2 STRUCTURE BAPIRET2
*" TABLES
*"      FLIGHTLIST STRUCTURE BAPISFLIST
*"-----------------------------------------------------
JCo runs on top of
  the SAP-proprietary
     RFC interface
(Remote Function Call)
JCo can be used in
Client and Server mode
Example code calling a
 function module in
        SAP...
JCoDestination destination = JCoDestinationManager.getDestination( "NSP" );
JCoFunction function =
   destination.getRepository().getFunction( "BAPI_FLCUST_GETLIST" );
function.getImportParameterList().setValue( "MAX_ROWS", 10 );

function.execute( destination );

JCoParameterList tableParams = function.getTableParameterList();
JCoTable table = tableParams.getTable( "CUSTOMER_LIST" );

List<Customer> customers = new ArrayList<Customer>();

for ( int i = 0; i < table.getNumRows(); i++ )
{
    table.setRow( i );
    Customer customer = new Customer();
    customer.setId( table.getLong( "CUSTOMERID" ) );
    customer.setLastName( table.getString( "CUSTNAME" ) );
    customers.add( customer );
}
...
=> Lots of glue code,
 tedious mapping of
     parameters
But - JCo has some
benefits that make it a
 good fit for business
        apps...
It can be used with
    Transactions
It implements
Connection Pooling
SAP functions can be
called asynchronously
It is fast
The bad points...
The programming
     model
Does not fit very well
into the Java EE world:
Not trivial to use it
    with CMT
The same goes for
     Security
The alternative:
Java EE Connector
Architecture (JCA)
JCA is a Java EE
   standard
JCA was created for
the interaction of Java
 EE applications with
Enterprise Information
 Systems, such as SAP
A Resource Adapter is
an implementation of
 JCA for a certain EIS
A RA is deployed in an
 Application Server in
  form of a Resource
     Archive (.rar)
The RA takes care of...
Transaction
Management
Connection
Management
Security
Management
... all this in a standard
             way
JCA solves a lot of
problems, except one...
The programming
     model
       :-(
JCA defines the
   Common Client
 Interface (CCI) for a
standard way to access
         an EIS
Because of the many
   different natures of
EIS‘s, it is overly generic
It operates on Lists,
Maps and/or ResultSets
 representing the data
Additionally, a lot of
glue code needs to be
       written
In this, it is not too
different from SAP‘s
  Java Connector...
@Resource( mappedName = "java:jboss/eis/NSP" )
private ConnectionFactory connectionFactory;

...

Connection connection = connectionFactory.getConnection();
Interaction interaction = connection.createInteraction();

RecordFactory rf = connectionFactory.getRecordFactory();

MappedRecord input = rf.createMappedRecord( "BAPI_FLCUST_GETLIST" );
input.put( "CUSTOMER_NAME", "Ernie" );
input.put( "MAX_ROWS", 20 );

MappedRecord output = ( MappedRecord ) interaction.execute( null, input );
...
List<Customer> customers = new ArrayList<Customer>();

IndexedRecord customerTable = ( IndexedRecord ) output.get( "CUST_LIST" );
            
for ( Object row : customerTable )
{
    MappedRecord record = ( MappedRecord ) row;

    Customer customer = new Customer();
    customer.setId( ( String ) record.get( "CUSTOMERID" ) );
    customer.setName( ( String ) record.get( "CUSTNAME" ) );
    ...
    result.addCustomer( customer );
}
SAP offers a RA that
 only runs on SAP
Application Servers
Any more alternatives?
For read-only and
less frequent SAP calls
     consider using
     Web Services
A SOA platform may be
well suited for not-so-
   tight integration
Introducing the cool
       stuff...




          Photo by Alan Levine, CC-BY 2.0, http://www.flickr.com/photos/cogdog
It implements JCA
     version 1.5
It currently only
  supports the
 outbound way
Under the hood, it uses
    the SAP Java
  Connector (JCo)
The next steps...
Upgrading Cuckoo to
  JCA version 1.6
Adding inbound
  capability
Cuckoo is
Open Source under
  LGPL License
More info:
https://sourceforge.net/p/cuckoo-ra/
Example application:
https://github.com/cerker/
     cuckoo-example
What was all the fuss
about the programming
        model?
We still have to solve
  this problem...
Hibersap is something
like an O/R mapper for
      SAP functions
It makes use of Java
  annotations to map
SAP functions and their
   parameters to Java
        objects
It has an API that is
   quite similar to
   Hibernate/JPA
Thus it fits very well
into the modern Java
        world
Hibersap takes care of
most of the glue code
It can be either used
with JCo or with a JCA
   Resource Adapter
Switching between
them is a matter of
   configuration
This makes integration
   testing a breeze
Finally, some code...
The business object...
@Bapi( "BAPI_FLCUST_GETLIST" )
public class CustomerList
{
  @Import @Parameter("MAX_ROWS")
  private int maxRows;

  @Table @Parameter( "CUSTOMER_LIST" )
  private List<Customer> customers;
  ...
}                              public class Customer
                               {
                                 @Parameter("CUSTOMERID")
                                 private String id;

                                @Parameter( "CUSTNAME" )
                                private String firstName;
                                ...
                            }
The API...
Session session = sessionManager.openSession();

CustomerList customerList = new CustomerList( 10 );
session.execute( customerList );

List<Customer> customers = customerList.getCustomers();
The configuration...
META-INF/hibersap.xml                                            => JCA


<hibersap>
  <session-manager name="NSP">
     <context>org.hibersap.execution.jca.JCAContext</context>
     <jca-connection-factory>
        java:jboss/eis/sap/NSP
     </jca-connection-factory>
     <annotated-classes>
        <annotated-class>
            de.akquinet.jbosscc.cuckoo.example.model.CustomerSearch
        </annotated-class>
        ...
     </annotated-classes>
  </session-manager>
</hibersap>
META-INF/hibersap.xml                                            => JCo
<hibersap>
  <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.ashost" value="10.20.30.40" />
" " " <property name="jco.client.sysnr" value="00" />
             ...
" " </properties>
     <annotated-classes>
        <annotated-class>
            de.akquinet.jbosscc.cuckoo.example.model.CustomerSearch
        </annotated-class>
        ...
     </annotated-classes>
  </session-manager>
</hibersap>
Bean Validation can be
 used on parameter
       fields...
@Parameter( "COUNTR_ISO" )
@NotNull @Size(min = 2, max = 2)
private String countryKeyIso;
Converters allow for
data type or format
  conversion on
 parameter fields...
@Parameter( "TYPE" )
@Convert( converter = SeverityConverter.class )
private Severity severity;
Hibersap is Open
Source and licensed
   under LGPL
More info:
http://hibersap.org
Putting it all together...
In a Java EE application
     we should use
       Cuckoo RA
Thus, we can make use
   of CMT in EJBs
...and all the other
   benefits of JCA
Using Hibersap, we gain
    an elegant and
      lightweight
 programming model
... especially when using
   Hibersap‘s EJB tools
Thus, we get much
nicer code that is easier
to understand, maintain
        and test
Example application:
https://github.com/cerker/
cuckoo-hibersap-example
Tooling...
JBoss Forge plugin:
  https://github.com/
 forge/plugin-hibersap

        See also:
http://blog.akquinet.de/
      2012/07/12/
Hibersap-Camel
     Component:
  https://github.com/
bjoben/camel-hibersap
About me...
Carsten Erker
Software Architect and Consultant
akquinet AG in Berlin / Germany

carsten.erker@akquinet.de
Questions?

Integrating SAP the Java EE Way - JBoss One Day talk 2012