by Lars Vogel

Follow me on twitter

Lars Vogel on Google+

Java and SAP - Java Connector (JCo) Tutorial

Lars Vogel

Version 0.8

18.08.2010

Revision History
Revision 0.1 03.10.2007 Lars
Vogel
Created
Revision 0.2 - 0.4 11.10.2008 - 26.01.2009 Lars
Vogel
Update to JCo 3.0
Revision 0.5 - 0.9 19.03.2009 - 18.08.2010 Lars
Vogel
bug fixes and enhancements

SAP JCo

This article demonstrate how to connect Java to SAP using the SAP Java Connector (JCo). It is based on SAP JCo 3.0.4 and Java 1.6. The development environment is Eclipse 3.6 (Helios).


Table of Contents

1. SAP JCo (Java Connector)
2. Installation
3. Connection to SAP
3.1. Domain model for SAP System
3.2. Setup the SAP connection
3.3. Test the connection
4. Simplifying JCo access
5. Stateful RFC
6. Debugging the SAP system
7. Thank you
8. Questions and Discussion
9. Links and Literature

1. SAP JCo (Java Connector)

SAP Systems provides interfaces to down-and upload data. For example you can SAP data via BAPI's (Business Application Programming Interfaces) and SAP remote function calls RFC's). BAPI's are technical RFC's which are official released and supported by SAP. SAP provides the Java Connector (JCo) for connecting Java programs with an SAP backend system.

This tutorial will explain how you can use JCo to call RFC's.

This article distributes the classes over several projects and assumes that you know how to handle inter-project dependencies. If you do not know this please use one project for all classes this will make you life easier.

2. Installation

You find the JCo on the SAP service marketplace http://service.sap.com/connectors/.

To download the software you have to have a valid user. Registration is free of charge. The following assumes that you are using MS Windows.

The download contains the following files.

  • sapjco3.jar

  • sapjco3.dll

In the Windows OS you have to place the .dll in the same location as the jar file. In an OSGi environment you have to add a entry to the MANIFEST.MF, see how to use native code (Windows DLL) in OSGi for details. For any other operating system please check the installation notes of SAP.

3. Connection to SAP

3.1. Domain model for SAP System

I have create a separate Java Project "de.vogella.sap.system.model" for the SAP system domain model. This domain model captures all data required to connect to a SAP system.

				
package de.vogella.sap.system.model;

/** * Represents a SAP System Immutable object * * @author Lars Vogel * */
public class SapSystem implements java.lang.Cloneable { private final String name; private final String host; private final String client; private final String systemNumber; private final String user; private final String password; private final String language ="en"; // English will be used as login language
/** * Constructor, Login language is assumed to be English * @param name * @param client * @param user * @param password * @param host * @param systemNumber */
public SapSystem(String name, String host, String client , String systemNumber, String user, String password) { this.name = name; this.client = client; this.user = user; this.password = password; this.host = host; this.systemNumber = systemNumber; } public String getName() { return name; } public String getClient() { return client; } public String getUser() { return user; } public String getPassword() { return password; } public String getLanguage() { return language; } public String getHost() { return host; } public String getSystemNumber() { return systemNumber; } @Override public String toString() { return "Client " + client + " User " + user + " PW " + password + " Language " + language + " Host " + host + " SysID " + systemNumber; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((client == null) ? 0 : client.hashCode()); result = prime * result + ((host == null) ? 0 : host.hashCode()); result = prime * result + ((language == null) ? 0 : language.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((password == null) ? 0 : password.hashCode()); result = prime * result + ((systemNumber == null) ? 0 : systemNumber.hashCode()); result = prime * result + ((user == null) ? 0 : user.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SapSystem other = (SapSystem) obj; if (client == null) { if (other.client != null) return false; } else if (!client.equals(other.client)) return false; if (host == null) { if (other.host != null) return false; } else if (!host.equals(other.host)) return false; if (language == null) { if (other.language != null) return false; } else if (!language.equals(other.language)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (password == null) { if (other.password != null) return false; } else if (!password.equals(other.password)) return false; if (systemNumber == null) { if (other.systemNumber != null) return false; } else if (!systemNumber.equals(other.systemNumber)) return false; if (user == null) { if (other.user != null) return false; } else if (!user.equals(other.user)) return false; return true; } @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return null; } }

3.2. Setup the SAP connection

Create the Java project "de.vogella.sap.rfc.core" for the following Java classes. Create a folder "lib". Add "sapjco3.jar" and the "sapjco3.dll" to this folder and add the jar to the project build path .

The class "JCoDestinationManager" requires that you register a System system. The method .getDestination(String s) can then be used to get the connection to a SAP system.

We implement our own class "MyDestinationDataProvider" which uses an instance of SapSystem to configure itself. This class is later registered at "JCoDestinationManager".

				
package de.vogella.sap.rfc.core.connection;

import java.util.Properties;

import com.sap.conn.jco.ext.DestinationDataEventListener;
import com.sap.conn.jco.ext.DestinationDataProvider;

import de.vogella.sap.system.model.SapSystem;

/** * Represents the destination to a specific SAP system. * The destination is maintained via a property file * */
public class MyDestinationDataProvider implements DestinationDataProvider { static String SAP_SERVER = "SAP_SERVER"; private final Properties ABAP_AS_properties; public MyDestinationDataProvider(SapSystem system) { Properties properties = new Properties(); properties.setProperty(DestinationDataProvider.JCO_ASHOST, system .getHost()); properties.setProperty(DestinationDataProvider.JCO_SYSNR, system .getSystemNumber()); properties.setProperty(DestinationDataProvider.JCO_CLIENT, system .getClient()); properties.setProperty(DestinationDataProvider.JCO_USER, system .getUser()); properties.setProperty(DestinationDataProvider.JCO_PASSWD, system .getPassword()); ABAP_AS_properties = properties; } @Override public Properties getDestinationProperties(String system) { return ABAP_AS_properties; } @Override public void setDestinationDataEventListener( DestinationDataEventListener eventListener) { } @Override public boolean supportsEvents() { return false; } }

The following class encapsulates the functionality to connect to a SAP system. It allow to access a RFC via getFunction(). The parameter of this function can then be filled. Afterwards you can execute the function via execute().

				
package de.vogella.sap.rfc.core.connection;

import com.sap.conn.jco.JCoContext;
import com.sap.conn.jco.JCoDestination;
import com.sap.conn.jco.JCoDestinationManager;
import com.sap.conn.jco.JCoException;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoRepository;

import de.vogella.sap.system.model.SapSystem;

/** * Connection allows to get and execute SAP functions. The constructor expect a * SapSystem and will save the connection data to a file. The connection will * also be automatically be established. */
public class Connection { static String SAP_SERVER = "SAP_SERVER"; private JCoRepository repos; private JCoDestination dest; public Connection(SapSystem system) { MyDestinationDataProvider myProvider = new MyDestinationDataProvider(system); com.sap.conn.jco.ext.Environment .registerDestinationDataProvider(myProvider); try { dest = JCoDestinationManager.getDestination(SAP_SERVER); System.out.println("Attributes:"); System.out.println(dest.getAttributes()); repos = dest.getRepository(); } catch (JCoException e) { throw new RuntimeException(e); } }
/** * Method getFunction read a SAP Function and return it to the caller. The * caller can then set parameters (import, export, tables) on this function * and call later the method execute. * * getFunction translates the JCo checked exceptions into a non-checked * exceptions */
public JCoFunction getFunction(String functionStr) { JCoFunction function = null; try { function = repos.getFunction(functionStr); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException( "Problem retrieving JCO.Function object."); } if (function == null) { throw new RuntimeException("Not possible to receive function. "); } return function; }
/** * Method execute will call a function. The Caller of this function has * already set all required parameters of the function * */
public void execute(JCoFunction function) { try { JCoContext.begin(dest); function.execute(dest); } catch (JCoException e) { e.printStackTrace(); } finally { try { JCoContext.end(dest); } catch (JCoException e) { e.printStackTrace(); } } } }

3.3. Test the connection

Create Java project "de.vogella.sap.rfc.core.test" maintain your project dependencies and write the following test to check if the connection works. I'm calling a simple BAPI which returns the list of users. Other BAPI's can be found in the SAP Transaction "BAPI".

The following uses JUnit to test the connection. See JUnit Tutorial to learn about JUnit.

				
package de.vogella.sap.rfc.core.test;

import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoTable;

import de.vogella.sap.rfc.core.connection.Connection;
import de.vogella.sap.system.model.SapSystem;

public class ConnectionTester {
	static String SAP = "SAP_SERVER";

	@Test
	public void checkConnection() {
		// SAP System
		SapSystem system = new SapSystem("PFT", "pwdf6394.wdf.sap.corp", "600", "76", "mytester", "welcome");
		
		Connection connect = new Connection(system);

		JCoFunction function = connect.getFunction("BAPI_USER_GETLIST");
		function.getImportParameterList().setValue("MAX_ROWS", 10);
		connect.execute(function);
		JCoTable table = function.getTableParameterList().getTable("USERLIST");
		assertTrue("User Tabelle should not be empty", !table.isEmpty());
	}
}

			

4. Simplifying JCo access

One of the possible parameters of a SAP RFC is a table. This following class wraps the JCoTable class and try to provide a simpler interface. The adapter can be found in project "de.vogella.sap.rfc.helper" and the test in project "de.vogella.sap.rfc.helper.test".

			
package de.vogella.sap.rfc.helper;
import com.sap.conn.jco.JCoTable;

/** * TableAdapter is used to simplify the reading of the values of the Jco tables */
public class TableAdapterReader { protected JCoTable table; public TableAdapterReader(JCoTable table) { this.table = table; } public String get(String s) { return table.getValue(s).toString(); } public Boolean getBoolean(String s) { String value = table.getValue(s).toString(); return value.equals("X"); } public String getMessage() { return table.getString("MESSAGE"); } public int size() { return table.getNumRows(); } public void next() { table.nextRow(); } }

This is the test.

			
package de.vogella.sap.rfc.helper.test;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoTable;

import de.vogella.sap.rfc.core.connection.Connection;
import de.vogella.sap.rfc.helper.TableAdapterReader;
import de.vogella.sap.system.model.SapSystem;

public class TableAdapterTester {
	@Test
	public void checkConnection() {
		// SAP System
		SapSystem system = new SapSystem("PFT", "pwdf6394.wdf.sap.corp", "600",
				"76", "mytester", "welcome");

		Connection connect = new Connection(system);

		JCoFunction function = connect.getFunction("BAPI_USER_GETLIST");
		function.getImportParameterList().setValue("MAX_ROWS", 10);
		connect.execute(function);
		JCoTable table = function.getTableParameterList().getTable("USERLIST");
		TableAdapterReader adapter = new TableAdapterReader(table);

		System.out.println("Number of Users: " + adapter.size());
		for (int i = 0; i < adapter.size(); i++) {
			// USERNAME is a column in the table "USERLIST"
			String s = adapter.get("USERNAME");
			assertNotNull(s);
			assertTrue(s.length() > 0);
			System.out.println(s);
			adapter.next();
		}

		assertTrue("User Tabelle should not be empty", !table.isEmpty());
	}
}

		

5. Stateful RFC

You can also have stateful RFC calls, via JCoContetxt.begin(destination) and JCoContetxt.end(destination). Between these call you can have several calls. This is sometimes necessary as some BAPI's require a call to the function BAPI_TRANSACTION_COMMIT to write their results to the database.

6. Debugging the SAP system

SAP allows to debug function calls which are issued from external systems. To enable external debugging, select your function module in the transaction se37. Select "Settings" or (depending on your system version) "Utilities(M) -> Settings" Select the tab "Debugging". Maintain your user their.

If you now set an external breakpoint you should be able to debug the called function modul in the SAP system. This requires that you are logged into the SAP system.

7. Thank you

Please help me to support this article:

Flattr this

8. Questions and Discussion

Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.de Google Group. I have created a short list how to create good questions which might also help you.

9. Links and Literature

http://www.vogella.de/articles/Eclipse/article.html - Using Eclipse as IDE - Tutorial

http://www.vogella.de/articles/EclipseMicrosoftIntegration/article.html - Eclipse Microsoft Integration (Outlook )- Tutorial

http://www.vogella.de/articles/EclipseJFreeChart/article.html - JFreeChart in Eclipse RCP Tutorial - How-to-Guide