Você está na página 1de 17

Simplified Queries of SAP Tables from Java

By Jay Brown and Steve Renard (Colgate-Palmolive)


This article discusses how to easily query SAP tables in your SAP Portal applications. It is divided into
two parts; the first part discusses the implementation and use of the Java classes that expose the SAP data.
The second part discusses enhancing the backend function to suit your companys functionality and
security needs.
Any Java based SAP Enterprise Portal application that communicates with R/3 will almost certainly use
RFCs and BAPIs to perform its work on the backend system. Suppose you want to write an ESS
application to allow an employee to change her HR personal data. You would most likely use the standard
BAPI_PERSDATA_CHANGE function module to make the changes in SAP. This BAPI, like most, has
parameters that have a defined set of valid values, which are stored in SAP tables.
As an example, lets use the BAPI_PERSDATA_CHANGE Import Parameter MARITALSTATUS, which
specified the employees marital status. In your application, you would provide a drop-down list control
with the various values (Married, Single, etc). This import parameters valid values are stored in the
Marital Status Designators table, which is table T502T. In your application, you may choose to supply this
fields valid options in a couple of ways:
1.
2.

Hard-code the values in the application. In the beginning, this would seem to be the fastest solution.
In the long term, this is a very bad idea. If new values are added or deleted, you will need to modify
your code.
Code a custom RFC to perform the SELECT statement against the desired R/3 table. This is a more
traditional way that keeps your applications options in sync with the back-end systems.
Unfortunately, this can become a maintenance burden as more tables need to be read and more custom
RFCs need to be developed.

To handle this problem, we attempted to use the Function Module RFC_READ_TABLE. This RFC will
query the specified table in the R/3 system and return the results in an unformatted table. Optionally, you
may also specify the field names to return, the number of rows to return, as well as a selection (WHERE)
clause. Because the result set is unformatted, the data need to be parsed for them to be usable. Ideally, we
would like a JCO Table to be created that accurately reflects the table structure and data from the response.
Having the data in a JCO Table allows us to use it in many tasks, such as displaying the data in a tableView
control on the Portal. Below is a simple illustration of how the table data are returned:

As you can see, the requested tables fields are returned as a single row in the DATA table. Fortunately,
the FIELDS table describes the data table, so we can parse out each field.
We decided to develop a wrapper class called R3Table to hide the gory details of the
RFC_READ_TABLE function module. We have also made our own custom version of
RFC_READ_TABLE, called ZRFC_READ_TABLE. You can use R3Table class even if you dont
implement your own custom version of ZRFC_READ_TABLE, but youll probably want to when you read
more about it the section RFC_READ_TABLE vs. ZRFC_READ_TABLE later in this document. If you
decide to implement the ZRFC_READ_TABLE, be sure to change the READ_TABLE_FUNCTION_NAME
static variable (in R3Table.java) to contain the name of your custom function ZRFC_READ_TABLE.
The R3Table factory class is a subclass of JCO.Table. To use it, you must invoke one of the getInstance
methods to create an instance of the class. There are many forms of the getInstance method to allow you to
specify the fields to return, the maximum number of rows to return, the starting row, and the where clause.
Refer to the JavaDoc for details. The most basic getInstance documentation is listed below.
Public static R3Table getInstance(com.sap.mw.jco.JCO.Client client,
Java.lang.String tableName)
throws R3TableException,
com.sap.mw.jco.JCO.Exception

Method getInstance Short Form. Instantiates a R3Table class populated with the
data selected from the specified table. Returns ALL rows, ALL fields, without
skipping.
Parameters:
Client An already connected JCO.Client.
tableName - SAP Table to query.

For example, to load ALL rows and fields from SAP Table T502T:
...
client = clientService.getJCOClient("SAP_HR_SYS", request);
client.connect();
R3Table table = R3Table.getInstance(client, "T502T");
...

Returns:
R3Table
Example.
The following basic example gets and connects a JCO Client to the SAP_HR_SYS system. After
successfully connecting, it gets an instance of R3Table populated with all rows and fields from the T502T
table on the SAP_HR_SYS system.
try {
IportalComponentRequest request = (IportalComponentRequest)
this.getRequest();
JCO.Client client = null;
IJCOClientService clientService = (IJCOClientService)
request.getService(IJCOClientService.KEY);

Client = clientService.getJCOClient("SAP_HR_SYS", request);


Client.connect();
R3Table table = R3Table.getInstance(client, "T502T");
System.out.println(table.toString());
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (client != null)
client.disconnect();
}
Output: The R3Table.toString() output shows the information about the R3Table populated from the
T502T table.
Fetch Function: RFC_READ_TABLE
Where Clause:
Max Rows: All
Delimiter: |
Query Response Time (ms): 531
Skip Count: 0
Fields: FTEXT, MANDT, SPRSL, FAMST
----------| TABLE 'T502T'
----------| MA| | | FTEXT|
----------|012|3|4|567890|
----------|151|1|0|Single|
|151|1|1|Marr. |
|151|1|2|Wid. |
|151|1|3|Div. |
|151|1|4|NM
|
|151|1|5|Sep. |
... ...
To use R3Table in the real world, you would want to pass its data along to an HTMLB control such as a
dropdownListBox or tableView. To do this, you simply construct one of the List Model classes (see
below) and pass it to your control. The R3TableDemo example below illustrates this by constructing a
JCOTableViewModel and passing it to an HTMLB tableView control.
Flow of R3TableDemo Portal Component

The R3TableDemo IView

This IView simply gets an instance of an R3Table filled with data from the T502T table, and creates a
JCOTableViewModel object that will be used by the tableView control in the JSP file.
Code excerpt. See full example code at the end of this document.
In your Bean
In your JSP
// Getter method for tableListModel
<hbj:tableView
public JCOTableViewModel
id="tview"
model="myBean.tableListModel"
getTableListModel() {
R3Table table =
design="ALTERNATING"
R3Table.getInstance(client,tName);
headerVisible="TRUE"
Return new JCOTableViewModel(table);
footerVisible="FALSE"
}
fillUpEmptyRows="FALSE"
navigationMode="BYPAGE"
selectionMode="NONE"
headerText="Contents of TABLE"
visibleFirstRow="1"
visibleRowCount="10"
rowCount="10"
width="75%"/>

List Models on the PDK that use JCO Table:


http://localhost:8080/irj/services/htmlb/docs/api/com/sapportals/htmlb/JCOChartModel.html
http://localhost:8080/irj/services/htmlb/docs/api/com/sapportals/htmlb/JCOListModel.html
http://localhost:8080/irj/services/htmlb/docs/api/com/sapportals/htmlb/table/JCOTableViewModel.html

RFC_READ_TABLE vs. ZRFC_READ_TABLE


There are a few reasons why you might want to consider making your own copy of the function
RFC_READ_TABLE in your R/3 system(s). The most compelling of these reasons is security. If the users
of your external applications are only making connections to R/3 under their own R/3 user IDs, then you
must give fairly broad access to each of these users when using RFC_READ_TABLE. Rather than giving
out this broad access to a large group of people, another option would be to use 2 types of connections
within your applicationone connection under the users own ID for normal RFC or BAPI calls that are
required, and the other connection under a generic ID for calling RFC_READ_TABLE. Neither of these
options is appealing. A third more attractive option that is much easier to implement is to create your own
copy of RFC_READ_TABLE and make some minor modifications. Below are 3 reasons to consider
creating your own copy of RFC_READ_TABLE in your R/3 system(s), along with some details on a
couple of changes you might want to consider.

1. Security
The very first action of the function RFC_READ_TABLE is to call another function named,
VIEW_AUTHORITY_CHECK. At first glance, this seems harmless. The name of the table to be read is
passed, along with a view option of S (which one would assume to represent, viewing, or, reading).
However, if you drill-down into the function VIEW_AUTHORITY_CHECK and look through its source
code, you will discover that it is ultimately doing a check on the authorization object S_TABU_DIS.
The security object S_TABU_DIS checks against the users authorization to perform an action (read,
change, create records, etc.) on tables belonging to a particular table classIt is not checking authorization
for an individual table. What this means for you as an application developer is that the users of your
application will need to have access to the table class or classes to which the table or tables belong, for any
tables that are being read by RFC_READ_TABLE. A single table class can have thousands of tables as
members, so in some cases you must give your users read access to thousands of tables so they can simply
read a single table. This is something your security group will certainly frown upon if they understand the
security object S_TABU_DIS, or if you bring it to their attention. As mentioned above, you could use a
generic ID for R/3 connections when calling RFC_READ_TABLE, but as a long term solution looking
forward to many applications using RFC_READ_TABLE, this would require a lot of extra work.

2. DATA_BUFFER_EXCEEDED
The function RFC_READ_TABLE reads table records into a table with the structure TAB512. As the
name somewhat indicates, this table has a single field with the length of 512 characters. This means you
are limited to reading a combination of fields from your table that does not exceed 512 characters in width.
In most cases, if you are limiting your call to the specific fields you need, this should not be a problem.
However, you should be aware of this limitation. Exceeding 512 characters in width will result in an
exception of DATA_BUFFER_EXCEEDED.

3. As of 4.6c, RFC_READ_TABLE is not Released to Customers


O.K. This last reason is pretty weak. The fact that a function module is not released seldom stops
anyone from using it. If its interface changes in the future, though, just keep in mind, I told you so.

Copying ZRFC_READ_TABLE and Changes You may want to Consider


Since RFC_READ_TABLE is the only function that belongs to the function group SDTX, it is a piece of
cake to copy. Simply go to transaction SE38, and copy the program SAPLSDTX. When you are prompted
for a new function group name, enter ZSDTX. If you have never copied a function group like this before,
you should not be alarmed that you are creating a new program that does not begin with, Z. The function
group you create will have the name, SAPLZSDTX. As part of the copy process, you will be directed to
now copy the functions that belong to the group. Since there is only 1 function, this is very simple. Just
enter the name ZRFC_READ_TABLE. Again, since there is only 1 function in this group, you do not need
to worry about cross references between functions in your new group, which gets pretty complicated for
larger function groups.

Security Changes
After activating your new group, you should have a fully functional copied function module with the name,
ZRFC_READ_TABLE. Now you are free to make any changes you desire. The first change you should
consider on the authorization check that is performed.
Rather than calling the function
VIEW_AUTHORITY_CHECK, you might want to create your own authorization object that is checked by
individual table, and use it instead. For example, replace the following code:
-------------------------------------------------------------------------------------------------------------------------------call function 'VIEW_AUTHORITY_CHECK'
exporting
view_action
= 'S'
view_name
= query_table
exceptions
no_authority
= 2
no_clientindependent_authority = 3
table_not_found
= 4.
if sy-subrc = 2 or sy-subrc = 3.
raise not_authorized.
elseif sy-subrc = 1.
raise table_not_available.
endif.
-------------------------------------------------------------------------------------------------------------------------------with this:
-------------------------------------------------------------------------------------------------------------------------------DATA: tabname LIKE dd02l-tabname.
SELECT SINGLE tabname FROM dd02l INTO tabname
WHERE tabname EQ query_table
AND as4local EQ 'A'.
IF sy-subrc NE 0. RAISE table_not_available. ENDIF.
AUTHORITY-CHECK OBJECT 'Z_TABL_MNT'
ID 'ACTVT' FIELD '03'
ID 'TABLE' FIELD query_table.
IF sy-subrc NE 0. RAISE not_authorized. ENDIF.
-------------------------------------------------------------------------------------------------------------------------------The authorization object Z_TABL_MNT could be defined as follows:

This list of permitted activities is completely up to you. If you are only using this security object for
ZRFC_READ_TABLE, you only need a permitted activity of display. However, this security object might
be useful in many other places, so you could add a full list of activities.

Avoiding the Exception DATA_BUFFER_EXCEEDED


If you need more space than the allotted 512 characters for you table records, you can change the reference
type of the functions table parameter DATA from TAB512 to some other similar structure having a single,
larger character field. Anyone familiar with searching the R/3 data dictionary (transaction SE11) should be
able to find a similar table with a larger character field in a matter of a few minutes. Simply swap the
newfound table or structure into the reference type for DATA using the function builder (transaction.
SE37). If you cannot find a suitable standard table or structure for your needs, you can simply create your
own using SE11. You should keep in mind that as you increase the size of your record buffer, the
performance of your function will wane. That can be a very critical issue for web applications.

We welcome any suggestions of other standard function modules that could be used for the purpose of
generically reading tables from applications external to R/3, or any standard security object that could be
used for limiting read access by individual tables.
steve_renard@colpal.com
jay_brown@colpal.com

R3Table.java
package com.colpal.util.portal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.StringTokenizer;
import
import
import
import

com.sap.mw.jco.IFunctionTemplate;
com.sap.mw.jco.IMetaData;
com.sap.mw.jco.IRepository;
com.sap.mw.jco.JCO;

/**
* @version 1.0, 08/20/2003
* @author J. Brown
* Colgate-Palmolive
* <p>
* Utility class to facilitate simple access to SAP Tables.
*
* The intention of this class is to enable Enterprise Portal applications
* to load drop-down values into fields at runtime instead of hard-coding the
* values in the application.
* </p>
*
*<blockquote><pre>
*The steps to use this class are as follows:
*<ol>
*<li>Obtain a JCO.Client to the desired SAP.
*<li>Connect the Client.
*<li>Use one of the getInstance() methods of this class to create a R3Table loaded with
your favorite data.
*<li>Create a Model, such as JCOListModel to be used in your JSP.
*</ol>
*
*...
*client = clientService.getJCOClient("SAP_HR_SYS", request);
*client.connect();
*R3Table table = R3Table.getInstance(client, "T002");
*...
*</pre></blockquote>
*
*
* JCOChartModel
* JCOListModel
* JCOTableViewModel
*
*/
public class R3Table extends com.sap.mw.jco.JCO.Table {
public static final String READ_TABLE_FUNCTION_NAME = "RFC_READ_TABLE";
public static final String DATA_DELIMITER = "|";
private long queryDuration = 0;
private String tableName = "";
private String whereClause = "";
private int maxRows = 0;
private int skipCount = 0;
private HashMap desiredFields = null;
/**
* Private class to track field size and offset.
*/
private class FieldInfo {
FieldInfo(String _name, int _offset, int _length, String _type) {
this._name = _name;
this._endindex = _offset + _length;
this._offset = _offset;
this._length = _length;
this._type = _type;
}
int _endindex;
String _name;
int _offset;
int _length;
String _type;
}
/**
* Method shouldIKeepField.
* Determines if the specified field name should be recorded.
*

* @param fieldName
* @return boolean
*/
private boolean shouldIKeepField(String fieldName) {
// if null (none specified), we want all fields
if (desiredFields == null)
return true;
// if we have a list and the field name is there.
if (desiredFields.containsKey(fieldName.toUpperCase()))
return true;
return false;
}
/**
* Method getFieldInfo.
* @param table
*/
private void getFieldInfo(JCO.Table table) {
table.firstRow();
HashMap fieldList = new HashMap(table.getNumColumns());
do {
String fn = table.getField("FIELDNAME").getString().toUpperCase();
if (shouldIKeepField(fn)) {
FieldInfo fi = new FieldInfo(table.getField("FIELDNAME").getString(),
table.getField("OFFSET").getInt(),
table.getField("LENGTH").getInt(),
table.getField("TYPE").getString());
fieldList.put(fn,fi);
}
} while(table.nextRow());
desiredFields = fieldList;
}
/**
* Method recordDesiredFields.
* Records the desired field names that should come back from the RFC call.
* @param fieldList
*/
private void recordDesiredFields(String fieldList) {
StringTokenizer st = new StringTokenizer(fieldList,", ");
if (st.hasMoreTokens()) {
desiredFields = new HashMap();
while (st.hasMoreTokens()) {
String fn = st.nextToken().toUpperCase();
if (!desiredFields.containsKey(fn))
desiredFields.put(fn, null);
}
}
}
/**
* Method processRows.
* Loops through the raw JCO.Table rows and parses the field values into their
* corresponding fields in the current table.
*
* @param table
* @throws Exception
*/
private void processRows(JCO.Table table) throws JCO.Exception {
Object[] fieldList = desiredFields.values().toArray();
for (int i=0; i < table.getNumRows();i++) {
table.setRow(i);
String row = table.getField("WA").getString();
appendRow();
for (int f=0;f<fieldList.length;f++) {
FieldInfo fi = (FieldInfo)fieldList[f];
int endIndex = fi._endindex;
if (endIndex > row.length())
endIndex = row.length();
String val = row.substring(fi._offset, endIndex);
setValue(val.trim(), fi._name);
}
}

}
/**
* Private Constructor, use static method R3Table.getInstance to
* create an instance of this class.
*
* @see com.sap.mw.jco.JCO.MetaData#MetaData(IMetaData)
*/
private R3Table(IMetaData imd) {
super(imd);
}
/**
* Returns a string representation of the object,
* which is a result of R3Table info + a call to JCO.Table.toString().
* <br>
* <pre>
* Fetch Function: RFC_READ_TABLE
* Where Clause:
* Max Rows: 5
* Delimiter: |
* Query Response Time (ms): 172
* Skip Count: 4
* Fields: LAND1, NATIO, MANDT, LANDX, SPRAS
* ------------------------------------* | TABLE 'T005T'
* ------------------------------------* | MA| | LA| LANDX
| NATIO
|
* ------------------------------------* |012|3|456|789012345678901|234567890123456|
* ------------------------------------* |151|1|AI |Anguilla
|Anguilla
|
* |151|1|AL |Albania
|Albanian
|
* |151|1|AM |Armenia
|Armenian
|
* |151|1|AN |Dutch Antilles |Dutch
|
* |151|1|AO |Angola
|Angolan
|
* ------------------------------------* </pre>
*
* @see java.lang.Object#toString()
*/
public String toString() {
StringBuffer retStr = new StringBuffer();
retStr.append("Fetch Function: " + READ_TABLE_FUNCTION_NAME + "\n");
retStr.append("Where Clause: " + whereClause + "\n");
retStr.append("Max Rows: " + (maxRows >0 ? "" + maxRows : "All") + "\n" );
retStr.append("Delimiter: " + DATA_DELIMITER + "\n" );
retStr.append("Query Response Time (ms): " + queryDuration + "\n");
retStr.append("Skip Count: " + skipCount + "\n");
retStr.append("Fields: ");
if (desiredFields != null) {
for (Iterator i = desiredFields.keySet().iterator() ; i.hasNext() ;) {
retStr.append(i.next());
if (i.hasNext())
retStr.append(", ");
}
}
else {
retStr.append("ALL");
}
retStr.append("\n");
return retStr.toString() + super.toString();
}
/**
* Method executeQuery.
* Connects to the R/3 system associated with client and fetches the raw table data.
* @param repository
* @param client
* @throws R3TableException
* @throws Exception
*/
private void executeQuery(IRepository repository, JCO.Client client) throws
R3TableException, JCO.Exception {
IFunctionTemplate rfc = null;
JCO.Table rawData = null;

JCO.Table fieldData = null;


JCO.Table options = null;
rfc = repository.getFunctionTemplate(READ_TABLE_FUNCTION_NAME);
JCO.Function function = new JCO.Function(rfc);
JCO.ParameterList importList = function.getImportParameterList();
importList.setValue(tableName, "QUERY_TABLE");
importList.setValue(DATA_DELIMITER, "DELIMITER");
importList.setValue(" ", "NO_DATA");
if (maxRows > 0)
importList.setValue(maxRows, "ROWCOUNT");
if (skipCount > 0)
importList.setValue(skipCount, "ROWSKIPS");
if (whereClause.length() > 0) {
options = function.getTableParameterList().getTable("OPTIONS");
options.appendRow();
options.setValue(whereClause, "TEXT");
}
client.execute(function);
rawData = function.getTableParameterList().getTable("DATA");
fieldData = function.getTableParameterList().getTable("FIELDS");
getFieldInfo(fieldData);
processRows(rawData);
}
/**
* Method getInstance - Short Form. Instantiates an R3Table class populated with the
data selected from the specified table.
* Returns ALL rows, ALL fields, without skipping.
* @param client An already connected JCO.Client.
* @param tableName SAP Table to query.
*
*<p>
*For example, to load ALL rows and fields from SAP Table T502T
*<blockquote><pre>
*...
*client = clientService.getJCOClient("SAP_HR_SYS", request);
*client.connect();
*R3Table table = R3Table.getInstance(client, "T502T");
*...
*</pre></blockquote>
*<p>
*
*
* @return R3Table
*
* @throws R3TableException
* @throws com.sap.mw.jco.JCO.Exception
*/
public static R3Table getInstance(JCO.Client client, String tableName) throws
R3TableException, JCO.Exception {
return getInstance(client, tableName, "", "", 0, 0);
}
/**
* Method getInstance - Medium Form. Instantiates an R3Table class populated with the
data selected from the specified table.
* Returns ALL rows, ALL fields, without skipping.
* @param client An already connected JCO.Client.
* @param tableName ABAP Table to query.
* @param whereClause ABAP WHERE CLAUSE such as <code>SPRAS = 'Q' OR SPRAS = 'T'</code>
* @return R3Table
*
* @throws R3TableException
* @throws com.sap.mw.jco.JCO.Exception
*/
public static R3Table getInstance(JCO.Client client, String tableName, String
whereClause) throws R3TableException, JCO.Exception {
return getInstance(client, tableName, whereClause, "", 0, 0);
}

/**
* Method getInstance - Medium Form. Instantiates an R3Table class populated with the
data selected from the specified table.
* Returns ALL rows, without skipping.
* @param client An already connected JCO.Client.
* @param tableName ABAP Table to query.
* @param whereClause ABAP WHERE CLAUSE such as <code>SPRAS = 'Q' OR SPRAS = 'T'</code>
* @param desiredFields A List of Field Names delimited by commas. An empty String
indicates ALL fields.
* @return R3Table
*
* @throws R3TableException
* @throws com.sap.mw.jco.JCO.Exception
*/
public static R3Table getInstance(JCO.Client client, String tableName, String
whereClause, String desiredFields) throws R3TableException, JCO.Exception {
return getInstance(client, tableName, whereClause, desiredFields, 0, 0);
}
/**
* Method getInstance - Long Form. Instantiates an R3Table class populated with the data
selected from the specified table.
* Returns specified number of rows, without skipping.
* @param client An already connected JCO.Client.
* @param tableName ABAP Table to query.
* @param whereClause ABAP WHERE CLAUSE such as <code>SPRAS = 'Q' OR SPRAS = 'T'</code>
* @param desiredFields A List of Field Names delimited by commas. An empty String
indicates ALL fields.
* @param maxRows The maximum number of row to return.
* @return R3Table
*
* @throws R3TableException
* @throws com.sap.mw.jco.JCO.Exception
*/
public static R3Table getInstance(JCO.Client client, String tableName, String
whereClause, String desiredFields, int maxRows) throws R3TableException, JCO.Exception {
return getInstance(client, tableName, whereClause, desiredFields, 0, maxRows);
}
/**
* Method getInstance - Long Form. Instantiates an R3Table class populated with the data
selected from the specified table.
* @param client An already connected JCO.Client.
* @param tableName ABAP Table to query.
* @param whereClause ABAP WHERE CLAUSE such as <code>SPRAS = 'Q' OR SPRAS = 'T'</code>
* @param desiredFields A List of Field Names delimited by commas. An empty String
indicates ALL fields.
* @param skipCount The number of rows to skip. 0 indicates no skipping.
* @param maxRows The maximum number of row to return.
* @return R3Table
*
* @throws R3TableException
* @throws com.sap.mw.jco.JCO.Exception
*/
public static R3Table getInstance(JCO.Client client, String tableName, String
whereClause, String desiredFields, int skipCount, int maxRows) throws R3TableException,
JCO.Exception {
R3Table retTable;
IRepository repository = JCO.createRepository("repository." + client.toString(),
client);
retTable = new R3Table(repository.getTableDefinition(tableName));
retTable.setMaxRows(maxRows);
retTable.setWhereClause(whereClause);
retTable.setTableName(tableName);
retTable.recordDesiredFields(desiredFields);
retTable.setSkipCount(skipCount);
long st = System.currentTimeMillis();
retTable.executeQuery(repository, client);
long et = System.currentTimeMillis();
retTable.setQueryDuration(et - st);
return retTable;
}

// ************* Private setters ***************


private void setMaxRows(int maxRows) {
this.maxRows = maxRows;
}
private void setQueryDuration(long queryDuration) {
this.queryDuration = queryDuration;
}
private void setTableName(String tableName) {
this.tableName = tableName;
}
private void setWhereClause(String whereClause) {
this.whereClause = whereClause;
}
private void setSkipCount(int skipCount) {
this.skipCount = skipCount;
}
}

demoBean.java
package com.colpal.demo.R3Table;
import
import
import
import

com.sapportals.htmlb.IListModel;
com.sapportals.htmlb.table.JCOTableViewModel;
com.colpal.util.portal.*;
com.sap.mw.jco.JCO;

import java.io.Serializable;
public class demoBean implements Serializable {
private JCOTableViewModel tableListModel = null;
private R3Table table = null;
private boolean error = false;
private String lastMessage = "";
private boolean bHasData = false;
public boolean isError() {
return error;
}
public boolean hasData() {
return bHasData;
}
public void loadTable(JCO.Client client, String tableName) {
setLastMessage("");
error = false;
try {
table = R3Table.getInstance(client, tableName);
bHasData = true;
}
catch (Exception e) {
setLastMessage(e.getMessage());
error = true;
}
}
/**
* Returns the tableListModel.
* @return TableViewModel
*/
public JCOTableViewModel getTableListModel() {
return new JCOTableViewModel(table);
}
/**
* Sets the tableListModel
*/
public void setTableListModel(JCOTableViewModel employmentListModel) {
this.tableListModel = employmentListModel;
}
/**
* Returns the lastMessage.
* @return String
*/
public String getLastMessage() {
return lastMessage;
}
/**
* Sets the lastMessage.
* @param lastMessage The lastMessage to set
*/
public void setLastMessage(String lastMessage) {
this.lastMessage = lastMessage;
}
}

page1.jsp
<%@ taglib uri="tagLib" prefix="hbj" %>
<jsp:useBean id="myBean" scope="session" class="com.colpal.demo.R3Table.demoBean" />
<hbj:content id="myContext" >
<hbj:page title="PageTitle">
<hbj:form id="myFormId" >
<hbj:textView

id="dispID" text="R3Table Demo" design="EMPHASIZED"/>

<% if (myBean.hasData()) {%>


<hbj:tableView
id="tview"
model="myBean.tableListModel"
design="ALTERNATING"
headerVisible="TRUE"
footerVisible="FALSE"
fillUpEmptyRows="FALSE"
navigationMode="BYPAGE"
selectionMode="NONE"
headerText="Contents of TABLE"
visibleFirstRow="1"
visibleRowCount="10"
rowCount="10"
width="75%"/>
<%}%>
<!-- Table to align button -->
<hbj:formLayout width="100%">
<hbj:formLayoutRow>
<hbj:formLayoutCell width="60px" align="LEFT">
<hbj:inputField id="tableName" visible="true" type="String"/>
</hbj:formLayoutCell>
<hbj:formLayoutCell>
<hbj:button id="load" text="Load Table" width="100"
tooltip="Click here."
onClick="loadTable" disabled="false" design="STANDARD"/>
</hbj:formLayoutCell>
</hbj:formLayoutRow>
</hbj:formLayout>
<%
String ImageURL = componentRequest.getWebResourcePath()+ "/images/";
%>
<%if (myBean.isError()){%>
<hbj:image id="Error" src="<%= ImageURL +\"error.gif\" %>"
alt="error.gif"/>&nbsp;<font color="RED"><hbj:textView wrapping="TRUE" id="ErrorMessage"
layout="NATIVE" text= "<%=myBean.getLastMessage()%>" design="STANDARD"/></font>
<%}%>
</hbj:form>
</hbj:page>
</hbj:content>

AppController.java
package com.colpal.demo.R3Table;
import
import
import
import
import
import
import
import
import

com.colpal.demo.R3Table.demoBean;
com.sapportals.htmlb.*;
com.sapportals.htmlb.enum.*;
com.sapportals.htmlb.event.*;
com.sapportals.htmlb.page.*;
com.sapportals.portal.htmlb.page.*;
com.sapportals.portal.prt.component.*;
com.sapportals.portal.prt.service.jco.IJCOClientService;
com.colpal.util.portal.*;

import
import
import
import

com.sap.mw.jco.JCO;
com.sap.mw.jco.IFunctionTemplate;
com.sap.mw.jco.IRepository;
com.sap.mw.jco.*;

public class AppController extends PageProcessorComponent {


public DynPage getPage(){
return new AppControllerDynPage();
}
public static class AppControllerDynPage extends JSPDynPage{
private demoBean myBean = null;
public void getBeanFromFramework() {
IPortalComponentSession componentSession =
((IPortalComponentRequest)getRequest()).getComponentSession();
Object o = componentSession.getValue("myBean");
if(o==null || !(o instanceof demoBean)){
myBean = new demoBean();
componentSession.putValue("myBean",myBean);
}
else {
myBean = (demoBean) o;
}
}
public void doInitialization() {
getBeanFromFramework();
}
public void onLoadTable(Event event)

IPortalComponentRequest request = (IPortalComponentRequest) this.getRequest();


JCO.Client client = null;
IJCOClientService clientService = (IJCOClientService)
request.getService(IJCOClientService.KEY);
getBeanFromFramework();
String tableName = null;
Component component = getComponentByName("tableName");
if (component != null)
if (component instanceof InputField)
tableName = ((InputField)component).getValueAsDataType().toString();
if (tableName != null) {
try {
client = clientService.getJCOClient("SAP_GHD_151", request);
client.connect();
myBean.loadTable(client,tableName.toUpperCase());
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (client != null)
client.disconnect();
}
}

}
public void doProcessAfterInput() throws PageException {
}
public void doProcessBeforeOutput() throws PageException {
this.setJspName("page1.jsp");
}
}
}

Você também pode gostar