17.1.8.Exposing Stored Procedures as SOAP Objects

The special physical path /SOAP/ in the Virtuoso Web server is reserved for SOAP objects. Virtuoso makes available any stored procedure created in the default qualifier of the SOAP user, with execution privileges granted to the SOAP user. You can also use Virtuoso's virtual host mechanism to create new logical paths for accessing SOAP objects. A logical path property soap_user determines the db user for SOAP. If a logical path points to the /SOAP/ special physical path, it will expose any procedures created in the default qualifier of, and with execution privileges to, soap_user to the world as SOAP objects.

If the physical path of /SOAP exists under the VSP root directory then any non-SOAP specific HTTP requests will be directed there for content. This can be useful for helping to establish the presence and location of a SOAP endpoint - some applications attempt a standard HTTP connection first. You might configure a virtual directory, intended for SOAP, with a default page referencing a description of the SOAP endpoint, a page in the <VSPROOT>/SOAP directory, preventing an HTTP 404 style error misleading an application into believing the SOAP endpoint is down regardless of whether it tried to talk SOAP to it or not.

[Note] Note:

Procedures exposed as SOAP procedures run as any other stored procedure in Virtuoso and can call and get return values from other procedures and functions not exposed through SOAP. The ability to execute procedures attached from remote data sources facilitates SOAP-enabling existing database applications in a heterogeneous environment.

Example17.8.Creating a new virtual host for SOAP execution

Create new user in the database for SOAP:

SQL>CREATE USER SOAPDEMO;

Set the default catalogue/qualifier for the new user to WS. This is where procedures to be used as SOAP objects will be created:

SQL>USER_SET_QUALIFIER ('SOAPDEMO', 'WS');

Create a new virtual host definition, using vhost_define() .

SQL>VHOST_DEFINE (vhost=>'*ini*',lhost=>'*ini*',lpath=>'/mysoapdomain',ppath=>'/SOAP/',soap_user=>'SOAPDEMO');

An existing mapping could be removed using the command:

SQL>VHOST_REMOVE (vhost=>'*ini*',lhost=>'*ini*',lpath=>'/mysoapdomain')
[Note] Note:

'*ini* ' is a special value that instructs Virtuoso to use the default values from the Virtuoso initialization file.

All procedures that are created with the WS.SOAPDEMO qualifier and then granted execution to SOAPDEMO will be visible to SOAP. Make a simple SOAPTEST procedure and grant the appropriate privileges to the SOAPDEMO user:

SQL> create procedure
  WS.SOAPDEMO.SOAPTEST (in par varchar)
{
  return (upper(par));
};

SQL> grant execute on WS.SOAPDEMO.SOAPTEST to SOAPDEMO;

The SOAP object may now be tested by using the soap_client() function, which returns a vector representation of the SOAP object returned by the call. The example below simply extracts the returned string with aref() , as the exact format of the object returned is known:

SQL>select aref(aref(
        soap_client (url=>sprintf ('http://example.com:%s/mysoapdomain', server_http_port ()),
        operation=>'SOAPTEST',
        parameters=>vector('par', 'demotext')),
        1), 1);
callret
VARCHAR
_______

DEMOTEXT

Printing the output on the console or server log with dbg_obj_print() would output something like:

(("SOAPTESTResponse" ) (("CallReturn" ) "DEMOTEXT" ) )

The automatic service description generation can be verified by retrieving http://<server:port>/mysoapdomain/services.wsdl , and preferably tested by pointing a web browser at http://<server:port>/mysoapdomain/services.vsmx

SQL> select http_get (sprintf ('http://example.com:%s/mysoapdomain/services.wsdl', server_http_port()));
callret
VARCHAR
_______________________________________________________________________________

<?xml version="1.0"?>
<definitions
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
 xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
 xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:s="services.wsdl"
 xmlns:tns="services.wsdl"
 targetNamespace="services.wsdl"
 name="VirtuosoSOAP" xmlns="http://schemas.xmlsoap.org/wsdl/">

  <types>
  <schema targetNamespace="services.wsdl"
   xmlns="http://www.w3.org/2001/XMLSchema"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
    <complexType name="echoStringArrayResponse">
      <sequence>
        <element name="return" type="ArrayOfstring_literal"/>
      </sequence>
    </complexType>
    <complexType name="echoVoid"/>
    <complexType name="ArrayOffloat">
      <complexContent>
        <restriction base="soapenc:Array">
          <sequence>
            <element name="item" type="float" minOccurs="0" maxOccurs="unbounded"/>
          </sequence>
          <attributeGroup ref="soapenc:commonAttributes"/>
          <attribute ref="soapenc:offset" />
          <attribute ref="soapenc:arrayType" wsdl:arrayType="float[]"/>
        </restriction>
      </complexContent>
    </complexType>
    <complexType name="SOAPStruct">
      <sequence>
        <element name="varString" type="string"/>
        <element name="varInt" type="int"/>
        <element name="varFloat" type="float"/>
      </sequence>
    </complexType>
    <complexType name="echoStructResponse">
      <sequence>
        <element name="return" type="SOAPStruct"/>
      </sequence>
    </complexType>
    <complexType name="echoVoidResponse"/>
    <complexType name="ArrayOfString2D">
    ...