Here is a problem that many people have asked me how to do it. “Returning an array of string” with the code first approach. The API or WSDL generation annotation guide, http://wso2.org/project/wsf/php/2.0.0/docs/wsdl_generation_api.html contain all the things required in details. Here is an example of a service that return an array of string.

<?php

/** splitMe function
 * @param string $string_to_split string to split
 * (maps to the xs:string XML schema type )
 * @return array of string $result split to array
 *(maps to the xs:double XML schema type )
 */
function splitMe($string_to_split)
{
    return array("result" => split(":", $string_to_split));

}

$operations = array("splitMe"=>"splitMe");
$opParams = array("splitMe"=>"MIXED");

$svr = new WSService(array("operations"=>$operations,
                           "bindingStyle"=>"doclit",
                           "opParams"=>$opParams));

$svr->reply();
?>

Note that the annotation corresponding to the return value.

 * @return array of spring $result split to array

This will generate an schema with an element of maxOccurs=’unbounded’. Note that you can get the wsdl from the ’serviceurl?wsdl’.

<xsd:element name="splitMeResponse">
    <xsd:complexType>
        <xsd:sequence>
            <xsd:element name="result" maxOccurs="unbounded" type="xsd:string"/>
        </xsd:sequence>
    </xsd:complexType>
</xsd:element>

Now just generate a client for this service using wsdl2php and try invoke it. You will get an array of string as the response.

    $input = new splitMe();
    $input->string_to_split = "a:b:c:d";

 
    // call the operation
    $response = $proxy->splitMe($input);
    print_r($response);

WSO2 announced the release of the Web Services Framework for C++ (WSF/C++) version 2.0.0. Similar to WSF/PHP which is really popular among the PHP community, WSF/CPP is the C++ language binding for the Apache Axis2/C and the other supporting web services projects like Apache Sandesha/C, Apache Rampart/C.

With this release C++ developers will be able to write web services and web service clients to inter-op with .NET/Java/PHP or any other platform built-on web service standards. The release is shiped with a code generation tool that will be used to generate the code for skeletons and stubs from a WSDL, so developers only need to concentrate on their business logic as the generated code will take care of building or parsing xmls and running them on top of the framework.
Here are the key features of the new release.

  1. Support core web service standards like SOAP 1.1, SOAP 1.2, WSDL 1.1, WSDL 2.0, REST
  2. Support for web services QoS specifications.
    • WS-Addressing
    • WS-Security
    • WS-Policy
    • WS-Security-Policy
    • WS-Reliable-Messaging
  3. Support binary attachment with MTOM and SWA (With the Support for large binaries)
  4. Code generation tool.
  5. Proven interoperability with .NET.

As a side note, you will be able to participate to a free summer school training session on the WSF/CPP conducted by Nandika Jayawardane who is the project lead of both WSF/CPP and WSF/PHP on 30th July. You can register to it (for free) from here.

Web services use SOAP faults to report fault cases back to clients. The faults can be generated from the SOAP framework in a case of invalid SOAP messages, invalid security tokens or they can be generated from the service business logic itself. The fault messages may contain simply a string indicating the error, or it may contain lot of details which could be useful to the clients find the problem. In fact the format of the SOAP fault is a standard. But services can send custom details within the details element in a SOAP fault.

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>soapenv:Sender</faultcode>
         <faultstring>..</faultstring>
         <detail> You Custom Message </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>

And you can define the schema of your custom fault message in a WSDL, so the clients can prepare to handle fault scenarios. In facts tools like Apache Axis2 WSDL2C, WSDL2Java tool will help you to work with custom faults when they are defined in the WSDL.  Here is an example section of a WSDL with an operation which can throw two faults “MyFirstException”, “MySecondException”.

<!-- fault schemas -->
<types>
 <schema ..>
  <element name="MyFirstException">
   <complexType>
    <sequence>
     <element name="text" type="xsd:string"/>
    </sequence>
   </complexType>
  </element>
  <!-- fault element -->
  <element name="MySecondException">
   <complexType>
    <sequence>
     <element name="number" type="xsd:int"/>
    </sequence>
   </complexType>
  </element>
 </schema>
</types>

<!-- the fault messages -->
<message name="MySecondExceptionFault">
 <part name="fault" element="ns1:MySecondException"/>
</message>

<message name="MyFirstExceptionFault">
 <part name="fault" element="ns1:MyFirstException"/>
</message>

<!-- operation to throw fault -->
<portType name="MyType">
 <operation name="myOperation">
  <input message="tns:myOperationRequest"/>
  <output message="tns:myOperationResponse"/>
  <fault name="MySecondException" message="tns:MySecondExceptionFault"/>
  <fault name="MyFirstException" message="tns:MyFirstExceptionFault"/>
 </operation>
</portType>

Note that the operation “myOperation” is throwing faults “MyFirstException”, “MySecondExcpetion”. If you generate the Java code for this operation, it would be simple as this,

public MyOperationRequest
MyOperation(MyOperationRequest) throws
          MyFirstExcpetion,
          MySecondExcpetion {
  // here is your business logic
}

Anyway we are going to write codes in ‘C’ language, which doesn’t have similar exception mechanism. Let see how we can do it, starting with writing the service and then writing a client.

Writing Services With Custom SOAP Faults

Once you generate the ‘C’ codes for the WSDL using WSDL2C tool, you should first have a look at the skeleton header file.

    /**
     * the generated fault union for operation "myOperation|urn:myuri:1.0",
     * in a case you want to return a fault, put the appropriate adb object for
     * the union variable pointer comes as the last parameter of the method
     */
    typedef union
    {
        adb_MyFirstException_t* MyFirstException;
        adb_MySecondException_t* MySecondException;

    } axis2_skel_MyService_myOperation_fault;

    /**
     * auto generated function declaration
     * for "myOperation|urn:myuri:1.0" operation.
     * @param env environment ( mandatory)
     * @param _myOperation of the adb_myOperation_t*
     *
     * @return adb_myOperationResponse_t*
     */
    adb_myOperationResponse_t* axis2_skel_MyService_myOperation(const axutil_env_t *env,
                                      adb_myOperation_t* _myOperation,
                                      axis2_skel_MyService_myOperation_fault *fault);

And at the very end of the header file, you will see an enumeration of constants corresponding to each fault is generated.

    typedef enum
    {
        AXIS2_SKEL_MYSERVICE_ERROR_NONE = AXIS2_SKEL_MYSERVICE_ERROR_CODES_START,

        AXIS2_SKEL_MYSERVICE_MYOPERATION_FAULT_MYFIRSTEXCEPTION,
        AXIS2_SKEL_MYSERVICE_MYOPERATION_FAULT_MYSECONDEXCEPTION,

        AXIS2_SKEL_MYSERVICE_ERROR_LAST

    } axis2_skel_MyService_error_codes;

That’s all you need to aware of. The plan is whenever you need to report the fault, you have to do three things inside the business logic.

  1. Create the adb object for the fault, in this case either “adb_MyFirstException_t” or “adb_MySecondException_t” and set it to the fault pointer variable.
  2. Set the constant corresponding to the fault using “AXIS2_ERROR_SET” function
  3. return NULL

Here is an example how you do it inside the actual business logic code.

    adb_myOperationResponse_t* axis2_skel_MyService_myOperation(const axutil_env_t *env,
                                      adb_myOperation_t* myOperation,
                                      axis2_skel_MyService_myOperation_fault *fault )
    {
        /* the buisness logic */

        ....

        if(/* checking some condition to throw the "MyFirstException" fault */)
        {
          /* 1. Creating the adb object and set it to the fault pointer variable */
          adb_MyFirstException_t *exp = NULL;
          exp = adb_MyFirstException_create(env);
          adb_MyFirstException_set_text(exp, env, "this is the exception 1"); /* custom value */

          fault->MyFirstException = exp;

          /* 2. Setting the error constant corrosponding to the fault */
          AXIS2_ERROR_SET(env->error,
                      AXIS2_SKEL_MYSERVICE_MYOPERATION_FAULT_MYFIRSTEXCEPTION,
                      AXIS2_FAILURE);

          /* 3. Returning NULL */
          return NULL;
        }

        else if(/* checking some condition to throw the "MySecondException" fault */)
        {
          /* 1. Creating the adb object and set it to the fault pointer variable */
          adb_MySecondException_t *exp = NULL;
          exp = adb_MySecondException_create(env);
          adb_MySecondException_set_number(exp, env, 2);/* custom value */

          fault->MySecondException = exp;

          /* 2. Setting the error constant corrosponding to the fault */
          AXIS2_ERROR_SET(env->error,
                      AXIS2_SKEL_MYSERVICE_MYOPERATION_FAULT_MYSECONDEXCEPTION,
                      AXIS2_FAILURE);
          /* 3. Returning NULL */
          return NULL;
        }

        /* return the response in no fault scenario */
        return response;
    }

That’s all you have to do, Axis2/C will make sure to build the fault and put your custom message inside the details element.

Writing Clients to Handle custom SOAP Faults

After generating the code for clients using WSDL2C tool, this time you should look at the generated stub header file first. It is just similar to the skeleton header files may be except all the “skel” prefixes are renamed to “stub” and additional parameter “stub” for the operation.

    /**
     * the generated fault union for operation "myOperation|urn:myuri:1.0",
     * in a case the server return a fault, the corresponding adb object will be loaded for
     * the union variable pointer comes as the last parameter of the method
     */
    typedef union
    {
        adb_MyFirstException_t* MyFirstException;
        adb_MySecondException_t* MySecondException;

    } axis2_stub_MyService_myOperation_fault;

    /**
     * auto generated function declaration
     * for "myOperation|urn:myuri:1.0" operation.
     * @param env environment ( mandatory)
     * @param _myOperation of the adb_myOperation_t*
     *
     * @return adb_myOperationResponse_t*
     */
    adb_myOperationResponse_t* axis2_stub_MyService_myOperation(axis2_stub_t* stub, const axutil_env_t *env,
                                      adb_myOperation_t* _myOperation,
                                      axis2_stub_MyService_myOperation_fault *fault);

    typedef enum
    {
        AXIS2_STUB_MYSERVICE_ERROR_NONE = AXIS2_STUB_MYSERVICE_ERROR_CODES_START,

        AXIS2_STUB_MYSERVICE_MYOPERATION_FAULT_MYFIRSTEXCEPTION,
        AXIS2_STUB_MYSERVICE_MYOPERATION_FAULT_MYSECONDEXCEPTION,

        AXIS2_STUB_MYSERVICE_ERROR_LAST

    } axis2_stub_MyService_error_codes;

Looking at this, you may have got the idea how to differentiate what fault is being thrown by the server and how to extract the parameters of the custom fault. Here is an example client code correctly handling exceptions.

    /* the structure to keep the fault */
    axis2_stub_MyService_myOperation_fault fault;

    ..... /* the part preparing the request is ignored here */

    /* invoking the "myOperation" operation */
    response = axis2_stub_op_MyService_myOperation(stub, env, op, &fault);

    /* checking the response == NULL implies fault is sent  */
    if(response == NULL)
    {
        /* getting the error number to distinguish the fault */
        error_code = env->error->error_number;

        /* compare error code with constants of each faults */
        if(error_code == AXIS2_STUB_MYSERVICE_MYOPERATION_FAULT_MYFIRSTEXCEPTION) {

            /* extracting out the adb objects */
            axis2_char_t *text = adb_MyFirstException_get_text(fault.MyFirstException, env);

            /* do a printf of the message */
            printf("My First Exception called: with param %s\\n", text);

        }
        else if(error_code == AXIS2_STUB_MYSERVICE_MYOPERATION_FAULT_MYSECONDEXCEPTION) {
            /* extracting out the adb objects */
            int number = adb_MySecondException_get_number(fault.MySecondException, env);

            /* do a printf of the message */
            printf("My Second Exception called: with param %d\\n", number);

        }

    }

Note that this feature is available only in the very latest WSDL2C tool. Try to get latest build from Axis2/Java to use this up to date tool.

You can download the WSDL and codes used in this example from here, https://issues.apache.org/jira/secure/attachment/12399724/case45.zip

Now you can view the article I wrote titling “Introduction to PHP Data Services“. There I explain how you can design and implement Data Services in PHP using WSF/PHP Data Services Library.

This article covers,

  1. Designing your Data Service API.
  2. Writing the Data Service.
  3. Deploying and Testing Data Service.
  4. Make the Data Service available in both SOAP and RESTful form.
  5. Use of WS-* features in your Data Service.

If you are thinking of adapting SOA in to your database backed PHP applications, this article will be a good starting point.

LAMP (Linux + Apache + Mysql + PHP) stack powers many servers in the Internet today. For a LAMP  server, PostgreSQL could be the first alternative to Mysql. Similar to PHP + MySQL,  PHP + PostgreSQL too can be easily used in to host data services. Here are the steps to do it.

  1. If you already don’t have Apache + PHP + PostgreSQL download them from the following locations. Apache – http://httpd.apache.org/download.cgi, PHP – http://php.net and PostgreSQL – http://www.postgresql.org/download/
  2. You have to enable the PHP pdo_pgsql, pdo and pgsql plugins. Read here for the instructions to setup these libraries. (For an example: if you are windows you have to set the system ‘PATH’ variable to the <postgresql_installed_dir>/bin directory.
  3. If you already don’t have WSF/PHP, download and install it according to the guidelines provided in wsf/php installation guide.NOTE: You can check pdo_pgsql and wsf/php has properly installed with the help of phpinfo() function.
  4. Now lets start with creating a sample Database table. For this example I created a database called ‘workshop’, schema called ‘workshop’ and inside there the table ‘Employee’ with the following schema.
    Column Name Column Type
    employId integer
    name character varying
    email character varying
    jobTitle character varying
    project character varying

    Note: You can use phpPgAdmin (web based) or pgAdmin III to create tables from GUI

  5. Then you can write a small php script to expose the data in the above table as a web service.
    <?php
    
    //Including the Data Services library
    require_once("wso2/DataServices/DataService.php");
    
    // Including the connection information (i.e. PGSQUL USERNAME
    // and PGSQL_PASSWORD) for my PGSQL Connection
    require_once("constants.php");
    
    // database configurations
    $config = array(
    		"db" => "pgsql",
    		"username" => PGSQL_USERNAME,
    		"password" => PGSQL_PASSWORD,
    		"dbname" => "workshop",
    		"dbhost" => "localhost"
    		);
    
    $output_format = array(
                        "resultElement" => "employees",
                        "rowElement" => "employee",
                        "elements" => array(
    			    "id" => "employeeId",
                                "name" => "name",
                                "email" => "email",
                                "jobTitle" => "jobTitle",
                                "project" => "project"));
    
    $sql = "SELECT * FROM workshop.Employees";
    
    $get_employees_op = array("outputFormat" => $output_format, "sql" => $sql);
    
    $get_employees_url = array("HTTPMethod" => "GET", "RESTLocation" => "employees");
    
    // list of operations
    $operations = array(
                    "getEmployees" => $get_employees_op,
                    );
    
    // list of rest url mappping (operation => url)
    $restmap = array(
                    "getEmployees" => $get_employees_url,
                    );
    
    // creating DSService and reply
    $service = new DataService(array(
             "config" => $config,
             "operations" => $operations, "RESTMapping"=>$restmap));
    $service->reply();
    ?>
  6. We just wrote a PostgreSQL Data Services that provides its service as both REST and SOAP form. To deploy this service, We just need to copy this in to the web root directory. And the web URL for the script will be the endpoint to the web service.
  7. We can test the service either by calling its SOAP interface, which we may need to write a small SOAP client or by calling its REST interface, which only need a GET request from the browser. Say my script name is “my_dataservice.php” and I’ve put it in the web root directory, then the URL to call the REST interface of the service is
    http://localhost/my_dataservice.php/employees

WSDL Generation for PostgreSQL Data Service
You can get the WSDL for the service from the URL formed adding the suffix “?wsdl” (or “?wsdl2″ to wsdl v2.0) to the service URL,

http://localhost/my_dataservice.php?wsdl

Here all the schema data types are shown as xsd:anyType, which may not be the behavior that you want. In fact you can provide the schema data types to the fields from the code itself. Lets change the $outputFormat variable to provide the schema information as well using the following code snip.

$output_format = array(
                    "resultElement" => "employees",
                    "rowElement" => "employee",
                    "elements" => array(
			    "id" => array("column" => "employeeId",
		    			  "xsdType" => "xsd:int"),
			    "name" => array("column" => "name",
		    			  "xsdType" => "xsd:string"),
			    "email" => array("column" => "email",
		    			  "xsdType" => "xsd:string"),
			    "jobTitle" => array("column" => "jobTitle",
		    			  "xsdType" => "xsd:string"),
			    "project" => array("column" => "project",
		    			  "xsdType" => "xsd:string")));

Note that you provide the xsd type for each field explicitly. In fact this change is not needed for mysql pdo extension since it allows identifying field types programatically. Since this feature is not available in all the other pdo drivers, we have to explicitly give xsd type information for them.

If you wan to provide data services with SQLite or MSSQL, You can check my other posts on MSSQL(Microsoft SQL) Data Services In PHP and Data Services with SQLite in PHP.

  1. WS-Addressing Action is used by web services to dispatch the operation for an incoming request SOAP message. It is one way of dispatching operations in WSF/PHP and it base Apach Axis2/C, other ways are SOAP action based dispatching which covers in my early blog “The Use of SOAP Action with WSF/PHP“,  Body based dispatching and URI based dispatching.
  2. In WSF/PHP client, we can enable the addressing by setting the “action” field in the request WSMessage instance and setting “useWSA”=> TRUE in the WSClient instance. Here is an example.
    $requestPayloadString = <<<XML
    <ns1:echoString xmlns:ns1="http://wso2.org/wsfphp/samples">
       <text>Hello World!</text>
    </ns1:echoString>
    XML;
    
    $client = new WSClient(array("to" => "http://localhost/samples/echo_service.php",
                                 "useWSA" => TRUE));
    
    $requestMessage = new WSMessage($requestPayloadString,
    	    array("action" => "http://localhost/samples/echo_service/echoString"));
    
    $responseMessage = $client->request($requestMessage);
    
    printf("Response = %s <br>", htmlspecialchars($responseMessage->str));

    If you doesn’t set “useWSA” => TRUE explicitly, the client will send the action as a SOAP action rather than a WSA Action. The above is the same example I used in demonstrating SOAP action with just the addition of “useWSA” option.

  3. You can select WS-Addressing version among “submission” which .NET support by default and “1.0″, just by mention it in the “useWSA” field.
    I.e.

    “useWSA” => “submission” Then the namespaces are having the values defined in the submission specification of WS-Addressing.
    “useWSA” => 1.0 Then the namespace are having the values defined in the WS-Addressing 1.0 spec.
  4. In the option “actions” in the WSService, we can provide the action to operation map, so the service will direct the SOAP messages to the correct operation by looking at the WS-Addressing action of the SOAP message.
    Here is a sample code that use action to dispatch the operation.

    function echoStringFunc($inMessage) {
        // logic of echoString operation
    }
    
    function echoIntFunc($inMessage) {
        // logic of echoInt operation
    }
    
    // we will take echoString and echoInt as tow operations
    $operations = array("echoString" => "echoStringFunction",
                        "echoInt" => "echoIntFunction");
    
    // soap action to operation map
    $actions = array("http://localhost/samples/echo_service/echoString" => "echoString",
                     "http://localhost/samples/echo_service/echoInt" => "echoInt");
    
    // creating the service with the operations and actions set
    $service = new WSService(array("operations" => $operations,
                                   "actions" => $actions));
    
    $service->reply();

    Note that this code is same as the code I post in a previous blog “The Use of SOAP Action with WSF/PHP” which uses SOAP action to dispatch the operation. In fact WSService will adjust to dispatch SOAP messages, so if there is a SOAP action in the message, it will be dispatched using that, and if it contains WS-Addressing action, it will used to do dispatching without the need of writing a single additional line of code. Note that this same code for both “submission” and “1.0″ WS-Addressing versions.

  5. In a WSDL 1.1, WS-Addressing action can be declared in the message element in the portType section.
        <wsdl:portType name="echoPortType">
            <wsdl:operation name="echoString">
                <wsdl:input message="ns0:echoStringRequest" wsaw:Action="http://localhost/samples/echo_service/echoString"/>
                <wsdl:output message="ns0:echoStringResponse" wsaw:Action="http://localhost/samples/echo_service/echoStringResponse"/>
            </wsdl:operation>
            <wsdl:operation name="echoInt">
                <wsdl:input message="ns0:echoIntRequest" wsaw:Action="http://localhost/samples/echo_service/echoInt"/>
                <wsdl:output message="ns0:echoIntResponse" wsaw:Action="http://localhost/samples/echo_service/echoIntResponse"/>
            </wsdl:operation>
        </wsdl:portType>

    When you use WSF/PHP in wsdl mode, it will pick the action declared in the WSDL and set it in the SOAP message, if you have enabled the addressing for the WSClient by setting non-null value for “useWSA” option.

November 19th, 2008WS-SecurityPolicy With PHP

WS-SecurityPolicy specification defines standards for defining security policies for your web service. WSF/PHP allows you to declare your security policies according to these standards.

You can take one of following approaches to associate policies to your web service or client.

  • PHP Array to represent your policies
  • Policy file compliant with WS-Security Policy.
  • Declaring policies inline with the WSDL.

Declaring Policies with a PHP Array

This is a WSF/PHP specific API to declare policies for a web service. You don’t need to learn WS-Security Policy to write policies with this approach. You can set whether you want to use encryption, signing or usernameToken in a PHP array and create a WSPolicy object using it.

// here is the security array to declare your policies in simple manner
$sec_array = array("encrypt" => TRUE,
 "algorithmSuite" => "Basic256Rsa15",
 "securityTokenReference" => "IssuerSerial");

// creating WSPolicy instance using the policy array
$policy = new WSPolicy(array("security"=> $sec_array));

You can use this policy object to create a service along with a WSSecurityToken which contain the user parameters like the server private key and the client certificate.

$sec_token = new WSSecurityToken(array(
 "privateKey" => $server_pvt_key,
 "receiverCertificate" => $client_pub_key));

$svr = new WSService(array("actions" => $actions,
 "operations" => $operations,
 "policy" => $policy,
 "securityToken" => $sec_token)); // here is the policy object you just created

$svr->reply();

You can invoke this service just by writing a simple web service client. There also you need to provide the policies declared in the service, so the client can build his request to validate with server policies. You will be using a similar WSPolicy object to set these policies at the client side too, as show in the below code segment.

 $sec_token = new WSSecurityToken(array(
   "privateKey" => $pvt_key,
   "receiverCertificate" => $rec_cert));

 $client = new WSClient(array("useWSA" => TRUE,
    "policy" => $policy, /* the policy object */
    "securityToken" => $sec_token));

 $resMessage = $client->request($reqMessage);

Declaring Policies with a Policy File

You can set your policies in the server or client side using a policy file compliant with WS-Security Policy specification. You have to take this approach if your policy requirements are too complicated, like you want to sign only some parts of the message or you want to encrypt some soap headers.

Similar to the above method, here too you will use the WSPolicy object to set your policies. But unlike the above where you give the policies as a PHP array , here you can just give the policy file as an argument to the WSPolicy constructor.

// creating the WSPolicy instance from a policy file
$policy_xml = file_get_contents("policy.xml");
$policy = new WSPolicy($policy_xml);

Here is an example of a complete policy file written according to the WS-Security Policy standards. And you can find a quick guide on WS-Security Policy from the article Understanding WS-Security Policy Language written by Nandana, a key leader of Apache Rampart project.

Declaring Policies inline in a WSDL

We use WSDL to describe our web services. WSDL has the information about the service endpoint, the transport protocols (e.g. http), messaging protocols (e.g. SOAP) and the message schemas and many others about the service. You can attach your policies inside a WSDL.

Here is an example of a WSDL with inline policies. The difference in this approach is you can set your policies separately for each messages or each operations or each endpoints of your service. The following segment of a WSDL shows how you refer to different policies which are declared in the early part of the WSDL.

     <wsdl:binding name="CalendarSOAP12Binding" type="ns1:CalendarPortType">
       <!-- Endpoint policies are declared here.
          these are common to all messages transferring
          through this protocols (i.e. SOAP12, http)-->
        <wsp:PolicyReference URI="#transport_binding_policy"/>
        <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>
        <wsdl:operation name="login">
           <soap12:operation soapAction="urn:login" style="document"/>
           <wsdl:input>
              <!-- policy specific to the 'login' operation -->
              <wsp:PolicyReference URI="#username_token_policy"/>
              <soap12:body use="literal"/>
           </wsdl:input>
           <wsdl:output>
              <soap12:body use="literal"/>
           </wsdl:output>
         </wsdl:operation>
         <wsdl:operation name="register">
            <!-- no specific policies are set for the 'register' operation
            <soap12:operation soapAction="urn:register" style="document"/>
            <wsdl:input>
              <soap12:body use="literal"/>
            </wsdl:input>
            <wsdl:output>
               <soap12:body use="literal"/>
            </wsdl:output>
         </wsdl:operation>
           ....
       </wsdl:binding>

This is the binding section of a WSDL where we bind messaging protocol and transport protocols with a service endpoint. Here we have “login” and “register” operations. Note that we are referring to “transport_binding_policy” from the parent level of each operation elements. That means these policies are common to all the operation in that binding. And inside the “login” operation we are referring to “username_token_policy”, so in order to invoke this operation, you have to send username token headers. And “register” doesn’t require any operation specific policies allowing users to register without any prior authentications.

You can select any of the above mentioned approach to define policies of your web service or to invoke a web service that support WS-Policy. If your policy requirements are simple, it will be easy to use the array based approach. If your policy requirements are complex or you have a good understanding of WS-Policy and WS-Security Policy you can rely on the policy file based approach or defining policy inline with WSDL. And the former 2 methods will give you a nice separation of the logic code and security configurations. The selection is yours:)

As many of other languages, XML schema too have data types. Basically it can be categorized in to two groups.

  1. Simple Types
  2. Complex Types

The different between these 2 types are so easy to identify. Say you have a schema element with a simple type like this.

<xs:element name="xx" type="someSimpleType"/>

Then a possible xml to validate against this schema is

<xx>Bingo</x>

Inside the ‘xxx’ you can only find texts, But in a case of a  schema element with complex types,

<xs:element name="xx" type="someComplexType"/>

The XML will be set of nested elements.

<xx>
  <yy>hi</yy>
  <zz>Nested elements</zz>
</xx>

Simply complex type contains elements with simple types or complex types similar to the class types in OOP languages which contain member variables with different types.

But unlike most of the other languages, in schema simple types are not always primitive types. There can be user derived simple types as well.

I will talk about each of these variations in schema types and their PHP representation of WSDL2PHP tool.

  • Primitive Types & Built-in Types
  • List Types
  • Union Types
  • Faceted Types

Primitive Types & Built-in Types

The XML schema specification talks about 19 primitive types. Some of the common of these simple types and the corresponding PHP types generated by WSDL2PHP tool are,

Schema Type PHP Type
string string
boolean boolean
decimal float
float float
double double
duration string
dateTime string (from above wsf/php 2.0 it is an integer – representing timestamp)

You may have noticed the famous types like ‘integer’, ‘byte’, ’short’ are missing out of the above list. In fact these types exist, but they are not primitive types. They are derived from decimal (special cases when the fraction digits are 0 :) . Anyway still these types are considered built-in types in xml schema. Here is the complete list of built-in types (both primitive and non-primitive built-in types)

‘integer’, ‘byte’ and ’short’ are mapped to PHP integer types by the WSDL2PHP tool.

To show an example how WSDL2PHP tool generating code for simple types, I will take the following schema Element.

<xs:element name="myName" type="xs:string"/>

And WSDL2PHP will generate a simple public variable (Assuming this is generating inside some class) for that element with a comment to describing it.

    /**
     * @var string
     */
     public $myName;

So if I specified some value for the variable (Taking the variable name of the parent class is $parent),

$parent->myName = "James";

I will get the following nice XML.

<myName>James</myName>

This is the same approach for all the other built-in types as well.

List Types

The list types are derived from list of simple types. It still a simple type because it list all the element in the list as a white-space separated text inside the parent element.

Here is how you may declare a list type in an xml schema.

<xs:simpleType name="mylist">
    <xs:list itemType="xs:int"/>
</xs:simpleType>

<!-- example element to have the above list value -->
<xs:element name="xCoordinates" type="tns:mylist"/>

Then the WSDL2PHP generated PHP code would be something like,

    /**
     * @var array of int
     */
    public $xCoordinates;

As the comment implies, you have to feed the values in an php array.

$parent->xCoordinates = array(1, 3, 8, 7, 9);

And Here is the XML you are getting,

<xCoordinates>1 3 8 7 9</xCoordinates>

Similarly you can have list of any simple types regardless whether it is built-in or derived.

Union Types

The union in schema is similar to the unions in ‘C’. In C variables of a union can have one (and not more than one) of the types declared inside the union type. Similarly in schema elements with union types can have one and only one simple type among the member types declared in the union. Here is an example of declaring union type,

<xs:simpleType name="myIntStringUnion">
    <xs:union memberTypes="xs:int xs:string"/>
</xs:simpleType>

<!-- example element to have the above union value -->
<xs:element name="garbage" type="tns:myIntStringUnion"/>

And the WSDl2PHP generated code,

    /**
     * @var int/string
     */
    public $garbage;

So if you read the comment you can have an idea that this variable accept either ‘in’ or ’string’ type without digging in to the WSDL.

Faceted Types

You can apply facets and restrict the value space of a simple type.

  • length
  • minLength
  • maxLength
  • pattern
  • enumeration
  • whiteSpace
  • maxInclusive
  • maxExclusive
  • minExclusive
  • minInclusive
  • totalDigits
  • fractionDigits

Some facets are specific to some built-in data types or types derived from these built-in datatypes. Here is a table of valid facets for each of the above mentioned catagory of types.

I have earlier blogged about how you work on faceted types in PHP in the post “Coding Schema Inheritance in PHP“. So Here I will list out a similar example  to demonstrate the PHP generated code by WSDL2PHP tool for facets.

Here is a schema with the ‘enumeration’ facet.

<!-- applying enumeration facet to the xs:string -->
<xs:simpleType name="mySubject">
    <xs:restriction base="xs:string">
         <xs:enumeration value="Maths"/>
         <xs:enumeration value="Physics"/>
         <xs:enumeration value="Chemistry"/>
    </xs:restriction>
</xs:simpleType>

<!-- example element to have the above faceted value -->
<xs:element name="subject" type="tns:mySubject"/>

And here is the WSDL2PHP generated code,

    /**
     * @var string
     *     NOTE: subject should follow the following restrictions
     *     You can have one of the following value
     *     Maths
     *     Physics
     *     Chemistry
     */
    public $subject;

It clearly says your variable ’subject’ is only allowed to have the list of values mentioned in the ‘enumeration’.

So I just wrote about some variations of simple schema types and how they are represented in the WSDL2PHP generated code. As you may have observed, you don’t need to know any thing about the WSDL or the schema to write a PHP code around that, since WSDL2PHP gives you a generated code mentioning all the guidelines, restrictions about using them.

November 11th, 2008WSF/PHP Test Cases Explained

WSO2 WSF/PHP comes with a comprehensive set of test cases. It covers the most of the basic/concrete scenarios supported by WSF/PHP. You can find these test cases inside the “src/tests” directory of WSF/PHP source package. Or you can find the latest test-suite from the SVN location.

Here are some aspects covered in the test-suit.

Scenario Test Cases For Client Test Cases For Service
Basic Functionality echo_client*.phptmath_*.phpt samples/echo_service*.php
samples/math_service.php
Basic Schema Types BasicDataTypes/*.phpt services/BasicTypesDoclitBSvc/*.php
Complex Schema Types cmplxDataTypes/*.phpt services/ComplexDataTypesWSvc/*.php
services/ComplexDataTypesBSvc/*.php
WSDL/Schema Variations wsdl_mode/*.phpt services/wsdl_mode/*.php
WSDL Generation with Annotations wsdl_generation/*.phpt services/wsdl_generation/*.php
Reliable Messaging echo_rm*.phpt samples/echo_service_rm*.php
Security echo_encrypt_client*.phptecho_signing_client*.phpt

echo_timestamp_client*.phpt

echo_username_token_client*.phpt

encrypt_service*.phpsigning_service*.php

timestamp_service*.php

username_token_service*.php

MTOM mtom_*.phpt samples/mtom/*.php

(Note that Here ‘*’ is used as a wild card represent 0 or many characters)

Steps to Run Tests

  • First you need to install WSF/PHP correctly. Please read the WSF/PHP installation manual for that.
  • You have to have the ‘pear’ utility tool comes with PHP. And add this to the PATH environment variable.
  • Copy the samples and src/tests/samples/services directory (paths are relative to the root directory of the wsf/php package) to the web root directory.
  • Then go to the src/tests directory and execute the following command.
    pear run-tests -r

    This will execute all the test cases under the ‘tests’ directory and finally give a summery of the test results.

  • You can run individual test cases separately by providing the relative path to the test case from the ‘test’ directory. E.g. To run the echo_client.phpt test case, you may type
    pear run-tests samples/echo_client.phpt

If you like to add test cases for the WSF/PHP scenarios, follow this comprehensive guideline titled Writing Simple phpt Test Scripts For PHP Web Services.

November 7th, 2008WSF/PHP Samples Explained

Here is a simple categorization of the WSF/PHP samples. You can access all the wsf/php samples from http://labs.wso2.org/wsf/php/solutions/samples/index.html.

Sample Category Example Client Source Code Example Service Source Code Online Demo
Beginners echo_client.php echo_service.php Demo
REST echo_client_rest.php echo_service_with_rest.php Demo
WSDL Mode (Contract First) wsdl_11_client.php wsdl_11_service.php Demo
WSDL Generation (Code First) doclit_client.php doclit_service.php Demo
MTOM Attachments mtom_download_client.php mtom_download_service.php Demo
Security encryption_client.php encryption_service.php Demo
Reliable Messaging echo_client_rm.php echo_service_rm.php Demo
Data Services CustomerDetailsClient.php CustomerDetailsService.php Demo

If you have downloaded the WSF/PHP binaries or souce code package you can find all these samples, inside the ’samples’ directory


© 2007 Dimuthu’s Blog | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress