Tuesday, April 21, 2015

Connecting to SAP from Fuse 6.1 Part 2 - Java Connector (JCo) Component

In the first part of connecting to SAP from Fuse 6.1 we showed how to use the Camel SAP Netweaver Gateway Component with a sample developer account and sample data.  The Netweaver Gateway component is part of Camel as of 2.12.   In this second part we examine using the Camel SAP JCo (Java Connector) component.  This camel component is included as part of the Fuse 6.1 Enterprise product and is supported by Red Hat but is not part of the Camel community at this point.

The diagram shows the technical schema of data conversion in the SAP JCo (standalone version). Starting from a Java application, a Java method is forwarded via the JCo Java API (Application Programming Interface) and an additional Middleware Interface to RFC Middleware, where it is converted to an RFC (ABAP) call using the JNI(Java Native Interface) layer, and sent to the SAP system. Using the same method in the other direction, an RFC Call is converted to Java and forwarded to the Java application.

SAP provides SAP Java Connector as a standalone software component that can be installed independently of the SAP system. You can access the installation files at service.sap.com/connectors.  In order to download the Java Connector you must  have a S User or service account which is explained in this article.



Overview

The SAP Component enables outbound and inbound communication to and from SAP systems using synchronous remote function calls, sRFC.  The component uses the SAP Java Connector (SAP JCo) library to facilitate bidirectional communication with SAP.  The component supports two types of endpoints: destination endpoints and server endpoints.  You can find more on the Fuse 6.1 Camel JCo Component in the Red Hat documentation.  We will give a quick comparison of the two components, discuss the demonstration setup and then show how to run the demonstration.

SAP Netweaver Gateway Component

Pros
  • Familiar tools and technologies for Java developers
  • Existing ABAP functions/dialogs can easily be exposed as a gatway service
Cons
  • Netweaver Gateway needs to be installed in SAP backend or separately at a cost
  • Creating services in ABAP not trivial for for more complex scenarios
  • Not transactional
JCo Camel Component

Pros
  • Fits well into the Java EE world
  • No additional installs on SAP backend
  • Bidirectional communication (Java Calls SAP, SAP calls Java)
  • Transactional
Cons
  • Proprietary protocol
  • Complexity
Demonstration Overview

For our sample we will start a timer that will fire only once, get customers, log them and then save the customers to a file.  The Camel Route is shown in this diagram.  Let's take a quick look at the setup of the project in order to use the JCo component.  


Project Setup

The following will be required in the pom.xml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<dependency>               
 <groupId>com.sap.conn.jco</groupId>              
 <artifactId>sapjco3</artifactId>              
 <version>3.0.11</version>              
 <scope>system</scope>              
 <systemPath>/home/kpeeples/sapjco3/sapjco3.jar</systemPath>        
 </dependency>   
<dependency>          
 <groupId>org.fusesource</groupId>          
 <artifactId>camel-sap</artifactId>         
 <version>1.0.0.redhat-379</version>         
 <exclusions>                
  <exclusion>                      
   <groupId>com.sap.conn.jco</groupId>
              <artifactId>sapjco3</artifactId>
   </exclusion>             
  </exclusions>        
</dependency>

The first dependency defines the location of the sapjco3.jar.   The sapjco3 folder also contains the libsapjco3.so.  The second dependency is required for the camel-sap component.  Now we can define our route in our Camel Context.  The URI Scheme of the component is:

sap:[destination:destinationName|server:serverName]rfcName?options

The destination: prefix designates a destination endpoint and destinationName is the name of a specific outbound connection to an SAP instance. Outbound connections are named and configured at the component level. The rfcName in a destination endpoint URI is the name of the RFC invoked by the endpoint in the connected SAP instance.

The server: prefix designates a server endpoint and serverName is the name of a specific inbound connection from an SAP instance. Inbound connections are named and configured at the component level.  The rfcName in a server endpoint URI is the name of the RFC handled by the endpoint when invoked from the connected SAP instance.

The SAP component maintains three maps to store destination data, server data and repository data. The component’s property, destinationDataStore, stores destination data keyed by destination name, the property,serverDataStore, stores server data keyed by server name and the property, repositoryDataStore, stores repository data keyed by repository name. These configurations must be passed to the component during its initialization.  So for our demo we have the following since we are just going to retrieve customer data:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  <bean id="sap" class="org.fusesource.camel.component.sap.SAPComponent">
   <property name="destinationDataStore">
    <map>
     <entry key="NPL" value-ref="nplDestinationData" />
    </map>
   </property>
   <property name="serverDataStore">
    <map />
   </property>
   <property name="repositoryDataStore">
    <map />
   </property>
  </bean>

The configurations for destinations are maintained in the destinationDataStore property of the SAP component. Each entry in this map configures a distinct outbound connection to an SAP instance. The key for each entry is the name of the outbound connection and is used in the destinationName component of a destination endpoint URI as described in the URI format section.

1
2
3
4
5
6
7
8
  <bean id="nplDestinationData" class="org.fusesource.camel.component.sap.model.rfc.impl.DestinationDataImpl">
   <property name="ashost" value="nplhost" />
   <property name="sysnr" value="00" />
   <property name="client" value="001" />
   <property name="user" value="developer" />
   <property name="passwd" value="password" />
   <property name="lang" value="en" />
  </bean>

Now we can look at our camel context.


1
2
3
4
5
6
7
8
<camel:camelContext xmlns="http://camel.apache.org/schema/spring">
   <camel:route>
    <camel:from uri="timer:runOnce?repeatCount=1" />
    <camel:to uri="sap:destination:NPL:BAPI_FLCUST_GETLIST" />
    <camel:to uri="log:sapintegration?level=INFO" />
    <camel:to uri="file:target?fileName=BAPI_FLCUST_GETLIST.xml" />
   </camel:route>
  </camel:camelContext>

We start the route with a timer that will just run once.  We use the sap component with the destination endpoint with the destination name NPLdestination.   Then we use the rfcName BAPI_FLCUST_GETLIST that we populate in the SAP setup, which in our case is the cloud appliance described below.  Once we retrieve the customer list from SAP we log the response and save the data to a file.

The full source code is at https://github.com/jbossdemocentral/fuse-components-sap.  But before we can run the Camel Context we have to setup the SAP Server with the data.  So in our demonstration as we stated before we are using a Cloud Appliance.

I’ll assume you have an SAP instance you can have access to.  If that is not the case, please go here to create your own SAP Cloud Appliance in AWS, that covers what’s needed for running this demo:

- Amazon account creation and prerequisites for configuring it
- Using the Access and Secret keys
- The 5 steps to get the SAO Cloud Appliance ready in cal.sap.com
- Create and install a Minisap license
- Create example data to work with (380 entries on CUSTOMER_LIST)

Run the Project to list the Customer Data
After creating the project as described above or from cloning the repository and then importing into JBDS, right click on the camel-context.xml under src/main/resources/META-INF/spring/ then select Run As then Camel Context (without tests)


You will see the Camel Context start with the results below.  You can turn on trace to get more information.


You can view the BAPI_FLCUST_GETLIST.xml file to find all the data returned from SAP.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<bapi_flcust_getlist:response xmlns:bapi_flcust_getlist="http://sap.fusesource.org/rfc/NPL/BAPI_FLCUST_GETLIST">
  <customer_list>
    <row city="Walldorf" countr="DE" countr_iso="DE" custname="SAP AG" customerid="00000001" email="[email protected]" form="Firma" phone="06227-34-0" pobox="" postcode="69190" region="" street="Dietmar-Hopp-Allee 16">
    <row city="Walldorf" countr="DE" countr_iso="DE" custname="Andreas Klotz" customerid="00000002" email="[email protected]" form="Herr" phone="05344-676792" pobox="" postcode="69190" region="" street="Pimpinellenweg 9">
.
.
.
    <row city="Mannheim" countr="DE" countr_iso="DE" custname="Christine Pan" customerid="00004686" email="[email protected]" form="Frau" phone="0621/812547" pobox="" postcode="68163" region="" street="Emil-Heckel-Str. 102">
    <row city="Emmendingen" countr="DE" countr_iso="DE" custname="Horst Mechler" customerid="00004687" email="[email protected]" form="Herr" phone="07641 927813" pobox="" postcode="79312" region="" street="Elzstrasse 27">
  </row></row></row></row></customer_list>
  <customer_range>
  <extension_in>
  <extension_out>
  <return>
    <row field="" id="BC_IBF" log_msg_no="000000" log_no="" message="Method was executed successfully" message_v1="" message_v2="" message_v3="" message_v4="" number="000" parameter="" system="NPLCLNT001" type="S">
  </row></return>
</extension_out></extension_in></customer_range></bapi_flcust_getlist:response>