Back to Contents 


Writing a GWS Client Application

The Genero Web Services package (GWS) allows a BDL program to access Web services found on the Internet. GWS supports the WSDL 1.1 specification of March 15, 2002. This example illustrates a client application that accesses the Add operation in the GWS Web Service MyCalculator. See: Tutorial: Writing a GWS Server Application for additional information about the Service.

Topics

See also: The fglwsdl Tool


Obtaining the WSDL information

To access a remote Web service, you must get the WSDL information from the service provider. Sample services can be found through UDDI registries or on other sites such as XMethods (http://www.xmethods.net).

You can use the fglwsdl tool provided by the Genero Web Services package to obtain the necessary WSDL information. The following example obtains the WSDL information for the GWS Service MyCalculator created by the Server tutorial:

fglwsdl -o Example2Client http://localhost:8090/MyCalculator?WSDL

This generates the following files:

Note: The MyCalculator GWS Service must be running on the specified port in order to provide the WSDL information.

The following definitions were generated in the globals file, Example2Client.inc:

Input and Output records

DEFINE Add RECORD ATTRIBUTE( XMLName="Add" , XMLNamespace="http://tempuri.org/webservices" )
  a INTEGER ATTRIBUTE( XMLName="a", XMLNamespace="" ),
  b INTEGER ATTRIBUTE( XMLName="b", XMLNamespace="" )
END RECORD

DEFINE AddResponse RECORD ATTRIBUTE( XMLName="AddResponse", XMLNamespace="http://tempuri.org/webservices" )
  r INTEGER ATTRIBUTE(XMLName="r",XMLNamespace="" )
END RECORD

Since BDL functions cannot have complex structures as parameters, the data types are defined as global or modular variables.

Function prototypes for the Operations

This globals file contains the prototype of two functions for the Add operation.

The Add function uses input and output parameters, and returns the status and result.  This function can only be used if the input and output parameters are not complex structures such as arrays or records. Using this function, developers do not access the global records directly.

The Add_g function can be used with the global input and output records. Before calling this function, you must set the values in the variables of the global input record.

Operation: Add 
#
# FUNCTION: Add_g()
# RETURNING: soapStatus
# INPUT: GLOBAL Add
# OUTPUT: GLOBAL AddResponse
#
# FUNCTION: Add(p_a, p_b)
# RETURNING: soapStatus ,p_r

See The fglwsdl tool (WSDL and XSD) and Client stub and handlers for more details regarding the fglwsdl tool, its output and the generated functions.

Back to the top


Calling the Web Service

Step 1: Import the COM library of the GWS package

The methods associated with creating and publishing a Web Service are contained in the classes that make up the Genero Web Services Library (com). If you use any of these methods in your client application, you must import the library. Since this example application sets the timeout period that the client will wait for the Service to respond, include the following line at the top of the module:

IMPORT com

If your generates .inc file uses xml class data types, you need to add IMPORT xml.

Step 2:  Specify the globals file

Use a GLOBALS statement to specify the generated globals file.

GLOBALS "Example2Client.inc"

Step 3: Write the MAIN program block

Provide values for the input and output messages of the operation, and call one of the generated functions.  Since the input and output messages are simple integers, we can call the Add function.

MAIN
  DEFINE op1        INTEGER
  DEFINE op2        INTEGER
  DEFINE result     INTEGER
  DEFINE wsstatus   INTEGER
  
  LET op1 = 1
  LET op2 = 2
  CALL Add(op1, op2) RETURNING wsstatus, result
  IF wsstatus = 0 THEN
    DISPLAY "Result: ", result
  ELSE
   -- Use the global wsError record
   DISPLAY "Error: ", wsError.description
  END IF
END MAIN

Alternatively, we can use the global input and output records directly, calling the Add_g function:

MAIN
  DEFINE wsstatus INTEGER

  LET Add.a = 1
  LET Add.b = 2
  LET wsstatus = Add_g()
  IF wsstatus != 0 THEN
    -- Use the glocal wsError record
    DISPLAY "Error :", wsError.Description
  ELSE
    DISPLAY "Result: ", AddResponse.r
 END IF
END MAIN

These examples are very basic versions of the code. For complete examples, see the code samples provided with the package in demo/WebServices.

Back to the top


Setting a Time Period for the Response

To protect against remote server failure or unavailability, you can set a timeout value that indicates how long you are willing to wait for the server to respond to your request.  Use  the SetOption() method of the WebServiceEngine class to set the the "readwritetimeout" option. 

For example, to wait no more than 10 seconds:

CALL com.WebServiceEngine.SetOption( "readwritetimeout", 10 )
A timeout value of -1 means "wait forever". This is the default value.

Back to the top


Handling GWS Server Errors

When a GWS Service operation returns a status that is non-zero, you can get a more detailed error description from the global record wsError:

Field Name Description
wsError.code Short error message
wsError.codeNS Namespace of the error code
wsError.description Long error message
wsError.action Internal "SOAP action"

Back to the top


Compiling the Client application

The library file WSHelper.42m, included in the $FGLDIR/lib directory of the Genero Web Services package, should be linked into every client or server program. Assuming the example client code shown above is in a module named clientmain.4gl, you can compile and link the client program as follows:

fglcomp clientmain.4gl Example2Client.4gl
fgllink -o myclient.42r clientmain.42m Example2Client.42m WSHelper.42m
Back to the top