Professional Documents
Culture Documents
Tips&Tricks - JCo - Programming - Otiimmooooooo PDF
Tips&Tricks - JCo - Programming - Otiimmooooooo PDF
http://service.sap.com/connectors and try the sample (RFM) in SAP, JCo needs to translate between the
programs. For a great introduction to the library, read ABAP and Java data types. JCo uses six different
Robert Chu’s articles in the September/October 2003 Java data types to represent the ABAP data types.
issue of this publication. Figure 1 shows the mapping between the ABAP and
Java data types used by JCo.
Upgrade to JCo 2.1.1 Corresponding to these six Java data types, JCo
offers six data-type-specific access methods for fields
When you compare the quality of different SAP (e.g., getBigDecimal()) plus a generic access method
products, JCo is definitely in the top 10 percent. (getValue()). See Figure 2 for a complete list of these
That notwithstanding, there have been some releases seven methods.
that introduced “features” (a.k.a. bugs) that we could
have lived without. An automatic update to the latest In addition, JCo provides convenience methods
release is therefore dangerous. Release 2.1.1, I that are useful if you need different data types in
am happy to report, is a very stable release and I your application (see Figure 3). Some of these
recommend that you upgrade to it sooner or later. methods may be new even to experienced JCo
Sooner especially if you are still using JCo 1.x, for developers because SAP has added them
which support has ended with 2003. comparatively recently.
106 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
To change the value of a field, you utilize the Figure 4 Data Types Allowed in setValue()
setValue() method. This method is overloaded for byte[]
the data types listed in Figure 4. Again, JCo will try
to convert and throw an exception if you pass an char
unconvertible value. int
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 107
SAP Professional Journal January/February 2004
108 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
JCO.Function function =
createFunction("BAPI_COMPANYCODE_GETLIST");
mConnection.execute(function);
JCO.Structure bapiReturn = function.getExportParameterList()
.getStructure("RETURN");
if ( ! (bapiReturn.getString("TYPE").equals("") ||
bapiReturn.getString("TYPE").equals("S")) ) {
System.out.println(bapiReturn.getString("MESSAGE"));
System.exit(0);
}
JCO.Table table =
function.getTableParameterList().getTable("COMPANYCODE_LIST");
int records = table.getNumRows();
for (int i = 0; i < records; i++) {
table.setRow(i);
function = createFunction("BAPI_COMPANYCODE_GETDETAIL");
function.getImportParameterList()
.setValue(table.getString("COMP_CODE"),
"COMPANYCODEID");
mConnection.execute(function);
bapiReturn = function.getExportParameterList()
.getStructure("RETURN");
if ( ! (bapiReturn.getString("TYPE").equals("") ||
bapiReturn.getString("TYPE").equals("S")) ) {
System.out.println(bapiReturn.getString("MESSAGE"));
}
}
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 109
SAP Professional Journal January/February 2004
In the standard JCo programming model, these objects of type JCO.ParameterList, accessed via the
three parameter types are represented by three JCO.Function object’s getImportParameterList(),
110 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 111
SAP Professional Journal January/February 2004
import com.sap.mw.jco.*;
try {
if (JCO.getClientPoolManager().getPool(POOL_NAME) == null) {
OrderedProperties logonProperties =
OrderedProperties.load("/logon.properties");
JCO.addClientPool(POOL_NAME, 10, logonProperties);
}
JCO.Pool pool = JCO.getClientPoolManager().getPool(POOL_NAME);
}
catch (Exception ex) {
ex.printStackTrace();
}
112 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
jco.client.client=001
jco.client.user=userid
jco.client.passwd=secret
jco.client.ashost=hostname
jco.client.sysnr=00
creates a pool object based on the information in a file replace multiple calls to the appendRow() method
(Figure 11). You can initialize your Properties object by one call to appendRows(int num_rows). An
whichever way you like, but for your convenience alternative approach is the ensureBufferCapacity(int
class OrderedProperties is provided in Appendix C required_rows) method, which was added in
on page 130. JCo 2.1.1.
function.getTableParameterList().setActive(false, "TABLE_PARAM");
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 113
SAP Professional Journal January/February 2004
import com.sap.mw.jco.*;
import de.arasoft.java.ARAsoftException;
import de.arasoft.sap.jco.BapiMessageInfo;
import de.arasoft.sap.jco.StandardRepositoryManager;
public CompanyCodes() {
try {
if (JCO.getClientPoolManager().getPool(POOL_NAME) == null) {
OrderedProperties logonProperties =
OrderedProperties.load("/logon.properties");
JCO.addClientPool(POOL_NAME, 10, logonProperties);
}
JCO.Pool pool = JCO.getClientPoolManager().getPool(POOL_NAME);
mRepository =
StandardRepositoryManager.getSingleInstance()
.getRepository(pool, true);
mConnection = JCO.getClient(POOL_NAME);
JCO.Function function =
createFunction("BAPI_COMPANYCODE_GETLIST");
mConnection.execute(function);
BapiMessageInfo returnMessage =
new BapiMessageInfo(function.getExportParameterList()
.getStructure("RETURN"));
if ( ! returnMessage.isBapiReturnCodeOkay() ) {
System.out.println(returnMessage.getFormattedMessage());
System.exit(0);
}
JCO.Table table =
function.getTableParameterList().getTable("COMPANYCODE_LIST");
function = createFunction("BAPI_COMPANYCODE_GETDETAIL");
that the structure to be collected contains. This for COMPANYCODE_DETAIL as the only
is accomplished by invoking the constructor of parameter (see Figure 13 for sample code for
JCO.Table, passing the structure parameter object this and subsequent operations).
114 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
Figure 13 (continued)
JCO.Table infos =
new JCO.Table(function.getExportParameterList()
.getStructure("COMPANYCODE_DETAIL"));
infos.ensureBufferCapacity(table.getNumRows());
}
infos.writeHTML("c:\\infos.html");
}
catch (Exception ex) {
ex.printStackTrace();
}
finally {
JCO.releaseClient(mConnection);
}
}
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 115
SAP Professional Journal January/February 2004
116 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
offers methods that make this exercise very simple, Debugging the ABAP Code
by allowing you to create HTML files for JCO.Record
(and hence its subclasses JCO.ParameterList, Sometimes you are quite certain that your Java code
JCO.Structure, JCO.Table, JCO.Request, and is correct and the problem to be debugged probably
JCO.Response) and JCO.Function objects. The resides in the invoked ABAP code. How can you find
pertinent method is writeHTML(java.lang.String out whether you are right? SAP actually allows you
html_filename). If you use it for a JCO.Table (as to debug the ABAP code if the following prerequisites
shown towards the end of Figure 13), by default are met:
only the first 100 rows plus the last row of the table
are written to the HTML file (see Figure 15 for a • SAPGUI is installed on the machine on
screenshot of the beginning of the HTML file created which the JCo client code is running.
by running the code in Figure 13). This is because a
JCO.Table object could potentially contain millions of • You invoke setAbapDebug(true)
records, and browsers (at least Internet Explorer) have for the relevant JCO.Client or JCO.Pool
problems displaying very large HTML pages. If you object before the connection to SAP is
need more than these 101 rows, you can change the established.
jco.html.table_max_rows property by calling
the setProperty() method of class JCO. Then, as if by magic, the ABAP debugger will
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 117
SAP Professional Journal January/February 2004
appear. It obviously helps to be able to operate this way may be a bit difficult, because you may not be
debugger and understand ABAP source code. You allowed direct access to that server or it does not
may have to ask an ABAP expert for help here. See have SAPGUI installed. This is one of several
Figure 16 for a screenshot of the ABAP debugger reasons why I keep recommending that all SAP-
in action. related application functionality be encapsulated
in classes that can be tested separately.
If the RFM that you are invoking is not in
the repository cache yet, the first few calls you
will see in SAP will be to metadata retrieval
functions like DDIF_FIELDINFO_GET. Just Combining ABAP Date
continue until the RFM you are interested in is and Time Fields
reached.
ABAP uses different data types for date (D) and
Obviously, debugging a web application this time (T) information. In Java, both date and time
118 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
import com.sap.mw.jco.util.SyncDateFormat;
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 119
SAP Professional Journal January/February 2004
Figure 18 contains a utility method that invokes not available in other ABAP-based SAP components
MSS_GET_SY_DATE_TIME and returns a Java Date like CRM.
object, making use of the combineDateAndTime()
method just discussed.
120 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
try {
if (object instanceof JCO.Structure) {
return (object.getString("TYPE").equals("") ||
object.getString("TYPE").equals("S"));
}
if (object instanceof JCO.Table) {
itable = (JCO.Table)object;
int count = itable.getNumRows();
if (count == 0) return true;
boolean allOkay = true;
for (int i = 0; i < count; i++) {
itable.setRow(i);
if ( ! ( itable.getString("TYPE").equals("") ||
itable.getString("TYPE").equals("S") ) ) {
allOkay = false;
break;
}
}
return (allOkay);
}
}
catch (Exception ex) {}
return false;
}
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 121
SAP Professional Journal January/February 2004
JCO.Function function =
createFunction("BAPI_COMPANYCODE_GETLIST");
mConnection.execute(function);
JCO.Structure bapiReturn = function.getExportParameterList()
.getStructure("RETURN");
if ( ! isBapiReturnCodeOkay(bapiReturn) ) {
System.out.println(bapiReturn.getString("MESSAGE"));
System.exit(0);
}
This method defines a parameter of type parameter list or the table parameter list, depending
JCO.Record, the superclass of both JCO.Structure on how the BAPI has defined the RETURN
and JCO.Table. parameter.
Figure 21 shows sample code using the This slight inconvenience can be removed by
isBapiReturnCodeOkay() method. providing an overloaded version of the
isBapiReturnCodeOkay() method that accepts an
One disadvantage to the isBapiReturnCodeOkay() object of type JCO.Function (Figure 22). This new
method from Figure 20 is that the application program version finds out for itself whether the RETURN
must pass the RETURN parameter. If you use parameter is a structure or a table and then calls
the standard JCo programming model, that means our first isBapiReturnCodeOkay() method with the
that the application must either access the export correct parameter.
122 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Tips and Tricks for SAP Java Connector (JCo) Client Programming
JCO.Function function =
createFunction("BAPI_COMPANYCODE_GETLIST");
mConnection.execute(function);
if ( ! isBapiReturnCodeOkay(function) ) {
System.exit(0);
}
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 123
SAP Professional Journal January/February 2004
Appendix A:
Class ARAsoftException
package de.arasoft.java;
/*
* Copyright (c) 2001 ARAsoft GmbH
* All Rights Reserved.
*/
/**
* Exception class
*
* @author ARAsoft GmbH
* @version 1.0
* @since 1.0
*/
/**
* Constructor.
*/
public ARAsoftException() {
super();
}
/**
* Constructor to be used if we wrap another exception.
* @param originalException The original exception
*/
public ARAsoftException(java.lang.Exception originalException) {
super(originalException.toString());
mOriginalException = originalException;
}
/**
* Constructor with a message string.
* @param s Exception string
*/
public ARAsoftException(String s) {
super(s);
}
124 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Appendix A: Class ARAsoftException
/**
* Constructor to be used if we wrap another exception and have an
* additional message string.
* @param s Exception string
* @param originalException The original exception
*/
public ARAsoftException(String s, Exception originalException) {
super(s);
mOriginalException = originalException;
}
/**
* Returns the original exception.
* @return The original exception.
*/
public Exception getOriginalException() {
return mOriginalException;
}
/**
* Returns the exception message.
* @return The exception message.
*/
public String getMessage() {
if (mOriginalException == null)
return super.getMessage();
return super.getMessage() + '\n' +
"Original exception:" + '\n' +
mOriginalException.toString();
}
}
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 125
SAP Professional Journal January/February 2004
Appendix B:
Class StandardRepositoryManager
package de.arasoft.sap.jco;
import java.util.TreeMap;
import com.sap.mw.jco.*;
import de.arasoft.java.ARAsoftException;
/*
* Copyright (c) 2002 ARAsoft GmbH
* All Rights Reserved.
*/
/**
* A singleton object that manages JCO.Repository objects.
*
* @author ARAsoft GmbH
* @version 2.5
* @since 2.5
*/
protected StandardRepositoryManager() {
items = new TreeMap();
}
/**
* Returns the singleton instance of this class.
* @return The singleton instance.
*/
static public synchronized StandardRepositoryManager
getSingleInstance() {
if ( repositoryManager == null )
repositoryManager = new StandardRepositoryManager();
return repositoryManager;
}
/**
* Creates a JCO.Repository object for the SAP system to which the pool
* is connected.
* Throws an exception if a repository for this system already exists.
126 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Appendix B: Class StandardRepositoryManager
/**
* Checks whether a JCO.Repository object for the specified SAP system
* already exists.
* @return Does a repository for the specified SAP system exist?
* @param systemId The system ID of the SAP system.
*/
public boolean existsRepository(String systemId) {
JCO.Repository repository = (JCO.Repository) items.get(systemId);
return ( repository != null );
}
/**
* Checks whether a JCO.Repository object for the SAP system to which
* the pool is connected already exists.
* @return Does a repository for this system exist?
* @param pool The JCO.Pool object.
*/
public boolean existsRepository(JCO.Pool pool)
throws ARAsoftException {
JCO.Client client = null;
try {
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 127
SAP Professional Journal January/February 2004
client = JCO.getClient(pool.getName());
String name = client.getAttributes().getSystemID();
JCO.releaseClient(client);
client = null;
return this.existsRepository(name);
}
catch (Exception ex) {
throw new ARAsoftException(ex);
}
finally {
if ( client != null ) {
JCO.releaseClient(client);
}
}
}
/**
* Returns the JCO.Repository object for the SAP system to which the
* pool is connected.
* Throws an exception if no repository exists.
* @return The repository object.
* @param pool The JCO.Pool object.
*/
public synchronized JCO.Repository getRepository(JCO.Pool pool)
throws ARAsoftException {
return this.getRepository(pool, false);
}
/**
* Returns the JCO.Repository object for the SAP system to which the
* pool is connected. If no repository exists and
* <code>createIfItDoesNotExist</code>
* is <code>true</code>, a new repository is created,
* otherwise an exception is thrown.
* @return The repository object.
* @param pool The JCO.Pool object.
* @param createIfItDoesNotExist Should a new repository be created
* if none exists?
*/
public synchronized JCO.Repository getRepository
(JCO.Pool pool, boolean createIfItDoesNotExist)
throws ARAsoftException {
JCO.Client client = null;
try {
client = JCO.getClient(pool.getName());
String name = client.getAttributes().getSystemID();
JCO.releaseClient(client);
client = null;
try {
return this.getRepository(name);
128 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
Appendix B: Class StandardRepositoryManager
}
catch (ARAsoftException ax) {
if ( createIfItDoesNotExist ) {
return this.createRepository(pool);
} else {
throw ax;
}
}
}
catch (Exception ex) {
throw new ARAsoftException(ex);
}
finally {
if ( client != null ) {
JCO.releaseClient(client);
}
}
}
/**
* Returns the JCO.Repository object for the specified SAP system.
* If no repository exists an exception is thrown.
* @return The repository object.
* @param systemId The system ID of the SAP system.
*/
public synchronized JCO.Repository getRepository(String systemId)
throws ARAsoftException {
JCO.Repository repository = (JCO.Repository) items.get(systemId);
if ( repository == null )
throw new ARAsoftException
("No repository exists for system '"
+ systemId + "'.");
return repository;
}
/**
* Removes the specified JCO.Repository object.
* @param repository The repository to be removed.
*/
public synchronized void removeRepository(JCO.Repository repository)
{
String name = repository.getName();
if ( items.containsValue(repository) ) {
items.remove(name);
}
}
}
©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved. 129
SAP Professional Journal January/February 2004
Appendix C:
Class OrderedProperties
import java.util.*;
import java.io.*;
public OrderedProperties() {
super();
}
public OrderedProperties(java.util.Properties defaults) {
super(defaults);
}
130 ©2004 SAP Professional Journal. Reproduction prohibited. All rights reserved.
the leading technical journal for
SAP administrators, architects,
consultants, and developers
Each issue features step-by-step instruction on the SAP projects that top your to-do list right now. You can
immediately put to use practical advice that can't be found anywhere else.
Your team is your strongest asset, and giving them access to SAP Professional Journal is the best investment you
can make in them -- guaranteeing your organization’s SAP knowledge and skills stay on the cutting edge. To learn more
about our Electronic License Program call 781-751-8799 or send a message to licenses@sappro.com.
Subscribe Risk-Free
SAP Professional Journal is backed by a 100% money-back guarantee. If at any point, for any reason, you are not
completely satisfied, we will refund your subscription payment IN FULL. Don't wait any longer to benefit from the most
respected technical journal for SAP expertise. This is the most in-depth publication written specifically for SAP
professionals like you. Subscribe to SAP Professional Journal today at www.SAPpro.com or call us at 781-751-8799.
SAP Professional Journal 990 Washington Street, Ste. 308 Dedham MA 02026, USA
www.SAPpro.com