참조 : http://books.gigatux.nl/mirror/beaweblogic8.1/0672324873_ch32lev1sec7.html
* Repository— Contains a new repository object that extends the basic repository and implements IRepository
* Server— Extends a JCO.Server object and handles all the requests for our program
The wrapper class implements JCO.ServerExceptionListener to handle any exceptions that might be thrown. It also contains a simple main() method that calls the runServer() method to start the server. The following code shows how this works:
public class JCoServer implements JCO.ServerExceptionListener{
protected static IRepository repository; //define my Repository
JCO.Server server = null; //define my Server
...
public static void main(String[] argv)
{
JCO.setTraceLevel(0);
JCoServer myserver = new JCoServer();
myserver.runServer();
}
Creating a Repository//Create a static repository to hold all metadata for our functions.
static public class Repository extends
JCO.BasicRepository implements com.sap.mw.jco.IRepository {
public Repository(String repname)
{
super(repname);
}
}
With the inner class Repository defined, we must now create the data for the repository. For performance reasons, we use a static block within the wrapper class. This code will be run only once: when the class is instantiated. The important JCo class needed to add the metadata is JCO.MetaData. This class has an overloaded addInfo() method that's used to add different types of metadata. In our case, we need to define two types of metadata: * Function interface data— Metadata that defines the import, export, and table parameters for the function
* Structure definition data— Metadata that defines the underlying structure of the import, export, and table parameters The addInfo() method for adding our function interface data contains these arguments:
* name— Name of the field
* type— JCo data type
* length— Length of the parameter used if the parameter is a scalar
* offset— Field offset in the JCo buffer used if a parameter is a scalar
* decimals— Number of decimals a field contains; used with JCO.TYPE_BCD and JCO.TYPE_FLOAT
* flags— Specifies whether the parameter is an import (JCO.IMPORT_PARAMETER), an export (JCO.EXPORT_PARAMETER), an optional (JCO.OPTIONAL_PARAMETER), an inactive (JCO.INACTIVE_PARAMETER), or a table (insert int value 0) parameter
* structure_metadata— Takes an object, but for structures and tables, populate with the name of the underlying structure in SAP
When creating data for the structure, we do not need the flags or the table metadata. So, the addInfo() method has an overloaded method without these parameters added.
The final step is storing the JCO.MetaData objects in the repository. The repository object has two methods for this:
* addFunctionInterfaceToCache()— Adds the function metadata to the repository
* addStructureDefinitionToCache()— Adds the structure metadata to the repository
Now that we know what each function does, let's look at the code. Listing 32.3 is the static block within our wrapper class used to define our repository data.
Listing 32.3 Defining the JCo Repository
//for performance reasons, define a singleton for repository
static {
repository = new Repository("serverRepository");
JCO.MetaData functionMetaData = new JCO.MetaData("RFC_CUSTOMER_GET");
functionMetaData.addInfo("KUNNR",
JCO.TYPE_CHAR, 10, 0, 0, JCO.IMPORT_PARAMETER , null);
functionMetaData.addInfo("NAME1",
JCO.TYPE_CHAR, 35, 0, 0, JCO.IMPORT_PARAMETER, null);
functionMetaData.addInfo("CUSTOMER_T",
JCO.TYPE_TABLE, 0, 0, 0, 0, "BRFCKNA1");
repository.addFunctionInterfaceToCache(functionMetaData);
JCO.MetaData structureMetaData = new JCO.MetaData("BRFCKNA1");
structureMetaData.addInfo("KUNNR", JCO.TYPE_CHAR, 10, 0, 0);
structureMetaData.addInfo("ANRED", JCO.TYPE_CHAR, 15, 10, 0);
structureMetaData.addInfo("NAME1", JCO.TYPE_CHAR, 35, 25, 0);
structureMetaData.addInfo("PFACH", JCO.TYPE_CHAR, 10, 60, 0);
structureMetaData.addInfo("STRAS", JCO.TYPE_CHAR, 35, 70, 0);
structureMetaData.addInfo("PSTLZ", JCO.TYPE_CHAR, 10, 105, 0);
structureMetaData.addInfo("ORT01", JCO.TYPE_CHAR, 35, 115, 0);
structureMetaData.addInfo("TELF1", JCO.TYPE_CHAR, 16, 150, 0);
structureMetaData.addInfo("TELFX", JCO.TYPE_CHAR, 31, 166, 0);
repository.addStructureDefinitionToCache(structureMetaData);
}
Notice how the offset length has to be specified in the structure metadata and not in the parameters. The offset is very important; if it's incorrect, the values will be populated incorrectly. The JCO.Server object must be extended to do anything useful with SAP. In our example, we create an inner class for extending the JCo server and create a constructor. The constructor takes a very specific set of arguments. The list of arguments in our example is as follows:
* Gateway host— The SAP gateway server name or IP address
* Gateway service number— The service number; usually sapgw00
* Program ID— The program ID that must match the program ID specified in the RFC
* Repository— The function Repository object
TIP
If you aren't familiar with these terms, contact your SAP basis administrator to help you set them up.
//Create a server to take requests from SAP
static public class Server extends JCO.Server {
public Server(String gwhost, String gwserv,
String progid, IRepository repository)
{
super(gwhost,gwserv,progid,repository);
}
...
}
Now that we have the basic object taken care of, let's look at the handleRequest() method that must be overridden (it's empty { } by default). The handleRequest() method is called every time the SAP system contacts JCo. The lone argument passed is a JCO.Function object. At this point, the programmer is free to do whatever he wants. I suggest checking for each function your application supports, and then minimally writing a separate method for each function. To keep the example readable, our sample application only contains one function and populates a table if the customer is correctly matched. Let's examine the code shown in Listing 32.4. // The default method handles nothing. override for all functions that are needed
protected void handleRequest(JCO.Function function)
{
System.out.println("function " + function.getName() + " called from SAP");
if (function.getName().equals("RFC_CUSTOMER_GET")) {
JCO.Table tables =
function.getTableParameterList().getTable("CUSTOMER_T");
System.out.println(
function.getImportParameterList().getString("KUNNR"));
if("1234567890".equals(function.getImportParameterList().getString("KUNNR"))){
tables.appendRow();
tables.setValue("1234567890", "KUNNR");
tables.setValue("Michael Jordan", "NAME1");
tables.setValue("91607", "PSTLZ");
tables.setValue("USA", "STRAS");
tables.setValue("CALIFORNIA", "ORT01");
tables.setValue("818-555-5555", "TELF1");
}
else{
throw new JCO.AbapException(
"NO_RECORD_FOUND","No Current Record could be found!!!");
}
}
}//handleRequest
The code in Listing 32.4 could be separated into a separate method, but for this short example, there's no need to do so. Using the same methods we learned about on the client side, we first check the customer number KUNNR. If it matches the required value, we return a row of data to SAP. If it doesn't match, we throw an ABAP exception.