Creating SOAP Services and Web Clients with Ensemble
Creating an Ensemble Web Service
[Back] [Next]
   
Server:docs1
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter describes how to create an Ensemble web service, which is a web service in an Ensemble production. When you do this, you are providing a SOAP-enabled interface to the production. This chapter discusses the following:

For settings not listed in this book, see Settings in All Productions in Managing Ensemble Productions.
For an alternative approach, see the appendix Using the SOAP Inbound Adapter.”
Tip:
Ensemble also provides specialized business service classes that use SOAP, and one of those might be suitable for your needs. If so, no programming would be needed. See Connectivity Options in Introducing Ensemble.
Overall Behavior
An Ensemble web service is based on EnsLib.SOAP.Service or a subclass. This class extends both Ens.BusinessService (so that it is an Ensemble business service) and %SOAP.WebService (so that it can act as a web service as well). An Ensemble web service behaves as follows:
Communication with the outside world is done via SOAP request and response messages. Ensemble request and response messages are used within the production.
Basic Requirements
To create a web service in an Ensemble production, you create a new business service class as described here. Later, add it to your production and configure it.
You must also create appropriate message classes, if none yet exist. See Defining Ensemble Messages in Developing Ensemble Productions.
The following list describes the basic requirements of the business service class:
The following example shows in general what the class might look like:
Class Hospital.MyService Extends EnsLib.SOAP.Service
{

///For this business service, ADAPTER should be "" so that we use the normal SOAP processing
Parameter ADAPTER = "";

Parameter SERVICENAME = "MyService";

Parameter NAMESPACE = "http://www.myhospital.org";

Parameter USECLASSNAMESPACES = 1;

Method GetAuthorization(patientID As %Integer, RequestedOperation As %String, 
LikelyOutcome As %String) As %Status [ WebMethod ]
{
    set request = ##class(Hospital.OperateRequest).%New()
    set request.PatientID = patientID
    set request.RequestedOperation = RequestedOperation
    set request.LikelyOutcome = LikelyOutcome
    set tSC=..SendRequestSync("Hospital.PermissionToOperateProcess",request,.response)
    // Create the SOAP response, set its properties, and return it.
}

}
Defining Web Methods for Use in Ensemble
This section describes the basic requirements for an Ensemble web method.
Important:
In most cases, web methods should be instance methods. Within a web method, it is often necessary to set properties of and invoke methods of the web service instance to fine-tune the behavior of the method. Because a class method cannot do these tasks, a class method is usually not suitable as a web method.
For additional notes, see Basic Requirements in the chapter Creating Web Services in Creating Web Services and Web Clients in Caché.
Basic Steps of an Ensemble Web Method
Within an Ensemble web service, a web method should generally do the following:
  1. Create an Ensemble request message and set its properties with information from the inbound SOAP message.
  2. Call a suitable method of the business service to send the request to a destination within the production. Specifically, call SendRequestSync(), SendRequestAsync(), or (less common) SendDeferredResponse(). For details, see Sending Request Messages in Developing Ensemble Productions
    Each of these methods returns a status (specifically, an instance of %Status).
  3. Check the status returned from the previous step and react appropriately.
  4. Then:
Returning Faults to the Caller
By default, if an error occurs when a web method runs, the web service returns a SOAP message to the caller, but this message does not indicate where precisely the fault occurred. An example follows:
  <SOAP-ENV:Body>
   <SOAP-ENV:Fault>
    <faultcode>SOAP-ENV:Server</faultcode>
    <faultstring>Server Application Error</faultstring>
   <detail>
      <error xmlns='http://www.myapp.org' >
        <text>ERROR #5002: Cache error: <INVALID OREF>
            zGetCustomerInfo+10^ESOAP.WebService.1</text>
      </error>
   </detail>
   </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
Your web methods should check for an error and use ReturnMethodStatusFault() or ReturnStatusFault(). In case of error, the message will be more informative, as follows:
  <SOAP-ENV:Body>
   <SOAP-ENV:Fault>
    <faultcode>SOAP-ENV:Method</faultcode>
    <faultstring>Server Application Error</faultstring>
    <faultactor>ESOAP.WebService</faultactor>
    <detail>
      <error xmlns='http://www.myapp.org' >
       <text>ERROR <Ens>ErrException:
             <DIVIDE>zGetCustomerRequest+8^ESOAP.MyOperation.1 -
             logged as '13 Jul 2007' number 4 @'    set x=100/0'</text>
     </error>
   </detail>
   </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
The ReturnMethodStatusFault() and ReturnStatusFault() methods return a SOAP fault to the caller and then generate an exception which will create an Ensemble alert (depending on settings). These methods have the following signatures:
ClassMethod ReturnStatusFault(pCode As %String,
                              pStatus As %Status)

ClassMethod ReturnMethodStatusFault(pStatus As %Status)
Here:
Also notice that these methods set the <faultactor> element of the SOAP fault.
Example
The following shows a simple example:
Method GetCustomerInfo(ID As %Numeric) As ESOAP.SOAPResponse [WebMethod]
{
    //create Ensemble request message with given ID
    set request=##class(ESOAP.CustomerRequest).%New()
    set request.CustomerID=ID

    //send Ensemble request message 
    set sc= ..SendRequestSync("GetCustomerInfoBO",request,.response)
    if $$$ISERR(sc) do ..ReturnMethodStatusFault(sc)

    //use info from Ensemble response to create SOAP response
    set soapresponse=##class(ESOAP.SOAPResponse).%New()
    set soapresponse.CustomerID=response.CustomerID
    set soapresponse.Name=response.Name
    set soapresponse.Street=response.Street
    set soapresponse.City=response.City
    set soapresponse.State=response.State
    set soapresponse.Zip=response.Zip

    quit soapresponse
}
Viewing the WSDL
Ensemble automatically creates and publishes a WSDL document that describes your Ensemble web service. Whenever you modify and recompile the web service, Ensemble automatically updates the WSDL correspondingly.
To view the WSDL for the web service, use the following URL:
base/app-name/web_serv.cls?WSDL
Here base is the base URL for your web server (including port if necessary), /csp/app is the name of the CSP application in which the web service resides, and web_serv is the class name of the web service. (Typically, /csp/app is /csp/namespace, where namespace is the Ensemble namespace that contains the CSP application. )
For example:
http://localhost:57772/csp/samples/MyApp.StockService.cls?WSDL
The browser displays the WSDL document as an XML document. The following shows an example:
Web Service Example
The following simple example shows an Ensemble web service that can be used to look up customer information, given a customer ID.
Class ESOAP.WebService Extends EnsLib.SOAP.Service
{

Parameter ADAPTER;

Parameter NAMESPACE = "http://www.myapp.org";

Parameter SERVICENAME = "CustomerLookupService";

Method GetCustomerInfo(ID As %Numeric) As ESOAP.SOAPResponse [WebMethod]
{
    //create Ensemble request message with given ID
    set request=##class(ESOAP.CustomerRequest).%New()
    set request.CustomerID=ID

    //send Ensemble request message 
    set sc= ..SendRequestSync("GetCustomerInfoBO",request,.response)
    if $$$ISERR(sc) do ..ReturnMethodStatusFault(sc)

    //use info from Ensemble response to create SOAP response
    set soapresponse=##class(ESOAP.SOAPResponse).%New()
    set soapresponse.CustomerID=response.CustomerID
    set soapresponse.Name=response.Name
    set soapresponse.Street=response.Street
    set soapresponse.City=response.City
    set soapresponse.State=response.State
    set soapresponse.Zip=response.Zip

    quit soapresponse
}

}
The SOAP response class is as follows:
///
Class ESOAP.SOAPResponse Extends (%RegisteredObject, %XML.Adaptor)
{

Property CustomerID As %Numeric;
Property Name As %String;
Property Street As %String;
Property City As %String;
Property State As %String;
Property Zip As %Numeric;

}
Note the following points:
Enabling SOAP Sessions
The SOAP specification does not include session support. However, it is often useful to maintain a session between a web client and the web service that it uses. You can do this with an Ensemble web service. If a web service uses sessions, it establishes a session ID and allows repeated calls on the service after one successfully authenticated call from a client.
Support for SOAP sessions is controlled by the SOAPSESSION class parameter. The default is 0, which means that the web service does not use sessions.
To enable SOAP sessions, create a subclass of EnsLib.SOAP.Service and set SOAPSESSION to 1 in the subclass. Base your Ensemble web service on this subclass.
For more information on SOAP sessions, see Creating Web Services and Web Clients in Caché in the Caché documentation.
Additional Options
Because your Ensemble web service extends %SOAP.WebService, you can use all the SOAP support provided by that class. This support includes options for the following customizations, among others:
For these options and others, see Creating Web Services and Web Clients in Caché in the Caché documentation set.
Adding and Configuring the Web Service
To add your Ensemble web service (a business service) to an Ensemble production, use the Management Portal to do the following:
  1. Add an instance of your custom class to the Ensemble production.
    Important:
    Ensure that the configuration name is the same as the full class name, including package. This is a requirement for running an Ensemble web service.
  2. Enable the business service.
  3. Set the Pool Size setting to 0.
    For other settings, see Configuring Ensemble Productions.
  4. Run the production.