Webservices Progress 10
Webservices Progress 10
TM
Web Services
2004 Progress Software Corporation. All rights reserved.
Progress software products are copyrighted and all rights are reserved by Progress Software Corporation. This manual is also copyrighted and all rights are
reserved. This manual may not, in whole or in part, be copied, photocopied, translated, or reduced to any electronic medium or machine-readable form without
prior consent, in writing, from Progress Software Corporation.
The information in this manual is subject to change without notice, and Progress Software Corporation assumes no responsibility for any errors that may appear
in this document.
The references in this manual to specific platforms supported are subject to change.
Allegrix, A [Stylized], ObjectStore, Progress, Powered by Progress, Progress Fast Track, Progress Profiles, Partners in Progress, Partners en Progress, Progress en
Partners, Progress in Progress, P.I.P., Progress Results, ProVision, ProCare, ProtoSpeed, SmartBeans, SpeedScript, and WebSpeed are registered trademarks of
Progress Software Corporation or one of its subsidiaries or affiliates in the U.S. and/or other countries. AccelEvent, A Data Center of Your Very Own, Allegrix
& Design, AppsAlive, AppServer, ASPen, ASP-in-a-Box, BusinessEdge, Business Empowerment, Empowerment Center, eXcelon, Fathom, Future Proof,
IntelliStream, ObjectCache, OpenEdge, PeerDirect, POSSE, POSSENET, ProDataSet, Progress Business Empowerment, Progress Dynamics, Progress
Empowerment Center, Progress Empowerment Program, Progress for Partners, Progress OpenEdge, Progress Software Developers Network, PSE Pro, PS Select,
Real Time Event Engine, SectorAlliance, SmartBrowser, SmartComponent, SmartDataBrowser, SmartDataObjects, SmartDataView, SmartDialog, SmartFolder,
SmartFrame, SmartObjects, SmartPanel, SmartQuery, SmartViewer, SmartWindow, Technical Empowerment, Trading Accelerator, WebClient, and Who Makes
Progress are trademarks or service marks of Progress Software Corporation or one of its subsidiaries or affiliates in the U.S. and other countries.
SonicMQ is a registered trademark of Sonic Software Corporation in the U.S. and other countries.
Vermont Views is a registered trademark of Vermont Creative Software in the U.S. and other countries.
Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
Any other trademarks or service marks contained herein are the property of their respective owners.
OpenEdge includes Imaging Technology copyrighted by Snowbound Software 1993-2003. www.snowbound.com.
OpenEdge includes software developed by the Apache Software Foundation (http://www.apache.org/). Copyright 1999 The Apache Software Foundation. All
rights reserved (Xerces C++ Parser (XML)) and Copyright 2000-2003 The Apache Software Foundation. All rights reserved (Ant). The names Apache,
Xerces, ANT, and Apache Software Foundation must not be used to endorse or promote products derived from this software without prior written
permission. Products derived from this software may not be called Apache, nor may Apache appear in their name, without prior written permission of the
Apache Software Foundation. For written permission, please contact [email protected]. Software distributed on an AS IS basis, WITHOUT WARRANTY
OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License agreement that accompanies
the product.
OpenEdge includes software are copyrighted by DataDirect Technologies, 1991-2002.
OpenEdge includes software developed by Vermont Creative Software. Copyright 1988-1991 by Vermont Creative Software.
OpenEdge includes software developed by IBM and others. Copyright 1999, International Business Machines Corporation and others. All rights reserved.
OpenEdge includes code licensed from RSA Security, Inc. Some portions licensed from IBM are available at http://oss.software.ibm.com/icu4j/.
OpenEdge includes the UnixWare platform of Perl Runtime authored by Kiem-Phong Vo and David Korn. Copyright 1991, 1996 by AT&T Labs. Permission
to use, copy, modify, and distribute this software for any purpose without fee is hereby granted, provided that this entire notice is included in all copies of any
software which is or includes a copy or modification of this software and in all copies of the supporting documentation for such software. THIS SOFTWARE IS
BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T LABS
MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS
FOR ANY PARTICULAR PURPOSE.
OpenEdge includes the RSA Data Security, Inc. MD5 Message-Digest Algorithm. Copyright 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
OpenEdge includes software developed by the World Wide Web Consortium. Copyright 1994-2002 World Wide Web Consortium, (Massachusetts Institute of
Technology, European Research Consortium for Informatics and Mathematics, Keio University). All rights reserved. This work is distributed under the W3C
Software License [http://www.w3.org/Consortium/Legal/2002/copyright-software-20021231] in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
August 2004
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Preface1
Part I Introduction
iv
Contents
5. Sample Code with SOAP Messages for Progress 4GL Web Services . . . . . . 51
Sample Web service specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Accessing a session-managed Web service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Accessing a session-free Web service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Running a Progress non-persistent procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Creating and using a ProcObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
ProcObject session context. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510
ProcObject IDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
ProcObject class factory methods. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511
Running an internal procedure or user-defined function . . . . . . . . . . . . . . . . . . . . 514
Creating and using a SubAppObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
SubAppObject/Client associations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
SubAppObject IDs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
SubAppObject class factory methods . . . . . . . . . . . . . . . . . . . . . . . . . . . 517
Releasing an object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 518
Passing static and dynamic temp-table parameters . . . . . . . . . . . . . . . . . . . . . . . 519
Invoking a method with a TABLE parameter (RPC/Encoded) . . . . . . . . 519
Invoking a method with a TABLE-HANDLE parameter
(RPC/Encoded). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524
Receiving a SOAP fault message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 528
Learning more about SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
v
Contents
vi
Contents
Mapping XML Schema data types to Progress 4GL data types . . . . . . . . . . . . . . 824
Simple data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 824
Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836
Complex data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 837
10. Invoking Web Service Operations from the Progress 4GL . . . . . . . . . . . . . . . 101
Preparing to invoke operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Creating a Web service procedure object . . . . . . . . . . . . . . . . . . . . . . . . 102
Specifying SOAP header callback procedures at run time . . . . . . . . . . 103
Using the SET-CALLBACK-PROCEDURE( ) method . . . . . . . . . . . . . . 104
Defining SOAP header callback procedures. . . . . . . . . . . . . . . . . . . . . . 104
Invoking operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Using the RUN Statement. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Using a User-defined Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
Managing operation parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Managing complex data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
Types of complex data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Complex data example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
vii
Contents
Part IV Appendices
viii
Contents
ix
Contents
D. Data Type Casting Rules for Progress 4GL Calls to Web Services . . . . . . . . . D1
CHARACTER or LONGCHAR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D3
DATE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D4
DATETIME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D5
DATETIME-TZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D6
DECIMAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D7
INTEGER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D9
LOGICAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D12
MEMPTR or RAW . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . D13
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Index1
x
Contents
Figures
Figure 11: Progress 4GL Web services architecture . . . . . . . . . . . . . . . . . . . . . . 15
Figure 12: Progress 4GL clients accessing Web services . . . . . . . . . . . . . . . . . . 116
Figure 41: OpenEdge Web services architecture . . . . . . . . . . . . . . . . . . . . . . . . . 414
Figure 61: Progress 4GL Web services sample applications . . . . . . . . . . . . . . . . 62
Figure 71: WSAViewer main window . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
Figure 81: WSDL Analyzer index document for multiple services . . . . . . . . . . . . 85
Figure 82: WSDL Analyzer operation index document . . . . . . . . . . . . . . . . . . . . . 87
Figure 83: WSDL Analyzer service document for one of multiple services . . . . . . 88
Figure 84: WSDL Analyzer service document for a single service only . . . . . . . . 810
Figure 85: WSDL Analyzer port type document (up to the Summary) . . . . . . . . . 812
Figure 86: WSDL Analyzer port type document (connection parameters) . . . . . . 814
Figure 87: WSDL Analyzer port type document (services and ports) . . . . . . . . . . 815
Figure 88: WSDL Analyzer port type document (example connection code) . . . . 816
Figure 89: WSDL Analyzer port type document (operation detail start) . . . . . . . . 818
Figure 810: WSDL Analyzer port type document (operation detail finish) . . . . . . . 819
Figure 811: WSDL Analyzer data types document (summary list) . . . . . . . . . . . . . 821
Figure 812: WSDL Analyzer data types document (data type detail) . . . . . . . . . . . 822
Figure 111: Referencing a header entry in the SOAP header object model . . . . . . 115
Figure 112: Accessing entry elements in the SOAP header object model . . . . . . . 116
Figure 121: SOAPSpy window opened by ProSOAPView . . . . . . . . . . . . . . . . . . . 1211
Figure 122: ProSOAPView Spy menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1212
Figure 123: ProSOAPView status bar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1213
Figure 124: ProSOAPView Call types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1213
Figure 125: ProSOAPView Request tab . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1214
Figure 126: ProSOAPView Call menu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1214
xi
Contents
Tables
Table 11: WSDL sections overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Table 12: AppServer and Web service access compared . . . . . . . . . . . . . . . . . . 125
Table 13: Attributes on Web service asynchronous request object handle . . . . . 135
Table 14: Results for asynchronous Web service requests . . . . . . . . . . . . . . . . . 136
Table 21: WSDL style and use attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Table 22: Supported SOAP message formats . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Table 23: WSDL element overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Table 41: Supported XML data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
Table 42: Valid date input formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427
Table 43: XML data types for TABLE (static temp-table) parameter columns . . . 431
Table 44: XML data types for TABLE-HANDLE (dynamic temp-table)
parameter columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
Table 51: Sample Web service specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Table 71: Setting error levels for WSA and Web services . . . . . . . . . . . . . . . . . . 74
Table 72: OpenEdge log files providing Web service-related messages . . . . . . . 77
Table 73: Some SOAP message viewers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 710
Table 74: WSA administration error logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 713
Table 75: Sample Web service specification for error scenarios . . . . . . . . . . . . . 715
Table 81: WSDL Analyzer docIndex document for multiple services . . . . . . . . 86
Table 82: WSDL Analyzer docOperation index document list . . . . . . . . . . . . . . 87
Table 83: WSDL Analyzer docService document (from multiple services) . . . . 89
Table 84: WSDL Analyzer docService document (from one service) . . . . . . . . 811
Table 85: WSDL Analyzer docPort type document beginning sections . . . . . . 813
Table 86: WSDL Analyzer docPort type document connection details . . . . . . . 817
Table 87: WSDL Analyzer docPort type document operation detail . . . . . . . . . 820
Table 88: WSDL Analyzer docData types document . . . . . . . . . . . . . . . . . . . . 823
Table 89: Suggested XML Schema mappings to Progress 4GL data types . . . . . 825
Table 810: Supported casts between XML Schema and Progress 4GL
data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 831
Table 91: Web service connection parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Table 111: 4GL to manage object memory for SOAP headers . . . . . . . . . . . . . . . . 1132
Table 112: SOAP header object attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1133
Table 113: SOAP header object methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1134
Table 114: SOAP header-entryref object attributes . . . . . . . . . . . . . . . . . . . . . . . . 1134
Table 115: SOAP header-entryref object methods . . . . . . . . . . . . . . . . . . . . . . . . . 1135
Table 121: ERROR-STATUS handle attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Table 122: SOAP fault object attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Table 123: SOAP fault-detail object attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Table 124: SOAP fault-detail object methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
Table 125: Web service message viewers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Table 131: DatatypeFormats sample applicationexample formats . . . . . . . . . . . 1318
Table 132: DatatypeFormats sample applicationinput parameters . . . . . . . . . . . 1319
Table 133: DatatypeFormats sample applicationoutput parameters . . . . . . . . . . 1319
xii
Contents
xiii
Contents
Procedures
WSDL Containing an object ID definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 416
SOAP header containing an object ID . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
arraySample procedure signature . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
Array parameter definition for RPC/Encoded WSDL . . . . . . . . . . . . . . . . . . . . . . . . . . . 421
RPC/Encoded WSDL schema example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
Array parameter definition for RPC/Literal WSDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 423
RPC/Literal WSDL schema example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 424
Array parameter definition for Document/Literal WSDL . . . . . . . . . . . . . . . . . . . . . . . . . 425
Document/Literal WSDL schema example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426
TABLE parameter row schema for all SOAP formats . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
TABLE parameter for RPC/Encoded . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
TABLE parameter for RPC/Literal and Document/Literal . . . . . . . . . . . . . . . . . . . . . . . . 429
TABLE parametersgeneral RPC/Encoded format . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429
TABLE parametersgeneral Document (or RPC)/Literal format . . . . . . . . . . . . . . . . . . 430
TABLE-HANDLE definition for all dynamic temp-table parameters . . . . . . . . . . . . . . . . 432
TABLE-HANDLE parametersgeneral format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 432
Progress 4GL procedure prototype . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435
WSDL message section defining request and response messages . . . . . . . . . . . . . . . . 435
WSDL portType section defining an operation signature on an object . . . . . . . . . . . . . . 436
WSDL Bindings section defining an operation and object binding . . . . . . . . . . . . . . . . . 437
WSDL service section defining the Web service location . . . . . . . . . . . . . . . . . . . . . . . . 438
Interface method prototype (VB.NET) generated from a WSDL operation definition . . . 438
Interface method call (VB.NET) generating SOAP messages . . . . . . . . . . . . . . . . . . . . 439
SOAP request message for method input parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 439
SOAP response message for method output parameters . . . . . . . . . . . . . . . . . . . . . . . 440
SOAP faultsgeneral format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
VB.NET method declarations on AppObject, OrderInfo . . . . . . . . . . . . . . . . . . . . . . . . . 52
VB.NET method declarations on ProcObject, CustomerOrder . . . . . . . . . . . . . . . . . . . . 53
VB.NET method declarations on SubAppObject, Payroll . . . . . . . . . . . . . . . . . . . . . . . . 53
VB.NET prototype for an AppObject Connect_Object method . . . . . . . . . . . . . . . . . . . . 54
VB.NET client code for the connect method on AppObject, OrderInfo . . . . . . . . . . . . . . 55
SOAP connect request for AppObject, OrderInfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
SOAP response to OrderInfo AppObject connect request . . . . . . . . . . . . . . . . . . . . . . . 56
VB.NET client code to instantiate session-free AppObject, OrderInfo . . . . . . . . . . . . . . 57
Progress 4GL prototype for a non-persistent external procedure . . . . . . . . . . . . . . . . . . 58
VB.NET prototype for a method that runs a Progress non-persistent procedure . . . . . . 58
VB.NET client code calling an external procedure method . . . . . . . . . . . . . . . . . . . . . . . 58
SOAP request from calling the FindCustomerByNum procedure method . . . . . . . . . . . 59
SOAP response from calling the FindCustomerByNum method . . . . . . . . . . . . . . . . . . . 59
Progress 4GL prototype for a persistent procedure to implement a ProcObject . . . . . . . 511
VB.NET prototype for the ProcObject CreatePO_CustomerOrder method . . . . . . . . . . 511
VB.NET client code to create the ProcObject, CustomerOrder . . . . . . . . . . . . . . . . . . . 512
SOAP request to create ProcObject, CustomerOrder . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
xiv
Contents
xv
Contents
Request header handler modifying a saved SOAP response header (start) . . . . . . . . . 1123
Request header handler modifying a saved SOAP response header (end) . . . . . . . . . . 1124
SOAP request header created entirely by the client . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1126
Invoking a request that creates a SOAP request header on the client . . . . . . . . . . . . . . 1127
Procedure to create a SOAP request header (start) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1128
Procedure to create a SOAP request header (continuation) . . . . . . . . . . . . . . . . . . . . . 1129
Procedure to create a SOAP request header (end) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1130
Request header handler passing a client-created SOAP request header . . . . . . . . . . . 1130
Sample SOAP fault message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Sample SOAP fault procedure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
xvi
Preface
This Preface contains the following sections:
Purpose
Audience
Organization
Typographical conventions
OpenEdge messages
OpenEdge Development: Web Services
Purpose
This manual describes how OpenEdge supports Web services. It describes the technology for
exposing AppServer application services as Web services (Progress 4GL Web services),
and how to access industry Web services from the Progress 4GL as a Web service client. It also
describes the requirements for programming industry Web service clients to access Progress
4GL Web services. And it defines the Web services industry standards that OpenEdge supports.
This manual provides a brief overview of Web services architecture in OpenEdge. However, for
a complete description of the Web services architecture in OpenEdge, including all components
and how they work together, see OpenEdge Getting Started: Application and Integration
Services.
This manual describes the general procedures and facilities for building Progress 4GL Web
services, as well as specific client requirements. However, for specific information on Web
service development, deployment, and administration, see the following documentation:
OpenEdge Development: Messaging and ESB (for deploying and managing Progress
4GL Web services for the Sonic ESB using the Sonic ESB Adapter)
Audience
The most appropriate reader for this manual is one or both of the following:
An experienced Progress 4GL (or SpeedScript) developer who wants to access industry
Web services from their 4GL (or SpeedScript) application.
Preface2
Preface
Organization
Part I, Introduction
Chapter 2, WSDL and Web Service Objects in Progress 4GL Web Services
Describes how the interface to Progress 4GL Web services is based on the Open Client
object model and defined in a Web Service Description (WSDL) file.
Chapter 3, Session Models and Object IDs in Progress 4GL Web Services
Describes how Progress 4GL Web services support AppServer session models.
Chapter 4, General Client Programming Model for Progress 4GL Web Services
Describes how to program client access to Progress 4GL Web services using the Open
Client object model, including a description of session model programming, data type
mapping, handling SOAP headers, and SOAP faults.
Chapter 5, Sample Code with SOAP Messages for Progress 4GL Web Services
Describes, in detail, the techniques for coding Progress 4GL Web service operations using
VB.NET as the sample client platform, showing the types of SOAP messages that are
generated for various types of SOAP requests supported by the Open Client object model.
Describes the sample Progress 4GL Web services that are installed with OpenEdge and
the sample client applications to access them (also installed).
Preface3
OpenEdge Development: Web Services
Describes how to test and debug Progress 4GL Web services using log files, SOAP
viewers, and basic SOAP fault handling techniques.
Describes how to run the WSDL Analyzer to generate documentation on a Web service.
This documentation describes how to connect to a Web service defined in the WSDL and
how to call its operations from the 4GL. The chapter also describes how OpenEdge maps
Progress 4GL data types to the XML Schema data types interpreted by Web services.
Describes how to connect to and manage connections to a Web service from the 4GL once
you have generated the WSDL documentation for it.
Chapter 10, Invoking Web Service Operations from the Progress 4GL
Describes how to invoke and manage Web service operations from the 4GL once you have
generated the WSDL documentation for it. This includes information on how to configure
Web service operations for managing SOAP message headers in the 4GL.
Describes how to manage SOAP message headers in the 4GL for Web service operations
that are configured for SOAP header management. This includes a detailed description of
the 4GL techniques for accessing, manipulating, creating, and managing all elements of a
SOAP message header.
Describes how to manage errors from 4GL requests to Web services in general and for
SOAP faults in particular. This includes a detailed description of the 4GL techniques for
accessing all elements of a SOAP fault message.
Describes some of the sample 4GL applications installed with OpenEdge that access Web
services, both public Web services and sample Web services provided with OpenEdge for
deployment.
Preface4
Preface
Provides a quick reference to the basic Progress 4GL elements provided by OpenEdge to
access Web services.
Appendix D, Data Type Casting Rules for Progress 4GL Calls to Web Services
Describes in finer detail the key rules used to transform data for Web service operation
parameters between alternative mappings of Progress 4GL data types and XML Schema
data types.
Typographical conventions
This manual uses the following typographical conventions:
Convention Description
SMALL, BOLD Small, bold capital letters indicate OpenEdge key functions and
CAPITAL LETTERS generic keyboard keys; for example, GET and CTRL.
Preface5
OpenEdge Development: Web Services
Convention Description
KEY1 KEY2 A space between key names indicates a sequential key sequence:
you press and release the first key, then press another key. For
example, ESCAPE H.
Syntax:
Period (.) All statements except DO, FOR, FUNCTION, PROCEDURE, and REPEAT
or end with a period. DO, FOR, FUNCTION, PROCEDURE, and REPEAT
colon (:) statements can end with either a period or a colon.
{} Large braces indicate the items within them are required. They are
used to simplify complex syntax diagrams.
{} Small braces are part of the Progress 4GL language. For example,
a called external procedure must use braces when referencing
arguments passed by a calling procedure.
... Ellipses indicate repetition: you can choose one or more of the
preceding items.
Preface6
Preface
Syntax
FOR is one of the statements that can end with either a period or a colon, as in this example:
Syntax
In this example, the outer (small) brackets are part of the language, and the inner (large) brackets
denote an optional item:
Syntax
A called external procedure must use braces when referencing compile-time arguments passed
by a calling procedure, as shown in this example:
Syntax
{ &argument-name }
In this example, EACH, FIRST, and LAST are optional, but you can choose only one of them:
Syntax
Preface7
OpenEdge Development: Web Services
In this example, you must include two expressions, and optionally you can include more.
Multiple expressions are separated by commas:
Syntax
In this example, you must specify MESSAGE and at least one expression or SKIP [ (n) ], and
any number of additional expression or SKIP [ ( n ) ] is allowed:
Syntax
In this example, you must specify {include-file, then optionally any number of argument or
&argument-name = "argument-value", and then terminate with }:
Syntax
{ include-file
[ argument | &argument-name = "argument-value" ] ... }
Syntax
Preface8
Preface
In this example, ASSIGN requires either one or more field entries or one record. Options
available with field or record are grouped with braces and brackets:
Syntax
OpenEdge messages
OpenEdge displays several types of messages to inform you of routine and unusual occurrences:
Compile messages inform you of errors found while OpenEdge is reading and analyzing
a procedure before running it; for example, if a procedure references a table name that is
not defined in the database.
Startup messages inform you of unusual conditions detected while OpenEdge is getting
ready to execute; for example, if you entered an invalid startup parameter.
Preface9
OpenEdge Development: Web Services
Continues execution, subject to the error-processing actions that you specify or that are
assumed as part of the procedure. This is the most common action taken after execution
messages.
Returns to the Progress Procedure Editor, so you can correct an error in a procedure. This
is the usual action taken after compiler messages.
Halts processing of a procedure and returns immediately to the Progress Procedure Editor.
This does not happen often.
OpenEdge messages end with a message number in parentheses. In this example, the message
number is 200:
If you encounter an error that terminates OpenEdge, note the message number before restarting.
Choose HelpMessages and then enter the message number to display a description of
a specific OpenEdge message.
Preface10
Preface
On UNIX platforms, use the Progress pro command to start a single-user mode character
OpenEdge client session and view a brief description of a message by providing its number.
install-dir/dlc/bin/pro
3. Type the message number and press ENTER. Details about that message number appear.
4. Press F4 to close the message, press F3 to access the Progress Procedure Editor menu, and
choose File Exit.
Preface11
OpenEdge Development: Web Services
Preface12
Part I
Introduction
Deploy Web services that you build from Progress 4GL application services running on
the AppServer. These Progress 4GL Web services are accessible from any application
that can access industry Web services as a client.
Access industry Web services and invoke Web service operations from any 4GL
application, and otherwise manage interactions with Web services from the 4GL in a
manner consistent with industry Web service clients.
This chapter describes the general support for Web services in OpenEdge and contains the
following sections:
For a general introduction to Web services and a detailed architectural overview of Web
services in OpenEdge, see OpenEdge Getting Started: Application and Integration Services.
OpenEdge Development: Web Services
You can define Web services using the Open Client Toolkit much as you define traditional Open
Client proxies. However, instead of generating Open Client proxies for immediate access by
Open Client applications, you generate a client interface definition, Web Service Mapping file
(.wsm), and deploy this definition generating a Web Service Description Language (WSDL) file
and property files that you then manage, along with the operational Web service, within the
context of the WSA.
The WSA is a Java servlet running on a Web server or stand-alone JSE. Situated between the
client and AppServer, this Java servlet understands how to communicate at run time:
With a Web service client using Simple Object Access Protocol (SOAP).
With an AppServer using the Progress 4GL interface to the application service.
The WSA also generates the WSDL file required by Web service clients during Web service
deployment, and it maintains the status of all 4GL Web services that have been deployed to its
Web application context. It serves as the SOAP-to-business interface gateway and Web service
management engine for your 4GL Web service. The WSA provides client access to the Web
12
Web Services in OpenEdge
service WSDL file and supports Web service administration; it also manages the exchange of
Web service SOAP requests and generates SOAP responses between Web service clients and
AppServers at run time.
For an overview of the components and procedures for building Progress 4GL Web services,
see the Turning 4GL application services into Web services section on page 15.
The 4GL views a Web service very much like an application service provided directly through
the AppServer. To access a Web service, OpenEdge provides many of the same 4GL elements
that you use to access a session-free AppServer, and it provides additional elements specifically
designed to manage calls to a Web service that are not required to access an AppServer directly.
In general, all 4GL network deployment models support inherent access to Web services,
including:
A WebClient application.
All you need is the WSDL file, any additional documentation provided for using the Web
service, and a networked 4GL session and development environment to develop and deploy
4GL applications that access Web services.
For an overview of the tools and procedures for accessing industry Web services in the 4GL,
see the Programming 4GL clients to access industry Web services section on page 116.
13
OpenEdge Development: Web Services
It is possible for a 4GL application to access Progress 4GL Web services. However, the greater
efficiency achieved by accessing an AppServer directly over the Internet using the AppServer
Internet Adapter (AIA), and certainly the ability to access an AppServer directly within an
intranet, makes the choice to use a Progress 4GL Web service interface for the same purpose
somewhat less useful.
However, if you happen to use a Web service written in the Progress 4GL, you can follow the
same procedures required of any Web service client to access a Progress 4GL Web service. For
more information, see Part II, Clients Accessing Progress 4GL Web Services.
WSDL WSDL 1.1 (W3C Notethe de facto standard). For more information on
WSDL, visit the following Web address:
http://www.w3.org/TR/wsdl
SOAP SOAP 1.1 HTTP Binding. For more information on SOAP, visit the following
Web address:
http://www.w3.org/TR/SOAP
XML Schema W3C 2001 XML Schema. For more information on XML Schema, visit
the following Web address:
http://www.w3.org/TR/xmlschema-0/
14
Web Services in OpenEdge
Web service
Web server/JSE AppServer
Web services
client
Post (SOAP)
Web Services
Java
HTTP listener
VB.NET Progress
Adapter
HTTP/S
(WSA)
Progress 4GL
... business
Response (SOAP) logic
WSDL
In this figure, the standard set of components required for Web services in general appear with
gray shading, and those required for Progress 4GL Web services appear with darker gray
shading. Otherwise, the Progress 4GL Web services architecture provides features that are
virtually identical to any other Web services architecture in the industry.
15
OpenEdge Development: Web Services
OpenEdge supports these features with the components of the Web service tools for all phases
of Web service development, deployment, and management:
The AppServer supports four operating modes for Web service applications:
The stateless, state-aware, and state-reset operating modes (supported for all OpenEdge
clients). As with other OpenEdge clients, these operating modes maintain a private and
persistent connection for each client of the Web service. So, the AppServer accepts all
requests from each client over this private connection.
The state-free operating mode (not supported for Java and .NET Open Clients). With this
operating mode, the AppServer accepts requests from any and all Web service clients
without the use of connections.
These operating modes thus support two distinct session models for Web services:
16
Web Services in OpenEdge
The session-managed model provides varying types of support for maintaining and managing
session context across client requests, throughout the life of the client connection. With this
model, the type of context management supported depends on the actual operating mode of the
AppServer, and the AppServer application must be written to maintain session context
accordingly. With this model, the AppServer handles all requests from a single client
sequentially, completing each request before accepting another, which allows an orderly
maintenance of context from one request to the next.
For more information on setting up and programming the AppServer for Web services using
both session models, see OpenEdge Application Server: Developing AppServer Applications
Thus, the Open Client interface definition that you specify and that ProxyGen generates
includes at least one AppObject, zero or more SubAppObjects, and zero or more ProcObjects.
These Web service object definitions, when processed using a Web service client platform,
become the client interface objects that a client application accesses to interact with the Web
service.
17
OpenEdge Development: Web Services
In addition to other Web service deployment information, ProxyGen allows you to specify the
following basic features of a Web service interface:
SOAP format OpenEdge supports the deployment of a Web service definition using
any one of three SOAP formats. To support multiple client platforms, you might generate
and deploy a Web service with multiple SOAP formats by generating a separate Web
service definition for each format. Each separate WSDL definition identifies a unique Web
service, even though the underlying AppServer application is the same. When you deploy
the same Web service definition for multiple SOAP formats, you also must specify a
unique target namespace for each one in order to deploy it to the same WSA instance.
Otherwise, you must deploy the same Web service definition with different SOAP formats
to different WSA instances.
Session model This setting must match the session model supported by the AppServer
application. The session model also determines the standard object management methods
required for the Web service, and ProxyGen defines these methods according to the
session model that you choose.
For more information on how the Open Client object model supports Web service development
and on using ProxyGen to define a Web service definition, see OpenEdge Development: Open
Client Introduction and Programming. For more information on how the ProxyGen-generated
or deployed WSDL reflects the Open Client object model for Web services, see Chapter 2,
WSDL and Web Service Objects in Progress 4GL Web Services.
2. Generates and manages WSDL files for Web services as they are deployed and makes
these WSDL files available for download by potential Web service clients.
18
Web Services in OpenEdge
3. Directs incoming SOAP messages for client requests to specified Web services and
converts the SOAP requests to AppServer requests as defined by the Web service WSAD
file. It then converts AppServer responses to SOAP messages and returns these outgoing
response messages from the specified Web services to the Web service clients that are
waiting for them.
You can define multiple WSA server instances (Java servlets), each with different properties,
and you can deploy multiple Web services to each WSA instance. Each WSA instance then
supports the three WSA functions for its own set of Web services (see the information on WSA
configuration, Web service deployment components, and client development components in
OpenEdge Getting Started: Application and Integration Services). For example, you might
create separate WSA instances to deploy Web services that share the same SOAP format. This
can be useful when you want to deploy the same Web service application to support multiple
SOAP formats (see the information on SOAP in the Web services section of OpenEdge Getting
Started: Application and Integration Services).
For more information on WSA configuration and administration and on WSA deployment and
Web service run-time support, see OpenEdge Application Server: Administration.
You can also use the Progress Explorer or wsaman to temporarily change a selected set of WSA
instance properties at run time (WSA Run-time Properties). This can be helpful for debugging
or testing certain settings before making them permanent in your WSA configuration.
19
OpenEdge Development: Web Services
You must also use Progress Explorer or wsaman to deploy Web services to a particular WSA
instance and to manage deployed Web services at run time. Each deployed Web service behaves
according to the settings of a predefined set of run-time properties. While these properties have
maintainable default values initially set for all Web services deployed to a WSA instance, you
can set and reset their values, under prescribed run-time conditions, for each Web service
individually.
For more information on WSA configuration and administration and on deploying and
configuring Web services, see OpenEdge Application Server: Administration.
Securing the data connection between a Web service and the AppServer using SSL
tunneling.
For more information on security options for managing WSA configuration and administration
and on managing access control for Web services, see OpenEdge Application Server:
Administration. For more information on how OpenEdge supports security for Progress 4GL
Web services, see OpenEdge Getting Started: Security.
110
Web Services in OpenEdge
Open Client object model The Open Client object model supports certain built-in
object management methods whose availability and use depends on the session model of
the Web service application and the particular type of Open Client object in use. For
example, in a session-managed application, the instantiation of each object returns a
unique ID that identifies that object and must be maintained and supplied in all method
calls on that object. In general, the client programmer needs to understand when they can
and should use these built-in methods on an object and how to use them.
SOAP format All Web service client platforms support a limited choice of SOAP
formats, often fewer than the three supported by OpenEdge. The client programmer needs
to know the SOAP format that a particular Web service uses in order to know whether their
client platform supports it. This information is certainly available in the WSDL, but it
might be helpful to know before downloading the WSDL. Also, you might provide
versions of the Web service for each supported SOAP format and identify them
accordingly.
Relational data OpenEdge allows you to build Web services that pass arrays of
complex data types as input and output parameters, thus supporting the exchange of
relational data (sometimes known as data sets, result sets, data objects, or as in Progress
temp-tables). For many 4GL-built Web services, the WSDL supplies all the schema
information required to access these relational data, particularly for static temp-tables.
However, for Web services that pass dynamic temp-tables, where the schema is not
defined at compile-time, the client programmer needs additional documentation on the
schema required to pass dynamic temp-tables as input parameters.
SOAP faults The client programmer needs to understand the format of error messages
that are returned from 4GL-built Web services.
For more information on all these requirements (and more) for programming client applications
to access Progress 4GL Web services, see Part II, Clients Accessing Progress 4GL Web
Services.
111
OpenEdge Development: Web Services
The first step in building any new Web service application is to understand the requirements of
its intended clients. This can help with deciding certain details of a Web service design and
implementation, including (but not limited to):
The session model to support with a new Web service application. For more information,
see OpenEdge Application Server: Developing AppServer Applications
The types of Open Client objects to use in designing the Web service (also closely
associated with the session model of the Web service). For more information, see
OpenEdge Development: Open Client Introduction and Programming.
The SOAP formats (style and use) to support for Web service deployment. For more
information, see Chapter 2, WSDL and Web Service Objects in Progress 4GL Web
Services and Chapter 4, General Client Programming Model for Progress 4GL Web
Services.
Note: For an existing AppServer application, the requirements of intended Web service clients
are already likely to be known and reflected in the existing AppServer application.
112
Web Services in OpenEdge
Once the client requirements are known, you can design and write a new AppServer application
for a Web service, or decide whether to enable an existing AppServer application as a Web
service. You can enable the complete interface to a smaller application, or selected interface
components of a larger application, as client requirements dictate. The session model that the
AppServer must support for a new application also determines the complexity of its
programming. For information on configuring and programming AppServers, see OpenEdge
Application Server: Administration and OpenEdge Application Server: Developing AppServer
Applications.
After you have built and compiled the Progress r-code for the AppServer application, you can
use ProxyGen to prepare the application for deployment as a Web service. As you define the
Web service, your knowledge of the application and client requirements helps to decide how
best to organize and include the procedures of your application as Open Client objects and
methods. For information on how to use ProxyGen to define the Web service, see OpenEdge
Development: Open Client Introduction and Programming. ProxyGen saves the Web service
definition as a WSM file.
At any time in the cycle of Web service design and development, you can create and configure
a WSA instance to host your Web service when you are ready to deploy it. Many considerations
might determine when and how you do this, such as the available server and network resources,
as well as any other requirements that you determine for deploying the Web service (for
example, support for different client SOAP formats). You also need to think carefully about
security requirements for the WSA instance and the Web services you plan to deploy to it.
Note: Creating and configuring a WSA instance is a two-step process in which you (1) use the
Progress Explorer to define and Progress Explorer or the wsaman utility to configure the
instance on the OpenEdge side, and (2) use whatever tools are available to define the
WSA instance as a Java servlet to your JSE. After completing the creation and
configuration of a WSA instance, you might have to restart the JSE to start up the Java
servlet for that instance to deploy Web services to the context of the WSA instance. See
your JSE documentation for information on the requirements for running and accessing
instances of the JSE context.
For information on how to create and configure WSA instances, see OpenEdge Application
Server: Administration.
113
OpenEdge Development: Web Services
After you have defined the Web service and configured a WSA instance for it, you can deploy
the Web service definition to that WSA instance using Progress Explorer or the wsaman utility.
Caution: You can update a deployed Web service to change its deployment information and
object definitions. However, never update a deployed Web service that you have
enabled for live access by production clients. Instead, create a new version of the
Web service with the intended updates and deprecate the old version of the Web
service once all clients have moved to the new version.
You can also adjust the values for a variety of properties of a deployed Web service or change
the default values that are automatically assigned when you first deploy a Web service.
For more information on deploying and managing a deployed Web service, see OpenEdge
Application Server: Administration.
Typically, the earliest that you can begin writing the code to access a Web service in a client
application is after you have obtained the WSDL file for a Web service (and any required
documentation). You can obtain this WSDL file before deployment by selecting the option to
generate it directly from ProxyGen when you first define the Web service.
However, the order in which you actually develop the client and Web service side of a complete
application solution depends on your application and the environment in which it runs. For
example, if you are writing both the client and Web service as a single application solution for
an intranet environment, you might begin developing the client side as a way of determining the
exact requirements for the Web services you need to develop.
There are also additional techniques for testing and debugging a Web service with or without
writing a client for it.
Caution: Before you begin testing a Web service, deploy it to a WSA instance that is dedicated
for Web service testing and otherwise isolated from the intended client domain. This
allows you to enable the Web service for access by clients doing preproduction
testing without making it visible and live to post-production clients. Once testing
is complete, you can redeploy or import the Web service to the context of the
production WSA instance.
114
Web Services in OpenEdge
For more information on writing client applications for a 4GL Web service, see Part II, Clients
Accessing Progress 4GL Web Services. For more information on testing and debugging Web
services, see Chapter 7, Testing and Debugging Progress 4GL Web Services.
When you initially deploy a Web service, it is disabled from access by clients over the network.
This allows you to adjust Web service property values and perform other administrative tasks,
such as setting up the WSA instance to distribute the WSDL file to users, before making it
visible and accessible to the intended network clients. When the Web service is ready for
production, you can enable it for client access using an option in Progress Explorer or the
wsaman utility.
Caution: Do not make a newly deployed Web service available to production clients until you
ensure that all Web service testing, updating, and administration is complete to
support that Web service in the production client domain. (See the Writing a client
and testing the Web service section on page 114.)
For more information on when and how to enable and disable Web services for client access,
see OpenEdge Application Server: Administration.
Both during preproduction testing and full production access by real clients, you can monitor
various run-time statistics accumulated for both the WSA instance and the Web services that are
deployed to it. Over time, this will allow you to adjust WSA instance and Web service property
values to yield the best performance metrics.
Note: Remember also to monitor and tune the AppServer configurations that support your Web
services along with monitoring and tuning the Web services themselves.
For information on monitoring and tuning AppServer configurations, WSA instances, the Web
services that are deployed to WSA instances, see OpenEdge Application Server:
Administration.
115
OpenEdge Development: Web Services
Web service
Progress 4GL
client Web service Application
provider server
SOAP processor
HTTP/S listener
4GL client logic
Client interface
Post (SOAP)
HTTP/S
Businessi Interface
Business
SOAP processor
HTTP/S listener
logic:
Response (SOAP)
Java
C#.NET
Progress
WSDL
As you can see, the client architecture for a Progress 4GL application accessing a Web service
mirrors the Web service provider and application server architecture. The additional
components on the 4GL client specifically for accessing Web services are indicated in a darker
gray. The WSDL file, obtained from the Web service provider describes both the logical and
physical interface required by the client to access the Web service. At the logical level,
OpenEdge uses the WSDL file to define the client interface (API) required to program calls to
Web service operations and to provide support for interpreting those operations at run time.
116
Web Services in OpenEdge
At the physical level, OpenEdge contains its own SOAP processor to convert between calls to
4GL-defined procedures and SOAP messages understood by the Web service, and it supports
both nonsecure HTTP and SSL using its HTTP/S listener to manage the transport of these SOAP
messages across the wire.
Once the logical and physical interface to a Web service is known, you can interact with that
Web service in the 4GL in a manner very similar to interacting with a session-free AppServer.
Many of the same 4GL elements are used to support the same logical functionality. In addition,
the OpenEdge and the Progress 4GL provides functionality that allows you to handle the unique
requirements of managing a Web service request:
In the request-response scenario, a client (Web service client) sends a SOAP request message
to invoke a Web service operation and the operation sends a response back to the client in the
form of a SOAP response message (for a successful invocation) or in the form of a SOAP fault
message (for an invocation that results in an error).
117
OpenEdge Development: Web Services
SOAP messages have a common XML document structure that consists of the following
ordered elements:
1. Envelope (mandatory) Defines all the namespaces used in the document. Namespaces
are identifiers that provide a way to define XML elements without name conflicts. This is
important for a Web service because it must be able to define its elements uniquely across
the Internet, as well as to identify elements from other namespaces commonly used by all
Web services on the Internet, such as the namespace for the SOAP specification itself. A
namespace is typically defined by a Universal Resource Identifier (URI), usually in the
form of a Universal Resource Locator (URL) or a Universal Resource Name (URN). The
WSDL files that define Web service interfaces use namespaces in the same way (see the
WSDLan overview section on page 121).
118
Web Services in OpenEdge
3. Body (mandatory) Contains data and SOAP formatting information according to the
type of message it is. So, for a:
SOAP request message The body contains the operation name and its input
parameter values.
SOAP response message The body contains any operation output parameters and
any return value for a successful request.
SOAP fault message The body contains error information for a failed request,
including a set of standard attributes sufficient to identify the error and zero or more
detail elements unique to the application that provide more complete information
about what caused the error.
With some Web services, you do not have to have any direct knowledge of SOAP message
structure to use them. These are Web services for which all the operation parameters map
directly to 4GL data type parameters. For such Web services, especially where even SOAP
faults can be ignored, you can interact with them in the 4GL without regard to SOAP message
structure. The WSDL Analyzer also reduces your need to know SOAP in depth because it
provides documentation on exactly what you need to do in the 4GL to use Web service
operations. For an example of 4GL interaction with such a service, see the Interacting with a
Web service and its operations section on page 124.
Many of the more complex Web services require direct 4GL interaction with the underlying
XML in each SOAP message, in addition to any mapping of Web service parameters directly to
4GL data types. The Progress 4GL supports access to XML with an implementation of the
Document Object Model (DOM) and Simple API for XML (SAX). For more information this
XML support, see OpenEdge Development: Programming Interfaces. For more information on
when and what you need to do to access the XML for SOAP request and response messages,
see the Handling Web service operation outputs and inputs section on page 129.
Also, if you must handle the SOAP faults returned from a Web service request, you might need
to access the underlying XML for the SOAP fault. For more information on when and what you
need to do to access the underlying XML for a SOAP fault, see the Handling Web service
errors section on page 132.
119
OpenEdge Development: Web Services
SOAP messages can be generated using several different formats, depending on the
communications scenario. OpenEdge supports request-response scenarios that use the
following SOAP formats:
RPC/Encoded
RPC/Literal
Document/Literal
To hide the details of these SOAP formats, OpenEdge provides the WSDL Analyzer. This
utility reads a WSDL file and translates the Web service interface definition into a 4GL interface
that you can use to access the Web service. Generally, when writing a Web service client in the
4GL, especially if you use the WSDL Analyzer (see the OpenEdge WSDL Analyzer section
on page 124), you have no need to know the SOAP message format of the Web service you
are using. However, if the Web service that you choose supports a different SOAP format than
those supported by OpenEdge, the analyzer indicates that OpenEdge cannot support the Web
service.
Note: Web services do not generally require that you have a WSDL file to access them.
However, the Progress 4GL does require this file for both development and run-time
access to the Web service.
120
Web Services in OpenEdge
WSDLan overview
If you have built Web services in the 4GL, you might already be familiar with the basic structure
of a WSDL file and how OpenEdge uses it to define 4GL Web services (see Chapter 2, WSDL
and Web Service Objects in Progress 4GL Web Services). This section describes a WSDL file
more generically, as it might define any Web service you might want to access from the 4GL.
Note: Accessing some Web services requires little, if any, knowledge of WSDL. However, for
complex Web services, you must have a basic understanding of WSDL to make full use
of the Web service and to access its data appropriately.
A single WSDL file describes a single Web service and contains a series of major sections that
define features of the Web service interface, from data and operations to the binding information
needed to access the Web service on the network. Each section is defined by a corresponding
WSDL element.
Table 11 lists and describes these major WSDL sections in the order that they appear in a
WSDL file.
Note: This information is similar to the description of WSDL file sections provided for
Progress 4GL Web services (see Chapter 2, WSDL and Web Service Objects in
Progress 4GL Web Services). However, Table 11 describes the WSDL sections from
a more general perspective. The WSDL files that you see in the industry do not
necessarily define Web services in the same way that OpenEdge uses them to define
4GL Web services.
121
OpenEdge Development: Web Services
Section Description
Types Defined by one occurrence of the <types> element. This section provides
data type definitions used to describe the messages exchanged between a
Web service and the Web service client. These data type definitions
typically use the XML Schema specification.
Port types Defined by one or more <portType> elements. Each <portType> element
defines a set of abstract operations (one <operation> element for each
operation) and the abstract messages (operation parameters) involved. Each
port type is uniquely named among all port types defined within the WSDL
file.
122
Web Services in OpenEdge
Section Description
Bindings Defined by one or more <binding> elements. This section specifies how the
client and Web service exchange messages for each operation (<operation>
element).
Each binding element contains information that specifies the protocol by
which the client accesses the Web service. OpenEdge supports the SOAP
protocol, which specifies a message protocol that includes an envelope,
header, and body.
For SOAP, the binding information includes a transport attribute that
identifies the transport protocol used by the binding. OpenEdge supports the
transport protocols, HTTP and HTTPS (HTTP/S).
A SOAP binding also identifies a format used for each operation to
exchange messages, indicated by the style and use attributes. OpenEdge
supports the message formats named style/use respectively as:
RPC/Encoded
RPC/Literal
Document/Literal
Each <binding> element corresponds to a previously-defined <portType>
element, specifying appropriate information about the same set of
operations. As described for port types, a <portType> element defines the
abstract elements of each operation, the parameters and their data types that
the client must interact with at the logical level. The corresponding
<binding> element defines the physical details of how messages for these
same operations are exchanged over the network.
Note: The message style also has an effect on how the Messages and Types
sections relate to each other to define messages for operation
parameters.
123
OpenEdge Development: Web Services
For more information on how to use the WSDL file to help program the 4GL interface to a Web
service, see Chapter 8, Analyzing WSDL for Progress 4GL Access to Web Services. For
complete information on WSDL and its meaning, see the official WSDL specification at the
following URL:
http://www.w3.org/TR/wsdl
OpenEdge makes accessing Web services from the 4GL much easier by providing a utility (the
WSDL Analyzer) that can read the WSDL file and produce a reference guide that documents
exactly how to use the 4GL to access the Web service. This guide is a series of HTML
documents with hyperlinks that clearly define all Web service operations and their 4GL
interfaces, including how complex Web service data types are represented in the WSDL. It also
provides the binding information necessary to access the Web service on the Internet. Finally,
it includes any internal WSDL file comments as documentation from the Web service provider.
To make use of the OpenEdge features that allow you to access a Web service at run time, the
client application must have access to a current WSDL file for the Web service you want to use.
Using the reference output is optional, but highly recommended to most effectively structure
your code to access the Web service. The way OpenEdge interprets the run-time invocation of
Web service operations is consistent with the WSDL Analyzer processing to produce its
reference documentation. For an example of how the WSDL Analyzer can help you to program
your 4GL interaction with a Web service, see the Interacting with a Web service and its
operations section on page 124. For more information on WSDL, how the 4GL maps Web
services based on WSDL, and how you can use the WSDL Analyzer to help you write the
necessary 4GL, see Chapter 8, Analyzing WSDL for Progress 4GL Access to Web Services.
124
Web Services in OpenEdge
Table 12 lists and compares the 4GL elements used for session-free AppServer access and
Web service access, listed in rough order of use.
Server object handle to access the Server object handle to access the Web
AppServer application service. service.
CONNECT( ) method on the server handle to CONNECT( ) method on the server handle to
logically connect (bind) the server object to logically connect (bind) the server object to
the application service. the Web service.
RUN statement to instantiate a remote RUN statement to access a port type in the
persistent procedure on an AppServer and Web service and map it to a Web service
map it to a proxy persistent procedure proxy procedure handle.
handle.
RUN statement and the proxy persistent RUN statement and the Web service proxy
procedure handle to execute an internal procedure handle (Web service procedure
procedure of the remote persistent object) to invoke an operation of the port
procedure. type as a remote internal procedure.
Note: All Web service operations can be
invoked as remote internal
procedures, allowing them to be
invoked asynchronously. However,
some Web service operations can
also be invoked as remote
user-defined functions.
FUNCTION prototype statement with the FUNCTION prototype statement with the Web
proxy procedure handle and function service proxy procedure handle, and
invocation to return the value of a remote function invocation to return the value of a
user-defined function. Web service operation that the WSDL
Analyzer indicates can be invoked as a
function.
NO-ERROR option and the ERROR-STATUS NO-ERROR option and the ERROR-STATUS
system handle to trap 4GL statement errors. system handle to trap 4GL statement errors
and Web service SOAP faults.
125
OpenEdge Development: Web Services
DISCONNECT( ) method on the server handle DISCONNECT( ) method on the server handle
to logically disconnect (unbind) the server to logically disconnect (unbind) the server
object from the application service. object from the Web service.
DELETE object statement to delete object DELETE object statement to delete object
handles that are no longer needed. handles that are no longer needed.
As you can see from Table 12, you can access a Web service using the same basic 4GL element
framework used to access a session-free AppServer. The following sample code shows a
working 4GL program that accesses the TemperatureService Web service. This is an actual
public Web service whose WSDL file is available at the following location on the Internet:
http://www.xmethods.net/sd/2001/TemperatureService.wsdl
Note: While this is the URL to an actual Web service at this time of writing, the URL or
availability of any public Web service can change at any time.
126
Web Services in OpenEdge
This is a simple Web service that allows you to get the current temperature for a United States
zip code (hard-coded in the example). Here is the 4GL program that accesses it, with numbered
comments (such as, /*2*/ or /*7*/) corresponding to the ordered description that follows:
This code:
hWeatherWS To be used as the server object handle for the Web service.
hPortType To be used as the Web service proxy procedure handle to map the port
type that contains the requested Web service operation.
cTemp To receive the current temperature value for the given zip code.
2. Creates the server object on hWeatherWS to use for binding the Web service.
3. Logically binds the Web service to the server object using the CONNECT( ) method, which
specifies:
The location of the Web service WSDL file for run-time access.
The physical service and port (endpoint) through which all communications pass
between the 4GL client and the Web service.
127
OpenEdge Development: Web Services
In this example, no service and port are is explicitly specified because there is only one
valid service and port in the WSDL file. For information on the full range of binding
options for Web services, see the Chapter 9, Connecting to Web Services from the
Progress 4GL.
4. Using the RUN statement syntax, creates the Web service proxy procedure object and maps
it to the port type (TemperaturePortType) that defines the getTemp operation for the Web
service.
5. Invokes the getTemp operation as a procedure for the ZIP code location input as "01730"
and the temperature at that location output as cTemp and displayed in a message. For more
information on mapping Web service port types and invoking operations on them, see the
Chapter 10, Invoking Web Service Operations from the Progress 4GL.
6. Deletes (cleans up) the hPortType procedure object, using the DELETE PROCEDURE
statement, after it is no longer needed.
7. Unbinds the Web service from the hWeatherWS server object using the DISCONNECT( )
method on the hWeatherWS server handle.
8. Deletes (cleans up) the hWeatherWS server object, using the DELETE OBJECT statement,
after it is no longer needed.
Note: At this point, the program can use the same hWeatherWS server object to bind to
another Web service or another binding for the same Web service, perhaps to return
humidity or wind speed at a zip code location using a different port type. If it is
completely finished accessing Web services and AppServers, but has more work to
do, it might clean up by deleting the hWeatherWS server object using the DELETE
object statement.
For more information on managing Web service bindings, see the Chapter 9, Connecting
to Web Services from the Progress 4GL.
This sample shows the similarity between basic AppServer and Web service access using
synchronous interaction with the client. Another common feature between client interaction
with an AppServer and client interaction with a Web service is the ability to invoke procedures
asynchronously. For information on when and what you need to do to invoke Web service
requests asynchronously, see the Managing asynchronous requests section on page 133.
128
Web Services in OpenEdge
All of the information for writing the code in the previous example is likely to be found in the
WSDL file used to bind the Web service at run time (often accessed directly from the WSDL
URL location). If you run the WSDL Analyzer on the WSDL file to generate the interface
documentation, it generates a hyperlinked document contain information on how to connect to
and invoke operations in the Web service, such as the:
Prototypes for 4GL procedures and user-defined functions used to invoke Web service
operations for a given port type.
Any complex types defined for use in Web service operation parameters.
Other information required to use the Web service, such as the way Web service errors
(SOAP faults) are returned to the client.
For more information on running the WSDL Analyzer and the documentation that it generates,
see Chapter 8, Analyzing WSDL for Progress 4GL Access to Web Services.
Passing information in the header of each SOAP request and response message with
varying degrees of structure and typing.
For both types of information exchange, it may be necessary to access the XML of the
underlying SOAP message in order to complete the necessary exchange of information. The
following sections describe when you might need to do this and the 4GL facilities that you can
use.
129
OpenEdge Development: Web Services
As shown in the previous sample (see the Basic Web service access cycle section on page
126), the WSDL Analyzer provides sufficient documentation to code a 4GL application as a
Web service client. Often, the input, output, and return parameters of Web service operations
can be mapped from their XML Schema types directly to 4GL data types. When this is the case,
handling the data for Web service requests is no more challenging than for an AppServer remote
procedure call. The 4GL provides recommended and alternative mappings between all basic
XML Schema data types and the data types of the 4GL. If for any reason OpenEdge is unable
to map the Web service parameter and corresponding 4GL parameter, it generates a run-time
error. For information on the 4GL data type mappings to XML Schema and how they are
supported in this release of OpenEdge, see Chapter 8, Analyzing WSDL for Progress 4GL
Access to Web Services.
For more complex data interactions, where a Web service parameter is itself an aggregate of
more than one XML Schema data type (known as a complex type), you must directly access and
interpret the XML for the parameter yourself. You can do this by converting between the string
representation of the serialized XML parameter and a parsed representation, such as provided
using the Document Object Model (DOM) or Simple API for XML (SAX) parser, both
supported in the 4GL (see OpenEdge Development: Programming Interfaces). For more
information on XML complex types and how OpenEdge maps them to the 4GL, see Chapter 8,
Analyzing WSDL for Progress 4GL Access to Web Services. For more information on how
to work with complex types for Web service input and output parameters, see Chapter 10,
Invoking Web Service Operations from the Progress 4GL.
Some Web services require that you pay attention to the content of the SOAP header in the
SOAP request message, the SOAP response message, or both messages for an operation. This
can be a simple task or a complex one, depending on the Web service and its application
requirements. OpenEdge supports either situation by giving you access to the content of the
SOAP header of any SOAP request or response message.
For a SOAP request message, you can access the SOAP header at a point just after invoking the
Web service operation and just prior to when OpenEdge sends the message to the Web service.
For a SOAP response message, you can access the SOAP header after the message arrives at
your Web service client and just prior to when OpenEdge returns the results of any operation
output and return parameters to your 4GL program.
130
Web Services in OpenEdge
The 4GL allows you to set a Progress callback for either or both of the SOAP request and
response messages exchanged as part of a Web service operation. A Progress callback specifies
an internal procedure that you make available for the calling context to execute as part of a core
Progress action, in this case, sending or receiving a SOAP message. The specified internal
procedure (callback procedure) provides access to the SOAP header at an appropriate point for
a request or response message, depending on the type of callback. From within callback
procedure you can access the SOAP header using the required procedure parameter and alter the
content as allowed by the type of callback.
For more information on setting up SOAP header callback procedures, see Chapter 10,
Invoking Web Service Operations from the Progress 4GL.
A SOAP header is a container for other elements known as SOAP header entries. To access a
SOAP header and its SOAP header entries, the 4GL provides two objects: a SOAP header
object, which provides access to the header and its header entries, and a SOAP header-entryref
object that references a given SOAP header entry and its attributes. To inspect or modify the
actual content of a SOAP header entry, you must access its underlying XML. The 4GL allows
you to access the header entry XML either as a serialized XML string or as a DOM tree, much
like you access a complex type parameter (see the Handling complex operation parameters
section on page 130). Using 4GL elements that manipulate DOM trees, you can create a SOAP
header to use for an outgoing SOAP request message, inspect a SOAP header for an incoming
SOAP response message to save header entry values, or modify the SOAP response header for
use as a SOAP request header during invocation of a following Web service operation.
For information on using callbacks to work with these headers for each type of SOAP message,
see Chapter 11, Handling SOAP Message Headers in the Progress 4GL.
131
OpenEdge Development: Web Services
3. An error intentionally raised by the 4GL application (using the RETURN ERROR statement)
in one of the following procedures:
The features of SOAP header callback procedures can add complexity to the error handling for
Web service requests. For more information on managing errors for Web service requests, see
Chapter 12, Handling Errors in Progress 4GL Requests to Web Services.
For a SOAP fault, you start out by handling the ERROR condition as usual in the 4GL, whether it
is:
If the Web service returns a SOAP fault from an error detected while processing a Web service
request, OpenEdge receives the SOAP fault and turns it into a Progress error message. If the
statement that invoked the request includes the NO-ERROR option, OpenEdge also attaches the
error message to the ERROR-STATUS system handle.
You can identify this error as a SOAP fault by the content of this message (using the
GET-MESSAGE( ) method) and also by examining the object referenced by the
ERROR-OBJECT-DETAIL attribute on the ERROR-STATUS handle. If the error resulted from a SOAP
fault, this attribute references a SOAP fault object, which in turn references an optional SOAP
fault-detail object, depending on the Web service application.
If there is no SOAP fault-detail object, you can get all the information available on the SOAP
fault from the remaining attributes of the SOAP fault object and the methods of the
ERROR-STATUS system handle.
132
Web Services in OpenEdge
If there is a SOAP fault-detail object, it likely stores more information about the SOAP fault in
XML defined by the Web service. You can access this XML in much the same way you access
the XML for a SOAP header entry (see the Handling the information in SOAP headers section
on page 130). That is, you can obtain this SOAP fault information as a serialized XML string
or as a DOM tree that you interpret as required, much like accessing a complex Web service
parameter (see the Handling complex operation parameters section on page 130).
For more information on using the ERROR-STATUS system handle, the SOAP fault object handle,
and SOAP fault-detail object handle to manage SOAP faults, see Chapter 12, Handling Errors
in Progress 4GL Requests to Web Services.
You can handle an internal ERROR condition raised for invocation of a 4GL statement as usual
by trapping it with the ON ERROR option or inspecting the ERROR-STATUS system handle directly
after invoking the request with the NO-ERROR option.
Within a SOAP header callback procedure you can invoke the RETURN ERROR statement as
though it were part of the 4GL statement that generated the request so it can be trapped using
standard 4GL error handling. However, for an asynchronous Web service request, an unhandled
internal error or RETURN ERROR statement invoked in the SOAP response header callback
procedure is propagated from the callback to the event procedure, rather than the point
following invocation of the asynchronous request (see the Managing asynchronous requests
section on page 133).
One reason to invoke RETURN ERROR in a SOAP header response callback procedure is to
respond to a SOAP header fault. You must determine that there is an error in the header of a
SOAP response message by inspecting the header XML. OpenEdge does not otherwise detect
a SOAP header fault returned from a Web service.
133
OpenEdge Development: Web Services
When it is time to handle the PROCEDURE-COMPLETE event, the specified event procedure
executes and manages any OUTPUT or INPUT-OUTPUT parameters that were passed to the
asynchronous request when it was invoked. These parameters are returned as INPUT parameters
to the event procedure, which can store the parameter values or otherwise process the result for
use by the mainline program. The mainline program can periodically inspect an asynchronous
request object handle (also available to the event procedure), which it sets during invocation of
the request, in order to determine if the specified asynchronous request has completed. If the
request has completed, the program can then make use of the results as provided by the internal
event procedure that handled them.
The model for asynchronous Web service request invocation is very similar to the model for
asynchronous remote procedure invocation on a session-free AppServer. However, the two
models are not exactly the same and have some differences. This section describes how the two
models differ as well as their basic similarities. For information on the model for invoking
asynchronous requests on a session-free AppServer, see OpenEdge Application Server:
Developing AppServer Applications.
Note: For certain features that support Web service requests in the 4GL (for example, error
handling), the feature behavior might differ depending on whether the request is
synchronous or asynchronous. The documentation describes these differences in the
chapters where the features are described.
You can only invoke an asynchronous Web service request as a procedure using the RUN
statement. This means that if a Web service operation is invoked as a user-defined function, you
can only invoke it synchronously, because all operations that have a return value can only be
invoked as user-defined functions, where the value must be made available at the point of
invocation. This is consistent with how OpenEdge supports the invocation of asynchronous
requests on the AppServer (remote procedures only).
Order of completion
Similar to a session-free AppServer request, the order of completion for an asynchronous Web
service request is determined solely by the Web service. The manner in which the 4GL client
send and response queues for an asynchronous request handle messages is identical for both
session-free asynchronous AppServer requests and asynchronous Web service requests. That is,
if the 4GL invokes multiple asynchronous Web service requests, the order of their completion
cannot be determined on the Web service or session-free AppServer client. So, you must write
your mainline program, and indeed your asynchronous event procedures, to make no
assumptions about the order in which multiple asynchronous Web service requests complete.
134
Web Services in OpenEdge
OpenEdge maintains an asynchronous request object for each asynchronous request, which
maintains the status of the request, including whether and how it has completed (successfully or
unsuccessfully). The handle to this asynchronous request object is available to the mainline
program and to the event procedure for an asynchronous Web service request in the same way
as for an asynchronous AppServer request. The Web service server object handle maintains its
own chain of pending asynchronous request object handles (FIRST-ASYNC-REQUEST and
LAST-ASYNC-REQUEST attributes), and the PROCEDURE-NAME attribute on each asynchronous
request object handle returns the name of its Web service operation as it returns the name of the
remote procedure executed for an asynchronous AppServer request.
Table 13 shows attributes on the asynchronous object handle with special meaning for Web
services.
ERROR Returns TRUE within the context of the event procedure when:
You invoke the RETURN ERROR statement within the
context of an associated SOAP response header callback
procedure.
A SOAP fault is returned for the asynchronous Web
service request.
135
OpenEdge Development: Web Services
SERVER Returns a handle to the server object for the Web service where
the asynchronous request is executed.
Results handling
A few differences exist in the results returned for an asynchronous Web service request
compared to an asynchronous AppServer request, as shown in Table 14.
ERROR-STATUS system handle If the ERROR attribute of the asynchronous request object
handle is set to TRUE because of a SOAP fault, the
ERROR-STATUS:ERROR-OBJECT-DETAIL attribute
references a SOAP fault object with information on the
SOAP fault (see the Handling Web service errors
section on page 132).
STOP condition The client can raise the STOP condition by executing the
CANCEL-REQUESTS( ) method on the Web service server
object handle. All outstanding Web service requests are
handled in a similar manner to those on an AppServer,
except that for any currently executing Web service
requests, the result is undefined. OpenEdge disconnects
from all ports to currently executing Web service
requests, and the exact response depends on how the
Web service responds to the lost connection.
136
Part II
Clients Accessing Progress 4GL Web
Services
Chapter 2, WSDL and Web Service Objects in Progress 4GL Web Services
Chapter 3, Session Models and Object IDs in Progress 4GL Web Services
Chapter 4, General Client Programming Model for Progress 4GL Web Services
Chapter 5, Sample Code with SOAP Messages for Progress 4GL Web Services
This chapter describes how Open Client objects are represented as Web service objects in the
WSDL for 4GL Web services and some of the requirements for access 4GL Web services using
WSDL as outlines in the following sections:
Read the WSDL file to identify the specified Web service operations, then code the client
application to directly create, send, and receive the SOAP messages over HTTP required
to invoke and handle the responses from these operations. Even with the help of SOAP and
HTTP libraries, this requires complex coding for simple operations.
Provide the WSDL file as input to a client development tool that generates a client
interface, which shields you from many of the complexities of HTTP and SOAP. A client
interface provides the native language API required by the client application to access the
Web service. It contains callable units of code written in the client development language
that ultimately invoke the operations specified in the WSDL. The code in this interface
knows how to create, send, and receive the SOAP over HTTP required to invoke and
handle the responses from these operations. Using the client interface, you only need to
code the client application to invoke these operations in the development language, with
minimal regard for the underlying SOAP management that the interface provides.
In either case, you will also need to consult any user documentation provided by the Web
service application developer that explains the programming model for the Web service and
how to access its operations.
22
WSDL and Web Service Objects in Progress 4GL Web Services
Hosting it with a WSA to which it is deployed using the Web services tools.
While the Web service developer can use any available technique to provide a
Web-services-tools-defined WSDL file, they can host the file on a network using a WSA by
deploying the Web service using the Web services tools. This deployed WSDL file resides at a
URL determined by the WSA installation and other information specified for the Web service
at deployment. Once the Web service is deployed, the WSA administrator can make the WSDL
available by enabling access to WSDL listings on the network. For more information on Web
service deployment, see the Web service chapters of OpenEdge Application Server:
Administration.
To obtain a WSDL file deployed to a WSA instance, you can download it over the network
through its URL, specified using the following syntax:
Syntax
http[s]://host:port[/web-server-context]/wsa-webapp-context/wsa-instance/
wsdl?targetURI=web-service-name
For example, here is a WSDL retrieval URL for a Web service with the friendly name,
OrderInfo, that is deployed to a WSA instance (wsa1) running in the WSA Web application
context (wsa):
http://servicehost:80/wsa/wsa1/wsdl?targetURI=OrderInfo
23
OpenEdge Development: Web Services
For more information on the syntax of the WSDL retrieval URL, see the chapters on the WSA
in OpenEdge Application Server: Administration.
Note: As an aid for developing client code to test Web services under development, the Web
service developer can optionally generate a WSDL file from ProxyGen when generating
versions of the Web service definition prior to deployment. This file is written to the
generation output directory specified in ProxyGen and can be used to create client
interface prototypes for reference during test development. For more information, see
OpenEdge Development: Open Client Introduction and Programming.
For more information on the Open Client object model and its architecture, see OpenEdge
Development: Open Client Introduction and Programming. For more information on how
object IDs are used in different session models, see Chapter 3, Session Models and Object IDs
in Progress 4GL Web Services. For more information on how the Open Client object model
supports Web services built using OpenEdge, see Chapter 4, General Client Programming
Model for Progress 4GL Web Services.
Object representation
WSDL does not have an inherent concept of objects for encapsulating operations. However,
Progress 4GL Web services follow common usage in representing each Web service object
within a unique namespace of the WSDL file. Typically, interface generators code each such
object defined in the WSDL file as a corresponding object in the client interface. However, the
interface generator on a particular client platform ultimately determines how each WSDL object
is represented in the client development language.
24
WSDL and Web Service Objects in Progress 4GL Web Services
Object binding
In addition to defining the Web service interface, the WSDL file also specifies how this
interface is bound to the application server that executes the operations of the Web service. For
Progress 4GL Web services, this binding information specifies how to generate and handle
SOAP messages exchanged over HTTP between the client and WSA instance that manages the
Web service. This includes information to identify the Web service and its WSA instance, as
well as to format and send the SOAP messages. The Web service deployer specifies this binding
and implementation information (deployment information) during Web service deployment.
Deployment information
This deployment information consists of the data stored in WSDL elements as follows:
Web service namespace A namespace used to uniquely identify the Web service to the
WSA instance where the Web service is deployed. In the WSDL, this value is specified by
the targetNamespace attribute of the <definitions> element. It is typically specified as
a Universal Resource Identifier (URI), usually in the form of a Universal Resource
Locator (URL) or Universal Resource Name (URN). The value can be specified in
ProxyGen, during Web service definition, or in Progress Explorer, during Web service
deployment.
WSA URL The URL for the WSA instance where the Web service is deployed, and
that forms the root for all URLs that access the Web services it manages. In the WSDL,
this is specified by the location attribute of the <soap:address> element within the
<services> element.
SOAP action A string (if specified) that the client application must place in the
SOAPAction HTTP header when it invokes operations on the Web service. In the WSDL,
this value is specified using the soapAction attribute of the <soap:operation> element,
and the value is included in the SOAPAction header of all HTTP messages that transport
SOAP messages for the Web service.
The SOAPAction HTTP header is normally required for all HTTP messages that carry
SOAP messages and is used by intervening security servers (such as firewalls) to
determine if each HTTP message is allowed to pass through to its destination. The default
is a blank string, but can be any string specified at deployment that is required by the
intervening security servers on the network.
25
OpenEdge Development: Web Services
SOAP format Two string values that specify the format of SOAP messages exchanged
between the client and the Web service. In the WSDL, these are specified by the style
attribute in the <soap:binding> and <soap:operation> elements, and by the use attribute
in the <soap:header>, <soap:body>, and <soap:fault> elements. While these values are
specified in many places within the WSDL, the same style and use values are used
everywhere in the file, ensuring that all SOAP messages generated for the Web service use
the same SOAP format. For more information on SOAP formats, see the SOAP message
formats section on page 26.
For more information on specifying this deployment information in a WSDL, see OpenEdge
Development: Open Client Introduction and Programming for the optional WSDL typically
used for development testing, and see the Web service deployment chapters in OpenEdge
Application Server: Administration for the WSDL deployed to a WSA instance. For more
information on how the WSDL file specifies this information, see the WSDL element
overview section on page 29.
Usually, client interfaces expose this request/response pair as a single object method. When the
client executes the method, the underlying interface sends a SOAP request message containing
any method input parameters and receives a SOAP response message containing any method
output parameters and any return value.
26
WSDL and Web Service Objects in Progress 4GL Web Services
WSDL/SOAP
attribute Value Description
27
OpenEdge Development: Web Services
WSDL/SOAP
attribute Value Description
In practical terms, there is little difference between using RPC or Document style when
exchanging request/response messages, as is typical with Web services. The most significant
difference in message structure is in the choice of use, Encoded (SOAP encoding) or Literal.
SOAP encoding allows for a simpler representation of complex, object-oriented data structures
than is possible with Literal encoding. However, Document/Literal messages have the
advantage that they can be validated by XML Schema.
28
WSDL and Web Service Objects in Progress 4GL Web Services
RPC/Encoded The client interface object method normally has the same function
signature as the 4GL procedure/function. This is possible because the
WSDL for RPC/encoded includes a parameterOrder attribute on
each request/response pair (operation). A return value (result) is
always present in the response message for a user-defined function. A
return value (result) is present in the response message for a procedure
only if specified in ProxyGen (mapped to the 4GL RETURN-VALUE).
Document/Literal The client interface object method might not have the same function
signature as the 4GL procedure/function. This is because the WSDL
for Document/Literal does not support the parameterOrder attribute.
The client toolkits generally create a method signature with the
parameters of the request message followed by the parameters of the
response message. A return value (result) is always present in the
response message for both procedures (mapped to the 4GL
RETURN-VALUE) and user-defined functions. The client interface can
represent this return value as a return value on the method or as an
output parameter named "result", depending on the client platform.
29
OpenEdge Development: Web Services
Thus, all Web-services-tools-generated WSDL files follow the W3C WSDL 1.1 specification
and include the element sections listed in Table 23.
Section Description
types Defined by one occurrence of the <types> element. Each Web service
object has its own schema (<schema> element) in the types section that
specifies all the <complexType> element definitions that the object requires,
including any object ID, and any Progress temp-tables. There is a separate
schema in the types section that specifies the <complexType> definition for
the SOAP fault <detail> element. Note that definitions for built-in XML
Schema data types are not listed in the types section. The elements in the
message section use these types section elements, as required, to define the
input (request) and output (response) parameters with these data types.
The types section also defines the object schema differently, depending on
the SOAP format of the Web service:
RPC/Encoded Temp-tables are represented as SOAP arrays. There
is no indication if a scalar parameter can be null (the 4GL Unknown
value, as specified in ProxyGen), though it can be supported by the
Web service application.
RPC/Literal Temp-tables are represented as <complexType>
element definitions. There is no indication if a scalar parameter can be
null (the 4GL Unknown value, as specified in ProxyGen), though it
can be supported by the Web service application.
Document/Literal Temp-tables are represented as <complexType>
element definitions. Operation request and response messages are also
defined as <complexType> element definitions, because there is no
inherent communications model supported by the Document style
(unlike RPC style, which inherently supports request/response
messaging). The schema indicates if a scalar parameter can be null (the
4GL Unknown value, as specified in ProxyGen) using the nillable
attribute.
210
WSDL and Web Service Objects in Progress 4GL Web Services
Section Description
message Defined by one or more <message> elements. This section defines the
request/response message pair for all operations (Progress procedures or
user-defined functions), as well as the built-in object management
operations supported by each Web service object. The parameters for each
operation are grouped in separate message definitions for input and output.
For Document/Literal format, the parameters are also defined with
reference to <schema> element definitions in the types section. In addition,
the message section defines the SOAP fault message returned by every
operation on occurrence of a Web service error.
For every operation, there is an input (or request) message, which is sent
from the client (through the WSA) to the AppServer, and there is an output
(or response) message, which is sent from the AppServer (through the
WSA) to the client. For RPC formats, the input parameters for each
operation appear in a single named message definition, and the output
parameters for each operation appear in a single, correspondingly named,
"Response" message definition. The WSDL defines input/output
parameters by defining the same parameter in both the input and
"Response" messages. Any return parameter, if present, always appears as
the first parameter in the "Response" message definition. For a
Document/Literal WSDL, the message definitions point to a
<complexType> element defined in the types section for each message.
portTypes Defined by one or more <portType> elements. This section defines the
signatures of all operations using the message definitions from the message
section. There is a separate <portType> element defined for each Web
service object.
Each <portType> element defines the operations for the specified object,
using a separate <operation> element to define each operation. Each such
<operation> element names the operation and references its input, output,
and fault message definitions from the message section.
211
OpenEdge Development: Web Services
Section Description
bindings Defined by one or more <binding> elements. This section defines the
SOAP bindings for all Web service operations. SOAP bindings specify
information that indicates how calls to Web service operations are
converted to SOAP request/response messages. The information for SOAP
bindings is specified during Web service deployment (see the Object
binding section on page 25) and determines the format and content of the
envelope, header, and body of all SOAP messages generated for the Web
service. There is a separate <binding> element defined for each Web
service object. Each <binding> element contains <operation> elements
that map directly to the <operation> elements used to define the operation
signatures in a corresponding <portType> element. The Bindings section
<operation> elements thus specify the SOAP binding for each element of
the corresponding operation signature defined by the portTypes section
<operation> elements. Note that while some binding information, such as
soapAction attribute and SOAP format (style and use attributes), is
specified individually for the elements of each operation, the same values
are used to bind all operations of the Web service.
service Defined by one occurrence of the <service> element. This section defines
the deployed location of all Web service objects based on the root URL for
the WSA instance that hosts the Web service. The <service> element
includes one <port> element for each Web service object whose bindings
are defined in the Bindings section. The same WSA root URL is defined for
each object, as specified by the location attribute of the <soap:address>
element.
For more information on WSDL and its meaning, see the WSDL specification at the following
URL:
http://www.w3.org/TR/wsdl
For information on the XML Schema definitions supported by the OpenEdge for 4GL Web
services, see Chapter 4, General Client Programming Model for Progress 4GL Web Services.
This book also provides additional WSDL examples.
212
3
Session Models and Object IDs in
Progress 4GL Web Services
When a Web service is defined in ProxyGen, the Web service developer must select a session
model for the Web service, and the selected model must match the session model used to
implement the Web service application on the AppServer. The choice of session model affects
how the AppObject for a Web service is defined in the WSDL, how the WSA manages the Web
service at run time, and how the client must access the Web service objects.
Session managed The Web service client maintains a persistent connection to the
AppServer, maintaining session context between requests for a single client application.
This allows a client to carry out complex transactions that span multiple requests, but often
requires extra code management, on the part of the client, for each request.
Session free The Web service client sends requests without any connection to an
AppServer. This allows more clients to simultaneously access the Web service with
minimal code management, but each request returns a complete result that has no certain
dependency on the results of any previous requests.
Note: Session-free Web services using ProcObjects can maintain limited session context
across multiple requests, but ProcObjects are not recommended for use by
session-free Web services. For more information, see the How session models
affect Web service objects section on page 34.
For more information on how the AppServer supports session models, see OpenEdge
Application Server: Developing AppServer Applications. This section, and other sections in this
chapter, describe the requirements for programming clients to access Web services running in
these session models.
32
Session Models and Object IDs in Progress 4GL Web Services
Note: SubAppObjects and ProcObjects have limited utility in the session-free model and
generally should not be defined for session-free Web services. See the How session
models affect Web service objects section on page 34, for more information.
The WSA creates a unique object ID when ever it instantiates one of these objects at the request
of a client when it connects an AppObject to a session-managed Web service or when it creates
a SubAppObject or ProcObject for any Web service. The WSA sends this object ID back to the
client in a SOAP response header. Once received, the client application must send the same
object ID to the WSA in the SOAP request header for every operation that it invokes on the
specified object. The value of this object ID must be identical to the original value returned
when the WSA instantiated the object.
The mechanism used by the client application to retrieve object IDs from the SOAP response
and to send object IDs in the SOAP request depends on the client platform. Some platforms
handle SOAP header information automatically and transparently to the application program.
Others require you to explicitly obtain the object ID from the SOAP response message and send
it in the next appropriate SOAP request message in a manner determined by the client platform.
For session-managed Web services, these object IDs allow each client to maintain
communications with its own set of Web service objects, and thus interact with the context
maintained by the AppServer for these objects. For session-free Web services, these object IDs
allow the use of SubAppObjects and ProcObjects, when it is necessary to do so.
33
OpenEdge Development: Web Services
Thus, for session-managed Web service objects, the AppServer can maintain session context
between requests, enabling the possibility of fine-grained, multi-request transactions on a
server-side database. For session-free Web service AppObjects and SubAppObjects, there is no
single AppServer to maintain session context, and any transactions on a server-side database
must be course-grained so that they begin and end for each request before the AppServer returns
the response to the client.
Note: SubAppObjects provide no additional functionality for a session-free Web service that
is not already provided by the AppObject, except to organize Web service operations
into developer-defined categories, much like using folders to organize files. However,
using session-free SubAppObjects adds complexity to the client application required to
manage the object IDs.
34
Session Models and Object IDs in Progress 4GL Web Services
Any ProcObject of a session-free Web service does maintain context on a single AppServer that
can be used to manage finer-grained, multiple-request database transactions. But because a
ProcObject reserves its AppServer connection until the object is released, that resource is not
available for other requests on objects of the session-free Web service.
Note: Progress Software Corporation recommends that Web service developers avoid defining
any ProcObjects for session-free Web services. Each instantiated ProcObject degrades
the performance of a session-free Web Service by taking AppServer connections out of
the connection pool that might otherwise be used by all other requests to the Web
service.
35
OpenEdge Development: Web Services
36
4
General Client Programming Model for
Progress 4GL Web Services
The starting point for developing a Web service client application is the WSDL for the Web
service. A typical client application development process consists of the following tasks, each
described in a section of this chapter:
Write your own code to send and receive the SOAP messages as specified in the WSDL.
Generate client interfaces directly from the WSDL using a Web service client toolkit.
Some of the client toolkits available today include:
Microsoft .NET
Apache Axis
Iona XMLBus
Progress 4GL
Most of this chapter assumes you are using a similar client toolkit to generate client interfaces.
These proxies provide an API that generally appears as an interface to application functions, but
that actually provides an interface to messaging operations that hide the complexity of
exchanging SOAP messages over HTTP. (For information on SOAP over HTTP, see the
Handling communications with Web services section on page 414.)
Each client toolkit generates these proxies in a unique manner, but most create objects with
methods. Usually, they create one object for each <portType> and one object for each
<complexType> specified in the WSDL.
These toolkits might generate methods to handle SOAP messages in any of the following ways
for each Web service operation:
Providing a request method with the response message as an output parameter or return
value.
Whatever differences exist in how client platforms generate and interpret SOAP messages, the
Web services tools generate WSDL that allows all clients to generate and interpret all SOAP
messages required to access Web-services-tools-defined Web services.
42
General Client Programming Model for Progress 4GL Web Services
Method signatures
For information on how some of these components appear in WSDL and SOAP, see Chapter 5,
Sample Code with SOAP Messages for Progress 4GL Web Services.
Method signatures
Client interface method signatures typically map to Progress 4GL prototypes as follows:
RPC/Encoded Method signatures normally match the prototypes in the Progress 4GL.
43
OpenEdge Development: Web Services
Always for user-defined functions. The result will be either the method return value
or the first output parameter.
Always for procedures. The result will either be the method return value or the first
output parameter. If specified in ProxyGen, the result will be the 4GL RETURN-VALUE.
If the 4GL RETURN-VALUE is not specified in ProxyGen the result is a null string.
44
General Client Programming Model for Progress 4GL Web Services
For every TABLE-HANDLE parameter within a Web service object, there is a single object
representing all TABLE-HANDLEs.
In both request messages (input) and response messages (output), the schema of the
TABLE-HANDLE must accompany the data.
For every input TABLE-HANDLE, you must include the schema of the TABLE-HANDLE in the
form of an XML Schema followed by the data in the form of an XML document fragment.
For every output TABLE-HANDLE, you must parse the XML Schema and data in the SOAP
response message.
Caution: For any session model, failing to call the release method on any Open Client object
that a Web service client uses (except a session-free AppObject) leaves any resources
reserved for that object unavailable for other uses. In effect, this creates a memory
leak in the WSA. The Web service deployer can manage these orphaned resources
by property settings on the Web service. For more information, see the Web service
properties reference sections of OpenEdge Application Server: Administration.
45
OpenEdge Development: Web Services
Before invoking any other method on a session-managed AppObject, you must instantiate
(create) and call a connect method on the object to establish a connection to the AppServer
context. The client must obtain the object ID for the AppObject after it is created. After
that, you can invoke any method on the AppObject. Calls to all AppObject methods are
sequential (calls follow one another) using the established connection. You must call the
release method on an AppObject when you no longer need the object (Web service).
You can create ProcObjects and SubAppObjects using class factory methods on the
AppObject or create ProcObjects on another SubAppObject. Once created, all objects
share the same connection. This connection terminates only after you have called the
release method on all Web service objects that you create. You must call each object's
release method when you no longer need the object.
You can call methods on a ProcObject as soon as you create it and after the client obtains
the object ID for it. Calls to all ProcObject methods (internal procedures and user-defined
functions) are sequential using the connection established by the AppObject. You must
call the release method on a ProcObject when you no longer need the object.
You can call methods on a SubAppObject as soon as you create it and after the client
obtains the object ID for it. Calls to all SubAppObject methods are sequential using the
connection established for the AppObject. You must call the release method on a
SubAppObject when you no longer need the object.
Once connected to a session-managed Web service, you must always send object IDs with
each method call.
46
General Client Programming Model for Progress 4GL Web Services
After you instantiate (create) a session-free AppObject, you can call any method on the
object and you never connect to an AppServer. Calls to all AppObject methods are
executed in parallel (calls execute simultaneously) using the available AppServer
connections in the Web service connection pool (a pool of AppServer connections
maintained for each session-free Web service). Each call to the AppObject is independent
of every other call and can come from any client, in any order.
You can create SubAppObjects and ProcObjects using class factory methods. Although no
connection is established for the AppObject, SubAppObjects and ProcObjects are
maintained uniquely for each client, and ProcObjects reserve their own AppServer
connections from the Web service connection pool. You must call each object's release
method when you no longer need the object and to return each objects AppServer
connections to the connection pool.
You can call methods on a ProcObject as soon as you create it and after the client obtains
the object ID for it. Calls to all ProcObject methods (internal procedures and user-defined
functions) are sequential using the connection established for the ProcObject. You must
call the release method on a ProcObject when you no longer need the object and to return
the objects AppServer connection to the connection pool.
You can call methods on a SubAppObject as soon as you create it and after the client
obtains the object ID for it. Calls to all SubAppObject methods are executed in parallel.
You must call the release method on a SubAppObject when you no longer need the object,
to remove it from the list of client SubAppObjects maintained by the WSA and to return
its AppServer connection to the connection pool.
Once an object is created, you must always send object IDs with each method call on a
session-free SubAppObject or ProcObject, but you never send object IDs on method calls
to a session-free AppObject.
47
OpenEdge Development: Web Services
AppObject The name of the AppObject for which the named item is defined or
associated.
SubAppObject The name of the SubAppObject for which the named item is defined or
associated.
ProcObject The name of the ProcObject for which the named item is defined or
associated.
ProcName The name of a method that executes a Progress 4GL non-persistent procedure
or internal procedure on the AppServer.
FuncName The name of a method that executes a Progress 4GL user-defined function
on the AppServer.
Many of the methods referenced in this section are standard methods from the Open Client
programming model. The precise syntax for invoking these methods differs depending on the
client development language used to access Web services; however, the basic signatures for
these methods are the same in all languages. For more information on how these methods are
used in Web service clients, see Chapter 5, Sample Code with SOAP Messages for Progress
4GL Web Services.
48
General Client Programming Model for Progress 4GL Web Services
Connect_AppObject (...)
This method must be executed before any other method can be called. The SOAP response
header returned by this method contains an AppObjectID element whose value must be sent in
the SOAP request header for all other methods invoked on this AppObject.
Release_AppObject ( )
Once this method is executed, no other methods on the AppObject can be called. The SOAP
request header must contain the value of the AppObjectID element. If other objects
(SubAppObjects or ProcObjects) are using the same connection, the connection is not
terminated until the corresponding release method is called on every object.
CreateAO_SubAppObject ( )
This method must be executed before calling any other methods on the SubAppObject. The
SOAP request header must contain the value of the AppObjectID element. The SOAP response
header returned by this method contains a SubAppObjectID element whose value must be sent
in the SOAP request header for all methods invoked on this SubAppObject.
Use this method to create a ProcObject and execute the corresponding persistent procedure:
CreatePO_ProcObject (...)
49
OpenEdge Development: Web Services
This method must be executed before calling any other methods on the ProcObject. The SOAP
request header must contain the value of the AppObjectID. The SOAP response header returned
by this method contains a ProcObjectID whose value must be sent in the SOAP request header
for all methods invoked on this ProcObject.
ProcName (...)
The SOAP request header must contain the value of the AppObjectID element.
ProcName (...)
Because no context is maintained for a session-free AppObject, calls to these methods require
no object IDs to be sent in the SOAP request header.
CreateAO_SubAppObject ( )
Note: SubAppObjects are not recommended for use in session-free Web services.
410
General Client Programming Model for Progress 4GL Web Services
This method must be executed before calling any other methods on the SubAppObject. The
SOAP response header returned by this method contains a SubAppObjectID element whose
value must be sent in the SOAP request header for all methods invoked on this SubAppObject.
Because no context is maintained for a session-free AppObject, calls to this method require no
object ID to be sent in the SOAP request header.
Use this method to create a ProcObject and execute the corresponding persistent procedure:
CreatePO_ProcObject (...)
Note: ProcObjects are not recommended for use in session-free Web services.
This method must be executed before calling any other methods on the ProcObject. The SOAP
response header returned by this method contains a ProcObjectID element whose value must
be sent in the SOAP request header for all methods invoked on this ProcObject. Because no
context is maintained for a session-free AppObject, calls to this method requires no object ID
to be sent in the SOAP request header.
ProcObject methods
Use this method to terminate and remove the context of the persistent procedure that is managed
by the ProcObject:
Release_ProcObject ( )
411
OpenEdge Development: Web Services
Once this method is executed, no other methods on the ProcObject can be called. The SOAP
request header must contain the value of the ProcObjectID element. If other objects (AppObject
or SubAppObjects) are sharing the same connection, the connection does not terminate until
you call the release method for all the objects sharing the connection.
Call a ProcName method on the ProcObject to execute a corresponding internal procedure in the
persistent procedure that is managed by the ProcObject:
ProcName (...)
The SOAP request header must contain the value of the ProcObjectID element.
FuncName (...)
The SOAP request header must contain the value of the ProcObjectID element.
SubAppObject methods
Release_SubAppObject ( )
Once this method is executed, no other methods on the SubAppObject can be called. The SOAP
request header must contain the value of the SubAppObjectID element. If other objects
(AppObject or ProcObjects) are sharing the same connection, the connection does not terminate
until you call the release method for all the objects sharing the connection.
Use this method to create a ProcObject and call the corresponding persistent procedure:
CreatePO_ProcObject (...)
412
General Client Programming Model for Progress 4GL Web Services
This method must be executed before calling any other methods on the ProcObject. The SOAP
request header must contain the value of the SubAppObjectID element. The SOAP response
header returned by this method contains a ProcObjectID element whose value must be sent in
the SOAP request header for all methods invoked on this ProcObject.
ProcName (...)
The SOAP request header must contain the value of the SubAppObjectID element.
413
OpenEdge Development: Web Services
Web services
Web server/JSE
Web service
clients
Post (SOAP)
Object manager
Java
Java
Web services
Java
VB.NET
VB.NET
adapter
VB.NET
listener
C#.NET
HTTP
C#.NET
Progress
Response (SOAP)
WSDL
WSDL
WSDL WSDL
WSAD
WSDL
files files
Note: The WSDL file defines the available Web service methods at development time, while
the WSAD file defines the mapping between a Web service method and AppServer
procedure at run time. For more information on how these files function in the 4GL Web
services development environment, see Chapter 1, Web Services in OpenEdge.
414
General Client Programming Model for Progress 4GL Web Services
Each SOAP message is an XML document that consists of the following ordered elements:
1. SOAP Envelope (mandatory) Used to define the namespaces used in the document.
2. SOAP Header (optional) Used to send the object ID, when required for the object.
3. SOAP Body (mandatory) Contains the data and SOAP formatting information. For a
SOAP request message, the body contains the method name and its input parameter
values. For a SOAP response message, the body contains one of the following sets of
components:
Any method output parameters and any return value for a successful request.
The remainder of this chapter contains many examples of SOAP messages, with all of these
elements.
Session-managed AppObjects
ProcObjects
SubAppObjects
Each client toolkit provides different means to access SOAP headers. In some environments,
such as Microsoft .NET, the interface automatically moves information from the response
header to subsequent request headers within the same object. You do have to do a little work to
move the information between objects (for example, copying a ProcObject ID from the
AppObject that creates a ProcObject to the ProcObject itself). In other environments, you are
responsible for extracting the information from the response header and sending it in the SOAP
headers for subsequent requests.
415
OpenEdge Development: Web Services
The WSDL defines the SOAP elements that hold the object ID using a <complexType>
declaration in the types section for each Web service object schema that requires it. The headers
in the SOAP messages that are sent and received for a given object then contain the required
object ID values.
<types>
<schema elementFormDefault="unqualified"
targetNamespace="urn:OrderSvc:OrderInfo"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="OrderInfoID">
<sequence>
<element name="UUID" type="xsd:string"/>
</sequence>
</complexType>
</schema>
</types>
The WSDL schema definition for each Web service object (except a session-free AppObject)
defines the SOAP header element that contains the value of its object ID as a <complexType>.
As shown in the example, the name for the SOAP header element is the name of the
<complexType>, in this example, "OrderInfoID". The name of the element that contains the
value of the object ID is "UUID", defined as an element of type "xsd:string". This definition
is the same for the object IDs of all Web service objects, differing only in the name of the object
ID element.
416
General Client Programming Model for Progress 4GL Web Services
<soap:Header>
<t:OrderInfoID xmlns:t="urn:OrderSvc:OrderInfo"
soap:encodingStyle=http://schemas.xmlsoap.org/soap/encoding/>
<UUID xsi:type="xsd:string">2e62cab6b81150d5:167f64e:f295e997b0:
-8000;<OrderInfo|PX-000001|AO>;M/IryPm3piDcF/W5DsH4GA==</UUID>
</t:OrderInfoID>
</soap:Header>
The value of the object ID appears in bold, contained by the <UUID> element.
The same basic <OrderInfoID> element contains the object ID in the SOAP response header
that initially returns the OrderInfoID object ID, when the object is created, and is required in
any subsequent SOAP request header sent by methods invoked on the OrderInfo object.
Thus, for all Web service objects that require object IDs, your client application must parse out
the object ID value in the <UUID> element contained by the object ID element (<OrderInfoID>
in the example) and returned in the SOAP response header at object creation, whether it happens
automatically or you must program it explicitly. Similarly, for every SOAP request sent by a
method invoked on this same object, your client application must create an object ID element
containing a <UUID> element that holds this identical object ID value in the SOAP header of the
request message.
417
OpenEdge Development: Web Services
Chapter 5, Sample Code with SOAP Messages for Progress 4GL Web Services
For examples of client applications that handle object IDs, see the sample 4GL Web service
applications installed with OpenEdge. For information on how to access these applications, see
Chapter 6, Sample Progress 4GL Web Services and Client Applications.
Table 41 lists the data type mappings for parameters between Progress 4GL and XML data
types. Most of these parameters can also be passed as arrays.
418
General Client Programming Model for Progress 4GL Web Services
CHARACTER xsd:string
COM-HANDLE xsd:long
DATE xsd:date
DATETIME xsd:dateTime
DATETIME-TZ xsd:dateTime
DECIMAL xsd:decimal
LOGICAL xsd:boolean
LONGCHAR1 xsd:string
MEMPTR1 xsd:base64Binary
RAW xsd:base64Binary
ROWID xsd:base64Binary
WIDGET-HANDLE xsd:long
complexType
TABLE (static temp-table)2
complexType (<any>)
TABLE-HANDLE (dynamic temp-table)2
1 LONGCHAR and MEMPTR data types are designed to support very large strings of data. Use of these data types
as parameters in Web services can result in a serious performance impact.
2
TABLE and TABLE-HANDLE data types cannot be passed as arrays. For more information on passing arrays,
see the Array parameters section on page 420.
Note: The Progress 4GL parameter type BUFFER, DATASET, or DATASET-HANDLE is not
supported.
419
OpenEdge Development: Web Services
Array parameters
The WSA supports arrays (extents) as parameters for the data types listed in Table 41. These
data types are mapped to XML Schema data types as indicated in this. In the WSDL document,
the XML Schema data types are housed in a complex structure whose type definition depends
on the encoding style. For details and examples of array representation for each WSDL style/use
format, see the Array mapping in WSDL documents section on page 421.
Note: TABLE (temp-table) and TABLE-HANDLE (temp-table handle) parameters cannot be array
parameters.
Fixed arrays
In cases where the Progress 4GL refers to fixed-array parameters, only the Document/Literal
WSDL style/use format represents the fixed size of the array; the RPC/Encoded and
RPC/Literal formats represent all arrays as unbounded. Therefore, when using either of the RPC
WSDL style formats, the developer must know the size of each array parameter that is expected.
The WSA returns a SOAP fault if the array sizes do not match.
The Document/Literal schema represents each parameter individually, and thus specifies the
size for each fixed array parameter. See the examples in the Array mapping in WSDL
documents section on page 421.
420
General Client Programming Model for Progress 4GL Web Services
RPC/Encoded
RPC/Literal
Document/Literal
The description of each WSDL format includes an example. The example shows the schema
information in the types section, plus the message sections for request and response, for a
4GLprocedure with the following signature in the CustomerAO AppObject:
/* arraySample*/
DEFINE INPUT PARAMETER names AS CHARACTER EXTENT.
DEFINE INPUT PARAMETER hireDates AS DATETIME EXTENT.
DEFINE OUTPUT PARAMETER quotas AS INTEGER EXTENT 12.
RPC/Encoded
For the RPC/Encoded format, an array parameter is represented as a SOAP array complexType
in an XML Schema type definition.
<complexType name="ArrayOfXMLType">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref=soapenc:arrayType" wsdl:arrayType="XMLType[]"/>
</restriction>
<complexContent>
</complexType>
The WSDL file contains a separate schema for each object defined in ProxyGen. Each such
schema includes one SOAP array complexType definition for each data type used as an array
parameter for any procedure or function in that object. For example, if the 4GL defines one or
more parameters in the object with the data type CHARACTER EXTENT, the schema includes a
complexType named ArrayOfString.
421
OpenEdge Development: Web Services
The RPC/Encoded WSDL document for the arraySample procedure shown at the beginning of
this section includes the following types and message sections:
<wsdl:types>
<schema targetNamespace="urn:tempuri-org:CustomerAO"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="unqualified">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<complexType name="ArrayOfInt">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="xsd:int[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="ArrayOfDateTime">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="xsd:dateTime[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="ArrayOfString">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="xsd:string[]"/>
</restriction>
</complexContent>
</complexType>
</schema>
</wsdl:types>
.
.
.
<wsdl:message name="CustomerAO_arraySample">
<part name="names" type="S1:ArrayOfString"/>
<part name="hireDates type="S1:ArrayOfDateTime"/>
</wsdl:message>
<wsdl:message name="CustomerAO_arraySampleResponse">
<part name="quotas" type="S1:ArrayOfInt"/>
</wsdl:message>
422
General Client Programming Model for Progress 4GL Web Services
RPC/Literal
For the RPC/Literal format, an array parameter is represented as an unbounded sequence of its
data type in an XML Schema type definition, where XMLType is the XML Schema type:
<complexType name="ArrayOfXMLType">
<sequence>
<element name="item" type="XMLType"
minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
The WSDL file contains a separate schema for each object defined in ProxyGen. Each such
schema includes one complexType definition for each data type used as an array parameter for
any procedure or function in that object. For example, if the 4GL defines one or more
parameters in the object with the data type CHARACTER EXTENT, the schema includes a
complexType named ArrayOfString.
423
OpenEdge Development: Web Services
The RPC/Literal WSDL document for the arraySample procedure shown at the beginning of
this section includes the following types and message sections:
<wsdl:types>
<schema targetNamespace="urn:tempuri-org:CustomerAO"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="unqualified"
<complexType name="ArrayOfInt">
<sequence>
<element name="item" type="xsd:int"
minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="ArrayOfDateTime">
<sequence>
<element name="item" type="xsd:dateTime"
minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
<complexType name="ArrayOfString">
<sequence>
<element name="item" type="xsd:string"
minOccurs="0" maxOccurs="unbounded"/>
</sequence>
</complexType>
</schema>
</wsdl:types>
<wsdl:message name="CustomerAO_arraySample">
<part name="names" type="S1:ArrayOfString"/>
<part name="hireDates" type="S1:ArrayOfDateTime"/>
</wsdl:message>
<wsdl:message name="CustomerAO_arraySampleResponse">
<part name="quotas" type="S1:ArrayOfInt"/>
</wsdl:message>
424
General Client Programming Model for Progress 4GL Web Services
Document/Literal
For the Document/Literal format, an array parameter is represented as a sequence of its data
type in an XML Schema type definition:
<complexType
<sequence>
<element name="paramName" type="XMLType"
minOccurs="zero_or_extentval"
maxOccurs="extentval_or_unbounded"/>
</sequence>
</complexType>
425
OpenEdge Development: Web Services
The Document/Literal WSDL document for the arraySample procedure shown at the beginning
of this section includes the following types and message sections:
<wsdl:types>
<schema targetNamespace="urn:tempuri-org:CustomerAO"
xmlns="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<element name="arraySample">
<complexType>
<sequence>
<element name="names" type="xsd:string"
minOccurs="0" maxOccurs="unbounded"
nillable=true>
<element name="hireDates" type="xsd:dateTime"
minOccurs="0" maxOccurs="unbounded"
nillable=true>
</sequence>
</complexType>
</element>
<element name="arraySampleResponse">
<complexType>
<sequence>
<element name="quotas" type="xsd:int"
minOccurs="12" maxOccurs="12"
nillable=true>
</sequence>
</complexType>
</element>
</schema>
</wsdl:types>
<wsdl:message name="CustomerAO_procName">
<part name="parameters" element="S1:procName"/>
</wsdl:message>
<wsdl:message name="CustomerAO_procNameResponse">
<part name="parameters" element="S1:procNameResponse"/>
</wsdl:message>
426
General Client Programming Model for Progress 4GL Web Services
In the case of a DATE field, the WSDL document maps the item unambiguously to the XML
Schema data type xsd:date. Both DATETIME and DATETIME-TZ, however, map to the
xsd:dateTime data type; therefore, the WSDL does not tell the client developer whether a time
zone value is required. The developer must obtain this information by another means and must
ensure that the client application sends the expected value.
Table 42 lists the XML date data formats that are valid as input for each of the 4GL data types;
use of any other input format results in a SOAP fault.
DATE CCYY-MM-DD
DATETIME1 CCYY-MM-DDThh:mm:ss
CCYY-MM-DDThh:mm:ssZ
CCYY-MM-DDThh:mm:ss+hh:mm
CCYY-MM-DDThh:mm:ss-hh:mm
DATETIME-TZ CCYY-MM-DDThh:mm:ssZ
CCYY-MM-DDThh:mm:ss+hh:mm
CCYY-MM-DDThh:mm:ss-hh:mm
1
Any time zone information input to DATETIME is lost.
427
OpenEdge Development: Web Services
For examples of client applications that use static and dynamic temp-tables, see Chapter 6,
Sample Progress 4GL Web Services and Client Applications. The following sections provide
more information on client temp-table management, with examples:
The following examples show some <complexType> definitions for TABLE rows and parameters.
The following WSDL sample defines a TABLE row named, staticTT_ttEmpRow, with two
columns, Name and Number:
<complexType name="staticTT_ttEmpRow">
<sequence>
<element name="Name" nillable="true" type="xsd:string"/>
<element name="Number" nillable="true" type="xsd:int"/>
</sequence>
</complexType>
428
General Client Programming Model for Progress 4GL Web Services
The following WSDL sample defines a temp-table parameter for the ttEmp row using the
RPC/Encoded SOAP format. Note that the parameter is a SOAP array of rows:
<complexType name="ArrayOfstaticTT_ttEmpRow">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="S2:staticTT_ttEmpRow[]"/>
</restriction>
</complexContent>
</complexType>
The following WSDL sample defines a TABLE parameter using the RPC/Literal or
Document/Literal SOAP formats. Note that the parameter is a sequence of multiple rows:
<complexType name="staticTT_ttEmpParam">
<sequence>
<element maxOccurs="unbounded"
minOccurs="0" name="ttEmpRow" type="S2:staticTT_ttEmpRow" />
</sequence>
</complexType>
For these SOAP formats, the row element name (ttEmpRow) is used to identify each element that
holds a data row sent in SOAP messages that pass a TABLE parameter.
Following are general formats for TABLE parameters in SOAP messages. For an RPC/Encoded
Web service, the TABLE parameter is represented as a SOAP array of TABLE rows, where each
row is encapsulated by an <Item> element:
429
OpenEdge Development: Web Services
In RPC/Encoded SOAP messages passing TABLE parameters, you might notice XML like this:
<Item href="#id2"/>
...
<...id="id2">
<!--- row instance 1 -->
<!--- row instance 2 -->
<!--- row instance 3 -->
...
</...>
Some client toolkits use the SOAP encoding href attribute to reference the data in a SOAP array
for a given row instance at a different location in the message (indicated by the id attribute with
the corresponding value). The WSA, however, does not use this indirect form of data reference
for TABLE parameters in RPC/Encoded SOAP messages.
Thus, using the sample row element named ttEmpRow, a SOAP message contains a TABLE
parameter for this row definition in the following form:
430
General Client Programming Model for Progress 4GL Web Services
Each column of a TABLE row can hold any data type shown in Table 43.
Table 43: XML data types for TABLE (static temp-table) parameter
columns
BLOB1 xsd:base64Binary
CHARACTER xsd:string
CLOB1 xsd:string
COM-HANDLE xsd:long
DATE xsd:date
DATETIME xsd:dateTime
DATETIME-TZ xsd:dateTime
DECIMAL xsd:decimal
LOGICAL xsd:boolean
RAW xsd:base64Binary
ROWID xsd:base64Binary
WIDGET-HANDLE xsd:long
1
BLOB and CLOB data types are designed to support very large objects. Use of these data types for table fields in
Web services can result in a serious performance impact.
431
OpenEdge Development: Web Services
<complexType name="TableHandleParam">
<sequence>
<any namespace="##local"/>
</sequence>
</complexType>
The client application must create (for input) and parse (for output) the XML Schema along with
the data for the parameter. How the client inserts the input schema and data in request messages
and how it parses the output schema and data from response messages is entirely dependent on
the client toolkit.
This is the general format in Progress 4GL Web services for representing a TABLE-HANDLE in a
SOAP message, where the schema is defined in a <schema> element and each row is
encapsulated by an <Item> element within a <Data> element:
<DataSet>
<schema>
</schema>
<Data>
</Data>
</DataSet>
432
General Client Programming Model for Progress 4GL Web Services
Each column of a TABLE-HANDLE row can hold any data type shown in Table 44.
CHARACTER xsd:string
DATE xsd:date
DATETIME-TZ xsd:dateTime
DECIMAL xsd:decimal
LOGICAL xsd:boolean
RAW xsd:base64Binary
1. ProxyGen generates a Web service definition that includes the selected Progress
procedure during Web service development (see OpenEdge Development: Open Client
Introduction and Programming).
2. The WSA generates the WSDL file for the Web service during Web service deployment
(see OpenEdge Application Server: Administration). This WSDL file includes a series of
elements that define a Web service operation that is mapped to the selected Progress
procedure in the context of some Open Client object as specified in ProxyGen.
433
OpenEdge Development: Web Services
3. A client developer obtains the WSDL file and typically generates the source code for the
client interface by running a client interface generator. This interface generator, which
often comes as part of a Web services client development platform, reads the WSDL file
and typically writes out the source code for the client interface as a series of objects and
methods, each of which represents a Web service operation. One of these methods maps
to the Web service operation defined in the WSDL file from Step 2.
4. The client developer writes the client application that uses the client interface generated in
Step 3. The application invokes the method mapped to the Web service operation defined
in Step 2, which sends a SOAP request message to the WSA where the Web service is
deployed.
5. The WSA receives the SOAP request and packages the input parameters in an AppServer
message which results in executing the corresponding Progress procedure on an
AppServer.
6. The Progress procedure then returns any output parameters and any return value to the
WSA.
7. The WSA packages these procedure results in a SOAP response message, which it returns
to the client that originally sent the request.
434
General Client Programming Model for Progress 4GL Web Services
/* FindCustomerByNum.p */
For ProxyGen, the main information mapped from this prototype into the corresponding Web
service operation definition is in bold, including the procedure name (filename for an external
procedure) and for any parameters, the parameter mode (input or output), names, and data types.
Note: Some information can only be specified in ProxyGen, such as whether the 4GL
RETURN-VALUE is used and (for external procedures) what Open Client object this
operation belongs to.
These are the message section definitions in the RPC/Encoded and RPC/Literal WSDL file for
the FindCustomerByNum operation request and response messages:
<message name="OrderInfo_FindCustomerByNum">
<part name="CustomerNumber" type="xsd:int"/>
</message>
<message name="OrderInfo_FindCustomerByNumResponse">
<part name="CustomerName" type="xsd:string"/>
</message>
Note that the request message contains the input parameter, CustomerNumber, and the response
message contains the output parameter, CustomerName, both defined by appropriate XML data
types.
435
OpenEdge Development: Web Services
This is the definition for the FindCustomerByNum operation in the portType section of the
WSDL:
<portType name="OrderInfoObj">
<operation name="FindCustomerByNum"
parameterOrder="CustomerNumber CustomerName">
<input message="tns:OrderInfo_FindCustomerByNum"/>
<output message="tns:OrderInfo_FindCustomerByNumResponse"/>
<fault name="OrderInfoFault" message="tns:FaultDetailMessage"/>
</operation>
...
</portType>
The portType section defines the object in which the operation is defined, in this case, the
AppObject, OrderInfo (as specified in ProxyGen). Note that this definition groups together the
request (input) and response (output) messages, along with a generic fault message as part of
the operation definition.
436
General Client Programming Model for Progress 4GL Web Services
This is the definition for the FindCustomerByNum operation in the Bindings section for the
AppObject, OrderInfo:
<operation name="FindCustomerByNum">
<soap:operation soapAction="" style="rpc"/>
<input>
<soap:header message="tns:OrderInfoID" part="OrderInfoID"
use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:OrderSvc:OrderInfo" wsdl:required="true">
</soap:header>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:OrderSvc:OrderInfo"/>
</input>
<output>
<soap:body use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:OrderSvc:OrderInfo"/>
</output>
<fault name="OrderInfoFault">
<soap:fault name="OrderInfoFault" use="encoded"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://servicehost:80/wsa/wsa1"/>
</fault>
</operation>
...
</binding>
Note that this definition specifies that the transport protocol as SOAP over HTTP, and goes on
to define the content for SOAP messages request (input) and response (output) messages for the
operation. This is where the object ID definitions are referenced for operations that require
them.
437
OpenEdge Development: Web Services
This is the port definition in the service section for the object (OrderInfo AppObject)
containing the FindCustomerByNum operation:
<service name="OrderInfoService">
<port name="OrderInfoObj" binding="tns:OrderInfoObj">
<documentation/>
<soap:address location="http://servicehost:80/wsa/wsa1"/>
</port>
...
</service>
Note that the URL for the WSA instance is specified here for the location of the Web service.
This prototype has basically the same information as the original Progress 4GL procedure
prototype (see the 4GL procedure prototype to WSDL operation (Web service development)
section on page 435). In this case, ByVal specifies a value for the CustomerNumber parameter
used for input, and ByRef specifies a reference to a variable for the CustomerName parameter
used for output. Also, when VB.NET generates the client interface object that contains this
method, the information provided in the WSDL portType, bindings, and service sections
specify the object on which this method is defined (<portType>), the format of SOAP messages
for this method (<binding>), and the location of the WSA instance to which the Web service is
deployed (<port> within <service>).
438
General Client Programming Model for Progress 4GL Web Services
Thus, the call passes a value of 3 for the CustomerNumber parameter as input and receives the
value returned by the CustomerName output parameter in a variable that happens also to be
named CustomerName.
This is the SOAP request message sent out by the client after invoking the
FindCustomerByNum( ) method. You can see that the value (3) for the input parameter,
CustomerNumber, is passed in the SOAP message body.
Note that the AppObject ID for OrderInfo is sent along in the SOAP header (<UUID> element).
.NET sends the AppObject ID automatically. For other client platforms, you have might have
to code this information into the SOAP message before it is sent:
For more information on how object IDs are defined, obtained, and sent in SOAP messages, see
the Retrieving and sending object IDshandling SOAP headers section on page 415.
439
OpenEdge Development: Web Services
This is the SOAP response message returned by the WSA with the value ("Hoops") for the
output parameter, CustomerName:
If an error occurred at any point after the SOAP request message was received by the WSA, a
SOAP fault message would be returned instead of the SOAP response message shown in the
example. For information on SOAP fault messages returned for a method, see the Handling
Web service errors and SOAP faults section on page 440.
Before a request is sent to the Web service. The nature of these errors and how they
are propagated depends on the client platform.
While the request is being sent to the Web service. These errors can be written to a
log and might result in a SOAP fault.
Server errors occur after the Web service begins processing the request, preparing and
sending the request to the AppServer. These errors can be written to a log and result in a
SOAP fault.
440
General Client Programming Model for Progress 4GL Web Services
Note: For the Progress 4GL, OpenEdge translates SOAP faults into Progress 4GL errors and
provides access to the SOAP fault information. For more information, see Chapter 12,
Handling Errors in Progress 4GL Requests to Web Services.
Caution: In any catch block or other error routine where you exit the program, you must
release all Web service objects that you have created in the program.
This is the general format for a SOAP fault, with content indicated by the XML comments:
For more information on catching and viewing SOAP faults and working with log files to debug
4GL Web services, see Chapter 7, Testing and Debugging Progress 4GL Web Services.
441
OpenEdge Development: Web Services
442
5
Sample Code with SOAP Messages for
Progress 4GL Web Services
The following samples provide individual examples of how SOAP messages are sent between
the client and Web service, and code that produces some of these messages. The language used
for both the client and interface code samples described in the following sections is VB.NET:
Releasing an object
TargetNamespace "urn:OrderSvc"
AppObject OrderInfo
ProcObject CustomerOrder
SubAppObject Payroll
Some of the information presented in these examples provides a review of concepts introduced
and described in previous chapters of this manual. Note that some SOAP messages and code
samples are edited for brevity.
Client references to the sample VB.NET interface include the following method declarations for
these interface objects:
52
Sample Code with SOAP Messages for Progress 4GL Web Services
53
OpenEdge Development: Web Services
2. Connect to an AppServer by calling the connect method on the AppObject before calling
any other Web Service (AppObject) method.
3. Obtain the AppObject ID value from the SOAP response header for the connect method
and use it for all subsequent calls to methods on the session-managed AppObject.
5. Ensure that the last method you invoke on the AppObject is the objects release method.
For more information, see the Releasing an object section on page 518.
As with other Open Clients, there is no Progress 4GL involved in implementing the connect
method on an AppObject. For Web services, however, the operation is an object method that is
required by the WSA.
Note: For more information on the parameters to this method, see the sections on connecting
to an AppServer in OpenEdge Development: Open Client Introduction and
Programming. Note that there is no AppServer URL parameter. For a Web service
(unlike other Open Client applications), the deployer manages the AppServer
connection information for each Web service through the WSA instance where the Web
service is deployed. Each deployed Web service has writable properties to specify this
information. For more information, see the sections on Web service deployment in
OpenEdge Application Server: Administration.
54
Sample Code with SOAP Messages for Progress 4GL Web Services
When the client executes the connect method, the SOAP response message contains a SOAP
header with the AppObject ID. You must send this AppObject ID in the SOAP header of the
request message for every subsequent method call on the AppObject.
This is a sample instantiation and invocation of the connect method on the OrderInfo
AppObject:
This is a sample RPC/Encoded SOAP request message that might be generated from invoking
the Connect_OrderInfo( ) method, as in the example:
Note the data for the request highlighted in the example for parameters passed as empty strings.
55
OpenEdge Development: Web Services
This is a sample RPC/Encoded SOAP response that might be generated by the WSA as a
response to the Connect_OrderInfo( ) method:
Note the value for the returned AppObject ID, OrderInfo, highlighted in the example. Thus, the
SOAP response header returns the following AppObject ID contained in the OrderInfoID
element:
2e62cab6b81150d5:167f64e:f295e997b0:-8000;<OrderInfo|PX-000001|AO>;M/IryPm3p
iDcF/W5DsH4GA==
56
Sample Code with SOAP Messages for Progress 4GL Web Services
Note: All AppServers that participate in the connection pool for a session-free Web service are
assumed to share the same version and capabilities and have access to the same set of
databases and other shareable resources on a network. For more information, see
OpenEdge Application Server: Developing AppServer Applications.
Require an object ID in the SOAP request header for each method invocation unless the
object is a session-free AppObject.
57
OpenEdge Development: Web Services
This is the Progress 4GL prototype for the sample FindCustomerByNum( ) method:
/* FindCustomerByNum.p */
This is a sample VB.NET declaration for the Progress non-persistent procedure method,
FindCustomerByNum( ):
Note: Methods that run a Progress 4GL procedure always return a String for
Document/Literal, and return a String for RPC/Encoded and RPC/Literal only if
specified in ProxyGen.
58
Sample Code with SOAP Messages for Progress 4GL Web Services
This is a sample RPC/Encoded SOAP request that might be generated from this
FindCustomerByNum( ) method invocation:
AppObject ID (OrderInfoID) sent using the <UUID> element of the SOAP header.
Data for the request highlighted in the example, including the request for a
CustomerNumber value of 3.
This is a sample RPC/Encoded SOAP response that is generated by the WSA from this
invocation of the FindCustomerByNum( ) method:
Note: The CustomerName value, "Hoops", returned and highlighted in the example.
59
OpenEdge Development: Web Services
2. Call the class factory method for this ProcObject on the parent AppObject or
SubAppObject to run the persistent procedure on the AppServer.
3. Obtain the ProcObject ID value from the response header of the class factory method. Use
this ProcObject ID for all subsequent calls to methods on the ProcObject.
5. Ensure that the last method you invoke on the ProcObject is the objects release method.
For more information, see the Releasing an object section on page 518.
Note: You can instantiate a ProcObject either before or after calling the class factory method
and getting the ProcObject ID, but you must complete all of these steps before you
invoke methods on the ProcObject.
510
Sample Code with SOAP Messages for Progress 4GL Web Services
ProcObject IDs
You use the same type of class factory method to create ProcObjects for both session-managed
and session-free Web Services. For a ProcObject whose defining parent is a SubAppObject or
a session-managed AppObject, you must send the object ID of the parent in the SOAP request
message header. However, for a ProcObject whose defining parent is a session-free AppObject,
you do not have an AppObject ID to send in the SOAP request header when you invoke the class
factory method to create the ProcObject.
For every ProcObject, regardless of its parent, the SOAP response header for the class factory
method returns a ProcObject ID that associates the ProcObject session context with the client.
You must send this ProcObject ID in the SOAP request header for all other method calls on the
ProcObject.
/* CustomerOrder.p */
Note: The parameter list for the persistent procedure that runs for the ProcObject class factory
method is AppServer application dependent, and is the basis for creating the parameter
list of the ProcObject class factory method. A persistent procedure can also be specified
in ProxyGen to return a string value using the 4GL RETURN statement.
511
OpenEdge Development: Web Services
Note: This method maps to a persistent procedure that has been specified to return the string
from the 4GL RETURN-VALUE function.
3. Copy the ProcObject ID to the ProcObject from the AppObject (webService) that creates
the ProcObject.
This is a sample RPC/Encoded SOAP request that might be generated from invoking the
CreatePO_CustomerOrder( ) method to create the ProcObject, passing in a custNum value of 3:
Note the value for the request highlighted in the example, especially the AppObject ID sent for
the AppObject, OrderInfo, which is the parent of the ProcObject being created for customer
number 3.
512
Sample Code with SOAP Messages for Progress 4GL Web Services
This is a sample RPC/Encoded SOAP response that is generated by the WSA from this
invocation of the CreatePO_CustomerOrder( ) method:
Note the value returned for the CustomerOrder ProcObject ID highlighted in the example. The
Web service returns this ProcObject ID even if it is session free, to allow the ProcObject to
access its own AppServer session context.
Thus, the SOAP response header returns the following ProcObject ID contained in the
CustomerOrderID element:
2e62cab6b81150d5:167f64e:f295e997b0:-8000;<OrderInfo|PX-000002|PO>;G1Vc/vmoh
vLnwxQQXwA6Cg==
Finally, note the 4GL RETURN-VALUE, result, returned from running the persistent procedure,
which returns the customer name, "Hoops".
513
OpenEdge Development: Web Services
Require a ProcObject ID in the SOAP request header, which is the object ID of the
defining ProcObject.
This is the Progress 4GL prototype for the sample user-defined function,
GetTotalOrdersByNumber( ):
/* CustomerOrder.p */
The following is a sample method call for the user-defined function method,
GetTotalOrdersByNumber, which is an interface method on the sample ProcObject,
CustomerOrder:
totNumber = custOrder.GetTotalOrdersByNumber(2150.99)
Note that user-defined function methods return a value whose data type maps to the Progress
data type of the user-defined functions return value.
514
Sample Code with SOAP Messages for Progress 4GL Web Services
This is a sample RPC/Encoded SOAP request that might be generated from invoking the
GetTotalOrdersByNumber( ) method to execute the Progress user-defined function, passing in
a Threshold order value of 2150.99:
Note the object ID for the ProcObject, CustomerOrder, sent to make the request on a method of
the ProcObject.
This is the SOAP response returning a function value of 5, which is the total number of orders
that satisfy the specified order Threshold value:
515
OpenEdge Development: Web Services
1. Call the class factory method for this SubAppObject on the parent AppObject.
3. Obtain the SubAppObject ID value from the response header. You use the SubAppObject
ID for all subsequent calls to methods on the SubAppObject.
5. Ensure the last method you invoke on the SubAppObject is the objects release method.
For more information, see the Releasing an object section on page 518.
Note: You can instantiate a SubAppObject either before or after calling the class factory
method, but you must do both to invoke methods on the SubAppObject.
SubAppObject/Client associations
For a session-managed SubAppObject, the class factory method associates the object with the
same AppServer session context established by the parent AppObject, sharing the same client
connection to the AppServer. For a session-free SubAppObject, this method establishes an
association between the client and the object managed for the Web service by the WSA.
However, there is no connection or session context established for the client of a session-free
SubAppObject.
516
Sample Code with SOAP Messages for Progress 4GL Web Services
SubAppObject IDs
You use the same type of class factory method to create SubAppObjects for both
session-managed and session-free Web Services. For a SubAppObject whose defining parent is
a session-managed AppObject, you must send the AppObject ID of the parent in the SOAP
request message header. However, for a SubAppObject whose defining parent is a session-free
AppObject, you do not have an AppObject ID to send in the SOAP request header when you
invoke the class factory method to create the SubAppObject.
For every SubAppObject, regardless of the session model, the SOAP response header for the
class factory method returns a SubAppObject ID that uniquely associates the SubAppObject
session with the client. You must send this SubAppObject ID in the SOAP request header for
all other method calls on the SubAppObject. You must also ensure that the last method you call
on the SubAppObject is the objects release method. For more information, see the Releasing
an object section on page 518.
517
OpenEdge Development: Web Services
webService.CreateAO_Payroll( )
Payroll = New OrderSvc.PayrollObj( )
Payroll.PayrollIDValue = webService.PayrollIDValue
Payroll.IncreaseSalary(54, 4500.00)
Note: The SOAP request/response messages for creating SubAppObjects are very similar to
those for creating ProcObjects. For more information, see the Creating and using a
ProcObject section on page 510.
Releasing an object
When you are finished using any Web service object, except a session-free AppObject, you
must invoke the built-in release method to release that object and return its resources for use by
other clients:
As with other Open Clients, there is no Progress 4GL involved in implementing the release
method on an Open Client object. However, for Web services, the operation is an object method
is required by the WSA.
Although this method takes no parameters, you must remember to send the object ID for the
object you are releasing in the SOAP header of the release request message.
518
Sample Code with SOAP Messages for Progress 4GL Web Services
These are sample calls to the release methods declared for the sample Web service:
custOrder.Release_CustomerOrder( )
Payroll.Release_Payroll( )
webService.Release_OrderInfo( )
Note: AppServer connections used by session-free methods are usually returned to the Web
service connection pool after the SOAP response message for the release method is
returned.
Create rows using the interface object that represents the TABLE row.
This the Progress 4GL prototype for a sample method, staticTT( ), that passes a TABLE
parameter:
/* staticTT.p */
519
OpenEdge Development: Web Services
This is the RPC/Encoded WSDL request message for the staticTT( ) method, which has a
TABLE parameter, ttEmp. The parameter, ttEmp, is a SOAP array of rows (ttEmpRow) defined in
the Types section of the WSDL:
<message name="Employee_staticTT">
<part name="ttEmp" type="S2:ArrayOfstaticTT_ttEmpRow"/>
</message>
The following are the WSDL row and SOAP array definitions for the TABLE:
<complexType name="staticTT_ttEmpRow">
<sequence>
<element name="Name" nillable="true" type="xsd:string"/>
<element name="Number" nillable="true" type="xsd:int"/>
</sequence>
</complexType>
<complexType name="ArrayOfstaticTT_ttEmpRow">
<complexContent>
<restriction base="soapenc:Array">
<attribute ref="soapenc:arrayType"
wsdl:arrayType="S2:staticTT_ttEmpRow[]"/>
</restriction>
</complexContent>
</complexType>
<complexType name="staticTT_ttEmpParam">
<sequence>
<element maxOccurs="unbounded" minOccurs="0" name="ttEmpRow"
type="S2:staticTT_ttEmpRow" />
</sequence>
</complexType>
520
Sample Code with SOAP Messages for Progress 4GL Web Services
This is the declaration for a VB.NET client interface method, staticTT( ), which has a TABLE
parameter, ttEmp, passed as the class, staticTT_ttEmpRow:
The following client code defines a two row array (myTempTable) according to a defined schema
(staticTT_ttEmpRow), then defines and creates two rows assigned with values. It then
initializes the array (as TABLE, ttEmp) with the two rows and passes it to the staticTT( )
interface method, which passes the TABLE to the Web service:
myRow1.Name = "Fred"
myRow1.Number = 1
myRow2.Name = "Barney"
myRow2.Number = 2
myTempTable(0) = myRow1
myTempTable(1) = myRow2
webService.staticTT(myTempTable)
521
OpenEdge Development: Web Services
The following is an RPC/Encoded SOAP message that this call to staticTT( ) might send:
Note: The staticTT( ) method must send the object ID for the Employee AppObject in the
SOAP request header because staticTT( ) is a method on the session-managed
AppObject.
522
Sample Code with SOAP Messages for Progress 4GL Web Services
As a point of comparison, the following is a Document/Literal SOAP message that this call to
staticTT( ) might send:
Note: The staticTT( ) method must send the object ID for the Employee AppObject in the
SOAP request header because staticTT( ) is a method on the session-managed
AppObject.
523
OpenEdge Development: Web Services
The client application must create and send an XML Schema along with the data to fully
describe the dynamic temp-table in the SOAP request message. The TABLE-HANDLE
parameter in a SOAP request or response consists of an XML <DataSet> element
containing two child elements:
An XML representation of data using an element, <Data>, with each row represented
as a sub-element, <Item>.
The client application must parse the XML Schema and data from the SOAP response
message to make the TABLE-HANDLE accessible as native data within the application.
This is the Progress 4GL prototype for a sample method, dynttIO( ), that passes a
TABLE-HANDLE parameter:
/* dynttIO.p */
This is the RPC/Encoded WSDL sample definition for the dynttIO( ) method request
message, which also defines a TABLE-HANDLE parameter (ttHandle). The parameters type is the
standard TABLE-HANDLE parameter definition (TableHandleParam) specified in the Types
section of the WSDL:
<message name="DynTT_dynttIO">
<part name="ttHandle" type="S2:TableHandleParam"/>
</message>
524
Sample Code with SOAP Messages for Progress 4GL Web Services
The following WSDL sample shows the definition for TableHandleParam, used for all dynamic
TABLE-HANDLE parameters:
<complexType name="TableHandleParam">
<sequence>
<any namespace="##local"/>
</sequence>
</complexType>
This is the declaration for a VB.NET client interface method (dynTTIO( )) which has a
TABLE-HANDLE parameter, ttHandle, as a VB.NET object:
The following VB.NET client code passes the dyntt object representing a TABLE-HANDLE to the
dynttIO( ) method:
... Code to build up the dyntt Object (XML Schema and data)
webService.dynttIO(dyntt)
For more information on how you might manage TABLE-HANDLE parameters in VB.NET, see the
subsections on handling TABLE-HANDLE parameters in Chapter A, Developing a .NET Client to
Access Progress 4GL Web Services, and in Java see the subsections on handling
TABLE-HANDLE parameters in Chapter B, Developing a Java Client to Access Progress 4GL
Web Services.
525
OpenEdge Development: Web Services
This is the structure of the RPC/Encoded SOAP request message that the sample dynttIO
method sends to pass a dynamic temp-table that you create for the ttHandle TABLE-HANDLE
parameter (see the Invoking a method with a TABLE-HANDLE parameter (RPC/Encoded)
section on page 524):
The ttHandle TABLE-HANDLE parameter becomes an XML <ttHandle> element containing the
<DataSet> element that contains the schema and the data.
Note: Not shown is any required object ID that must be sent in the SOAP header for the object
on which dynttIO( ) is invoked.
526
Sample Code with SOAP Messages for Progress 4GL Web Services
This is a sample XML Schema created by VB.NET for the TABLE-HANDLE contained by the
sample <DataSet> element in the sample RPC/Encoded SOAP request:
Note the definition of the <Data> element containing the data for the table, and how the column
type information is specified within the <Item> element.
This is a sample <Data> element you would create to accompany the specified schema in the
sample RPC/Encoded SOAP request, including the column values for the two rows initialized
in the sample VB.NET code:
<Data>
<Item>
<Name>Fred</Name>
<Number>1</Number>
</Item>
<Item>
<Name>Barney</Name>
<Number>2</Number>
</Item>
</Data>
527
OpenEdge Development: Web Services
Caution: When exiting the program in response to a SOAP fault, you must release all Web
service objects you created in the program.
The contents of the highlighted SOAP elements include some of the key components of the fault
message, containing such error information as a general error code (<faultcode>) and message
(<faultstring>). These elements are followed by more detailed information, including the
message indicating a more precise cause for the error (<errorMessage>), and a unique identifier
for the request that returned the error (<requestID>). The contents of the <detail> element is
defined in the WSDL Types section. For more information on handling errors, including SOAP
fault messages generated for WSA-managed Web services, see Chapter 7, Testing and
Debugging Progress 4GL Web Services.
528
Sample Code with SOAP Messages for Progress 4GL Web Services
http://www.w3.org/TR/SOAP
529
OpenEdge Development: Web Services
530
6
Sample Progress 4GL Web Services and
Client Applications
This chapter describes how to access the sample applications installed with OpenEdge sample
4GL Web services and client applications for accessing them, as outlines in the following
sections:
62
Sample Progress 4GL Web Services and Client Applications
The installation directory in this figure is C:\Progress\dlc. Thus, the folders under
C:\Progress\dlc\src\samples\webservices provide the following samples:
AppService The three Web services, including the ProxyGen project files to generate
the Web service definitions. These samples include one Web service that passes a dynamic
temp-table.
Java-Axis Java Axis client samples, including applications for sample session-free and
session-managed Web services, and in several choices of SOAP format. Also included
with these samples are sample Java helper classes for managing object IDs and dynamic
temp-table schemas and data.
Microsoft .NET client samples, including a C#.NET application for a session-free Web
service and VB.NET application for session-free and session-managed Web services.
These samples include the Web-services-tools-supported SOAP format choices that are
also supported by .NET.
63
OpenEdge Development: Web Services
64
7
Testing and Debugging Progress 4GL
Web Services
This chapter explains how to test and debug Progress 4GL Web services. It assumes you are
familiar with Web services and with the Web Services tools in OpenEdge, as described in the
preceding chapters of this manual. Information in this chapter is useful for both Web service and
client developers to troubleshoot 4GL Web services and client applications that access them.
Identifying errors
Unit testing from the Progress 4GL From the 4GL, you can access AppServer
functionality directly or as a Progress 4GL Web service.
Testing from a Web service client From a Web service client using any platform,
including the 4GL, you can thoroughly test the Web service as it might behave in the
environment you plan to deploy it.
The approach that you take depends on your preferences, needs, and experience.
The rapid prototyping capability of the Progress 4GL can also make it a convenient platform to
test the application service as a Web service, depending on the requirements of the Web service.
Some client platforms might handle certain types of Web service interaction more easily than
others. However, especially where the 4GL most easily handles a particular Web service
application feature, modifying an existing 4GL unit test bed to access the AppServer as a Web
service is a natural next step in testing Web service functionality.
Otherwise, especially if you expect your primary client base to use another platform, you might
want to test on that platform to fully understand what users of that platform need to do in order
to use the Web service that you plan to deploy.
72
Testing and Debugging Progress 4GL Web Services
2. Define the Web service and generate the Web service mapping (WSM) file using
ProxyGen. For more information, see OpenEdge Development: Open Client Introduction
and Programming.
3. Generate a test WSDL file from ProxyGen when you generate the WSM file, or deploy the
WSM file to a WSA instance to obtain a deployed WSDL file. For more information on
deploying a Web service, see the sections on deploying and managing Web services in
OpenEdge Application Server: Administration.
4. Write the test client application, using the WSDL file to help generate client interfaces or
to manually write the code to invoke Web service requests. For more information, see Part
II, Clients Accessing Progress 4GL Web Services. For information on building a
Progress 4GL client to access your Web service, see Part III, Progress 4GL Clients
Accessing Industry Web Services.
5. Once you have an executable test client, ensure that the AppServer and WSA are running,
and the WSA instance where you deployed the Web service is enabled to allow client
access to the Web service. For more information on running and enabling the WSA for
Web service client access, see the sections on working with the WSA and deploying Web
services in OpenEdge Application Server: Administration.
6. Begin testing the client. For information on debugging Web services during testing, see
the Testing the AppServer application as a Web service section on page 72.
73
OpenEdge Development: Web Services
Web service SOAP (Simple Object Access Protocol) fault response messages.
For information on managing logging for the AdminService, NameServer, and in general for all
OpenEdge servers managed by the Progress Explorer Framework, see OpenEdge Getting
Started: Installation and Configuration for Windows or OpenEdge Getting Started: Installation
and Configuration for UNIX. For more information on managing logging for an AppServer, see
OpenEdge Application Server: Administration. The following sections describe how to control
logging and SOAP fault information output for the WSA and Web services.
Table 71: Setting error levels for WSA and Web services
*.props serviceLoggingLevel=2
(Web service properties)
74
Testing and Debugging Progress 4GL Web Services
Note: For complete information on the log file settings for the WSA log file, including more
advanced logging properties, see the Progress Explorer online help and the
unbroker.properties.README file in the properties directory under the OpenEdge
installation directory.
Logging information
The properties in Table 71 have the following functions and value ranges (the greater the
value, the more information is provided):
loggingLevel Affects information logged for a single WSA instance. Set this property
to change the logging detail for WSA administration, WSDL document retrieval, user
authorization, and HTTP request handling. Valid values range between 1 and 4.
serviceFaultLevel Affects the information returned in all SOAP faults from a single
deployed Web service. Set this property to change the level of detail returned for client
exceptions. Valid values are 2 or 3.
3 To get information about user authorization errors or to log the start of a new client
request for any Web service deployed to this WSA instance.
75
OpenEdge Development: Web Services
3 To track Web service request execution. Use this value during Web service
development to provide more information for each Web service request error.
2 To reduce logging overhead when the Web service is running in production. This
value only allows severe errors to be recorded that affect the Web service as a whole, and
no errors to be recorded for single Web service requests.
During production run time, you might temporarily set the value to 3 or 4 when working with a
specific client to resolve an error, then return the logging level to 2 for general client access
when the problem has been resolved.
To change these settings, use the Progress Explorer or the wsaman utility. If you are working
with a WSA installation on a system that does not have an AdminServer installed, you must edit
the ubroker.properties file to change the persistent value of loggingLevel property.
For more information on setting these logging level properties and their appropriate values
using the Progress Explorer, see the online help. You can also set the loggingLevel property If
you are using the wsaman utility, see the sections on the wsaman utility in OpenEdge Application
Server: Administration. For more information on the serviceLoggingLevel and
serviceFaultLevel properties, see the Web service properties reference sections of OpenEdge
Application Server: Administration.
For more information on using log files, see the Identifying relevant log files section on page
77. For more information on handling SOAP faults, see the Working with SOAP faults
section on page 77.
76
Testing and Debugging Progress 4GL Web Services
AdminServer adminserv.log
AppServer instance-name.broker.log
instance-name.server.log
NameServer instance-name.NS.log
For information on managing logging for the AdminService, NameServer, and in general for all
OpenEdge servers managed by the Progress Explorer Framework, see your OpenEdge
Installation and Configuration Guide. For more information on managing logging for an
AppServer, see OpenEdge Application Server: Developing AppServer Applications.
77
OpenEdge Development: Web Services
Note that all Web service logging and fault levels are controlled individually for each Web
service to further reduce processing overhead. For more information on setting this property,
see the Setting error information levels section on page 74.
<soap:Fault>
<faultcode>SOAP-ENV:Server</faultcode>
<faultstring>An error was detected request. (10893) </faultstring>
<detail>
<ns1:FaultDetail soap:encodingStyle=http://schemas.xmlsoap.org//
xmlns:ns1="http://servicehost:8080/wsa/wsa1">
<errorMessage xsi:type=xsd:string">
The urn:OrderSvc:OrderInfo service is unavailable (10921)
</errorMessage>
<requestID xsi:type=xsd:string">
2e62cab6b81150d5:-17c6a3c:f1dffbd11b:-8000#1f
</requestID>
</ns1:FaultDetail>
</detail>
</soap:Fault>
Note that SOAP faults can be returned by the clients own SOAP libraries and might have a
different XML definition for the contents encapsulated by the <detail> element, depending on
the Web service client toolkit that is used. However, a SOAP fault generated by the OpenEdge
WSA always includes an <error Message> and <requestID> element within the <detail>
element section.
The SOAP <faultstring> element provides only a very general description of the error. For
the most effective diagnostic detail, always look at the information provided by the
<errorMessage> element.
78
Testing and Debugging Progress 4GL Web Services
Use the information provided by the <requestID> element when you contact the Web service
deployer for assistance with an error. This information tells the Web service deployer whether
more information can be obtained from the WSA log file. For more information on how the
WSA uses the information in the <requestID> element to log information, see the How the
WSA logs Web service information section on page 712.
Try
' Code to access the Web service
...
Catch soapEx As System.Web.Services.Protocols.SoapException
Dim detail As String, reqId As String
detail = parseSoapException(soapEx.Detail, reqId)
MsgBox(detail, MsgBoxStyle.Critical, soapEx.Message)
End Try
In this example, parseSoapException( ) is a client helper function to parse the SOAP fault
detail provided in .NET sample code. You can find more examples like this in both the .NET
and Java sample client applications. For more information on these sample applications, see
Chapter 6, Sample Progress 4GL Web Services and Client Applications.
79
OpenEdge Development: Web Services
Microsoft SOAP Toolkit Available for free download from Microsofts Web
site.
1. Change the Web service client to send requests to the port of the SOAP message viewer
by changing the SOAP end points URL host and port fields.
2. Configure the SOAP message viewer to forward requests to the host and port of the WSA,
where the Web service is deployed, and run the viewer.
1. Enter the wsaviewer command from a Proenv shell using the following syntax:
Syntax
2. Change the Web service URL in the Web service client to access the WSAViewer.
Assume that the original Web service URL in the is as follows:
http://bedrockquarry.com:8080/wsa/wsa1
710
Testing and Debugging Progress 4GL Web Services
In the client, change this URL to use an agreed-upon viewer listening port:
http://bedrockquarry.com:8081/wsa/wsa1
3. To run the WSAViewer, enter this command in the Proenv shell on the WSA machine:
The WSAViewer runs configured to listen for requests from the reconfigured client interface on
port 8081 and forward those requests to port 8080. SOAP responses from the WSA, then, move
in the reverse direction.
Figure 71 shows the main window of the WSAViewer when it first opens.
SOAP requests from the client appear in the left-hand viewer and SOAP responses from the
WSA forwarded back to the client appear in the right-hand viewer. A continuous stream of
requests and responses is recorded that you can review by using the vertical scroll bars.
To configure and run ProSOAPView, see Chapter 12, Handling Errors in Progress 4GL
Requests to Web Services.
ProSOAPView is more general purpose than WSAViewer, and it allows you to trace not only
SOAP messages, but also HTTP messages and other document contents exchanged between a
client and server. ProSOAPView works as both an HTTP proxy server and an HTTP client that
can connect to your choice of another proxy server or the final destination.
711
OpenEdge Development: Web Services
Identifying errors
This section describes how to identify errors and describes some of the more common errors
that occur in WSA administration requests and in Web service application requests.
ID 2bbafbc35852308b:7a8a02:f18e8ee918:-8000
When a WSA instance first receives a request for one of its deployed Web services, the WSA
instance assigns the request an alphanumeric identifier (request ID) that is unique for the current
session of the WSA instance. When the WSA logs information about a Web service request,
whether the information concerns processing steps or errors, the WSA always includes its
unique request ID in the log entry text using the following format, where reqid-value is the
request ID for the Web service request to which the log entry applies:
Syntax
(reqid:reqid-value)
When the WSA returns a SOAP fault to a client, it includes the request ID of the Web service
request that triggered the SOAP fault, as well as the WSA ID of the WSA instance where the
Web service is deployed. The WSA places these two IDs within the <requestID> element of
the SOAP fault message according to the following format, where wsaid-value is the WSA ID
and reqid-value is the request ID:
Syntax
wsaid-value#reqid-value
712
Testing and Debugging Progress 4GL Web Services
The client can then obtain these two IDs from the <requestID> element of the SOAP fault and
provide it to the WSA host operator to look up more detailed information in the corresponding
entries of the WSA log file. The WSA operator then uses the WSA ID to locate the WSA log
file for the corresponding WSA instance. They can now open the log file and search for log file
entries that contain the "(reqid:reqid-value)" string to find all information related to the
specific request and WSA instance.
While the request is being prepared in the AdminServer. In the AdminServer log.
While the request is being processed in the WSA. In the WSA instance log.
Client-side errors
A client-side error occurs before the request is sent or while it is being processed by the WSA.
713
OpenEdge Development: Web Services
Examples of errors occurring while the request is being sent (which involve a session-managed
AppServer application) include:
Network down.
These types of errors result in a SOAP fault response and log file entries.
Server-side errors
A server-side error occurs while the request is being processed by the WSA and the error is not
related to the contents of the SOAP request. Examples of server-side errors include:
Forgetting to enable client access to Web services for the WSA instance.
Configuring or starting an AppServer incorrectly. This might involve one or more of the
following issues:
Incompatible AppServer operating mode for the Web service session model.
Configuring the Java Servlet Engine (JSE) incorrectly so it does not recognize the WSA).
These types of errors result in a SOAP fault response and log file entries.
714
Testing and Debugging Progress 4GL Web Services
Name OrderInfo
TargetNamespace urn:www-progress-com:samples:Orderinfo
AppObject OrderInfo
ProcObject CustomerOrder
Connect_OrderInfo("","","")
2. The WSA gets the request and determines the Web service is disabled. At this point:
a. The WSA sends the client a SOAP response containing a SOAP fault.
715
OpenEdge Development: Web Services
5. The client displays the following error message (assuming the client application has a user
interface):
Note: All .NET client applications should always catch SOAP faults and handle them. If not,
the .NET Frameworks default exception handler displays the SOAP fault general error
information. This might well hide and cause the loss of the more useful error detail
information in the SOAP fault. For client applications without a user interface, all error
information must be written to an application log file to ensure it is not lost.
716
Testing and Debugging Progress 4GL Web Services
FindCustomerByNum(3, custNameVar)
2. The WSA gets the request and asks the AppServer to run the procedure
FindCustomerByNum.p.
3. The AppServer:
b. Detects a parameter-type mismatch and records the following error message in its
log, *.server.log:
717
OpenEdge Development: Web Services
4. The WSA:
b. Sends the following SOAP containing a SOAP fault back to the client:
Notice the correspondence between the "(reqid:6)" string in the log file entry and the
"<requestID> ...2e62...#6" string in the SOAP fault message, indicating information
for the same request.
718
Testing and Debugging Progress 4GL Web Services
7. The client displays the following error message (assuming the client application has a user
interface):
Note: All .NET client applications should always catch SOAP faults and handle them. If not,
the .NET Frameworks default exception handler displays the SOAP fault general error
information. This might well hide and cause the loss of the more useful error detail
information in the SOAP fault. For client applications without a user interface, all error
information must be written to an application log file to ensure it is not lost.
2. The WSA:
719
OpenEdge Development: Web Services
d. Sends a SOAP message with a SOAP fault back to the client. The message is as
follows:
5. The client displays the this error message (assuming the client application has a user
interface):
Note: All .NET client applications should always catch SOAP faults and handle them. If not,
the .NET Frameworks default exception handler displays the SOAP fault general error
information. This might well hide and cause the loss of the more useful error detail
information in the SOAP fault. For client applications without a user interface, all error
information must be written to an application log file to ensure it is not lost.
720
Part III
Progress 4GL Clients Accessing Industry
Web Services
Chapter 10, Invoking Web Service Operations from the Progress 4GL
The chapter describes how to understand and work with WSDL files for accessing Web services
in the Progress 4GL. This includes understanding how to generate Progress 4GL interface
documentation from a WSDL file to access the Web service and how OpenEdge maps Web
service parameters defined using the XML Schema types in WSDL to the Progress 4GL data
types in your Progress 4GL Web service client application.
To use the WSDL Analyzer, enter the bprowsdldoc command on your operating system
command line using this syntax:
Note: Use the command window (shell) opened by the proenv command tool to enter this
command with the correct path settings.
Syntax
bprowsdldoc
[ -h ]
|
{
[ -b | -nohostverify | -nosessionreuse
| -WSDLUserid username | -WSDLPassword password
| -proxyhost host | -proxyport port
| -proxyUserid username | -proxyPassword password
] ...
wsdl-url-or-filename [ target-directory ]
}
-h
82
Analyzing WSDL for Progress 4GL Access to Web Services
-b
Forces documentation of binding names. A Web service can offer two options for a Web
service client to connect (or bind) to it (see Chapter 9, Connecting to Web Services from
the Progress 4GL):
Using binding names (the names of the WSDL <binding> elements) with SOAP
endpoints that you must obtain separately (sometimes used to bind a SOAP viewer).
Normally, if a WSDL defines services, the Analyzer includes only the service and port
names in the generated documentation. If the WSDL does not define any services, the
Analyzer documents the binding names. This option tells the Analyzer to document the
binding names even when services are defined in the WSDL.
-nohostverify
Turns off host verification for a Secure Socket Layer (SSL) connection using HTTPS.
-nosessionreuse
Prevents any reuse of the SSL session ID for an HTTPS Web server connection when
reconnecting the same Web server using HTTPS.
-WSDLUserid username
-WSDLPassword password
-proxyhost host
Specifies the name or IP address of the host where an HTTP-based proxy server required
to access the WSDL file is located.
-proxyport port
Specifies the port on which the HTTP-based proxy server is listening for requests to
download WSDL files.
-proxyUserid username
83
OpenEdge Development: Web Services
-proxyPassword password
wsdl-url-or-filename
A string specifying the URL or path name to the WSDL file. If the string does not specify
a URL protocol ("file://", "http://", or "https://") it is assumed to be a a local file
path name.
target-directory
A string specifying the target directory (to be created if necessary) where the Analyzer will
write the generated documents. If not specified, the Analyzer assumes the current working
directory. Choose a directory dedicated for the specified WSDL file, as some generated
document filenames are the same for multiple WSDL files.
Given the options, the Analyzer produces five types of hyperlinked HTML documents in your
current working directory as described in the following sections. All of these documents are
hyperlinked from a starting index.html file generated in the target-directory:
84
Analyzing WSDL for Progress 4GL Access to Web Services
Index document
This document is the starting index.html file that the Analyzer generates to describe the WSDL
file. Figure 81 shows an example of this document.
If the WSDL file defines more than one service, as in this example, the index document
becomes a service index document that lists all defined services as hyperlinks, each to its own
service document containing sections that describe the service.
85
OpenEdge Development: Web Services
This list appears after all other sections that describe the WSDL file, as shown in Table 81.
This index document also contains a hyperlink to an operation index document that contains an
alphabetical list of all operations from all port types in all services (see the Operation index
document section on page 87).
If the WSDL file defines only one service, the index document redirects the browser to that
single service document, as shown in Table 84.
86
Analyzing WSDL for Progress 4GL Access to Web Services
The list is in the form of a table with columns describing the port type and service information
for each operation, as shown in Table 82.
Port type A hyperlinked port type name that links to the top
of the port type document.
87
OpenEdge Development: Web Services
The operation index document also contains a hyperlink to the service index (see the Index
document section on page 85) and data types document (see the Data types document
section on page 821).
Service document
The service document is an HTML document that provides an overview of a Web service
interface. Figure 83 shows an example of a service document for one of the services described
in a WSDL with multiple services.
Figure 83: WSDL Analyzer service document for one of multiple services
88
Analyzing WSDL for Progress 4GL Access to Web Services
Table 83 lists and describes the sections of a service document if the WSDL contains multiple
services, as in Figure 83.
Port types (persistent A hyperlinked listing of all the port types defined in
procedures) the Web service, including comments in any
WSDL <documentation> elements about them.
A service document for one of multiple services also contains a hyperlink to the service index
(see the Index document section on page 85) and data types document (see the Data types
document section on page 821).
89
OpenEdge Development: Web Services
Figure 84 shows an example of a service document for a WSDL containing only one service.
Figure 84: WSDL Analyzer service document for a single service only
810
Analyzing WSDL for Progress 4GL Access to Web Services
Table 84 lists and describes the sections of the service document if the WSDL contains only a
single service, as in Figure 84.
Port types (persistent A hyperlinked listing of all the port types defined in
procedures) the Web service, including comments in any
WSDL <documentation> elements about them.
This single service document also contains a hyperlink to an operation index document that
contains an alphabetical list of all operations from all port types in the service (see the
Operation index document section on page 87).
811
OpenEdge Development: Web Services
Figure 85: WSDL Analyzer port type document (up to the Summary)
812
Analyzing WSDL for Progress 4GL Access to Web Services
Table 85 lists and describes the sections that the beginning of a port type document contains.
A port type document for a WSDL with a single service also contains a hyperlink to the single
service document (Service document section on page 88), data types document (Data types
document section on page 821), and operation index document (Operation index document
section on page 87). A port type document for a WSDL with multiple services adds a link to
the service index (Index document section on page 85), as shown in Table 85.
813
OpenEdge Development: Web Services
Figure 86 shows an example of the connection parameters from the Connection details
section of a port type document, as described in Table 86.
814
Analyzing WSDL for Progress 4GL Access to Web Services
Figure 87 shows an example of service and port descriptions from the Connection details
section of a port type document.
Figure 87: WSDL Analyzer port type document (services and ports)
The WSDL Analyzer can also list the WSDL bindings that support the port type. For more
information on how the Analyzer describes services, ports, and bindings, see Table 86.
815
OpenEdge Development: Web Services
Figure 88 shows a connection code example from the Connection details section of a port type
document, as described in Table 86.
Figure 88: WSDL Analyzer port type document (example connection code)
816
Analyzing WSDL for Progress 4GL Access to Web Services
Table 86 lists and describes the Connection details section of a port type document.
817
OpenEdge Development: Web Services
Figure 89 shows an example of how the Analyzer starts describing a Web service operation in
the Operation (internal procedure) detail section of a port type document.
Figure 89: WSDL Analyzer port type document (operation detail start)
818
Analyzing WSDL for Progress 4GL Access to Web Services
Figure 810 shows an example of how the Analyzer finishes describing a Web service operation
in the Operation (internal procedure) detail section of a port type document, describing
parameters, return values, headers, and faults associated with the operation as described in
Table 87.
Figure 810: WSDL Analyzer port type document (operation detail finish)
819
OpenEdge Development: Web Services
Table 87 lists and describes the Operation (internal procedure) detail section of a port type
document.
The WSDL Analyzer maps all Web service operations from a port type to a 4GL internal
procedure prototype. This allows all Web service operations to be invoked either synchronously
or asynchronously as you require. For some Web service operations, the Analyzer also indicates
a mapping to a 4GL user-defined function prototype. For these dual-mapping operations:
The Analyzer describes both the internal procedure mapping and the user-defined function
mapping in the port type document.
You can invoke them either as 4GL procedures or user-defined functions, depending on
your requirements at any given point in your application. However, as with user-defined
functions in the native 4GL, you cannot invoke these Web service operations as functions
asynchronously.
Figure 89 and Figure 810 show most of an example description for a dual-mapping Web
service operation in the Operation (internal procedure) detail section of a port type document.
820
Analyzing WSDL for Progress 4GL Access to Web Services
821
OpenEdge Development: Web Services
Figure 812: WSDL Analyzer data types document (data type detail)
Table 88 lists and describes the sections that the data types document contains.
Note: This document does not describe standard XML Schema types. For information on how
the Analyzer maps XML Schema types to Progress 4GL data types, see the Mapping
XML Schema data types to Progress 4GL data types section on page 824.
822
Analyzing WSDL for Progress 4GL Access to Web Services
A data types document for a WSDL also contains a hyperlink to the current service document
(see the Service document section on page 88) and to the operation index document (see the
Operation index document section on page 87). It also provides a hyperlink to the beginning
(top) of the document from the detail for any data type entry.
823
OpenEdge Development: Web Services
This section identifies the mapping options and how they work going from one domain (XML
Schema) to the other (Progress 4GL) for the following types of data:
Arrays
For more information on how to manipulate these data types (especially complex data types) in
the Progress 4GL, see Chapter 10, Invoking Web Service Operations from the Progress 4GL.
Suggested mappings
OpenEdge suggests recommended mappings between Web service parameters and Progress
4GL parameters in the generated documentation produced by the WSDL Analyzer. These are
the mappings that are most semantically useful. Note also that wherever the WSDL file
indicates that a parameter of any data type is nillable, this means that on the Web service side
the parameter can have the null value and on the Progress 4GL side the parameter can pass the
4GL unknown value (?).
824
Analyzing WSDL for Progress 4GL Access to Web Services
Table 89 lists all the simple XML Schema data types in alphabetical order, showing for each
one the Progress 4GL data type that OpenEdge suggests for mapping it. The table also provides
notes on these mappings where appropriate.
anyURI CHARACTER
boolean LOGICAL
dateTime DATETIME-TZ
decimal DECIMAL The 4GL DECIMAL type may not hold the
entire XML Schema decimal value.
However, it is common in the industry to
do a mapping between XML Schema
decimal and another decimal data type.
double CHARACTER
duration CHARACTER
ENTITIES CHARACTER
ENTITY CHARACTER
825
OpenEdge Development: Web Services
float CHARACTER
gDay CHARACTER
gMonth CHARACTER
gMonthDay CHARACTER
gYear CHARACTER
gYearMonth CHARACTER
hexBinary MEMPTR
ID CHARACTER
IDREF CHARACTER
IDREFS CHARACTER
int INTEGER
integer DECIMAL The 4GL DECIMAL type may not hold the
entire XML Schema integer value, but
it is far more likely to do so than the 4GL
INTEGER type.
Language CHARACTER
826
Analyzing WSDL for Progress 4GL Access to Web Services
Name CHARACTER
NCName CHARACTER
negativeInteger DECIMAL The 4GL DECIMAL type may not hold the
entire XML Schema negativeInteger
value, but it is far more likely to do so
than the 4GL INTEGER type.
On INPUT, if the 4GL DECIMAL value is
outside the valid range of the XML
Schema negativeInteger type, it is a
run-time error.
On OUTPUT, if the value of the XML
Schema negativeInteger value is
outside the valid range of the 4GL
DECIMAL type, it is a run-time error.
NMTOKEN CHARACTER
NMTOKENS CHARACTER
827
OpenEdge Development: Web Services
nonNegativeInteger DECIMAL The 4GL DECIMAL type may not hold the
entire XML Schema
nonNegativeInteger value, but it is far
more likely to do so than the 4GL
INTEGER type.
nonPositiveInteger DECIMAL The 4GL DECIMAL type may not hold the
entire XML Schema
nonPositiveInteger value, but it is far
more likely to do so than the 4GL
INTEGER type.
normalizedString CHARACTER
NOTATION CHARACTER
828
Analyzing WSDL for Progress 4GL Access to Web Services
positiveInteger DECIMAL The 4GL DECIMAL type may not hold the
entire XML Schema positiveInteger
value, but it is far more likely to do so
than the 4GL INTEGER type.
On INPUT, if the 4GL DECIMAL value is
outside the valid range of the XML
Schema positiveInteger type, it is a
run-time error.
On OUTPUT, if the value of the XML
Schema positiveInteger value is
outside the valid range of the 4GL
DECIMAL type, it is a run-time error.
qName CHARACTER
string CHARACTER
token CHARACTER
829
OpenEdge Development: Web Services
You might need to work directly with an XML Schema value whose format is not represented
among the supported formats for the suggested Progress 4GL data type mapping, for example,
a 51-digit decimal value. To handle this requirement, you can pass an XML Schema-formatted
string version of the value into or out of the Web service invocation. OpenEdge automatically
passes the XML Schema-formatted value when you map either a CHARACTER or LONGCHAR data
type to any XML Schema data type that has a suggested mapping (see Table 89) other than
CHARACTER or LONGCHAR.
When you pass the XML Schema-formatted value as an INPUT parameter, the Web service
invocation incorporates it directly into the generated SOAP message. For an OUTPUT parameter,
the invocation copies the XML Schema-formatted value directly from the SOAP message into
the CHARACTER or LONGCHAR parameter.
When you pass an XML Schema-formatted value to a Web service, the invocation also validates
the format of the value to ensure that it conforms to XML Schema formatting rules for the data
type. Note that the invocation does not validate any facets declared in the <schema> element to
constrain the value. It ensures that the format of the value you provide is valid according to its
base XML Schema data type representation, but not, for example, if the value falls within a
given range.
830
Analyzing WSDL for Progress 4GL Access to Web Services
Thus, for example, if you pass a Progress 4GL CHARACTER as an INPUT parameter for an XML
Schema int, the invocation checks to ensure that it contains a properly formatted 32-bit integer
value. If you pass a Progress 4GL CHARACTER as an OUTPUT parameter for an XML Schema int,
the invocation copies the Schema-formatted value directly from the SOAP message into the
4GL CHARACTER parameter.
As described previously, OpenEdge supports a set of alternative Progress 4GL data types (in
addition to a suggested data type) to represent the value for an XML Schema data type in the
Progress 4GL. These alternative data types essentially force the Web service invocation to cast
the value between the specified native Progress 4GL representation and the corresponding XML
Schema data type. The result of this casting might not preserve as much accuracy as the
suggested mapping.
Table 810 shows all the supported castings (alternative mappings) between the XML Schema
and Progress 4GL data types. The suggested Progress 4GL data type mapping (see Table 89)
for each XML Schema type appears in bold font. For a detailed description of how OpenEdge
casts each supported mapping, see Appendix D, Data Type Casting Rules for Progress 4GL
Calls to Web Services.
Note: OpenEdge supports no castings for the RECID, ROWID, or HANDLE 4GL data types.
Table 810: Supported casts between XML Schema and Progress 4GL
data types (1 of 6)
anyURI CHARACTER
LONGCHAR
base64Binary CHARACTER
LONGCHAR
MEMPTR
RAW
boolean CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
831
OpenEdge Development: Web Services
Table 810: Supported casts between XML Schema and Progress 4GL
data types (2 of 6)
byte CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
date CHARACTER
DATE
DATETIME
DATETIME-TZ
dateTime CHARACTER
DATE
DATETIME
DATETIME-TZ
decimal CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
double CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
duration CHARACTER
LONGCHAR
ENTITIES CHARACTER
LONGCHAR
ENTITY CHARACTER
LONGCHAR
float CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
gDay CHARACTER
LONGCHAR
832
Analyzing WSDL for Progress 4GL Access to Web Services
Table 810: Supported casts between XML Schema and Progress 4GL
data types (3 of 6)
gMonth CHARACTER
LONGCHAR
gMonthDay CHARACTER
LONGCHAR
gYear CHARACTER
LONGCHAR
gYearMonth CHARACTER
LONGCHAR
hexBinary CHARACTER
LONGCHAR
MEMPTR
RAW
ID CHARACTER
LONGCHAR
IDREF CHARACTER
LONGCHAR
IDREFS CHARACTER
LONGCHAR
int CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
integer CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
Language CHARACTER
LONGCHAR
long CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
833
OpenEdge Development: Web Services
Table 810: Supported casts between XML Schema and Progress 4GL
data types (4 of 6)
Name CHARACTER
LONGCHAR
NCName CHARACTER
LONGCHAR
negativeInteger CHARACTER
DECIMAL
INTEGER
LONGCHAR
NMTOKEN CHARACTER
LONGCHAR
NMTOKENS CHARACTER
LONGCHAR
nonNegativeInteger CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
nonPositiveInteger CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
normalizedString CHARACTER
DATE
DATETIME
DATETIME-TZ
DECIMAL
INTEGER
LOGICAL
LONGCHAR
NOTATION CHARACTER
LONGCHAR
positiveInteger CHARACTER
DECIMAL
INTEGER
LONGCHAR
834
Analyzing WSDL for Progress 4GL Access to Web Services
Table 810: Supported casts between XML Schema and Progress 4GL
data types (5 of 6)
qName CHARACTER
LONGCHAR
short CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
string CHARACTER
DATE
DATETIME
DATETIME-TZ
DECIMAL
INTEGER
LOGICAL
LONGCHAR
time CHARACTER
INTEGER
LONGCHAR
token CHARACTER
LONGCHAR
unsignedByte CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
unsignedInt CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
835
OpenEdge Development: Web Services
Table 810: Supported casts between XML Schema and Progress 4GL
data types (6 of 6)
unsignedLong CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
unsignedShort CHARACTER
DECIMAL
INTEGER
LOGICAL
LONGCHAR
Arrays
OpenEdge maps arrays of simple types to Progress 4GL arrays. The WSDL Analyzer
determines that it must map to a Progress 4GL array when it recognizes a SOAP array
declaration or the use of the minOccurs and maxOccurs XML Schema attributes in a parameter
type definition. If a SOAP array is declared as unbounded, the Analyzer maps it to a Progress
4GL array with an indeterminate extent.
When it receives a SOAP response that includes a sparse array parameter, OpenEdge creates a
Progress 4GL array of the appropriate size and fills it. OpenEdge sets each unused entry in the
Progress 4GL array to the unknown value (?).
For arrays of complex types, the Progress 4GL represents them as arrays of LONGCHAR
(LONGCHAR[ ]) or CHARACTER (CHARACTER[ ]). Each array element you must then handle as a
complex type (see the Complex data types section on page 837).
836
Analyzing WSDL for Progress 4GL Access to Web Services
Once in the Progress 4GL, you can continue to work with data from Web service complex types
by directly manipulating the serialized XML in Progress 4GL CHARACTER or LONGCHAR variables,
or you can convert the serialized XML to a parsed representation using the Progress 4GL SAX
or DOM parser (see OpenEdge Development: Programming Interfaces). Whatever technique
you use to work with complex type data in the Progress 4GL, if you need to pass it back to the
Web service, you must pass it back as serialized XML. So, if you maintain the data for complex
types in a Progress 4GL DOM tree (de-serialized), you must serialize it again to a string before
passing it back to a Web service as a complex type parameter.
For more information on how to manage complex types as input and output parameters of Web
service operations and work with the data in the Progress 4GL, see Chapter 10, Invoking Web
Service Operations from the Progress 4GL.
837
OpenEdge Development: Web Services
838
9
Connecting to Web Services from the
Progress 4GL
The first step in using a Web service is to connect (or bind) your application to it. Web service
connections (or bindings) represent associations between your 4GL application and the Web
service, making it easier for you to access and manage your interaction with the Web service in
the 4GL. They are not physical connections managed by your host or the network.
The following sections describe the features of Web service connections and how you can create
and manage them in the 4GL:
For more information on invoking operations in a Web service that you have connected, see
Chapter 10, Invoking Web Service Operations from the Progress 4GL.
OpenEdge Development: Web Services
However, from the client application point of view, there is definitely a defined relationship
between itself and the Web service it is communicating with, and this relationship is more
properly defined as a binding. A binding retains a logical connection between the client
application and the Web service by maintaining a continuous association between specified
client resources and specified Web service resources. This is the same type of connection that
a 4GL client application maintains between itself and a session-free AppServer with which it is
communicating (see OpenEdge Application Server: Developing AppServer Applications).
This binding relationship makes it easier for the client to send requests to the Web service and
to manage those requests within its own environment until such time as it has no more need for
the bound Web service and its resources. At such a time, the client application can logically
disconnect (unbind) the Web service from its environment in order to free up resources for other
tasks.
While the Web service is bound, the process of invoking a Web service request includes telling
the client host where to send the application message on the Internet so the Web service can
receive and respond to it. This happens every time that the client invokes a Web service request
because, as noted previously, the client host maintains no knowledge of the Web service host
and its relationship to the client application. This lack of a physical connection provides
performance benefits. Given sufficient AppServer resources, a client never needs to wait for an
AppServer to service its Web service request, and whenever an AppServer completes a request,
it is free to service a request from any other client. This arrangement offers maximum scalability
for a given set of AppServer resources over an increasing client load.
To take further advantage of Web service availability on the network, OpenEdge allows the
4GL client to make both synchronous and asynchronous requests to a Web service, providing
greater flexibility in its own request management. For more information on asynchronous Web
service requests, see Chapter 1, Web Services in OpenEdge.
92
Connecting to Web Services from the Progress 4GL
Syntax
CONNECT (
connection-parameters
[ , userid ][ , password ][ , app-server-info ]
)
A Web service binding requires and uses only the connection-parameters argument, which is
a character string containing embedded parameter values to specify the binding. For a Web
service, the last three parameters are AppServer-specific parameters and are ignored if
specified.
The connection-parameters parameter string can contain connection parameters for either an
AppServer application service, a Web service, or both. If the string contains any Web service
parameters, OpenEdge assumes that the method is binding to a Web service and ignores any
AppServer-specific connection parameters in the string.
93
OpenEdge Development: Web Services
Connection parameters
The primary function of the connection parameters is to specify the location and transport
information for the Web service on the network. Web services provide two separate
mechanisms for doing this. OpenEdge supports both mechanisms through the Web service
connection parameters.
Syntax
The only fully required element is the -WSDL parameter to identify the WSDL document for the
Web service. Note that the remaining required elements specify service, port, and binding
information, but contain only optional elements. This is to indicate that if the WSDL document
contains enough unambiguous information to specify both a valid transport and location for the
Web service, you do not have to specify any of this information in the connection parameters,
and the Web service will be bound according to the WSDL. This is only possible for a WSDL
with a single service and port specification, because there is no provision for specifying a SOAP
endpoint in WSDL without defining a service.
94
Connecting to Web Services from the Progress 4GL
1. A valid service and port (transport and Web service URL location) specification (the most
common mechanism).
2. A valid binding (transport) and SOAP endpoint (Web service URL location) specification
(sometimes used to bind a SOAP viewer between the client and the Web service, or to
provide a consortia of equivalent Web service locations).
Also, if the WSDL unambiguously specifies only some of the required information, the
connection parameters need only contain the required options to unambiguously complete the
transport and location information in the WSDL document. So, for a service and port
specification, you can specify either a -Service option (to unambiguously identify one or more
services that define a single port in the WSDL) or a -Port option (to specify one of several ports
defined for a single service in the WSDL). For a binding and SOAP endpoint specification, the
minimum required element is the -SOAPEndpoint connection parameter, which can complete the
location specification for a WSDL that defines a single <binding> element. If the WSDL
contains multiple services, ports, or bindings, the connection parameters must specify the
necessary -Service/-Port or -Binding/-SOAPEndpoint options to uniquely and correctly
identify the transport and location.
If the WSDL defines a single service, port, and binding, and you include no service, port, and
binding options in the connection parameters, the WSDL-defined service and port take
precedence. If your connection parameters include both valid -Service/-Port and valid
-Binding/-SOAPEndpoint options, the CONNECT( ) method fails.
In all cases, any specified service, port, or binding options must match the corresponding WSDL
entries exactly with respect to namespace, local name, and letter case; otherwise, the
CONNECT( ) method fails. If the WSDL defines multiple services, ports, or bindings, and the
connection parameters do not specify the necessary service, port, or binding options, the
CONNECT( ) method also fails.
95
OpenEdge Development: Web Services
Table 91 provides a short description for each parameter in the Web service connection
parameter string, in the order they appear in the syntax. For more information on these
parameters, see the CONNECT( ) method entry in the OpenEdge Development: Progress 4GL
Reference.
96
Connecting to Web Services from the Progress 4GL
Using HTTPS
When you use HTTPS to make a secure connection to a Web service, you might have to manage
the OpenEdge certificate store to contain the necessary digital certificates for SSL verification.
For information on managing the OpenEdge certificate store, see OpenEdge Getting Started:
Security.
97
OpenEdge Development: Web Services
These examples show use of the two mechanisms for binding an actual Web service:
Binding a Web service in the 4GL using binding and SOAP endpoint
Note: The public Web service used in these examples might not always be available and its
URL can change at any time.
98
Connecting to Web Services from the Progress 4GL
Binding results
After a successful attempt to bind a Web service, the server object is initialized for the Web
service. This means that on the server object handle the:
Note: A value of TRUE does not indicate the state of the HTTP/S connection between the
client and Web service. Subsequent requests can fail if there is an HTTP failure at
any point between the client and Web service.
An attempt to bind a Web service can fail for any of the following reasons:
The value specified for the -TargetNamespace parameter does not match the target
namespace specified in the WSDL document. (This is a version check.)
99
OpenEdge Development: Web Services
You can also create more than one procedure object for a single port type assigned to different
procedure handles. This allows you greater flexibility in how you handle request and response
messages for the same set of Web service operations. For more information, see Chapter 10,
Invoking Web Service Operations from the Progress 4GL.
To work with additional port types in the same Web service or in different Web services, you
must create a separate Web service binding for each port type you want to access. Depending
on how you choose to manage Web service binding resources, you can do all this using one or
more pairs of server and procedure handles. If your application accesses many port types and
Web services, especially if it disconnects and connects Web service bindings frequently, be sure
to delete the created objects, especially the procedure objects, when you no longer need them in
order to prevent memory leaks in your application.
Syntax
As a result of executing a RUN statement using this syntax, you can access operations defined by
the specified port type (portTypeName) in the Web service mapped to the server object handle,
hWebService. You can invoke these operations by executing them as procedures or user-defined
functions on the procedure object handle, hPortType, which is now mapped to the port type,
portTypeName.
910
Connecting to Web Services from the Progress 4GL
The RUN statement accomplishes this mapping by creating a procedure object for the port type
and attaching it to the specified procedure object handle:
Note: The abbreviated URL for the Web service in this example is completely fictitious, and
any resemblance to an actual public Web service is coincidental.
You can now invoke and manage all of the operations in the port type, TemperaturePortType,
defined for the Web service, WeatherService. For more information on using procedure
handles to invoke Web service operations, see Chapter 10, Invoking Web Service Operations
from the Progress 4GL.
911
OpenEdge Development: Web Services
To access a different port type in a bound Web service using the same server object
handle:
1. Delete the procedure object mapped to the current port type, using the DELETE PROCEDURE
or DELETE OBJECT statement.
2. Unbind (logically disconnect) the server object handle from its current Web service
binding using the DISCONNECT( ) method.
3. Using the CONNECT( ) method on the same server object handle, bind the server object to
the Web service using a binding that supports the next port type.
4. Create and map a new procedure object to the next port type, using the RUN statement with
the same server object handle, and, if you want, setting the same procedure object handle
used to map the previous port type.
You can repeat this procedure for each port type you need to access in the same Web service,
or you can map all of the Web service port types at one time using multiple server object and
procedure object handles.
912
Connecting to Web Services from the Progress 4GL
This example binds two Web services (WeatherService and SailingService) in order to
access three port types (TemperaturePortType, WindPortType, and RentalPortType) at the
same time:
Note: The abbreviated URLs for the Web services in this example are completely fictitious,
and any resemblance to actual public Web services is coincidental.
913
OpenEdge Development: Web Services
914
10
Invoking Web Service Operations from
the Progress 4GL
Invoking a Web service operation can be a simple process of returning a value and using it
directly (see Chapter 1, Web Services in OpenEdge), or it can require a more complex
treatment. The more complex treatment can include interacting with the SOAP message
headers, handling SOAP faults, parsing and building complex parameters, or simply managing
the serialized XML of a simple parameter.
The following sections describe how to invoke and manage the data associated with an
operation for all of these requirements:
Invoking operations
Syntax
For a 4GL remote persistent procedure, you actually execute the procedure by name
persistently; for a Web service port type, you invoke the operation using the name of the port
type from the WSDL (portTypeName) that defines the operations you want to run. Otherwise,
you can set and access a Web service proxy procedure handle (hPortType) the same way as for
a remote persistent procedure. Like an AppServer, you use the server object handle bound to the
Web service (hWebService) to indicate the remote location to receive Web service requests.
Note the lack of parameters in this statement. Where you might pass parameters when
instantiating a remote persistent procedure, you cannot pass any parameters when creating a
Web service procedure object, and OpenEdge raises an error if you do so.
A Web service procedure object supports one additional method not used on a proxy procedure
object (SET-CALLBACK-PROCEDURE( )). All other attributes and methods on a Web service
procedure object work much like they do for any proxy procedure object, or they return
unknown values (?) and empty strings where they have no meaning for a Web service.
102
Invoking Web Service Operations from the Progress 4GL
Note: The SOAP response header callback procedure executes in response to receiving
either a normal SOAP response message or a SOAP fault message generated for
the Web service request. However, a SOAP header is only available in a SOAP
response that is not a SOAP fault.
A single Web service procedure object can support only one request header callback and one
response header callback at one time. This means that for a single procedure object, you must
use the same callbacks for all operations invoked on that procedure object. However, if you
want greater flexibility to use different callbacks for the same set of operations, you can use the
RUN portTypeName statement to create an additional Web service procedure object for the same
port type. You can then invoke the SET-CALLBACK-PROCEDURE( ) method on the new procedure
object to assign a different set of callback procedures for use by that same port type. By creating
additional Web service procedure objects this way, you can then assign as many callback
procedures for a single port type as you want.
103
OpenEdge Development: Web Services
Syntax
Synchronous Web service requests For either a SOAP request header callback or a
SOAP response header callback, the procedure context must remain active until the
operation invocation has completed execution.
Asynchronous Web service requests For a SOAP request header callback, the
procedure context must remain active until the operation invocation has completed
execution. For a SOAP response header callback, the procedure context must remain
active until activation of the PROCEDURE-COMPLETE event for the request and any results
have been returned to the PROCEDURE-COMPLETE event procedure.
104
Invoking Web Service Operations from the Progress 4GL
For each type of callback procedure that you define, you must provide a specific procedure
signature. For more information on this signature, see Chapter 11, Handling SOAP Message
Headers in the Progress 4GL.
Invoking operations
After you have created a Web service procedure object, you can invoke the operations made
available through that object. OpenEdge identifies Web service operations in the 4GL by the
same names and signatures used to define them in the WSDL file for the Web service, which
you specify when you bind the Web service using the CONNECT( ) method (see Chapter 9,
Connecting to Web Services from the Progress 4GL.).
The WSDL Analyzer determines if you can invoke the operation using only a 4GL RUN
statement or if you can also a user-defined function call:
If the Analyzer determines that the operation does not return a value, it defines the
operation as an internal procedure that you must call using the RUN statement.
If the Analyzer determines that the operation returns a value, it defines the operation in
both of the following ways:
b. As an internal procedure that you can call using the RUN statement.
Any attempt to invoke a Web service operation using a method not specified by the WSDL
Analyzer returns an error.
105
OpenEdge Development: Web Services
Syntax
As indicated, this statement invokes a Web service operation with the specified name
(operationName) defined in the port type mapped to the specified procedure object handle
(hPortType), passing any parameters with data types specified in the order they are defined for
the operation by the WSDL Analyzer. Also, you can invoke any operation using the RUN
statement either synchronously or asynchronously. For more information on asynchronous
invocation for Web service operations, see Chapter 1, Web Services in OpenEdge. For
complete information on the RUN statement syntax, see OpenEdge Development: Progress 4GL
Reference.
This is the general syntax for the forward reference to a function prototype:
Syntax
This statement invokes a Web service operation with the specified name (operationName)
defined in the port type mapped to the specified procedure object handle (hPortType), passing
any parameters with data types specified in the order they are defined for the operation by the
WSDL Analyzer, and passing the operation return parameter with the corresponding data type
(dataType).
106
Invoking Web Service Operations from the Progress 4GL
This is the syntax for simple invocation of one user-defined function in a single statement, the
same for both Web service operations and user-defined functions:
Syntax
This statement invokes a user-defined function with the specified name (operationName),
passing any parameters with data types specified in the order they are defined for the operation
by the WSDL Analyzer, and passing the operation return parameter as the value of the function,
which is assigned to a variable of compatible data type. As with any function, you can invoke
it in any 4GL statement where you need to use its value. However, you can only invoke a Web
service user-defined function synchronously. For complete information on the FUNCTION
statement prototype syntax, see OpenEdge Development: Progress 4GL Reference.
Depending on the results you want to achieve, you might use an alternative data type dictated
by the alternative castings supported by OpenEdge between XML Schema simple data types
and 4GL data types. Consistent with compatible data types in the 4GL, OpenEdge implicitly
converts between any XML Schema data type and any 4GL data type included in the supported
casting. If OpenEdge cannot complete the specified conversion, it generates a run-time error.
107
OpenEdge Development: Web Services
You can also map all XML Schema simple data types to the 4GL CHARACTER or LONGCHAR type,
because the SOAP messages used to exchange parameter values are XML character data. For
XML Schema simple data types where CHARACTER is not the suggested 4GL data type, using a
CHARACTER or LONGCHAR causes OpenEdge to assume that you are passing the XML
Schema-formatted string (the actual string value of the XML Schema element) as the value for
the parameter. This allows you to perform your own transformation on the value within your
4GL application and to manage the value as you see fit. In doing this, you must format the
CHARACTER/LONGCHAR values properly for any INPUT parameters to conform with the XML
Schema data type defined for the Web service parameter by the WSDL. The only processing
that OpenEdge does when passing XML Schema-formatted values is to perform any code page
conversion required on the character data (for example, between the CPINTERNAL code page
setting and UTF-8) and to validate that the format of the data is acceptable for the XML Schema
data type. OpenEdge does no range or value checking that might be specified in the WSDL file.
For XML Schema complex types, data types containing multiple XML Schema data elements
(including other complex types), you must map them to either the 4GL CHARACTER or LONGCHAR
type. Complex type values contain multiple values structured in a hierarchical fashion,
according to the arrangement of XML elements that describe them. To manage these values,
you must work with the serialized XML directly, typically using the XML parsers in the 4GL.
For more information, see the Managing complex data section on page 108.
In general, if the invocation of a Web service operation fails for any reason, OpenEdge sets all
OUTPUT and function return values to the unknown value (?).
108
Invoking Web Service Operations from the Progress 4GL
For an INPUT parameter, you can build or maintain the required <complexType> element using
the 4GL DOM parser, and save the result as a LONGCHAR value when you are ready to pass it as
an INPUT parameter to the Web service. (The DOM parser is your only choice, as there is no
4GL SAX writer to serialize the XML.)
Note: When you save the parsed XML as a serialized character string, the DOM parser adds a
prolog element to the XML data intended for input to the Web service. OpenEdge
automatically handles this prolog element when it inserts the intended INPUT parameter
value into the SOAP request message.
You can also use the same techniques to access and manage the data for SOAP header entries
and SOAP fault detail. You can get and set this data either as serialized character strings or as
DOM trees. For more information, see Chapter 11, Handling SOAP Message Headers in the
Progress 4GLand Chapter 12, Handling Errors in Progress 4GL Requests to Web Services.
PROCEDURE getAddress:
DEFINE INPUT PARAMETER ssn AS CHARACTER.
DEFINE OUTPUT PARAMETER Address AS LONGCHAR.
END PROCEDURE.
109
OpenEdge Development: Web Services
This is the schema for <complexType> element that returns the address information to the caller.
It contains five string data type elements representing the components of the address:
<complexType name="Address">
<sequence>
<element name="name" type="xsd:string">
<element name="street" type="xsd:string">
<element name="city" type="xsd:string">
<element name="state" type="xsd:string">
<element name="zip-code" type="xsd:string">
</sequence>
</complexType>
This sample 4GL procedure demonstrates how you can manage this complex type in the 4GL.
The variable to receive the parameter value, cmAddress, is defined as a LONGCHAR, which is
essentially a CHARACTER-compatible MEMPTR. After the Web service operation returns a value for
cmAddress, the LOAD( ) method on the x-document handle, hXDoc, parses and loads the
<complexType> element from cmAddress into the associated x-document object.
Because the schema of the complex type is known, the remaining x-document and x-noderef
handle methods simply retrieve the root node from the Address DOM tree, and pick off the
component value (text element) for each of the five component nodes that comprise the complex
type, in order, assigning them to the corresponding fields of a database record.
Note: The URL for the Web service in the following example is completely fictitious, and any
resemblance to an actual public Web service is coincidental.
1010
Invoking Web Service Operations from the Progress 4GL
hXDoc:GET-DOCUMENT-ELEMENT(hXRoot).
/* ... */
hXRoot:GET-CHILD(hXNode, 5).
hXNode:GET-CHILD(hXText, 1).
myTable.zip-code = hXText:NODE-VALUE.
/* clean up */
/* ... */
hWS:DISCONNECT( ).
1011
OpenEdge Development: Web Services
1012
11
Handling SOAP Message Headers in the
Progress 4GL
SOAP headers are an optional part of a SOAP message and the requirement to use them depends
on the Web service. Many Web services require no client handling of SOAP headers.
If the Web service requires you to handle SOAP headers, especially if you need to modify or
examine the contents of a SOAP header, you need to know XML and understand the Progress
4GL facilities for parsing and managing XML. This includes 4GL support for parsing and
directly manipulating an XML document in a Document Object Model (DOM) tree or parsing
and reading the elements of an XML document using the Simple API for XML (SAX). For more
information on these facilities, see OpenEdge Development: Programming Interfaces.
This chapter describes how to define and use specified callback procedures (header handlers)
that manage the SOAP headers for SOAP request and response messages:
For information on how to declare an internal procedure as a callback procedure for handling
headers, see Chapter 10, Invoking Web Service Operations from the Progress 4GL.
OpenEdge Development: Web Services
A header returned by the Web service in a SOAP response message is a SOAP response header.
A header sent in a SOAP request message by invoking a Web service operation is a SOAP
request header. Syntactically, there is no difference between these two types of headers.
However, keeping them conceptually separate helps to clarify how you can manage them for a
Web service operation. For a given operation, the content of any SOAP request header can be
different from that of any SOAP response header.
Why are headers necessary if operations already pass data as parameters? Headers can simplify
the management of data for users of certain Web services that require the management of
context (such as user authentication) during the course of Web service interaction. With the use
of headers, the mainline of a client application need have no concern about maintaining these
states. The Web service provider typically provides specific information about the content of
headers and how they must be handled by client applications. The client can then provide
special header handlers, which are callback procedures that manage the content of these
headers for the Web service application.
112
Handling SOAP Message Headers in the Progress 4GL
<soap:Envelope>
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
. . .
<soap:Header>
<q1:OrderInfoID
xmlns:q1="http://www.example.com/webservices/OrderInfo"
SOAP-ENV:mustUnderstand="1"
SOAP-ENV:actor="/WSA">
<uuid xsi:type="xsd:string">12345-67890-98765-4321</uuid>
</q1:OrderInfoID>
<t:Transaction
xmlns:t="http://www.example.com/webservices/Transaction"
SOAP-ENV:mustUnderstand="1" t:stepnum="1">
<t:TransID>5</t:TransID>
<t:SubID>871</t:SubID>
</t:Transaction>
</soap:Header>
<soap:Body ...>
<parameter-element> ... </parameter-element>
. . .
</soap:Body>
</soap:Envelope >
As you can see, the <Header> element is, itself, nothing more than a container for other
elements, the application-specific header entry elements. Any parameters generated for an
operation in this SOAP message appear in the <Body> element in much the same way.
In this case, the SOAP header contains two header entries, named q1:OrderInfoID and
t:Transaction (where q1: and t: are namespace prefixes). Each of these elements has a series
of attributes and contains one or more child elements. The <q1:OrderInfoID> element contains
one child element named uuid, and the <t:Transaction> element contains two child elements,
named t:TransID and t:SubID. All of these element names are application-defined.
113
OpenEdge Development: Web Services
To access the SOAP header and its elements from your 4GL application, you define callback
procedures using specific signatures to use as header handlers, depending on whether the
procedure is used to access a SOAP response header or a SOAP request header. As a minimum,
you might not have to access message headers at all. If you need to access the headers, you can
define one header handler to manage all of the SOAP request headers and another header
handler to manage all of the SOAP response headers that are generated for operations of a single
Web service procedure object. You can specify the handlers for a Web service procedure object
by invoking the SET-CALLBACK-PROCEDURE( ) method on the corresponding procedure handle.
If you want to add additional handlers for the same port type managed by a Web service
procedure object, you must map the port type using additional procedure objects. For more
information, see the information on specifying header callback procedures in Chapter 10,
Invoking Web Service Operations from the Progress 4GL.
Every time you invoke an operation for a port type where you have specified header handlers,
the handlers execute as part of the operation invocation. They intercept and manage the SOAP
headers as part of sending a SOAP request message, before the message is sent to the Web
service, and as part of receiving a SOAP response message, before any message parameters are
passed to complete invocation of the operation.
Note that there is no absolute requirement to use header handlers. The need for managing
headers depends entirely on the requirements of the Web service that you are accessing. You
can also set and reset the callbacks for header handlers as often as you need to specify the correct
handlers for different operations and port types, add additional header handlers for a single port
type by mapping the port type to additional Web service procedure objects, and you can remove
any previously specified callbacks entirely when you have no need to handle the SOAP headers
for an operation or port type. The only absolute requirement for a header handler is the signature
that you must use to define it.
How to specify callback procedures as header handlers, see Chapter 10, Invoking Web
Service Operations from the Progress 4GL.
The general cycle of operation for header handlers in the 4GL, see the Invoking a header
handler section on page 118.
Defining the callback procedures for header handlers, see the Defining header handlers
section on page 1110.
114
Handling SOAP Message Headers in the Progress 4GL
The complete SOAP header object model includes two types of objects:
SOAP header-entryref object References one of the header entry elements in a SOAP
header as specified by the GET-HEADER-ENTRY( ) method on the SOAP header object. The
SOAP header entryref object can also reference a header entry element that you add to the
SOAP header using the ADD-HEADER-ENTRY( ) method on the SOAP header object.
SOAP
header - Transaction
entryref object
GET/ADD-HEADER -ENTRY( )
SubID TransID
SOAP
header - OrderInfoID
entryref object
GET/ADD-HEADER-ENTRY( ) Uuid
Figure 111: Referencing a header entry in the SOAP header object model
115
OpenEdge Development: Web Services
The SOAP header object handle also provides attributes that return information about the name
of the header and the number of header entries that the header contains.
In Figure 111, one SOAP header-entryref object references the Transaction header entry and
another object references the OrderInfoID header entry. When working with a SOAP header,
you can also use a single SOAP header-entryref object to reference all of the header entries in
a SOAP header, one at a time. The SOAP header-entryref object handle provides several 4GL
attributes and methods that allow you to inspect and modify the contents of the header entry that
it references. The attributes return the values of standard SOAP attributes contained in the
header entry element, such as the name and namespace of the header entry.
The SOAP header-entryref object handle provides two methods for accessing the element
subtree of the SOAP header entry that it references, as shown in Figure 112.
Transaction
SOAP
X-noderef
header -
object SubID TransID
entryref object
GET/SET-NODE( )
OrderInfoID
LONGCHAR
GET/SET-SERIALIZED ( )
Uuid
Figure 112: Accessing entry elements in the SOAP header object model
116
Handling SOAP Message Headers in the Progress 4GL
The:
GET-NODE( ) method assigns an X-noderef object to reference the root node of the header
entry in the DOM subtree of the header entry. You can then use this X-noderef object to
examine the XML elements by walking and returning values for the nodes of the header
entry DOM subtree.
GET-SERIALIZED( ) method assigns a LONGCHAR value that contains the entire header entry
as a serialized XML string that you can parse yourself using either the 4GL SAX reader
or DOM parser.
The SOAP header-entryref object handle also provides two corresponding methods for
replacing the entire content of the SOAP header entry that it references:
The SET-NODE( ) method replaces the content of the header entry with the DOM subtree
whose root node is currently referenced by a specified X-noderef object.
The SET-SERIALIZED( ) method replaces the content of the header entry with a DOM
subtree that it parses from a specified LONGCHAR value containing the serialized XML
for the header entry.
For more information on these objects and all the attributes and methods that they support, see
the Creating and managing SOAP message headers section on page 1113.
117
OpenEdge Development: Web Services
This fragment specifies the response header handler for an internal procedure named
TransactionResponseHandler that is defined in the current external procedure context. Then,
it invokes a startTransaction procedure as the first operation. As the name and parameters
imply, this operation begins a transaction on the order (perhaps automatically retrieved or
created, as necessary) with the specified order number.
One can imagine that the SOAP response message returned by this operation has a header
containing database object and transaction state information for the transaction that was started.
Our typical SOAP message contains just such information, including an ID for the order (the
<q1:OrderInfoID> element) and some values identifying the transaction that is managing the
order (the <t:Transaction> element).
118
Handling SOAP Message Headers in the Progress 4GL
/*
This response handler looks for a header entry named "OrderInfoID" and
assumes that it contains an element named "uuid". The handler saves away
the value of "uuid". This routine assumes that the SOAP header is no longer
needed after the callback completes.
*/
PROCEDURE TransResponseHandler:
DEFINE INPUT PARAMETER hSOAPHeader AS HANDLE.
DEFINE INPUT PARAMETER cOperationNamespace AS CHARACTER.
DEFINE INPUT PARAMETER cOperationLocalname AS CHARACTER.
119
OpenEdge Development: Web Services
It then saves the uuid string value to an OUTPUT parameter(gcUUID)defined globally in the
calling procedure context. This is all accomplished using methods and attributes of the SOAP
header object, SOAP header entry object, and x-noderef objects to access the parsed XML
DOM tree of the SOAP header.
Syntax
PROCEDURE response-header-procname :
DEFINE INPUT PARAMETER hSOAPHeader AS HANDLE .
DEFINE INPUT PARAMETER cOperationNamespace AS CHARACTER .
DEFINE INPUT PARAMETER cOperationLocalName AS CHARACTER .
END PROCEDURE .
Syntax
PROCEDURE request-header-procname :
DEFINE OUTPUT PARAMETER hSOAPHeader AS HANDLE .
DEFINE INPUT PARAMETER cOperationNamespace AS CHARACTER .
DEFINE INPUT PARAMETER cOperationLocalName AS CHARACTER .
DEFINE OUTPUT PARAMETER lDeleteOnDone AS LOGICAL .
END PROCEDURE .
1110
Handling SOAP Message Headers in the Progress 4GL
hSOAPHeader A handle to a SOAP header object that encapsulates the header of the
SOAP message that is about to be sent (request header) or that has just been received
(response header). In a response header handler, the SOAP header object has no content if
the NUM-HEADER-ENTRIES attribute on the object handle returns the value 0; otherwise it
contains one or more SOAP header entries. In a request header handler, this is an OUTPUT
parameter, therefore if the outgoing SOAP message requires a SOAP header, you must
either build a SOAP header for this parameter to reference or provide an existing SOAP
header saved from a previous response callback.
lDeleteOnDone (Request callback only) Tells OpenEdge to delete the SOAP header
object and all of the parsed XML after the SOAP header has been inserted into the
out-bound SOAP message. For more information on the scope of these objects, see the
Managing memory for SOAP headers section on page 1131.
For both types of callback procedure you can use the INPUT parameters, cOperationNamespace
and cOperationLocalName, to determine the Web service operation for which the message is
generated. You might use this information either to determine how to parse the SOAP response
header based on the invoked operation or to build a SOAP request header that is specific to the
invoked operation.
1111
OpenEdge Development: Web Services
If you need to pass context between the code that invokes a Web service operation and a header
callback procedure, you can pass the context information as you might for any internal
procedure:
Use procedure variables global to the calling code, if the callback procedure is defined
within the context of the calling code.
Use the PRIVATE-DATA attribute on the procedure context handle (THIS-PROCEDURE) of the
header handler.
Caution: After receiving a response message for which a header handler has been defined,
OpenEdge creates a SOAP header object for input to the header handler even if the
message contains no SOAP header. Your application must manage the lifetime of
this response header object even if it does nothing else except delete the object
(typically done in the response header handler). To avoid having to manage SOAP
header objects for response messages that do not contain headers, do not define a
response header handler for these response messages or unregister any that you have
defined.
1112
Handling SOAP Message Headers in the Progress 4GL
If you create a SOAP header in the handler, with potentially multiple SOAP header entries, you
are responsible for cleaning up the memory that is used for it. As an aid for deleting this object,
and its memory, you can set the lDeleteOnDone parameter for output. Setting this parameter to
TRUE, directs OpenEdge to delete the SOAP header object after OpenEdge has copied the
object's contents to the outgoing message. Otherwise, your application must manage the lifetime
of this object and determine when the object gets destroyed.
Caution: Do not explicitly delete the header object within the context of the request header
handler (before it completes). If you do this, OpenEdge never gets the header to
include in the SOAP request message.
1. Re-using a SOAP header that it has created for a response message that you must return
unchanged in a subsequent request message.
2. Re-using a SOAP header that it has created for a response message that you must return in
a subsequent request message, but modified with additional or updated header entries.
3. Building a unique SOAP header from scratch to provide as output from the request header
handler.
1113
OpenEdge Development: Web Services
As described previously (see the SOAP header object model section on page 115), the 4GL
represents a SOAP message header as:
One X-noderef object to access a selected SOAP header entry as a DOM subtree, thus
modeling the underlying XML of the header entry for access by the Progress 4GL one
node at a time.
Depending on the situation, you might need to work only at the level of the SOAP header object
with no need to inspect the contents, or you might need to access individual SOAP header
entries and their individual XML elements.
Thus, the following sections describe examples of each of the three basic use cases presented in
this section that you are most likely to encounter when managing SOAP headers as part of Web
service access:
All of these examples are based on a fictitious Web service (HeaderExample), using code that
has been run against a working version of the Web service. In the code examples, listed steps
refer to the numbers in comments, such as /*2b*/ or /*9*/.
1114
Handling SOAP Message Headers in the Progress 4GL
<soap:Envelope>
. . .
<soap:Header>
<AuthHeader xmlns="http://ServiceHost/SOAPHeader">
<AccessID>XYZZY</AccessID>
</AuthHeader>
</soap:Header>
. . .
</soap:Envelope >
It contains one header entry, AuthHeader, that contains a value used as an access key
(AccessID). This type of header might be used when the Web service and client maintain a
consistent context for each other between requests.
1115
OpenEdge Development: Web Services
This is the mainline of a procedure that invokes the Web service to reuse the response header:
/*
* SOAPHeader1.p
*
* Calls a ficticious Web service, first to request access, which
* gets back a SOAP response header containing an AccessID,
* and sends the response header back as part of a new request
* using the required access credential that allows the Web service
* to respond appropriately to the follow-up request.
*
* The Web service has only one service and port available.
*/
/*1*/
/* Define local variables */
DEFINE VARIABLE hWebSrvc AS HANDLE.
DEFINE VARIABLE hPortType AS HANDLE.
DEFINE VARIABLE cResponse AS CHARACTER FORMAT "x(72)".
DEFINE VARIABLE g_header AS HANDLE.
1116
Handling SOAP Message Headers in the Progress 4GL
This code:
1. Defines several mainline variables, including a global handle to reference the reused
SOAP header (g_header).
2. Registers the request header (ReqHandler) and response header (RespHandler) handlers
after connecting to the Web service and instantiating the HeaderSoap port type procedure
object.
3. Runs the OpenAccess procedure to invoke the Web service operation that returns the
AccessID value in the SOAP response header (see the Response header handler for
returning a header for reuse section on page 1118).
4. Runs the HelloWorld procedure to invoke the next Web service operation, passing back
the SOAP response header to the Web service unchanged as the SOAP request header (see
the Request header handler for reusing a header section on page 1119).
5. Cleans up the global objects maintained in its context and disconnects from the Web
service. Note that one of the objects it deletes is the original SOAP response header saved
by the response header handler during execution of the OpenAccess procedure.
1117
OpenEdge Development: Web Services
This is the SOAP response header handler (RespHandler) that returns the header that is reused
for passing around the AccessID value:
This code:
2. Tests if the global header handle (g_header) already references a valid object:
a. If it does not reference an object, the handler must be running as part of the initial
call to OpenAccess and thus saves the input SOAP header object (hHeader) to the
global context (g_header) for use by subsequent requests. From this moment
forward, all requests to the Web service discard the header object input to the
response handler as unnecessary.
b. If it does reference an object, the handle must already reference a SOAP response
header returned in a prior request (the call to OpenAccess) and has no need of a
subsequent response header. It therefore deletes the unnecessary SOAP header
object returned to the handler through the hHeader parameter in order to prevent a
memory leak accumulating in subsequent requests.
1118
Handling SOAP Message Headers in the Progress 4GL
This is the SOAP request header handler (ReqHandler) that reuses the initial SOAP response
header to pass the AccessID value between the client and Web service:
This code:
1. Sends the SOAP request header for the HelloWorld request (and any request run after
running OpenAccess).
a. If it does not reference an object, the request handler must be running as part of the
initial call to OpenAccess and sets the output parameters to ensure that no initial
SOAP request header is sent.
b. If it does reference an object, the handler passes the global header object as output
using the request header parameter (hHeader) and ensures that the object is not
deleted (saving it for use in any further request).
1119
OpenEdge Development: Web Services
<SOAP-ENV:Envelope
. . .
<SOAP-ENV:Header>
<ns0:AuthHeader xmlns:ns0="http://ServiceHost/SOAPHeader">
<ns0:AccessID>XYZZY</ns0:AccessID>
<ns0:Password>Administrator</ns0:Password>
</ns0:AuthHeader>
</SOAP-ENV:Header>
. . .
</SOAP-ENV:Envelope>
Note that the client adds the <Password> element as a sibling to the <AccessID> element in the
existing AuthHeader header entry. Another approach is to create and add a new Password
header entry as a sibling to the AuthHeader header entry itself. Again, the actual approach
depends on the Web service itself, in this case the HeaderExample Web service. This type of
header modification might be used when the Web service and client maintain a consistent
context for each other between requests and the operation involved requires authorization or
authentication or some other additional context information.
Following is the mainline of a procedure that invokes the Web service to reuse the initial SOAP
response header by adding a password node to it before passing it back as a SOAP request
header. This code:
1. Defines several mainline variables, including handles to access the global reused SOAP
header (g_header) and its XML, and a variable to hold the password value (cPassword).
2. Registers the request header (ReqHandler) and response header (RespHandler) handlers
after connecting to the Web service and instantiating the HeaderSoap port type procedure
object.
3. Runs the OpenAccess procedure to invoke the Web service operation that returns the
AccessID value in the SOAP response header (see the Response header handler for
returning a header for reuse section on page 1118).
1120
Handling SOAP Message Headers in the Progress 4GL
/*
* SOAPHeader2.p
*
* An addition to SOAPHeader1.p.
*
* Calls a ficticious Web service.
* The first operation (OpenAccess) sends nothing in the request headers and
* gets back a SOAP response header containing an AccessID.
* The second operation (HelloWorld) sends the AccessID back in its request
* header. (No additional information is received in the response header.)
* The third operation (HelloSecureWorld) adds a Password node to the
* existing AccessID entry in its request header. This Password node is added
* as a sibling of the AccessID element and NOT as a new SOAP header entry.
* (Once again no additional information is received in the response header.)
*
* The Web service has only one service and port available.
*/
/*1*/
/* Define local variables */
DEFINE VARIABLE hWebSrvc AS HANDLE.
DEFINE VARIABLE hPortType AS HANDLE.
DEFINE VARIABLE cResponse AS CHARACTER FORMAT "x(72)".
DEFINE VARIABLE hXdoc AS HANDLE.
DEFINE VARIABLE hXnoderef1 AS HANDLE.
DEFINE VARIABLE hXnoderef2 AS HANDLE.
DEFINE VARIABLE hXtext AS HANDLE.
DEFINE VARIABLE cPassword AS CHARACTER INIT ?.
DEFINE VARIABLE g_header AS HANDLE.
/* Connect to the WS */
hWebSrvc:CONNECT("-WSDL
http://ServiceHost/SOAPHeader/HeaderExample.asmx?wsdl").
1121
OpenEdge Development: Web Services
/*4*/
/* Go again with the AccessID set from previous response */
cResponse = "".
RUN HelloWorld IN hPortType (OUTPUT cResponse).
DISPLAY cResponse LABEL "WS response" WITH FRAME bbb.
/*5*/
/* Go again with the AccessID set from previous response */
/* header together with an added Username and Password */
cResponse = "".
cPassword = "Administrator".
RUN HelloSecureWorld IN hPortType (OUTPUT cResponse).
DISPLAY cResponse LABEL "WS response" WITH FRAME ccc.
/*6*/
DELETE OBJECT g_header.
DELETE OBJECT hPortType.
hWebSrvc:DISCONNECT().
DELETE OBJECT hWebSrvc.
4. Runs the HelloWorld procedure to invoke the next Web service operation, passing back
the SOAP response header to the Web service unchanged as the SOAP request header (see
the Request header handler for reusing and modifying a header section on page 1123).
5. Runs the HelloSecureWorld procedure to invoke the next Web service operation, passing
back the password-modified SOAP response header as the Web service SOAP request
header (see the Request header handler for reusing and modifying a header section on
page 1123).
Note: The header handler processing for Step 4 is different from Step 5, to reflect that the
initial SOAP response header is unchanged for one request and modified for the
next.
6. Cleans up the global objects maintained in its context and disconnects from the Web
service. Note that one of the objects it deletes is the original SOAP response header saved
by the response header handler during execution of the OpenAccess procedure.
1122
Handling SOAP Message Headers in the Progress 4GL
This is the SOAP request header handler (ReqHandler) that reuses the initial SOAP response
header and adds a Password value to the existing AuthHead header entry to pass along with the
AccessID value between the client and Web service:
This code:
1. Sends the SOAP request header for the HelloWorld and HelloSecureWorld requests (and
any request run after running OpenAccess).
a. If it does not reference an object, the request handler must be running as part of the
initial call to OpenAccess and sets the output parameters to ensure that no initial
SOAP request header is sent.
b. If it does reference an object, the handler passes the global header object as output
using the request header parameter (hHeader) and ensures that the object is not
deleted (saving it for use in any further request).
1123
OpenEdge Development: Web Services
/*3e*/ hXdoc:APPEND-CHILD(hXnoderef2).
hXdoc:CREATE-NODE-NAMESPACE(hXnoderef1, ClientNS,
"Password", "ELEMENT").
/*3f*/ hXnoderef2:APPEND-CHILD(hXnoderef1).
hXdoc:CREATE-NODE(hXtext, "", "text").
hXnoderef1:APPEND-CHILD(hXtext).
hXtext:NODE-VALUE = cPassword.
/* Procedure/header cleanup */
/*3h*/ cPassword = ?. /* Use current password until replaced */
DELETE OBJECT hHeaderEntryref.
DELETE OBJECT hXdoc.
DELETE OBJECT hXnoderef1.
DELETE OBJECT hXnoderef2.
DELETE OBJECT hXtext.
END.
END. /* all subsequent requests */
END PROCEDURE.
1124
Handling SOAP Message Headers in the Progress 4GL
3. Tests if a password has been specified for the current Web service request, indicated by
any cPassword value that is other than the unknown value (?). If the current Web service
request is nonsecure (as with the HelloWorld operation), all work has been done and the
the request handler can end. If the current Web service request is secure (as with the
HelloSecureWorld operation), the request handler adds the password information to the
SOAP request header, as follows:
Note: After the first secure request, all future requests (secure or nonsecure) send a
request header that includes password information because the password
information is never deleted until replaced by a newly-specified password.
a. Creates the XML x-document and x-noderef objects to manipulate the SOAP header.
b. Creates the SOAP header entryref object (hHeaderEntryref) to access SOAP header
entries and defines the namespace (ClientNS) used for defining the SOAP header
entry for this request.
c. Returns the existing header entry from the saved global SOAP header object using
the GET-HEADER-ENTRY( ) method on the SOAP header object and accesses the
XML root node of the entry using the GET-NODE( ) method on the SOAP header
entryref object.
Note: The handler is adding the password information to an existing SOAP header
entry. If it was adding a new header entry to hold the information, it would
invoke the ADD-HEADER-ENTRY( ) method to add the header entry to contain
the new XML for it.
d. Imports the header entry root node into an x-document object in order to access and
modify the XML for the header entry, and also deletes any password data from a
previous secure request before adding the currently-specified password data.
g. Replaces the entire existing header entry in the global SOAP header object with the
header entry updated in the x-document object.
h. Sets the password value (cPassword) to unknown (?), which retains the current
password in the header entry until it is explicitly changed in cPassword. Deletes all
of the helper XML and SOAP header entryref objects created in the header handler.
1125
OpenEdge Development: Web Services
<SOAP-ENV:Envelope
. . .
<SOAP-ENV:Header>
<ns0:AuthHeader xmlns:ns0="http://ServiceHost/SOAPHeader">
<ns0:UserName>Scott</ns0:UserName>
<ns0:Password>Administrator</ns0:Password>
</ns0:AuthHeader>
</SOAP-ENV:Header>
. . .
</SOAP-ENV:Envelope>
The client creates a header very similar to the headers described in the previous examples. The
<UserName> and <Password> elements, in this case, provide user authentication for each Web
service request. The Web service requires this authentication for every Web service request.
Following is the mainline of a procedure that invokes the Web service to create the initial SOAP
request header containing a username and password node. This code:
1. Defines several mainline variables, including handles to access the global SOAP header
(g_header) created for requests and its XML, and variables to hold the username
(cUsername) and password (cPassword) values.
2. Builds the global request header used for all requests (see the Procedure to create a SOAP
request header section on page 1128).
3. Registers the request header (ReqHandler) handler after connecting to the Web service and
instantiating the HeaderSoap port type procedure object.
4. Runs the HelloMyWorld procedure to invoke a Web service operation, passing back the
global SOAP request header created by the client (see the Request header handler for
passing a globally-created header object section on page 1130).
5. Cleans up the global objects maintained in its context and disconnects from the Web
service. Note that one of the objects it deletes is the global SOAP request header create by
the client.
1126
Handling SOAP Message Headers in the Progress 4GL
/*
* SOAPHeader3.p
*
* Calls a ficticious web service, passes it a username and password through
* a SOAP message request header, and gets back a string.
*
* The Web service has only one service and port available.
*/
/* Connect to the WS */
hWebSrvc:CONNECT("-WSDL
http://ServiceHost/SOAPHeader/HeaderExample.asmx?wsdl").
1127
OpenEdge Development: Web Services
This is the procedure (BuildRequestHeader) that creates the global SOAP request header that
the client sends in all requests to the Web service:
This code:
1. Defines a single output parameter to return the global SOAP header object that it creates
to the client mainline context.
3. Creates the global SOAP header object that references the XML for the header using the
CREATE SOAP-HEADER statement, and creates the SOAP header entryref object that
references the XML for the header entry using the CREATE SOAP-HEADER-ENTRYREF
statement.
4. Creates the x-document and x-noderef objects required to build the XML to be added as
the header entry for the global SOAP header.
5. Adds a header entry to the newly-created SOAP header object, referenced by the
hHeaderEntryref object, using the ADD-HEADER-ENTRY( ) method.
1128
Handling SOAP Message Headers in the Progress 4GL
6. Creates the root node (<AuthHeader> element) for the header entry in the working
x-document object.
8. Creates the <Password> element as a second child node of the header entry.
9. Assigns the header entry in the global SOAP header object to the XML for the
<AuthHeader> element of the x-document object using the SET-NODE( ) method.
/*5*/
/* Create the header entry */
hHeader:ADD-HEADER-ENTRY(hHeaderEntryref).
/*6*/
/* Create the header namespace data */
hXdoc:CREATE-NODE-NAMESPACE(hXnoderef1, ClientNS,
"AuthHeader", "ELEMENT").
hXdoc:CREATE-NODE-NAMESPACE(hXAttribute,
"http://www.w3.org/2000/xmlns/",
"xmlns", "ATTRIBUTE").
hXAttribute:NODE-VALUE = ClientNS.
hXnoderef1:SET-ATTRIBUTE-NODE(hXAttribute).
hXdoc:INSERT-BEFORE(hXnoderef1, ?).
/*7*/
/* Create the Username/Password data */
hXdoc:CREATE-NODE-NAMESPACE(hXnoderef2, ClientNS,
"UserName", "ELEMENT").
hXnoderef1:APPEND-CHILD(hXnoderef2).
hXdoc:CREATE-NODE(hXtext,"","text").
hXnoderef2:APPEND-CHILD(hXtext).
hXtext:NODE-VALUE = cUsername.
/*8*/
hXdoc:CREATE-NODE-NAMESPACE(hXnoderef2, ClientNS,
"Password", "ELEMENT").
hXnoderef1:APPEND-CHILD(hXnoderef2).
hXdoc:CREATE-NODE(hXtext, "", "text").
hXnoderef2:APPEND-CHILD(hXtext).
hXtext:NODE-VALUE = cPassword.
/*9*/
/* Fill the header entry using a deep copy */
hHeaderEntryref:SET-NODE(hXnoderef1).
1129
OpenEdge Development: Web Services
/*9*/
/* Fill the header entry using a deep copy */
hHeaderEntryref:SET-NODE(hXnoderef1).
/*10*/
/* Procedure/header cleanup */
DELETE OBJECT hXdoc.
DELETE OBJECT hXAttribute.
DELETE OBJECT hXnoderef1.
DELETE OBJECT hXnoderef2.
DELETE OBJECT hXtext.
DELETE OBJECT hHeaderEntryref.
END PROCEDURE.
10. Cleans up by deleting all the helper objects created in the procedure before returning to the
client mainline.
This is the SOAP request header handler (ReqHandler) that passes the global SOAP request
header created by the client and the Web service for each request:
This code:
1. Sends the SOAP request header for the HelloMyWorld request (and any subsequent
request).
2. Passes the global SOAP header the request header output parameter and ensures that it is
not deleted until the client mainline has finished with it.
1130
Handling SOAP Message Headers in the Progress 4GL
Memory used for the SOAP header and SOAP header entry data that SOAP header and
SOAP header-entryref objects reference, that is, the underlying XML.
Memory used by the SOAP header object, including the memory for SOAP header entries
referenced by SOAP header-entryref objects, even if this header object memory does not
reference any underlying XML.
SOAP header objects can be created in the 4GL application in two ways:
No matter how the application creates these objects, the application is responsible for explicitly
deleting these and any other objects that it creates during a session, including the SOAP
header-entryref objects used to reference the header entries in a SOAP header object and any
X-document and X-noderef objects used to parse and build the XML structures that occupy
memory for the underlying XML.
1131
OpenEdge Development: Web Services
Deletes all
Deletes the underlying XML
4GL element Applied to object 4GL object DOM objects
Caution: Be sure that you always delete the underlying XML for a SOAP header-entryref
object before you delete the SOAP header-entryref object itself. If you lose all
reference to the underlying XML before deleting it, its memory becomes lost to your
application. If this occurs as part of an iterative process, it represents a memory leak
that could cause your application to crash.
1132
Handling SOAP Message Headers in the Progress 4GL
SOAP header object For accessing the name and header entries of a SOAP header.
SOAP header-entryref object For accessing each header entry in a SOAP header.
Each of these objects provide attributes and methods that manage header access according to a
SOAP header object model defined for the Progress 4GL. This object model maps to the SOAP
header XML in a manner analogous to the way x-document and x-noderef objects allow you to
access XML through the Document Object Model (DOM) supported in the Progress 4GL. In
fact, the attributes and methods that implement the SOAP header object model provide access
to the XML of a header by making it available to the standard XML support in the 4GL, such
as the DOM, and by allowing the XML to be exchanged between the two SOAP header
representations (SOAP object model and XML).
For more information on the SOAP header object model, see the SOAP header object model
section on page 115. The following sections describe all of the attributes and methods available
for each object in the SOAP header object model.
1133
OpenEdge Development: Web Services
Table 113 briefly describes all of the methods on the SOAP header object.
For more information on these attributes and methods, see OpenEdge Development: Progress
4GL Reference.
1134
Handling SOAP Message Headers in the Progress 4GL
Table 115 briefly describes all of the methods on the SOAP header-entryref object.
SET-ACTOR (string) LOGICAL Sets the value (string) of the actor attribute in
the underlying SOAP header entry. This method
returns TRUE only if there is an underlying SOAP
header entry (XML sub-tree) associated with the
object handle.
1135
OpenEdge Development: Web Services
For more information on these attributes and methods, see OpenEdge Development: Progress
4GL Reference.
1136
12
Handling Errors in Progress 4GL
Requests to Web Services
As described previously, the ERROR condition can result from a Web service request by:
3. An error intentionally raised by the 4GL application (using the RETURN ERROR statement)
in a SOAP request header callback procedure or a SOAP response header callback
procedure.
For a thorough overview of handling all types of errors, see Chapter 1, Web Services in
OpenEdge.
This chapter focuses on how to handle SOAP faults and generally how to debug Web service
requests, including the following sections:
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>VersionMismatch.Additionalinfo</faultcode>
<faultstring>The message does not conform to
expected version</faultstring>
<faultactor>http://www.stockvendor.com</faultactor>
<detail>
<e:badver xmlns:e=http://www.stockvendor.com/>
<message>Expect version 2 request,
received previous version</message>
<errorcode>523</errorcode>
</e:badver>
</detail>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
These three child elements of this SOAP fault are mostly application-defined, but typically
provide the following information:
<detail> (Optional) Contains elements completely defined by the Web service, but
which provide much more specific information about the fault.
122
Handling Errors in Progress 4GL Requests to Web Services
The error box displays the operation that generated the SOAP fault and the contents of the
<faultstring> element in the SOAP fault message.
If the statement that invokes a Web service operation traps an error using the NO-ERROR option,
this message and the information for any SOAP fault detail appears in the ERROR-STATUS system
handle, and as with all 4GL errors remains available until the next statement is invoked using
the NO-ERROR option. Table 121 lists the ERROR-STATUS handle attribute that help you to detect
and return the information for a SOAP fault. All other attributes and methods on this handle
work as they do for any 4GL error condition.
Once you have detected an error (ERROR-STATUS:ERROR=TRUE), you can determine if it is the
result of a SOAP fault using the ERROR-OBJECT-DETAIL attribute. If a SOAP fault caused the
error, this attribute returns a handle to a SOAP fault object containing the SOAP fault
information. Otherwise, it has the unknown value (?).
123
OpenEdge Development: Web Services
Table 122 lists the attributes on the SOAP fault object, which contains no methods.
As you can see, these attributes provide access to all the elements of a SOAP fault you might
encounter.
Because the <detail> element has essentially no standard definition, and can contain any
elements that the Web service chooses to generate, OpenEdge provides another object, the
SOAP fault-detail object to return this information to the 4GL application. If the SOAP fault
message contains a <detail> element, the SOAP-FAULT-DETAIL attribute on the SOAP fault
object handle returns a handle to the SOAP fault-detail object that is generated for it. Otherwise,
this attribute returns the unknown value (?). Like the SOAP fault object, OpenEdge makes the
SOAP fault-detail object available only until the next 4GL statement that executes with the
NO-ERROR option.
124
Handling Errors in Progress 4GL Requests to Web Services
Table 123 lists the single attribute and Table 124 lists the methods of the SOAP fault-detail
object.
GET-SERIALIZED( ) LONGCHAR Returns the XML for the underlying SOAP fault
detail information in serialized form.
The GET-NODE( ) and GET-SERIALIZED( ) methods provide access to the elements of the SOAP
fault detail information in exactly the same way as they provide access to SOAP header entries
for a SOAP header (Chapter 11, Handling SOAP Message Headers in the Progress 4GL).
The general approach to managing SOAP fault detail elements is identical to retrieving and
scanning the header entries of a SOAP response header. The structure of elements that make up
the SOAP fault detail information is completely undefined. For more information, see the
documentation available for the Web service you are accessing.
125
OpenEdge Development: Web Services
This code:
2. Assigns a handle variable (hSoapFault) to any valid SOAP fault object returned by the
ERROR-STATUS:ERROR-OBJECT-DETAIL attribute for code readability.
3. Examines the values of SOAP fault elements, as required, using appropriate attributes
(SOAP-FAULT-CODE) on the SOAP fault object handle.
4. Uses the 4GL VALID-HANDLE function to determine if this SOAP fault has SOAP fault
detail by testing the validity of the handle returned by hSoapFault:SOAP-FAULT-DETAIL.
6. Returns the root node of the underlying SOAP fault <detail> element by using the
hSoapFaultDetail:GET-NODE( ) method to assign the root node to the x-noderef object
referenced by the handle variable hxnoderef.
7. Can now use the methods and attributes of the x-noderef object handle (hxnoderef) and
additional handle variables to walk the XML DOM subtree referenced by hxnoderef to
examine the content of the SOAP fault <detail> element as specified by the WSDL for
the Web service.
126
Handling Errors in Progress 4GL Requests to Web Services
/*7*/ /* From here the application can walk the detail XML and
retrieve the relevant information. */
.
.
.
END. /* Examine SOAP-FAULT-DETAIL */
END. /* Return SOAP-FAULT-CODE info */
END. /* Examine ERROR-OBJECT-DETAIL */
END.
127
OpenEdge Development: Web Services
1. Determine if the WSDL file is still valid for the Web service you are accessing.
This is particularly necessary if you access the WSDL file at a location other than the URL
specified by the Web service provider, for example using a local file system that stores a
separate copy that you have made from the original. It is also very possible that the Web
service provider has changed the URL or target namespace to reference the WSDL file. If
this is the case, you must run the WSDL Analyzer against the new WSDL file to identify
any changes that might affect your code (see Chapter 8, Analyzing WSDL for Progress
4GL Access to Web Services).
So, this is a good first step to diagnose any Web service access failure.
2. If the WSDL file appears to be valid, use a SOAP message viewer at run time to compare
the content of SOAP request and response messages with what the application expects and
what the WSDL file specifies.
OpenEdge provides a set of SOAP viewers included with the installation, and many other
viewers are available. This chapter describes three of them to varying levels of detail.
3. Debug the 4GL code, possibly using the OpenEdge Debugger. For more information on
the Debugger, see OpenEdge Development: Debugging and Troubleshooting.
128
Handling Errors in Progress 4GL Requests to Web Services
SOAP Viewers
Table 125 lists some tools that you can use to view Web service messages as they are
exchanged between the client and the Web service.
The Microsoft SOAP Toolkit contains a variety of tools for working with SOAP messages on
Windows platforms. One advantage of WSAViewer and ProSOAPView is that they run on all
supported OpenEdge platforms.
Using WSAViewer
WSAViewer is a basic tool for viewing the SOAP messages between a given source and
destination, which you determine at startup. As such, it functions as a man in the middle
between the client and the Web service. It is useful if you are only interested in viewing the
content of the SOAP request and response. The simplicity of this tool makes it handy to use
when debugging 4GL Web services for which viewing the well-defined SOAP formats is the
primary focus. For more information on this tool, see Chapter 7, Testing and Debugging
Progress 4GL Web Services.
129
OpenEdge Development: Web Services
Change the connection parameters in your Web service CONNECT( ) method to send all
SOAP messages to WSAViewer. WSAViewer then forwards them to the actual Web
service.
Startup the 4GL client using the -proxyhost and -proxyport startup parameters to
redirect the SOAP messages to WSAViewer. Specify -proxyhost using the host name
where the viewer is running (typically localhost), and specify -proxyport using the port
on which WSAViewer listens for SOAP request messages (the listen-port value
specified for WSAViewer as shown in the following syntax).
The syntax to start the viewer is the same when working with any Web service as it is when
working with the OpenEdge Web Services Adapter (WSA):
Syntax
The listen-port is the port on which WSAViewer listens for SOAP request messages. The
webservice-host is the host name of the Web service and the webservice-port is the host port
on which the Web service listens for SOAP request messages.
Suppose you enter the following command line to start the viewer to listen on localhost at port
8080 and pass SOAP request messages to the Web service, www.stockvend.com, listening on
port 80:
You might code your 4GL Web service CONNECT( ) method like this:
The CONNECT( ) method still gets the WSDL file directly from www.stockvend.com, but all
SOAP messages go through WSAViewer on their way to the Web service and back to the client.
1210
Handling Errors in Progress 4GL Requests to Web Services
Using ProSOAPView
ProSOAPView is a more flexible tool than WSAViewer that allows you to view the following
message content exchanged between a client and Web service:
The content of any other document exchanged between the client and Web service.
This flexibility is especially helpful to debug industry Web services accessed from the 4GL
(which can originate anywhere and contain a greater variety of SOAP formats).
SOAPSpy works both an HTTP proxy server and as an HTTP client, meaning that it can serve
as a proxy between a Web service client and the Web service and also connect to its final
destination through another proxy, all without changing any of the Web service client code.
The data stream that SOAPSpy can track includes binary data as well as readable text. However,
binary data is represented schematically and all invalid text characters appear as the '?'
character.
1211
OpenEdge Development: Web Services
You run ProSOAPView by setting it up as a proxy server for the Progress 4GL client.
Syntax
prosoapview [ port-number ]
By default the SOAPSpy executable listens on TCP/IP port 4444. You can specify the
port-number value to change this port assignment.
2. To begin tracking HTTP and SOAP messages, be sure that the client application has not
yet executed the Web service CONNECT( ) method, then choose SpyStart Spying from
the menu bar, as shown in Figure 122, or click the spy icon in the SOAPSpy window.
3. Start up the Progress 4GL client adding the following startup parameters to the command
line:
Syntax
Set port-number to the TCP/IP listening port used by SOAPSpy (4444 by default). For
more information on these startup parameters and starting up a Progress 4GL client, see
OpenEdge Deployment: Startup Command and Parameter Reference.
1212
Handling Errors in Progress 4GL Requests to Web Services
Note: You do not have to change any connection parameters coded for the Web service
CONNECT( ) method in the 4GL client application to use ProSOAPView. Proxy
settings handle all redirection of message traffic that is required to inspect
messages sent between the 4GL client and the Web service.
After have opened the SOAPSpy window and begun tracking messages, the status bar indicates
the proxy host and port as shown in Figure 123, where the proxy host is name beata.
Once tracking begins, the SOAPSpy window shows a list of calls (Web service operation
invocations) on the left and a tab viewer on the right showing message content (see Figure
121).
Each call in the list is identified by its URI, the time of the call, and an icon that identifies the
type of call, as shown in Figure 124.
When you select a call in the list, its message content appears in the tab viewer. You can view
different message content for a call by selecting a tab in the viewer. The HTTP Request and
HTTP Response tabs show the raw content of every call. The SOAP Request and SOAP
Response tabs allow you to manipulate individual SOAP messages, including WSDL requests.
1213
OpenEdge Development: Web Services
For example, Figure 125 shows the content of a SOAP request message in the SOAP Request
tab.
If you want to remove a call from the call list, select the call and choose Remove Call (see
Figure 126), either in the Call menu or in the context menu that pops up on the call.
1214
13
Sample Progress 4GL Applications
Accessing Web Services
This release includes the following sample 4GL client procedures that invoke and manage Web
service requests:
Samples overview
Samples overview
The sample applications for 4GL clients accessing Web services reside in the following
OpenEdge installation path:
OpenEdge-install-dir/src/samples/webservices/4GLClient
Temperature
StockQuotes
DatatypeFormats
Note: The public Web services used by some of the samples are not always available and
Progress Software Corporation (PSC) has no control over the availability of these Web
services.
Temperature
This sample calls a public RPC/Encoded Web service that returns the temperature for a given
US zip code. In the process, it demonstrates the passing of a simple data type parameter to a
Web service.
For more information, see the Using the Temperature sample section on page 134.
132
Sample Progress 4GL Applications Accessing Web Services
StockQuotes
This sample calls a public Web service in Document/Literal SOAP format that returns stock
information for any number of US stocks. In the process, it demonstrates how the 4GL handles
parameters for Document/Literal Web services in general and an XML Schema complex type
as a parameter.
Input A complex type and an XML document that contains a comma or space
delimited list of stock symbols.
Output A complex type and an XML document that contains a .NET structure.
For more information, see the Using the StockQuotes sample section on page 139.
DatatypeFormats
This sample client calls a C#.NET Web service in Document/Literal SOAP format (included
with the client). It provides examples of how to format data for some of the XML Schema
simple data types displayed as a list. In the process, it demonstrates how the 4GL handles XML
Schema complex types as both input and output parameters.
For more information, see the Using the DatatypeFormats sample section on page 1318.
133
OpenEdge Development: Web Services
http://www.xmethods.net/
http://www.xmethods.net/sd/2001/TemperatureService.wsdl
Note: A public Web service used by a sample is not always available, and PSC has no control
over availability of a public Web service.
134
Sample Progress 4GL Applications Accessing Web Services
1. Prompts for the requested zip code using the Enter Zip Code field:
hWebService:CONNECT("-WSDL
'http://www.xmethods.net/sd/2001/TemperatureService.wsdl' ").
IF NOT hWebService:CONNECTED() THEN
MESSAGE "SERVER NOT CONNECTED" VIEW-AS ALERT-BOX.
135
OpenEdge Development: Web Services
4. Sets the handle to the port type in the WSDL where the Web service operation is defined
and waits for the user to invoke the request:
a. Retrieves the zip code entered in the Enter Zip Code field:
136
Sample Progress 4GL Applications Accessing Web Services
c. If there are no errors, assigns the output value from the getTemp procedure call to the
The Temp is field:
ON CHOOSE OF bgetTemp
DO:
cZipCode = fillin-1:SCREEN-VALUE.
RUN getTemp IN hPortType (INPUT cZipCode, OUTPUT cTemp) NO-ERROR.
IF ERROR-STATUS:ERROR THEN
DO:
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
MESSAGE ERROR-STATUS:GET-MESSAGE(i) VIEW-AS ALERT-BOX.
END.
IF VALID-HANDLE(ERROR-STATUS:ERROR-OBJECT-DETAIL) THEN
DO:
MESSAGE "Fault Code: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-CODE SKIP
"Fault String: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-STRING SKIP
"Fault Actor: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-ACTOR SKIP
"Error Type: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:TYPE
VIEW-AS ALERT-BOX.
IF VALID-HANDLE(ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL) THEN
MESSAGE "Error Type: "
ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL:TYPE
"Fault Detail: "
ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL:GET-SERIALIZED()
VIEW-AS ALERT-BOX.
END.
END.
ELSE
fillin-2:SCREEN-VALUE = STRING(cTemp, "99").
END.
137
OpenEdge Development: Web Services
ON CHOOSE OF bgetTemp
DO:
cZipCode = fillin-1:SCREEN-VALUE.
RUN getTemp IN hPortType (INPUT cZipCode, OUTPUT cTemp) NO-ERROR.
IF ERROR-STATUS:ERROR THEN
DO:
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
MESSAGE ERROR-STATUS:GET-MESSAGE(i) VIEW-AS ALERT-BOX.
END.
IF VALID-HANDLE(ERROR-STATUS:ERROR-OBJECT-DETAIL) THEN
DO:
MESSAGE "Fault Code: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-CODE SKIP
"Fault String: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-STRING SKIP
"Fault Actor: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-ACTOR SKIP
"Error Type: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:TYPE
VIEW-AS ALERT-BOX.
IF VALID-HANDLE(ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL) THEN
MESSAGE "Error Type: "
ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL:TYPE
"Fault Detail: "
ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL:GET-SERIALIZED()
VIEW-AS ALERT-BOX.
END.
END.
ELSE
fillin-2:SCREEN-VALUE = STRING(cTemp, "99").
END.
Note that after displaying all the available error messages, it verifies that a SOAP
fault caused the error by checking if a SOAP fault object is part of the error status
(ERROR-STATUS:ERROR-OBJECT-DETAIL references it). After displaying the basic
SOAP fault information, it further verifies that there is SOAP fault detail information
by checking if a SOAP fault-detail object is part of the SOAP fault object data
(ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-DETAIL references it) and
displays any SOAP fault detail information that it references.
138
Sample Progress 4GL Applications Accessing Web Services
which:
http://www.xmethods.net/
http://www.swanandmokashi.com/HomePage/WebServices/StockQuotes.asmx
Note: A public Web service used by a sample is not always available, and PSC has no control
over availability of a public Web service.
139
OpenEdge Development: Web Services
To get multiple quotes, you can enter ticker symbols separated by:
MSFT,YHOO,GE,PRGS
For a given ticker symbol, the Web service returns the following information:
Company name
Ticker
Stock quote
Price change
Open price
Volume
Market cap
Year range
1310
Sample Progress 4GL Applications Accessing Web Services
1. Prompts for the stock symbol(s) to populate the XML document entered using the Enter
Stock Symbols prompt:
1311
OpenEdge Development: Web Services
3. Connects to the Web service (which has only one valid service and port):
hWS:CONNECT("-WSDL
http://www.swanandmokashi.com/HomePage/WebServices/StockQ
uotes.asmx?wsdl).
IF NOT hWS:CONNECTED() THEN
MESSAGE "SERVER NOT CONNECTED" VIEW-AS ALERT-BOX.
4. Sets the handle to the port type in the WSDL where the Web service operation is defined
and waits for the user to invoke the request:
a. Constructs the XML document that is input to the Web service operation. The
document is created in this form:
<s0:GetStockQuotes xmlns:s0="http://swanandmokashi.com/">
<s0:QuoteTicker>stock-symbol(s)</s0:QuoteTicker>
</s0:GetStockQuotes>
1312
Sample Progress 4GL Applications Accessing Web Services
hDoc:CREATE-NODE-NAMESPACE(hRoot, "http://swanandmokashi.com/",
"s0:GetStockQuotes", "element").
hRoot:SET-ATTRIBUTE("xmlns:s0", "http://swanandmokashi.com/").
hDoc:APPEND-CHILD(hRoot).
hDoc:CREATE-NODE-NAMESPACE(hChild, "http://swanandmokashi.com/",
"s0:QuoteTicker", "element").
hRoot:APPEND-CHILD(hChild).
hDoc:CREATE-NODE(hTextNode, ?, "text").
hTextNode:NODE-VALUE = FILLIN-1:SCREEN-VALUE.
hChild:APPEND-CHILD(hTextNode).
hDoc:SAVE("longchar", lcSymbol).
.
.
.
1313
OpenEdge Development: Web Services
c. Checks for errors and manages the information for any that occur (see the Common
procedure for SOAP fault handling section on page 1327):
1314
Sample Progress 4GL Applications Accessing Web Services
d. If there are no errors, loads the XML document that was passed back as a LONGCHAR
OUTPUT parameter:
ON CHOOSE of bgetQuote
DO:
.
.
.
IF NOT err THEN
DO:
hDoc:LOAD("longchar", lcQuote, FALSE).
.
.
.
e. The Web service returns the output XML document with the following structure
(shown for a single quote example, PRGS):
<GetStockQuotesResponse xmlns="http://swanandmokashi.com/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<GetStockQuotesResult>
<Quote>
<CompanyName>PROGRESS SOFT</CompanyName>
<StockTicker>PRGS</StockTicker>
<StockQuote>21.41</StockQuote>
<LastUpdated>4:00pm</LastUpdated>
<Change>+0.86</Change>
<OpenPrice>N/A</OpenPrice>
<DayHighPrice>21.60</DayHighPrice>
<DayLowPrice>20.41</DayLowPrice>
<Volume>160721</Volume>
<MarketCap>740.4M</MarketCap>
<YearRange>11.50 - 24.06</YearRange>
</Quote>
</GetStockQuotesResult>
</GetStockQuotesResponse>
1315
OpenEdge Development: Web Services
The client then parses this document to get the relevant information and put it into a
CHARACTER variable for display:
1316
Sample Progress 4GL Applications Accessing Web Services
ON CHOOSE of bgetQuote
DO:
.
.
.
fillin-2:SCREEN-VALUE = cResult.
END. /* bgetQuote */
which:
1317
OpenEdge Development: Web Services
http://localhost/DatatypeFormats/Service1.asmx
This Web service is available at the following path under the OpenEdge installation directory:
src\samples\webservices\4GLClient\DatatypeFormats\CS.NET\DatatypeFormats
Table 131 shows some of the formats that SOAP requires to format the XML Schema data
types handled by this operation.
datetime 9999-99-99THH:MM:SS.SSS+HH:MM
duration P99Y99M99DT99H99M99S
gDay ---DD
gMonth --MM--
gMonthDay --MM-DD
gYear YYYY
gYearMonth YYYY-MM
1318
Sample Progress 4GL Applications Accessing Web Services
The complex type input parameter passed to MultiDatatypes( ) contains the simple type
parameters shown in Table 132.
Parameter
simple type Parameter name
boolean paramIn1
batetime paramIn2
duration paramIn3
gDay paramIn4
gMonth paramIn5
gMonthDay paramIn6
gYear paramIn7
gYearMonth paramIn8
The complex type output parameter passed to MultiDatatypes( ) contains the simple type
parameters shown in Table 133.
Parameter
simple type Parameter name
boolean paramIn1
batetime paramIn2
duration paramIn3
gDay paramIn4
gMonth paramIn5
gMonthDay paramIn6
gYear paramIn7
gYearMonth paramIn8
1319
OpenEdge Development: Web Services
2. Connects to the Web service (which has only one valid service and port):
hWS:CONNECT("-WSDL
http://localhost/DatatypeFormats/Service1.asmx?WSDL).
IF NOT hws:CONNECTED() THEN
DO:
MESSAGE "SERVER:CONNECTED : " hws:CONNECTED() VIEW-AS ALERT-BOX.
LEAVE.
END.
3. Sets the handle to the port type in the WSDL where the MultiDatatypes( ) operation is
defined:
1320
Sample Progress 4GL Applications Accessing Web Services
4. Creates the XML document used to pass the input complex type parameter as a LONGCHAR.
This operation requires that the INPUT and OUTPUT parameters are XML documents
because the Web service SOAP format is Document/Literal. The Web service expects the
XML document input parameter to have this structure:
<ns0:MultiDatatypes xmlns:ns0="http://tempuri.org/">
<ns0:paramIn1>boolean-value</ns0:paramIn1>
<ns0:paramIn2>dateTime-value</ns0:paramIn2>
<ns0:paramIn3>duration-value</ns0:paramIn3>
<ns0:paramIn4>gDay-value</ns0:paramIn4>
<ns0:paramIn5>gMonth-value</ns0:paramIn5>
<ns0:paramIn6>gMonthDay-value</ns0:paramIn6>
<ns0:paramIn7>gYear-value</ns0:paramIn7>
<ns0:paramIn8>gYearMonth-value</ns0:paramIn8>
</ns0:MultiDatatypes>
1321
OpenEdge Development: Web Services
This is a sample of the code showing the boolean value of the first parameter and the
gYearMonth value of the last parameter added to the newly-created XML document:
hDoc:CREATE-NODE-NAMESPACE(hRoot, "http://tempuri.org/",
"s0:MultiDatatypes", "element").
hRoot:SET-ATTRIBUTE("xmlns:s0", "http://tempuri.org/").
hDoc:APPEND-CHILD(hRoot).
/* paramIn1 boolean */
/* boolean value must one of the following values: true, false, 1, 0 */
lBoolIn = TRUE.
hDoc:CREATE-NODE-NAMESPACE(hNode, "http://tempuri.org/",
"s0:paramIn1", "element").
hRoot:APPEND-CHILD(hNode).
hDoc:CREATE-NODE(hText, ?, "text").
hText:NODE-VALUE = STRING(lBoolIn, "true/false").
hNode:APPEND-CHILD(hText).
.
.
.
/* paramIn8 gYearMonth */
/* dYearMonth must be in the format "YYYY-MM" */
sgYearMonthIn = "199902".
hDoc:CREATE-NODE-NAMESPACE(hNode, "http://tempuri.org/",
"s0:paramIn8", "element").
hRoot:APPEND-CHILD(hNode).
hDoc:CREATE-NODE(hText, ?, "text").
hText:NODE-VALUE = STRING(sgYearMonthIn, "9999-99").
hNode:APPEND-CHILD(hText).
1322
Sample Progress 4GL Applications Accessing Web Services
6. Invokes the MultiDatatypes( ) operation of the Web service by making a procedure call:
7. Checks for errors and manages the information for any that occur (see the Common
procedure for SOAP fault handling section on page 1327):
1323
OpenEdge Development: Web Services
8. If there are no errors, loads the XML document that was passed back in the OUTPUT
parameter:
DO:
.
.
.
IF NOT err THEN
DO:
ret = hDoc:LOAD("longchar" , lcOutput, FALSE).
.
.
.
END.
END.
The Web service returns the output XML document with the following structure:
<ns0:MultiDatatypesResponse xmlns:ns0="http://tempuri.org/">
<ns0:paramOut1>boolean-value</ns0:paramOut1>
<ns0:paramOut2>dateTime-value</ns0:paramOut2>
<ns0:paramOut3>duration-value</ns0:paramOut3>
<ns0:paramOut4>gDay-value</ns0:paramOut4>
<ns0:paramOut5>gMonth-value</ns0:paramOut5>
<ns0:paramOut6>gMonthDay-value</ns0:paramOut6>
<ns0:paramOut7>gYear-value</ns0:paramOut7>
<ns0:paramOut8>gYearMonth-value</ns0:paramOut8>
</ns0:MultiDatatypesResponse>
1324
Sample Progress 4GL Applications Accessing Web Services
9. Parses the XML document, with the following code showing how values are retrieved for
the boolean value of the first parameter and the gYearMonth value of the last parameter of
the complex type:
DO:
.
.
.
DO:
.
.
.
hDoc:GET-DOCUMENT-ELEMENT(hRoot).
DO i = 1 TO hRoot:NUM-CHILDREN:
hRoot:GET-CHILD(hNode, i).
IF hNode:SUBTYPE = "ELEMENT" THEN
DO:
IF hNode:NAME = "paramOut1" THEN /* boolean */
DO:
Ret = hNode:GET-CHILD(hChildNode, 1).
IF ret AND hChildNode:subtype = "TEXT" THEN
BoolOut = LOGICAL(hChildNode:NODE-VALUE).
END.
.
.
.
IF hNode:NAME = "paramOut8" THEN /* gYearMonth */
DO:
Ret = hNode:GET-CHILD(hChildNode, 1).
IF ret AND hChildNode:subtype = "TEXT" THEN
sgYearMonthOut = hChildNode:NODE-VALUE.
END.
END.
END.
.
.
.
END.
END.
1325
OpenEdge Development: Web Services
10. Displays the data that was extracted from the XML:
DO:
.
.
.
DO:
.
.
.
MESSAGE "Return Values = " SKIP
lBoolOut SKIP
dtzDateOut SKIP
sdurationOut SKIP
sgDayOut SKIP
sgMonthOut SKIP
sgMonthDayOut SKIP
sgYearOut SKIP
sgYearMonthOut
VIEW-AS ALERT-BOX.
END.
END.
which:
1326
Sample Progress 4GL Applications Accessing Web Services
This is the procedure that both procedures call to handle all errors, including SOAP faults
(modified to include numeric step comments that are referenced by the following description):
DO i = 1 TO ERROR-STATUS:NUM-MESSAGES:
MESSAGE ERROR-STATUS:GET-MESSAGE(i) VIEW-AS ALERT-BOX.
END.
/*2*/
IF VALID-HANDLE(ERROR-STATUS:ERROR-OBJECT-DETAIL) THEN
DO:
MESSAGE "Fault Code: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-CODE SKIP
"Fault String: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-STRING SKIP
"Fault Actor: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-ACTOR SKIP
"Error Type: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:TYPE
VIEW-AS ALERT-BOX.
/*3*/
IF VALID-HANDLE(ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-DETAIL)
THEN
MESSAGE "Error Type: "
ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-DETAIL:TYPE
"Fault Detail: "
ERROR-STATUS:ERROR-OBJECT-DETAIL
:SOAP-FAULT-DETAIL:GET-SERIALIZED()
VIEW-AS ALERT-BOX.
END.
END.
END.
1327
OpenEdge Development: Web Services
This code:
1. Determines whether an error has occurred from the value of the OUTPUT parameter, which
is set to TRUE if error messages exist. Each example procedure calls ErrorInfo after
invoking a Web service operation, for example:
If an error occurs, ErrorInfo has already processed the error information in expectation
that no normal results are available from the operation to process.
2. After displaying all the available error messages, ErrorInfo verifies that a SOAP fault
caused the error by checking if a SOAP fault object is part of the error status
(ERROR-STATUS:ERROR-OBJECT-DETAIL references it).
3. After displaying the basic SOAP fault information, ErrorInfo further verifies that there
is SOAP fault detail information by checking if a SOAP fault-detail object is part of the
SOAP fault object data (ERROR-STATUS:ERROR-OBJECT-DETAIL:SOAP-FAULT-DETAIL
references it) and displays any SOAP fault detail information that it references.
Note also that the error processing in ErrorInfo is essentially identical to the error processing
in the TemperatureSample.p procedure, which could be easily rewritten to call it.
1328
Part IV
Appendices
Appendix D, Data Type Casting Rules for Progress 4GL Calls to Web Services
A
Developing a .NET Client to Access
Progress 4GL Web Services
This appendix describes the basic tasks to develop a .NET client application to use a Progress
4GL Web service. as described in the following sections:
As described by Microsoft, .NET is a robust platform for developing the next generation
of applications.
Visual C# .NET
The .NET API, including data type support, is the same for all languages.
.NET provides a single development environment, Visual Studio .NET, to work with all
its supported languages.
.NET supports the following SOAP formats that are also supported by Progress 4GL Web
services:
RPC/Encoded
Document/Literal
A2
Developing a .NET Client to Access Progress 4GL Web Services
2. Add a Web reference for the Web service by specifying the WSDL file location. This
automatically creates a .NET interface.
3. Add logic to the client to create interface objects and call interface methods.
The language used in the rest of this chapter to demonstrate client development with .NET is
Visual Basic (VB.NET).
Property or
component Value or name Object type
URL http://servicehost:80/wsa/wsa1
TargetNamespace urn:OrderSvc:OrderInfo
A3
OpenEdge Development: Web Services
Property or
component Value or name Object type
CustomerOrderObj ProcObject
OrderInfoID AppObject ID
CustomerOrderID ProcObject ID
These sections review information presented in previous sections of the manual, to provide
context for understanding the VB.NET environment.
A4
Developing a .NET Client to Access Progress 4GL Web Services
1. Enter the URL for the WSDL file. The TargetURI can be set to either the Web service
friendly name (AppObject name, by default) or the TargetNamespace for the Web service,
as in the following examples:
http://servicehost:80/wsa/wsa1/wsdl?targetURI=OrderInfo
http://servicehost:80/wsa/wsa1/wsdl?targetURI=
urn:OrderSvc:OrderInfo
2. Rename the Web reference you added to the project appropriately (for example, from
servicehost to OrderService). Select the Show All Files toolbar button (or choose
ProjectShow All Files) to locate the Web reference file, Reference.vb under the
renamed Web reference.
The object ID for each Open Client object (except a session-free AppObject). For
example, OrderInfoID and CustomerOrderID.
A5
OpenEdge Development: Web Services
A member variable for its own object ID, such as OrderInfoID in the sample.
Member variables for the object IDs of any objects created using CreateXX_* methods
(SubAppObjects and ProcObjects), such as CustomerOrderID in the sample.
It takes the WSDL service name if the Web service has only one object (AppObject), such
as OrderInfoService.
A6
Developing a .NET Client to Access Progress 4GL Web Services
CHARACTER String
COM-HANDLE Long
DATE Date
DECIMAL Decimal
LOGICAL Boolean
MEMPTR Byte( )
RAW Byte( )
ROWID Byte( )
TABLE Object
TABLE-HANDLE Object
WIDGET-HANDLE Long
For scalar parameters, the client does not need to do any special additional processing to
use them.
TABLE and TABLE-HANDLE parameters require extra processing for the client to use them.
A7
OpenEdge Development: Web Services
Client interfaces contain an object for each WSDL <complexType> definition of a TABLE
row. For example, the OrderDetailsRow class is declared as follows:
The client interface represents the TABLE parameters as arrays of these row objects.
Table A3 lists the data type mappings for TABLE columns between the Progress 4GL and .NET.
Table A3: .NET data types for TABLE (static temp-table) parameter
columns
CHARACTER String
COM-HANDLE Long
DATE Date
DECIMAL Decimal
LOGICAL Boolean
RAW Byte( )
ROWID Byte( )
WIDGET-HANDLE Long
A8
Developing a .NET Client to Access Progress 4GL Web Services
Table A4 lists the typical data type mappings for TABLE-HANDLE columns between the Progress
4GL and .NET.
CHARACTER String
DATE Date
DECIMAL Decimal
LOGICAL Boolean
RAW Byte( )
When passing a TABLE-HANDLE parameter, the interface or the client views it with different
object types, depending on the Web service SOAP format:
For RPC/Encoded:
For Document/Literal, both the interface and the client represent the parameter as a
System.Xml.XmlElement type.
A9
OpenEdge Development: Web Services
Object ID classes
OrderInfoID:
CustomerOrderID:
AppObject class
OrderInfoObj:
A10
Developing a .NET Client to Access Progress 4GL Web Services
ProcObject class
CustomerOrderObj:
Connect_OrderInfo( ):
Release_OrderInfo( ):
Release_CustomerOrder( ):
A11
OpenEdge Development: Web Services
Note: The object ID in the SOAP headers are not shown in the VB.NET method prototypes.
Non-persistent procedure
Progress 4GL:
/* FindCustomerByNum.p */
Persistent procedure
Progress 4GL:
/* CustomerOrder.p */
Note: This procedure returns a value using the 4GL RETURN statement.
A12
Developing a .NET Client to Access Progress 4GL Web Services
User-defined function
Progress 4GL:
/* CustomerOrder.p */
Progress 4GL:
/* CustomerOrder.p */
PROCEDURE GetOrderDetails :
DEFINE OUTPUT PARAMETER TABLE FOR OrderDetails.
A13
OpenEdge Development: Web Services
TABLE definition
Progress 4GL:
/* CustomerOrder.p */
Progress 4GL:
/* DynTT.p */
A14
Developing a .NET Client to Access Progress 4GL Web Services
Creating a SubAppObject
Releasing an object
Notes: For more information on the concepts and procedures that underlie these tasks, see
Chapter 4, General Client Programming Model for Progress 4GL Web Services and
Chapter 5, Sample Code with SOAP Messages for Progress 4GL Web Services.
OpenEdge comes installed with complete sample client applications that access 4GL
Web services. For more information, see Chapter 6, Sample Progress 4GL Web
Services and Client Applications.
A15
OpenEdge Development: Web Services
Note: Note that the value of the OrderInfoIDValue is extracted from the SOAP response
header automatically by the interface. This value is then assigned to the
OrderInfoIDValue member variable of the AppObject (WS_OrderService).
Note: The OrderInfoIDValue is automatically inserted in the SOAP request header by the
interface.
A16
Developing a .NET Client to Access Progress 4GL Web Services
To create the context for a ProcObject on the AppServer and run the persistent
procedure:
A17
OpenEdge Development: Web Services
Note: The CustomerOrderIDValue is automatically inserted in the SOAP request header by the
interface.
Methods for running an internal procedure are essentially the same as those for running a
user-defined function.
Creating a SubAppObject
Complete the steps that follow to create a SubAppObject.
To create a SubAppObject:
Note: The OrderInfoIDValue will automatically be put into the SOAP request header by
the interface, and the PayrollIDValue AppObject member variable is filled in
automatically by the interface.
A18
Developing a .NET Client to Access Progress 4GL Web Services
Releasing an object
For releasing an object:
Every Open Client object except for a session-free AppObject has a release method.
The syntax is the same for all objects, as in the following example that releases the
CustomerOrder object, which happens to be a ProcObject:
Note: The CustomerOrderIDValue is automatically inserted in the SOAP request header by the
interface.
A19
OpenEdge Development: Web Services
' Loop through the rows to obtain some of the column values
Dim i As Integer
Dim OrderNum As Integer
Dim OrderStatus As String
Dim TotalDollars As Decimal
For i = 0 To WS_OrderDetails.Length - 1
OrderNum = WS_OrderDetails(i).OrderNum
OrderStatus = WS_OrderDetails(i).OrderStatus
TotalDollars = WS_OrderDetails(i).TotalDollars
Next i
Imports System.Xml
. . .
' Code to process the output TABLE-HANDLE from DynTT.p goes here
A20
Developing a .NET Client to Access Progress 4GL Web Services
' Insert schema and data nodes as children of the dataSetDoc root node
schemaNode = dataSetDoc.ImportNode(schemaDoc.DocumentElement, True)
dataNode = dataSetDoc.ImportNode(dataDoc.DocumentElement, True)
root.AppendChild(schemaNode)
root.AppendChild(dataNode)
dynTTEl = dataSetDoc.DocumentElement( )
A21
OpenEdge Development: Web Services
' Extract the schema and data elements from the output
schemaEl = Nothing
dataEl = Nothing
For i = 0 To dynTTEl.ChildNodes.Count - 1
node = dynTTEl.ChildNodes( i )
type = node.NodeType
If type = System.Xml.XmlNodeType.Element Then
If schemaEl Is Nothing Then
schemaEl = node
ElseIf dataEl Is Nothing Then
dataEl = node
Else
Too many elements, something is wrong
End If
End If
Next i
myDataSet.ReadXmlSchema(mySchemaReader)
myDataSet.ReadXml(myDataReader)
A22
Developing a .NET Client to Access Progress 4GL Web Services
Input Create the System.Array with the XmlElement containing schema and data.
Output Extract the last element of the System.Array, which is the XmlElement
containing schema and data.
This code goes after the code that creates XML document representing dynTTEl
and before calling the method taking the TABLE-HANDLE parameter
. . .
Create a System.Array containing dynTTEl
dynTTArray = System.Array.CreateInstance(dynTTEl.GetType, 1)
dynTTArray(0) = dynTTEl
Run DynTT.p
wsObj.DynTT(dynTTArray)
A23
OpenEdge Development: Web Services
Try
' Code to access the Web service
...
Catch soapEx As System.Web.Services.Protocols.SoapException
Dim detail As String, reqId As String
detail = parseSoapException(soapEx.Detail, reqId)
MsgBox(detail, MsgBoxStyle.Critical, soapEx.Message)
End Try
Caution: In any catch block where you exit the program, you must release all Web service
objects you created in the program.
The parseSoapException( ) method in this example is a client function provided in the .NET
samples installed with OpenEdge (see Chapter 6, Sample Progress 4GL Web Services and
Client Applications). It parses the detail error information from the SOAP fault message.
You can also use the Microsoft SOAP Toolkit to assist in debugging SOAP fault messages. For
more information, see Chapter 7, Testing and Debugging Progress 4GL Web Services.
A24
Developing a .NET Client to Access Progress 4GL Web Services
http://www.microsoft.com/net/default.asp
http://www.microsoft.com/vstudio/nextgen/default.asp
Information from other .NET developers at the Framework Community Web site:
http://www.gotdotnet.com
A25
OpenEdge Development: Web Services
A26
B
Developing a Java Client to Access
Progress 4GL Web Services
This appendix describes the basic tasks to develop Java client applications that use a Progress
4GL Web service, as described in the following sections:
JAX-RPC
The client development samples in the remainder of this section are provided using Axis as the
client-side Web services toolkit.
Also, if you are developing a secure Web service that relies on the secure socket layer (SSL)
managed by the Web server, OpenEdge provides a utility (procertm) to manage the digital
certificates for a Java client. This same utility is used to manage digital certificates for Java
Open Clients. For more information on this utility, see OpenEdge Development: Java Open
Clients.
B2
Developing a Java Client to Access Progress 4GL Web Services
Property or
component Value or name Object type
URL http://servicehost:80/wsa/wsa1
TargetNamespace urn:OrderSvc:OrderInfo
CustomerOrderObj ProcObject
OrderInfoID AppObject ID
CustomerOrderID ProcObject ID
B3
OpenEdge Development: Web Services
Proxy classes
Output parameters
To create client interfaces and client applications to access 4GL Web services, you must have
Java SDK 1.3 or later and the Axis Toolkit. For more information, see the README files in the
Java samples described in Chapter 6, Sample Progress 4GL Web Services and Client
Applications.
B4
Developing a Java Client to Access Progress 4GL Web Services
C:\OrderInfo.wsdl
http://servicehost:80/wsa/wsa1/wsdl?targetURI=OrderInfo
Each generated interface object is a class for an Open Client object an/ or some other component
of the WSDL that is represented as an object in the Java interface.
TargetNamespace="urn:OrderSvc:OrderInfo"
The relative directory structure created from this namespace is the following:
OrderSvc/OrderInfo
B5
OpenEdge Development: Web Services
Proxy classes
The Axis interface generator for this sample provides the classes for the Web service
components shown in Table B2. This represents one class for each specified Web service
(WSDL) object or component.
Table B2: Proxy classes for a sample Java Axis client (RPC/Encoded)
Web service
components Class Path
CustomerOrderObjStub .../OrderInfo/CustomerOrder
/CustomerOrderObjStub.java
OrderDetailsRowHolder .../CustomerOrder/
holders/OrderDetailsRowHolder
.java
B6
Developing a Java Client to Access Progress 4GL Web Services
CHARACTER String
COM-HANDLE long
DATE java.util.Date
DECIMAL java.math.BigDecimal
LOGICAL boolean
MEMPTR byte[]
RAW byte[]
ROWID byte[]
WIDGET-HANDLE long
Output parameters
The Java language does not provide a mechanism to pass output parameters. To work around
this, client interfaces use the Java standard of representing output parameters as holder classes,
which provide the reference space to return output parameter values. Axis provides holder
classes for all standard Java data types. The Axis interface generator (WSDL2Java) creates
holder classes for output TABLE and TABLE-HANDLE parameters. For more information on Axis
support for holder classes, see the Axis Users Guide.
B7
OpenEdge Development: Web Services
Represent output TABLE parameters using an array holder class and a row holder class for
the row objects, as in the following RPC/Encoded example:
B8
Developing a Java Client to Access Progress 4GL Web Services
Table B4 lists the data type mappings for TABLE columns between the Progress 4GL and Java.
Table B4: Java data types for TABLE (static temp-table) parameter
columns
CHARACTER String
COM-HANDLE long
DATE java.util.Date
DECIMAL java.math.BigDecimal
LOGICAL boolean
RAW byte[]
ROWID byte[]
WIDGET-HANDLE long
B9
OpenEdge Development: Web Services
For every Web service object containing a method that passes a TABLE-HANDLE parameter,
the WSDL contains a <TableHandleParam> element defined as a <complexType>
definition. Therefore, a TableHandleParam class is created for every client object which
contains a method that passes a TABLE-HANDLE parameter, for example:
For input TABLE-HANDLE parameters, the client must create a TableHandleParam object,
consisting of a MessageElement array containing the XML Schema and data for the
TABLE-HANDLE. For output TABLE-HANDLE parameters, the client must parse the XML
Schema and data in the MessageElement array.
Table B5 lists the typical data type mappings for TABLE-HANDLE columns between Progress
4GL and Java.
CHARACTER String
DATE java.util.GregorianCalendar
DECIMAL java.math.BigDecimal
LOGICAL boolean
RAW byte[]
B10
Developing a Java Client to Access Progress 4GL Web Services
This is an example of an AppObject release method for the OrderInfo AppObject as defined
for the OrderInfoObjStub class:
B11
OpenEdge Development: Web Services
Non-persistent procedure
Progress 4GL:
/* FindCustomerByNum.p */
Note: The output parameter holder class shown in bold is provided by Axis.
Persistent procedure
Progress 4GL:
/* CustomerOrder.p */
Note: This procedure returns a value using the 4GL RETURN statement.
B12
Developing a Java Client to Access Progress 4GL Web Services
User-defined function
Progress 4GL:
/* CustomerOrder.p */
Progress 4GL:
/* CustomerOrder.p */
PROCEDURE GetOrderDetails :
DEFINE OUTPUT PARAMETER TABLE FOR OrderDetails.
Note: The output parameter holder class shown in bold is generated by the Axis
WSDL2Java command.
B13
OpenEdge Development: Web Services
Temp-table definition
Progress 4GL:
/* CustomerOrder.p */
Progress 4GL:
/* DynTT.p */
B14
Developing a Java Client to Access Progress 4GL Web Services
Releasing an object
Notes: For more information on the concepts and procedures underlying these tasks, see
Chapter 4, General Client Programming Model for Progress 4GL Web Services and
Chapter 5, Sample Code with SOAP Messages for Progress 4GL Web Services.
OpenEdge comes installed with complete sample client applications that access 4GL
Web services. For more information, see Chapter 6, Sample Progress 4GL Web
Services and Client Applications.
B15
OpenEdge Development: Web Services
1. Create the Web service locator. For the sample, you generate the OrderInfo client's
service object that manages the connection with the WSA:
2. Instantiate the client objects that do the marshalling and unmarshalling of SOAP and
HTTP messages for methods on the OrderInfo object. For example, you might execute
the following method for the sample:
OrderInfoObjStub orderInfo =
(OrderInfoObjStub)service.getOrderInfoObj(connectURL);
3. Instantiate the client objects that do the marshalling and unmarshalling of SOAP and
HTTP messages for methods on the CustomerOrder object. For example you might
execute the following method for the sample:
CustomerOrderObjStub custOrder =
(CustomerOrderObjStub)service.getCustomerOrderObj(connectURL);
B16
Developing a Java Client to Access Progress 4GL Web Services
A client application defines one or more of these handlers and binds them to a <portType>
(Open Client object) defined in the Web service's WSDL document. Each time a SOAP request
or response message is handled by an object, the appropriate handlers bound to the object are
called and allowed access to the request or response message. For more information, see the
source code modules for the Java samples described in Chapter 6, Sample Progress 4GL Web
Services and Client Applications.
OpenEdge provides a sample handler class (PscObjectIDHandler) to manage object IDs. This
PscObjectIDHandler class is one possible implementation of a JAX-RPC handler. It provides
two essential pieces of functionality:
1. It is invoked for each incoming SOAP response for the <portType> element (Open Client
object type) where it is bound. When invoked, it scans the SOAP response header for an
object ID that corresponds to an Open Client object name. If it finds one of these Open
Client object IDs, it extracts the object ID value and stores it along with the object name.
The client application or the handler can then access this stored object ID to insert it into
a subsequent SOAP request header. If a handler does not already have an object ID value
reserved to insert in a given SOAP request header, it automatically uses the first object ID
that it stores.
2. It is invoked for each outgoing SOAP request for the <portType> element (Open Client
object type) where it is bound. It then inserts a SOAP header containing the object ID for
the Open Client object name that corresponds to the <portType> element where it is
bound. If an object ID value does not exist for the Open Client object name, the handler
does not insert a SOAP header into the request.
Along with the PscObjectIDHandler class provided with the Progress 4GL Web services
samples is a companion class, HandlerControlBlock. This class allows the Web service client
application to access object ID values stored in a PscObjectIDHandler object. It also gives the
application the ability to control the Object ID value the PscObjectIDHandler inserts into
SOAP request headers. For each PscObjectIDHandler object instance, there is a companion
HandlerControlBlock created and associated with it.
B17
OpenEdge Development: Web Services
The following steps create and register a unique handler for each Open Client object so it can
automatically insert its corresponding object ID into outgoing SOAP requests without
intervention by the client application.
To create and register a unique handler for each Open Client object:
1. Set the <portType> element name specified in the WSDL for the OrderInfoObjStub so a
PscObjectIDHandler can be bound to it:
orderInfo.setPortName("OrderInfoPort");
Note: Apache Axis does not automatically obtain the <portType> element name from the
WSDL document when it generates the client interface classes.
2. Set the <portType> element name specified in the WSDL for the CustomerOrderObjStub
so a PscObjectIDHandler can be bound to it:
custOrder.setPortName("CustomerOrderPort");
Note: Apache Axis does not automatically obtain the <portType> element name from the
WSDL document when it generates the client interface classes.
3. Declare the Open Client object names that the PscObjectIDHandler objects will use to
scan for object IDs in SOAP response headers returned from the WSA:
String[] orderInfoObjectNames =
new String[] { "OrderInfo", "CustomerOrder" };
B18
Developing a Java Client to Access Progress 4GL Web Services
Note: Both the "OrderInfo" and "CustomerOrder" object names are included because
the object IDs for both are returned from factory methods contained in the
OrderInfo AppObject.
orderInfoControlBlock =
PscObjectIDHandler.registerObjectIDHandler(
service,
orderInfoObjectNames,
"",
"OrderInfoPort",
debugHandler );
custOrderControlBlock =
PscObjectIDHandler.registerObjectIDHandler(
service,
orderInfoObjectNames,
"",
"CustomerOrderPort",
debugHandler );
B19
OpenEdge Development: Web Services
Caution: Now that the Web service is connected, remember to release the AppObject when it
is no longer needed.
The object ID handler automatically inserts the orderInfo object ID into the SOAP request
header.
B20
Developing a Java Client to Access Progress 4GL Web Services
orderInfo.createPO_CustomerOrder(3);
Caution: Now that the ProcObject is created, remember to release the object later, when
it is no longer needed.
if (null == orderInfoControlBlock.getObjectNameID("CustomerOrder"))
{
throw new Exception("No header returned from a create operation for
CustomerOrder.");
}
custOrderControlBlock.importObjectID("CustomerOrder",
orderInfoControlBlock.exportObjectID("CustomerOrder"));
B21
OpenEdge Development: Web Services
4. The client application must then remove (release) the object ID value for the
CustomerOrderObjStub object from the OrderInfoObjStub handler because it is no
longer needed by that handler:
orderInfoControlBlock.releaseObjectNameID("CustomerOrder");
try
{
int orderCount = custOrder.getTotalOrdersByNumber(new BigDecimal(5.0));
System.out.println("The total Customer Orders are: " + orderCount);
}
catch (NullPointer Exception e)
{
...
}
Note: The object ID handler automatically inserts the custOrder object ID into the SOAP
request header.
B22
Developing a Java Client to Access Progress 4GL Web Services
ArrayOfOrderDetailsRowHolder orderDetailsHolder =
new ArrayOfOrderDetailsRowHolder(null);
// Let's now ask the WebService for the order details of the
// current customer
custOrder.getOrderDetails(orderDetailsHolder);
Note: The object ID handler automatically inserts the custOrder object ID into the SOAP
request header.
// Loop through the rows and print some of the column values
B23
OpenEdge Development: Web Services
import DynTTSrvc.*;
import DynTTSrvc.DynTT.*;
import DynTTSrvc.DynTT.holders.*;
import org.apache.axis.message.MessageElement;
import org.w3c.dom.Element;
...
// Prepare the Schema and Data for the Input TABLE-HANDLE Parameter
// Create the XML Schema and data for the dynamic TEMP-TABLE.
// Then create the TableHandleParam object, ttHandle
...
// Create the holder for the INPUT-OUTPUT TableHandleParam parameter, ttHandle
TableHandleParamHolder ttHolder = new TableHandleParamHolder( );
ttHolder.value = ttHandle;
B24
Developing a Java Client to Access Progress 4GL Web Services
RowSet.java Represents the XML Schema and data for a TABLE-HANDLE parameter:
In the RowSet class, m_rows is a Vector of rows, each of which is a Vector of column data.
Each column datum is a Java object appropriate for the column data type. The m_schema
variable is the ColumnMetaData array representing the schema for the temp-table.
SchemaParser.java Parses the <schema> element from a SOAP response message and
creates a ColumnMetaData array for the RowSet class:
B25
OpenEdge Development: Web Services
rsIn.setSchema(schema);
...
B26
Developing a Java Client to Access Progress 4GL Web Services
/*
Call the buildRowSet method on the RowSet object.
buildRowSet creates a SchemaParser object to parse the <schema> element of the
dataSetOut and creates the m_schema ColumnMetaData[ ] array representing the
schema. buildRowSet then parses the <Data> element and creates the m_rows
Vector
representing the data.
*/
rsOut.buildRowSet(dataSetOut);
// print out the data for the dynamic temp-table to the console
rsOut.printData( );
B27
OpenEdge Development: Web Services
Releasing an object
The following steps use the object ID handler (PscObjectIDHandler) to manage the object IDs
of the two objects about to be released.
1. Release the logical connection. For example, to release the CustomerOrder ProcObject,
call this method:
custOrder.release_CustomerOrder( );
2. Remove (release) the ProcObject ID from the object ID handler, so this ProcObject ID
cannot be used again:
custOrderControlBlock.releaseObjectNameID("CustomerOrder");
orderInfo.release_OrderInfo( );
2. Remove (release) the AppObject ID from the object ID handler, so this AppObject ID
cannot be used again:
orderInfoControlBlock.releaseObjectNameID("OrderInfo");
B28
Developing a Java Client to Access Progress 4GL Web Services
Place a try...catch block around any code that accesses the Web server and catch the
AxisFault exception.
B29
OpenEdge Development: Web Services
This is an example of Axis client code to catch a SOAP fault (an AxisFault exception):
try
{
// code to Access the Web Service
}
catch (AxisFault e)
{
// Get the (single) child element of the SOAP Fault <detail> element,
// the <FaultDetail> element.
Caution: In any catch block where you exit the program, you must release all Web service
objects you created in the program.
B30
Developing a Java Client to Access Progress 4GL Web Services
1. Set up your Classpath as specified in the Axis Users Guide. Make sure you put the path
to your client interface on the Classpath.
2. Compile both the interface and your client application classes using the Java compiler.
The sample Progress 4GL Web services and client code provided with OpenEdge.
http://java.sun.com
B31
OpenEdge Development: Web Services
B32
C
Progress 4GL Elements for Accessing
Web Services
Many elements of the Progress 4GL support access to Web services, including some that are
extensions to other functionality and some that are unique for interacting with Web services.
The following sections describe all of these elements, including:
Asynchronous request object handle A type of handle that maintains the status of an
asynchronous request in a 4GL client application.
This handle provides methods and attributes that
allow you to check the status of an asynchronous
Web service operation.
C2
Progress 4GL Elements for Accessing Web Services
SOAP fault object handle A handle to an object that contains SOAP fault
information for a Web service request. This
system handle provides the SOAP fault object
handle as the value of its ERROR-OBJECT-DETAIL
attribute.
SOAP fault-detail object handle A handle to an object that references any <detail>
element returned in a SOAP fault message
generated for a Web service request. The SOAP
fault object handle provides any SOAP fault-detail
object handle as the value of its
SOAP-FAULT-DETAIL attribute.
SOAP header object handle A handle to an object that contains the SOAP
header for a SOAP request or response message
generated for a Web service operation. This can be
either an existing header from a SOAP response
message, or a newly-created header for a pending
SOAP request message.
C3
OpenEdge Development: Web Services
C4
Progress 4GL Elements for Accessing Web Services
C5
OpenEdge Development: Web Services
RUN operationName IN hPortType Invokes a Web service operation that does not
[ ASYNCHRONOUS contain a <return> parameter element, where
[ SET asyncRequestHandle ] operationName is the name of a Web service
operation specified in the WSDL file, hPortType
[ EVENT-PROCEDURE
is a handle to the procedure object that
eventInternalProcedure
encapsulates the operation, and parameter is a
[ IN procedureContext ]] 4GL procedure parameter as required by the
[ ( parameter WSDL for the operation. If the operation is
[ , parameter ] ... ) ] invoked asynchronously, asyncRequestHandle is
a handle that is set to the asynchronous request
[ NO-ERROR ] .
object created for the asynchronous request,
eventInternalProcedure is the name of a 4GL
internal procedure defined to handle the results of
the asynchronous request, and procedureContext
is a handle to an active 4GL procedure object that
encapsulates the event internal procedure.
C6
Progress 4GL Elements for Accessing Web Services
Table C3: Attributes, methods, and events to access Web services (1 of 10)
C7
OpenEdge Development: Web Services
Table C3: Attributes, methods, and events to access Web services (2 of 10)
C8
Progress 4GL Elements for Accessing Web Services
Table C3: Attributes, methods, and events to access Web services (3 of 10)
C9
OpenEdge Development: Web Services
Table C3: Attributes, methods, and events to access Web services (4 of 10)
C10
Progress 4GL Elements for Accessing Web Services
Table C3: Attributes, methods, and events to access Web services (5 of 10)
C11
OpenEdge Development: Web Services
Table C3: Attributes, methods, and events to access Web services (6 of 10)
C12
Progress 4GL Elements for Accessing Web Services
Table C3: Attributes, methods, and events to access Web services (7 of 10)
C13
OpenEdge Development: Web Services
Table C3: Attributes, methods, and events to access Web services (8 of 10)
C14
Progress 4GL Elements for Accessing Web Services
Table C3: Attributes, methods, and events to access Web services (9 of 10)
C15
OpenEdge Development: Web Services
Table C3: Attributes, methods, and events to access Web services(10 of 10)
C16
D
Data Type Casting Rules for Progress
4GL Calls to Web Services
This appendix describes how OpenEdge casts between the following 4GL data types and XML
Schema data types in parameters passed to Web services called from the 4GL. Any casting
between a 4GL type and an unsupported XML Schema type or an invalid match between a 4GL
type and a supported XML Schema type raises a 4GL run-time error, as described in the
following sections:
CHARACTER or LONGCHAR
DATE
DATETIME
DATETIME-TZ
DECIMAL
INTEGER
LOGICAL
OpenEdge Development: Web Services
MEMPTR or RAW
Note: The following tables describe data transformations for the 4GL INPUT and OUTPUT
parameter modes. The INPUT-OUTPUT parameter mode behaves in the same manner.
D2
Data Type Casting Rules for Progress 4GL Calls to Web Services
CHARACTER or LONGCHAR
Table D1 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL CHARACTER or LONGCHAR type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
All XML Schema INPUT1 Attempts to format the 4GL string value to match
types where the specified XML Schema type for inclusion in
CHARACTER is the the SOAP request message.2
suggested 4GL
mapping (see Chapter OUTPUT1 Converts the value from the formatting of the
8, Analyzing WSDL specified XML Schema type before copying it into
for Progress 4GL
the 4GL parameter as a string value.2
Access to Web
Services)
All XML Schema INPUT1 Copies the string value directly, with no attempt to
types where format it, for inclusion in the SOAP request
CHARACTER or message. OpenEdge performs minimal validation
LONGCHAR is not the to ensure that the string contains data formatted
suggested 4GL according to the rules of the XML Schema type.
mapping (see Chapter
8, Analyzing WSDL OUTPUT1 Copies the XML Schema value directly from the
for Progress 4GL SOAP response message to the 4GL parameter
Access to Web unchanged from its XML Schema format.
Services)
1
On both INPUT and OUTPUT parameters, OpenEdge translates the value between the cpinternal code page and
Unicode.
2
The process of serializing and de-serializing CHARACTER data inserts and removes XML character references,
for example, replacing "<" with "<".
D3
OpenEdge Development: Web Services
DATE
Table D2 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL DATE type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D4
Data Type Casting Rules for Progress 4GL Calls to Web Services
DATETIME
Table D3 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL DATETIME type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D5
OpenEdge Development: Web Services
DATETIME-TZ
Table D4 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL DATETIME-TZ type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D6
Data Type Casting Rules for Progress 4GL Calls to Web Services
DECIMAL
Table D5 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL DECIMAL type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D7
OpenEdge Development: Web Services
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D8
Data Type Casting Rules for Progress 4GL Calls to Web Services
INTEGER
Table D6 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL INTEGER type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D9
OpenEdge Development: Web Services
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D10
Data Type Casting Rules for Progress 4GL Calls to Web Services
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D11
OpenEdge Development: Web Services
LOGICAL
Table D7 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL LOGICAL type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
D12
Data Type Casting Rules for Progress 4GL Calls to Web Services
MEMPTR or RAW
Table D8 describes the supported castings in each 4GL parameter mode (INPUT and OUTPUT)
between the 4GL MEMPTR or RAW type and XML Schema.
In this 4GL
For this XML parameter
Schema type... mode... OpenEdge...
base64Binary INPUT Serializes the value of each byte in the 4GL value
hexBinary according to the XML Schema serialization rules
for the data type. If the mapping is to a
base64Binary value with the encoding attribute
set, the value is base-64 encoded and copied
directly from the 4GL parameter without
serialization.
D13
OpenEdge Development: Web Services
D14
Index
Client programming for 4GL Web services DATE 4GL client casting rules D4
41
DATETIME 4GL client casting rules D5
Client programming for SOAP faults 441
DATETIME-TZ 4GL client casting rules
Client requirements D6
4GL Web services 111
DECIMAL 4GL client casting rules D7
Complex data management
4GL clients of Web services 108 Defining client requirements 112
4GL examples 109
Defining the Web service 113
4GL types 109
Definitions section
Complex types
WSDL
4GL client and XML Schema 837
4GL Web services 210
Configuring the WSA 113 generic 122
Index2
Index
F L
4GL attributes and methods for accessing Literal format 28
Web services C7
Log files
4GL clients, See Progress 4GL applications 4GL Web service testing 77
13
LOGICAL 4GL client casting rules D12
4GL object handles for accessing Web
LONGCHAR 4GL client casting rules D3
services C2
Index3
OpenEdge Development: Web Services
Index4
Index
Index5
OpenEdge Development: Web Services
SOAP faults T
4GL clients handling 122
4GL Web services Temp-tables
clients handling 440 4GL Web services 428
detecting 123
example 4GL handling 126 Testing
4GL Web services
SOAP formats error identification 712
4GL Web services log files 77
client interface affects 43 sample error scenarios 715
SOAP header object model 115 setting error levels 74
SOAP faults 77
SOAP header objects SOAP message viewers 710
attributes and methods 1133 AppServers for 4GL Web services 72
Index6
Index
Index7
OpenEdge Development: Web Services
Index8