Skip to main content
Previous section   Next section

Creating an Ensemble Web Service

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:

  • Because it is a web service, it has a WSDL document (generated automatically) that describes the web methods available in it. The service can receive any SOAP message that conforms to the WSDL and sends SOAP responses in return.

  • Because it is an Ensemble business service, it is an integral part of the Ensemble production to which you add it. Monitoring, error logging, runtime parameters, and all the rest of the Ensemble machinery are available as usual.

    Note:

    An Ensemble web service is not available unless the production is running (and the business service is enabled).

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:

  • Your class should extend EnsLib.SOAP.Service. 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).

  • The class should define the ADAPTER parameter as null (""). For example:

    Parameter ADAPTER = "";
    Copy code to clipboard

    Or, equivalently:

    Parameter ADAPTER;
    Copy code to clipboard
  • The class should specify values for other parameters:

    Parameter Description
    SERVICENAME Name of the web service. This name must start with a letter and must contain only alphanumeric characters. The default service name is "MyEnsembleRequestWebService"
    NAMESPACE URI that defines the target XML namespace for your web service, so that your service, and its contents, do not conflict with another service. This is initially set to http://tempuri.org which is a temporary URI used by SOAP developers during development.
    TYPENAMESPACE XML namespace for the schema in the types defined by the web service. If you do not specify this parameter, the schema is in the namespace given by NAMESPACE instead.
    RESPONSENAMESPACE URI that defines the XML namespace for the response messages. By default, this is equal to the namespace given by the NAMESPACE parameter.
  • The class should define web methods, as described in the “Defining Web Methods” section.

  • For other options and general information, see “Defining a Business Service Class” in Developing Ensemble Productions.

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.
}

}
Copy code to clipboard

Defining Web Methods for Use in Ensemble

This section describes the basic requirements for an Ensemble web method.

  • Define the method within a subclass of EnsLib.SOAP.Service, as described in “Basic Requirements.”

  • Mark the method with the WebMethod keyword.

  • Ensure that all arguments and return values are XML-enabled:

    • If the method uses an object as an argument or a return value, you must ensure that the object is XML-enabled. That is, the class definitions for the types must extend %XML.Adaptor. The default settings for this class are normally suitable; if not, see Projecting Objects to XML.

    • If the method uses a data set as an argument or return value, you must ensure the data set is of type %XML.DataSet, which is an XML-enabled subclass of the standard %ResultSet.

    • To use a collection (%ListOfObjects or %ArrayOfObjects) as an argument or a return value, you must ensure that the ELEMENTTYPE parameter of the collection is set and refers to an XML-enabled class.

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:

    • In the case of success, look at the Ensemble response message that is returned by reference and use it to create the return value of the web method. As noted previously, the return value must be XML-enabled so that it can be packaged as a SOAP response.

    • In the case of failure, call the ReturnMethodStatusFault() or ReturnStatusFault() method of the web service so that a SOAP fault can be returned and an Ens.Alert can be generated; see the next section for details.

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>
Copy code to clipboard

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>
Copy code to clipboard

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)
Copy code to clipboard

Here:

  • pCode is a string that represents the error code to use in the <faultcode> element of the SOAP fault. The ReturnMethodStatusFault() method uses the generic error code SOAP-ENV:Method

  • pStatus is the status to use in the returned SOAP fault. This is used to create the details of the SOAP fault.

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
}
Copy code to clipboard

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
Copy code to clipboard

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
Copy code to clipboard

The browser displays the WSDL document as an XML document. The following shows an example:

images/esoap_example_wsdl_frag.png

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
}

}
Copy code to clipboard

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;

}
Copy code to clipboard

Note the following points:

  • The example web method (GetCustomerInfo) uses SendRequestSync() to communicate with a business operation elsewhere in the production. The method receives an Ensemble response message and uses it to create a SOAP response message.

  • The SOAP response class has the same properties as the corresponding Ensemble response class. Unlike the Ensemble response, however, the SOAP response class is XML-enabled and non-persistent.

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:

  • Customizing the SOAP headers

  • Passing attachments in the SOAP messages

  • Changing the binding style of the SOAP messages from document-style (the default) to rpc-style

  • Changing the encoding style of the messages from literal (the default) to SOAP-encoded

  • Customizing the XML types used in the SOAP messages

  • Customizing the SOAPAction header used to invoke a web method

  • Controlling whether elements are qualified (controlling the elementFormDefault attribute of the web service)

  • Controlling the form of null arguments (to be an empty element rather than omitted)

  • Writing the web method to have output parameters instead of return values

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.