Java to SAP integration Process flow.
The SAP Java Connector (JCO) is a middleware component that enables Java to access R/3 based systems and vice versa. This means that JCO as well serves as a client to call R/3 Remote Function Calls (BAPIs, Function Modules that can be called from outside) and in addition to that it offers the possibility to work as a Server that receives calls from R/3.
SAP JCo offers the following functions for creating SAP-compliant Java applications:
• SAP JCo is based on the JNI (Java Native Interface) which facilitates access to the CPIC library.
• It supports SAP (R/3) systems from Release 3.1H upwards, and other mySAP components that have BAPIs or RFMs (Remote Function Modules).
• We can execute function calls inbound (Java client calls BAPI or RFM) and outbound (ABAP calls Java Server).
• With SAP JCo, you can use synchronous, transactional, queued, and background RFC.
• SAP JCo can be used on different platforms
How to install JCO (on Windows)
1.1. Downloading JCO
JCO can be downloaded from http://service.sap.com/connectors under SAP Java Connector -> Tools & Services
1.2. .DLL files
JCO contains two .DLL files that enable JCO to call RFC based R/3 function modules:
- librfc32.dll -> Provides the base functionality to access RFCs from Windows. It is also used by SAP GUI. Copy that .DLL to your windows/systems32 directory. If there is a newer version already installed, don't overwrite it!
- sapjcorfc.dll -> As far as I know this .DLL wraps the librfc32.dll to enable JCO the access of this .DLL. Also copy this file to your windows/system32 directory.
1.3. .JAR files
In order to use JCO within JAVA, you'll need an API. This API is contained in sapjco.jar. You need to include this .JAR file within your application's classpath.
The SAP JCo Repository
The SAP Java Connector must be able to access the metadata of all Remote Function Modules (RFMs) that are to be used by a Java client. A JCoRepository object is created to do this. The current metadata for the RFMs is retrieved either dynamically from the SAP server at runtime (recommended) or hard-coded.
You must only create the JCoRepository object in the case of hard-coded metadata. This step is automatically executed internally by JCo when retrieving metadata.
Setting up a Repository
Procedure
• For the JCo Repository, you need the following interfaces:
o JCoRepository: Contains the runtime metadata of the RFMs.
o JCoFunctionTemplate: Contains the metadata for an RFM.
o JCoFunction: Represents an RFM with all its corresponding parameters.
• Make sure that the user ID for the Repository has all the required authorizations for accessing the metadata of the SAP servers.
Syntax
Creating a JCo Repository
JCoRepository mRepository;
mRepository = destination.getRepository ();
JCO.Repository Contains the runtime metadata for the Remote Function Modules.
IFunctionTemplate Contains the metadata for one single RFM.
JCO.Function Represents an RFM with all its parameters.
JCO.ParameterList Contains the import or export or table parameters of a JCO.Function (that represents an RFM).
JCO.Structure RFMs are able to receive/ pass structures. This class represents such structures.
JCO.Table RFMs are able to receive/ pass table. This class represents such tables.
Creating JCo Function Objects
Procedure
To create a JCo Function object, proceed as follows:
1. Execute the getFunction() method on the JCoRepository interface.
2. Execute the getFunctionTemplate method on the JCoRepository interface.
3. Execute the getFunction() method on the Template.
In addition to containing metadata, a function object also contains the current parameters for executing the RFMs. The relationship between a function template and a function in SAP JCo is similar to that between a class and an object in Java. The code displayed above encapsulates the creation of a function object.
Standalone Java Program for Creating a SAP Server Connection
We can write a Java program that establishes a server connection to a SAP gateway.
Procedure:
To do this, we need to implement the JCoServerFunctionHandler and the coding to be executed when the call is received.
Create an instance for your JCoServer implementation and start it with start().
Definition of Server Properties
import java.io.File;
import java.io.FileOutputStream;
import java.util.Hashtable;
import java.util.Map;
import java.util.Properties;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.ext.DestinationDataProvider;
import com.sap.conn.jco.ext.ServerDataProvider;
import com.sap.conn.jco.server.DefaultServerHandlerFactory;
import com.sap.conn.jco.server.JCoServer;
import com.sap.conn.jco.server.JCoServerContext;
import com.sap.conn.jco.server.JCoServerErrorListener;
import com.sap.conn.jco.server.JCoServerExceptionListener;
import com.sap.conn.jco.server.JCoServerFactory;
import com.sap.conn.jco.server.JCoServerFunctionHandler;
import com.sap.conn.jco.server.JCoServerState;
import com.sap.conn.jco.server.JCoServerStateChangedListener;
import com.sap.conn.jco.server.JCoServerTIDHandler;
public class StepByStepServer
{
static String SERVER_NAME1 = "SERVER";
static String DESTINATION_NAME1 = "ABAP_AS_WITHOUT_POOL";
static String DESTINATION_NAME2 = "ABAP_AS_WITH_POOL";
static
{
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "ls4065");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "85");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "800");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "farber");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "laska");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "en");
createDataFile(DESTINATION_NAME1, "jcoDestination", connectProperties);
connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
createDataFile(DESTINATION_NAME2, "jcoDestination", connectProperties);
Properties servertProperties = new Properties();
servertProperties.setProperty(ServerDataProvider.JCO_GWHOST, "binmain");
servertProperties.setProperty(ServerDataProvider.JCO_GWSERV, "sapgw53");
servertProperties.setProperty(ServerDataProvider.JCO_PROGID, "JCO_SERVER");
servertProperties.setProperty(ServerDataProvider.JCO_REP_DEST, "ABAP_AS_WITH_POOL");
servertProperties.setProperty(ServerDataProvider.JCO_CONNECTION_COUNT, "2");
createDataFile(SERVER_NAME1, "jcoServer", servertProperties);
}
static void createDataFile(String name, String suffix, Properties properties)
{
File cfg = new File(name+"."+suffix);
if(!cfg.exists())
{
try
{
FileOutputStream fos = new FileOutputStream(cfg, false);
properties.store(fos, "for tests only !");
fos.close();
}
catch (Exception e)
{
throw new RuntimeException("Unable to create the destination file " + cfg.getName(), e);
}
}
}
JCo Server
static class StfcConnectionHandler implements JCoServerFunctionHandler
{
public void handleRequest(JCoServerContext serverCtx, JCoFunction function)
{
System.out.println("----------------------------------------------------------------");
System.out.println("call : " + function.getName());
System.out.println("ConnectionId : " + serverCtx.getConnectionID());
System.out.println("SessionId : " + serverCtx.getSessionID());
System.out.println("TID : " + serverCtx.getTID());
System.out.println("repository name : " + serverCtx.getRepository().getName());
System.out.println("is in transaction : " + serverCtx.isInTransaction());
System.out.println("is stateful : " + serverCtx.isStatefulSession());
System.out.println("----------------------------------------------------------------");
System.out.println("gwhost: " + serverCtx.getServer().getGatewayHost());
System.out.println("gwserv: " + serverCtx.getServer().getGatewayService());
System.out.println("progid: " + serverCtx.getServer().getProgramID());
System.out.println("----------------------------------------------------------------");
System.out.println("attributes : ");
System.out.println(serverCtx.getConnectionAttributes().toString());
System.out.println("----------------------------------------------------------------");
System.out.println("req text: " + function.getImportParameterList().getString("REQUTEXT"));
function.getExportParameterList().setValue("ECHOTEXT", function.getImportParameterList().getString("REQUTEXT"));
function.getExportParameterList().setValue("RESPTEXT", "Hello World");
}
}
static void step1SimpleServer()
{
JCoServer server;
try
{
server = JCoServerFactory.getServer(SERVER_NAME1);
}
catch(JCoException ex)
{
throw new RuntimeException("Unable to create the server " + SERVER_NAME1 + ", because of " + ex.getMessage(), ex);
}
JCoServerFunctionHandler stfcConnectionHandler = new StfcConnectionHandler();
DefaultServerHandlerFactory.FunctionHandlerFactory factory = new DefaultServerHandlerFactory.FunctionHandlerFactory();
factory.registerHandler("STFC_CONNECTION", stfcConnectionHandler);
server.setCallHandlerFactory(factory);
server.start();
System.out.println("The program can be stopped using
}
Sample Example: Sales Order upload from JAVA to SAP
import java.sql.Timestamp;
import java.util.Calendar;
import com.sap.mw.jco.IFunctionTemplate;
import com.sap.mw.jco.IRepository;
import com.sap.mw.jco.JCO;
public class SalesOrder {
static final String SID = "R3";
static final String errorID = "E";
IRepository repository;
//String orderNumber = orderCreation("M-01","3000","0002",3,"ST");
int counter;
public SalesOrder()
{
try {
// Add a connection pool to the specified system
JCO.addClientPool(SID, // Alias for this pool
10, // Max. number of connections
"800", // SAP client
"develop", // userid
"bslabap", // password
"EN", // language
"172.18.33.20", // host name
"00");
// Create a new repository
repository = JCO.createRepository("MYRepository", SID);
}
catch (JCO.Exception ex) {
System.out.println("Caught an exception: \n" + ex);
}
}
// Retrieves and sales order Create
public void createSalesOrder(String PO_NO, String MAT,String RQTY,String CUSTMAT, String SOLD_NAME, String SOLD_STREET,String SOLD_COUNTRY, String SOLD_POST_CODE,String SHIP_NAME, String SHIP_STREET,String SHIP_COUNTRY, String SHIP_POST_CODE)
{
try {
// Get a function template from the repository
IFunctionTemplate ftemplate = repository.getFunctionTemplate("BAPI_SALESORDER_CREATEFROMDAT1");
JCO.MetaData so_metadata = new JCO.MetaData("BAPI_SALESORDER_CREATEFROMDAT1");
// Create a function from the template
JCO.Function function = new JCO.Function(ftemplate);
// Get a client from the pool
JCO.Client client = JCO.getClient(SID);
// Fill in input parameters
// Header
JCO.ParameterList input = function.getImportParameterList();
JCO.ParameterList tables = function.getTableParameterList();
JCO.Structure input_header = input.getStructure("ORDER_HEADER_IN");
// Item details
JCO.Table table_item = tables.getTable("ORDER_ITEMS_IN");
//JCO.Structure input_item = table_item.getStructure("ORDER_ITEMS_IN");
// Partner details
JCO.Table table_partner = tables.getTable("ORDER_PARTNERS");
// Populate the header details
input_header.setValue("ZAD5","DOC_TYPE"); // Document Type
input_header.setValue("3000","SALES_ORG"); // Sales Organization
input_header.setValue("10","DISTR_CHAN"); // Distribution Channel
input_header.setValue("00","DIVISION"); // Distribution Channel
input_header.setValue("20041212","REQ_DATE_H");// can be changed in yyyymmdd (Requested date)
input_header.setValue(PO_NO,"PURCH_NO_C");// can be changed ( Customer PO Number )
//Populate the item detalis
table_item.appendRow();
table_item.setRow(1);
table_item.setValue("000010","ITM_NUMBER");
table_item.setValue("AA01","PO_ITM_NO");// can be changed
table_item.setValue("IAD-SC3000","MATERIAL");
table_item.setValue(CUSTMAT,"CUST_MAT");// can be changed
table_item.setValue("20041212","REQ_DATE");// can be changed in yyyymmdd
table_item.setValue(RQTY,"REQ_QTY");// can be changed Qty * 1000
table_item.appendRow();
table_item.setRow(2);
table_item.setValue("000020","ITM_NUMBER");
table_item.setValue("AA01","PO_ITM_NO");// can be changed
table_item.setValue("IAD-SC3000","MATERIAL");
table_item.setValue(CUSTMAT,"CUST_MAT");// can be changed
table_item.setValue("20041212","REQ_DATE");// can be changed in yyyymmdd
table_item.setValue(RQTY,"REQ_QTY");// can be changed Qty * 1000
//Populate the Partner details
// Sold to Party
table_partner.appendRow();
table_partner.setRow(1);
table_partner.setValue("AG","PARTN_ROLE");
//table_partner.setValue("0000002007","PARTN_NUMB");
table_partner.setValue("0000100067","PARTN_NUMB");
table_partner.setValue(SOLD_NAME,"NAME"); // can be changed
table_partner.setValue(SOLD_STREET,"STREET"); // can be changed
table_partner.setValue(SOLD_COUNTRY,"COUNTRY");
table_partner.setValue(SOLD_POST_CODE,"POSTL_CODE"); // can be changed
// Ship to party
table_partner.appendRow();
table_partner.setRow(2);
table_partner.setValue("WE","PARTN_ROLE");
table_partner.setValue("0000100067","PARTN_NUMB");
table_partner.setValue(SHIP_NAME,"NAME");// can be changed
table_partner.setValue(SHIP_STREET,"STREET"); // can be changed
table_partner.setValue(SHIP_COUNTRY,"COUNTRY");
table_partner.setValue(SHIP_POST_CODE,"POSTL_CODE");// can be changed
// Call the remote system
client.execute(function);
// Print return message
JCO.Structure ret = function.getExportParameterList().getStructure("RETURN");
System.out.println("BAPI_SALES_ORDER_GETLIST RETURN: " + ret.getString("MESSAGE"));
// Get table containing the orders
//JCO.Table sales_orders = function.getTableParameterList().getTable("SALES_ORDERS");
JCO.Field sales_order = function.getExportParameterList().getField("SALESDOCUMENT");
// Print results
String so = sales_order.getString();
String message = ret.getString("MESSAGE");
String message_type = ret.getString("TYPE");
if (message_type.equalsIgnoreCase("E")) {
System.out.println("Error in Sales Order Creation:" + message);
}
else{
System.out.println("Sales Order " + so + " Created Succesfully");
}
// Release the client into the pool
JCO.releaseClient(client);
}
catch (Exception ex) {
System.out.println("Caught an exception: \n" + ex);
}
}
// Retrieves and sales order Create
public void listSalesOrders()
{
try {
// Get a function template from the repository
IFunctionTemplate ftemplate = repository.getFunctionTemplate("BAPI_SALESORDER_GETLIST");
// Create a function from the template
JCO.Function function = new JCO.Function(ftemplate);
// Get a client from the pool
JCO.Client client = JCO.getClient(SID);
// Fill in input parameters
JCO.ParameterList input = function.getImportParameterList();
//input.setValue("0000002007", "CUSTOMER_NUMBER" );
input.setValue( "3000", "SALES_ORGANIZATION");
//input.setValue( "0", "TRANSACTION_GROUP" );
//input.setValue("PO_NUMBER_JAVA01","PURCHASE_ORDER_NUMBER");
// Call the remote system
client.execute(function);
// Print return message
JCO.Structure ret = function.getExportParameterList().getStructure("RETURN");
System.out.println("BAPI_SALES_ORDER_GETLIST RETURN: " + ret.getString("MESSAGE"));
// Get table containing the orders
JCO.Table sales_orders = function.getTableParameterList().getTable("SALES_ORDERS");
// Print results
if (sales_orders.getNumRows() > 0) {
// Loop over all rows
do {
counter++;
System.out.println("--
" + counter + "--
");
// Loop over all columns in the current row
for (JCO.FieldIterator e = sales_orders.fields(); e.hasMoreElements(); ) {
JCO.Field field = e.nextField();
System.out.println(field.getName() + ":\t" + field.getString());
}//for
} while(sales_orders.nextRow());
}
else {
System.out.println("No results found");
}//if
// Release the client into the pool
JCO.releaseClient(client);
}
catch (Exception ex) {
System.out.println("Caught an exception: \n" + ex);
}
}
public static void main(String[] argv) {
SalesOrder so = new SalesOrder();
//
so.createSalesOrder("PO_NUMBER_JAVA02", "","0000000020000","121-223-2332-1231", "SOFTWARE SYSTEME GMBH-WE", "STREET-SH","US", "53125","SOFTWARE SYSTEME GMBH-WE", "STREET-SH","US", "53125");
//so.listSalesOrders();
}
}
Thank you Srinivas
ReplyDeleteHi, Naresh! Great post.
ReplyDeleteCan I catch all FMs with handler factory, i.e. without specification FM name?