"Preliminary" steps in Powerbuilder
This section describes the steps to follow in order to invoke a Web Service.
- Create a new PBL to hold the objects that will be created, especially if you just want to "play around". In this example it will be SAPDS.PBL.
- Create a new object: on the "Project" tab, select "Web Service Proxy Wizard"
- Check the "Use .Net Engine" checkbox, click Next.
- Indicate the WSDL file URL (see above) and the Assembly Name (e.g. SAPDataServices_Server.dll), then click NEXT.
Note that the Windows SDK for .Net Framework 4.0 must be installed on your system. If that is not the case, you have to do that first:
See the Troubleshooting section further down, if you have issues with this step. - Select a Service, e.g. "WebService.connection_Operations, click Next
- In the next step, you may set the prefix for the proxy.
The wizard says that by default, it is the portname for each port, but you may leave it empty. In the near future we may decide to set up a naming convention rule for this step. - Specify the project name and the library where it will be stored:
- You may verify your settings on the "Ready to Create Proxy" window before hitting Finish:
Note that the documentation states that "the assembly is generated in the current target directory". |
- After that, the proxy should be created. Clicking on the "Services..." button opens a window showing the services and structures.
- In the PBL, right-click the generated proxy (e.g. p_ws_sapds) and select "Deploy" to generate the Services and Structures in the PBL:
Invoking Web services through SOAP requires serialization and deserialization of datatypes, and the building and parsing of XML-based SOAP messages. The pbwsclient125.pbx file contains objects for the .NET Web service engine that enable you to perform these tasks without extensive knowledge of the SOAP specification and schema, the XML Schema specification, or the WSDL specification and schema. You can use these objects after you import the extension file into a PowerBuilder Web service application. |
- At this point it might be necessary to import a Powerbuilder extension file that should be located in "C:\Program Files (x86)\Sybase\Shared\pbwsclient125.pbx".
Right-click the PBL, select "Import PB Extension..." and select the PB extension file indicated above.
If you're getting an error message saying that the file is not a valid dll or pbx file you may have an old version of the file "libeay32.dll" loaded.
In my case, through a search with Process Monitor, it appeared that the file libeay32.dll was loaded from C:\Windows\SysWOW64 – but it was a very old version (from 2005). After deleting it, the import process was successful (after the 2nd try) and the following NVOs were generated:
These NVOs are needed, so there's no point in continuing if this step fails! |
The above are necessary "preliminary" steps, next we'll look at the Powerbuilder code needed to actually invoke a Web Service.
Powerbuilder code to invoke a Web Service
In order to verify the above steps, i.e. to test the Web Service(s), I created a function (f_ws_logon) in a new NVO (n_sap_ds_func) that is invoked through a button click in a very basic window (w_sapds_main).
These objects can be found in the attached PBL (the code was created just to prove the concept, so no need to discuss the naming nor code quality).
sapds.pbl
In the next section, the code is presented and some additional information given.
Variable declarations, object instantiation
connection_operations lnv_conn session lnv_ws_session
logonrequest lnv_log_req
runbatchjobrequest lnv_runbatchjobreq
batchjobresponse lnv_batchjobresp
batch_job_admin lnv_batch_jobadm
batch_jobs lnv_batch_jobs
soapconnection lnv_soap_conn
soapexception lnv_soap_exc
runbatchjobrequestvariable lnv_runbatchreqvar
job_webservice_call_poc_globalvariables lnv_globvar
integer li_val, li_val2, li_val3
boolean lb_sess
//
lnv_batch_jobadm = CREATE batch_job_admin
lnv_batch_jobs = CREATE batch_jobs
lnv_log_req = CREATE logonrequest
lnv_runbatchjobreq_HED = CREATE runbatchjobrequest
lnv_runbatchjobreq_DDO = CREATE runbatchjobrequest
lnv_batchjobresp_HED = CREATE batchjobresponse
lnv_batchjobresp_DDO = CREATE batchjobresponse
lnv_globvar = CREATE job_webservice_call_poc_globalvariables
|
Next, set some values and the Web Service parameters
Set values and Web Service parameters
// set values
lnv_log_req.username =
lnv_log_req.password =
lnv_log_req.cms_authentication = 0 // secEnterprise = 0, secLDAP = 1, secWinAD = 2, secSAPR3 = 3,
lnv_log_req.cms_system =
// sample Web Service
lnv_runbatchjobreq_DDO.jobname = "JOB_WEBSERVICE_CALL"
lnv_runbatchjobreq_DDO.reponame = "BOXI_DS4_LOCAL"
lnv_globvar.g_countermax = "2000000" // at test revealed that the web services are apparently executed asynchronously
|
Finally, the Web Service is called.
As noted in the comment above, the Web Service is apparently called asynchronously (the fact that there is a "cancelasync" method further supports this assumption). |
Note the comments in the code, as they provide some important additional information!
Finally, the Web Service is called.
Invoke Web Service and handle results, resp. errors
As noted in the comment above, the Web Service is apparently called asynchronously (the fact that there is a "cancelasync" method further supports this assumption). / call the Web Service
TRY
li_val = lnv_soap_conn.createinstance(lnv_conn, "connection_operations" )
li_val2 = lnv_soap_conn.createinstance(lnv_batch_jobadm, "batch_job_admin" )
li_val3 = lnv_soap_conn.createinstance(lnv_batch_jobs, "batch_jobs" )
IF li_val = 0 THEN // 0 means OK (in this example li_val, li_val2 and li_val3 all returned 0)
// OK
lnv_ws_session = lnv_conn.logon(lnv_log_req) // log on to get session
lb_sess = lnv_batch_jobadm.setsessionvalue(lnv_ws_session) // set the session value for the next call(s)
lnv_batchjobresp = lnv_batch_jobadm.run_batch_job(lnv_runbatchjobreq)
// display error message
IF lnv_batchjobresp.pid = -1 THEN
Messagebox( "Web Service error" , lnv_batchjobresp_HED.errormessage +
END IF
ELSE
// Not OK
// (add appropriate error handling)
END IF
CATCH (runtimeerror exc)
MessageBox ( "WS Runtime Error" , exc.text)
FINALLY
// Messagebox( "try... catch" , "finally clause" , Information!, OK!)
END TRY
|
The remaining code doesn't add much (destroying the created objects), so it's been left out for better lisibility.
Below we have 2 examples of responses with and without ErrorMessage
The LOGON call was obviously successful as it returned the needed session ID.
Session ID
If the session Id is not provided when calling an SAP Data Service Web Service, the following error message will be displayed (see the CATCH clause):
Debugging a Web Service
I've been using SOAPUI or Fiddler.
Troubleshooting
Installation of the "Windows SDK for Windows 7 and .NET Framework 4" failed on my system for no apparent reason:
The indicated file "Samples\Setup\HTML\ConfigDetails.htm" was not available. In fact, nothing remained after the failed installation, apparently the installation process deleted all copied/installed files.
The solution was to install the freely available "Microsoft Visual Studio 2010 Express", because that installs the needed .NET framework.