
SAP Java Connector (SAP JCo) es un componente middleware que permite el desarrollo en Java de componentes y aplicaciones compatibles con SAP. SAP JCo soporta la comunicación con un servidor SAP en ambas direcciones: llamadas de entrada, en las que un cliente Java externo se comunica con la BAPI (Business Application Programming Interface) o con los RFM (Remote Function Modules) de SAP; y llamadas de salida, donde desde ABAP (Advanced Business Application Programming) se establece una comunicación con un servidor Java externo.
Cuando desde una aplicación Java se invoca un método de la JCo Java API (Application Programming Interface), éste accede a la librería CPI-C siendo convertido en una RFC (Remote Function Call) utilizando JNI (Java Native Interface) y enviado al sistema SAP. CPI-C (Common Programming Interface for Communications) es una interfase estandarizada de comunicación entre programas creada por IBM que consiste en un conjunto de llamadas con las que dos programas pueden comunicarse mutuamente.
Para iniciar el desarrollo con JCo, desde
service.sap.com/connectors se puede descargar un archivo .zip que contiene los archivos de instalación de JCo. Se solicita usuario y contraseña registrados en SAP Service Marketplace.
Una vez descargado, el contenido del archivo .zip debe extraerse dentro de un directorio (por ejemplo C:\SAPJCo). El contenido del archivo .zip son los archivos sapjco3.jar
y sapjco3.dll
(en Linux libsapjco3.so
), los javadocs de SAP JCo y algunos ejemplos de uso. El archivo sapjco3.jar
debe estar incluido en el classpath de todos los proyectos que deseen utilizar SAP JCo.
Ejemplo de aplicación que accede al listado de materiales de SAP:
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
import com.sap.conn.jco.AbapException;
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.JCoTable;
import com.sap.conn.jco.ext.DestinationDataProvider;
public class ServiceOneSap {
static String ABAP_AS = "ABAP_AS_WITHOUT_POOL";
static String ABAP_AS_POOLED = "ABAP_AS_WITH_POOL";
static {
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "xxx.xxx.xxx.xxx");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "xx");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "xxx");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "xxxxxxxx");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "xxxxxxxx");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "xx");
createDataFile(ABAP_AS, "jcoDestination", connectProperties);
connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
createDataFile(ABAP_AS_POOLED, "jcoDestination", connectProperties);
}
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);
}
}
}
public static void MaterialList() throws JCoException {
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
JCoFunction function = destination.getRepository().getFunction("BAPI_MATERIAL_GETLIST");
if (function == null) {
throw new RuntimeException("BAPI_MATERIAL_GETLIST not found in SAP.");
}
try {
function.execute(destination);
} catch (AbapException e) {
System.out.println(e.toString());
return;
}
JCoTable selectionTable = function.getTableParameterList().getTable("MATNRSELECTION");
selectionTable.appendRow();
selectionTable.setValue("SIGN", "I");
selectionTable.setValue("OPTION", "CP");
selectionTable.setValue("MATNR_LOW", "*");
function.execute(destination);
JCoTable dataTable = function.getTableParameterList().getTable("MATNRLIST");
for (int loop = 0; loop < dataTable.getNumRows(); loop++){
System.out.println(dataTable.getValue("MATERIAL") + "\t" + dataTable.getValue("MATL_DESC"));
dataTable.nextRow();
}
}
public static void main(String[] args) throws JCoException {
MaterialList();
}
}
En el ejemplo, la configuración de acceso al servidor SAP se almacena en un archivo que es utilizado por el programa. Por razones de seguridad, es recomendable evitar esta práctica. Se configuran dos accesos o destinos, uno directo (ABAP_AS
) y otro con pool (ABAP_AS_POOLED
).
static String ABAP_AS = "ABAP_AS_WITHOUT_POOL";
static String ABAP_AS_POOLED = "ABAP_AS_WITH_POOL";
static {
Properties connectProperties = new Properties();
connectProperties.setProperty(DestinationDataProvider.JCO_ASHOST, "xxx.xxx.xxx.xxx");
connectProperties.setProperty(DestinationDataProvider.JCO_SYSNR, "xx");
connectProperties.setProperty(DestinationDataProvider.JCO_CLIENT, "xxx");
connectProperties.setProperty(DestinationDataProvider.JCO_USER, "xxxxxxxx");
connectProperties.setProperty(DestinationDataProvider.JCO_PASSWD, "xxxxxxxx");
connectProperties.setProperty(DestinationDataProvider.JCO_LANG, "xx");
createDataFile(ABAP_AS, "jcoDestination", connectProperties);
connectProperties.setProperty(DestinationDataProvider.JCO_POOL_CAPACITY, "3");
connectProperties.setProperty(DestinationDataProvider.JCO_PEAK_LIMIT, "10");
createDataFile(ABAP_AS_POOLED, "jcoDestination", connectProperties);
}
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);
}
}
}
Lo primero que hay que hacer, obviamente, es conectar con SAP. En el ejemplo se utiliza la conexión con pool.
JCoDestination destination = JCoDestinationManager.getDestination(ABAP_AS_POOLED);
A continuación, hay que ejecutar una función de la BAPI, en este caso BAPI_MATERIAL_GETLIST
.
JCoFunction function = destination.getRepository().getFunction("BAPI_MATERIAL_GETLIST");
if (function == null) {
throw new RuntimeException("BAPI_MATERIAL_GETLIST not found in SAP.");
}
try {
function.execute(destination);
} catch (AbapException e) {
System.out.println(e.toString());
return;
}
Una vez llamada la función de la BAPI, hay que acceder a las tablas correspondientes para obtener la información deseada. En este caso, primero hay que acceder a la tabla de selección (MATNRSELECTION
) y después a la tabla de datos (MATNRLIST
).
JCoTable selectionTable = function.getTableParameterList().getTable("MATNRSELECTION");
selectionTable.appendRow();
selectionTable.setValue("SIGN", "I");
selectionTable.setValue("OPTION", "CP");
selectionTable.setValue("MATNR_LOW", "*");
function.execute(destination);
JCoTable dataTable = function.getTableParameterList().getTable("MATNRLIST");
Para acceder a la tabla de selección se deben configurar una serie de parámetros y volver a ejecutar la función de la BAPI. Los parámetros de selección son los siguientes:
- SIGN. Criterios de inclusión / exclusión para tablas: I (Inclusión), E (Exclusión).
- OPTION. Operador de selección: EQ (Equal), NE (Not Equal), BT (BeTween), NB (Not Between), LT (Less Than), LE (Less Equal), GT (Greater Than), GE (Greater Equal), CP (Contains Pattern), NP (Not contains Pattern).
- LOW: Límite menor del rango de datos.
- HIGH: Límite mayor del rango de datos.
En el ejemplo se consultan todos los materiales, puesto que se utiliza la opción de Inclusión con el operador de selección CP (Contiene patrón) y se está indicando el patrón "*"
. Se podría también hacer una consulta de un rango de materiales (entre el 1000 y el 2000, por ejemplo) utilizando el operador de selección BT e indicando los rangos inferior y superior.
selectionTable.setValue("SIGN", "I");
selectionTable.setValue("OPTION", "BT");
selectionTable.setValue("MATNR_LOW", "1000");
selectionTable.setValue("MATNR_HIGH", "2000");