Data Services Best Practices

In simple term, data services are exposing data as web services. Anyway it is not a complete definition. Actually there are situations where we use data services not only to read data, but also to create, update or delete data. So it is better say data services are doing CRUD (Create, Read, Update, Delete) operations for data through web services. Simply it is like providing a web service interface for the database.

Anyway exposing  a database directly as a web service is like violating the first principles of software engineering. It will tightly couple the database structure with the interface, so whenever you do a simple change to the database schema, you will have to change the web service interface which will no doubt break all the clients depending on it.

So first of all, you have to design the service interface independent of the database schema you have. Most of the time you will able to find some query that would map the service interface to the database schema.

For an example think of publishing data in database table (say for table name “Games”) like this.

Teams
GameID Venue Date Team1 Team2 Team1Score Team2Score
1 xxx stadium 2008-12-18 Italy Sweden 34 33
2 yyy stadium 2008-12-19 France Spain 51 50

You will directly able to map these data to data service. So the response payload for a “getGames” operation would be something like,

<getGamesResponse>
   <Game>
      <Venue>
         xxx stadium
      </Venue>
      <Date>
         2008-12-18
      </date>
      <Team1>
          Italy
      </Team1>
      <Team2>
          Sweden
      </Team2>
      <Team1Score>
          34
      </Team1Score>
      <Team2Score>
          33
      </Team2Score>
   </Game>
   <Game>
      <Venue>
         yyy stadium
      </Venue>
      <Date>
         2008-12-19
      </date>
      <Team1>
          France
      </Team1>
      <Team2>
          Spain
      </Team2>
      <Team1Score>
          51
      </Team1Score>
      <Team2Score>
          50
      </Team2Score>
   </Game>
</getGamesResponse>

You can get this done with a SQL query simply as this,

SELECT * FROM `Games`

Say later if you decided to restructure the database table so the new database schema would be like this,

Games
GameId Venue Date
1 xxx stadium 2008-12-18
1 yyy stadium 2008-12-19
GamesTeams
GameId TeamId score
1 1 70
1 2 33
2 1 51
2 3 50
Teams
TeamId Name Coach
1 Italy Mr. ABC
1 Canada Mr. PQR
2 Spain Mr. XYZ

(Note here the Games and Teams are associated in the GamesTeams table.)

You can still use a query like the one in following to provide the same service interface, because it returns the same result set as the earlier one.

   SELECT Games.Venue,
              Games.Date,
              Team1.Name AS Team1,
              Team2.Name AS Team2,
              GameTeam1.Score AS Score1,
              GameTeam2.Score AS Score2
         FROM Teams Team1,
              Teams Team2,
              GamesTeams GameTeam1,
              GamesTeams GameTeam2,
              Games
        WHERE GameTeam1.gameId = Games.gameId  AND
              GameTeam2.gameId = Games.gameId AND
              GameTeam1.teamId = Team1.teamId AND
              GameTeam2.teamId = Team2.teamId AND
              Team1.teamId <> Team2.teamId AND
              Team1.name=?

This allows you to keep the service interface unchanged, regardless of the changes you done to the database schema.

In addition to that, we can uses the features of the data service libraries to give meaningful names for the response elements. If we take above example itself, say you want to rename ‘Score1’ to ‘Team1-Score’ and ‘Score2’ to ‘Team2-Score’. But the dash character (‘-‘) cannot be used as a variable in a database query. But you can provide that in the map of sql name to element name when you are writing the data service.

If you are using WSF/PHP php data services Here is how you provide that mapping,

$outputFormat = array("resultElement" => "getGamesResponse",
                      "rowElement" => "game",  // this is the repeating wrapper element for each game
                      "elements" => array( "Venue" => "Venue", // this is the mapping of xml name => sql name
                                           "Date" => "Date",
                                           "Team1" => "Team1",
                                           "Team2" => "Team2",
                                           "Team1-score" => "Score1", // we are using different names for sql and xml
                                           "Team2-score" => "Score2"));

If you write it using Java Data Services, you can use do this with the following configuration xml,

        <result element="getGamesResponse" rowName="game">
            <element name="Venue" column="Venu" />
            <element name="Date" column="Date" />
            <element name="Team1" column="Team1" />
            <element name="Team2" column="Team2" />
            <element name="Team1-Score" column="Score1" />
            <element name="Team2-Score" column="Score2" />
        </result>

Another consideration, when talking about the best practices of designing web services or data services is the granularity of the service interface. We say a web service is fine grained if the service contains tons of small operations. The opposite of that is the coarse grained services, which contains large but few operations. And it is recommended to use the later approach, you can see why from the following example.

Lets say you are developing a web service to upload some information. In order to upload the information first the user have to be authenticated and then the content should be validated. Then only he can submit the actual information. Say you design a fine grained web service for that. So it has three operations.

  1. authenticateUser
  2. validateContent
  3. submitInformation

If you design a coarse grained service interface it will be just the ‘uploadInformation’ operation. And all the three operation defined earlier will be called within the service logic and the clients will not be aware of that.

So here are some disadvantages that I see in the fine grained interface design compared with coarse grained design.

  1. The coupling is too high. Since the client is linked with the service in three adapters. Say you decided to change the service so that you first validate the content and depending on the content it sometime bypasses the authentication. You can’t do this with the former approach (fine grained approach) without changing the clients. But if it were designed as a coarse grained service (just one uploadInformation operation), the client need not to be changed.
  2. Two much time consumed for the transmission. Since we used three web service calls to do a single task the latency of the operation will largely depend on the network latency which will no doubt is comparatively very low. So the performance of the operation is degraded.
  3. The clients can bypass some steps!, Say in your fine grained service, some client bypass the authentication and validateContent steps and jump directly to the sumbitContent operation. In fact you have to write special code to make sure the clients call the service in the correct sequence, otherwise it will be a big security hole.

So I think these three points will be enough to explain why you should try to design a coarse grained interface for your web service.

You can apply these principle when you write data services as well. Lets take the same example explained above. Say there is another table that keep the scoring shots of each game like the one in following.

ScoringShots
GameID Time ScoringTeam ScoringPlayer

Here also you can keep the operation like ‘getGames’ which we defined in the above section. That operation only provide the basic information like the winner and the scores. So if the clients want to know about scoring shots as well, he have to call another operation, say getScoringShots(game) that will return the scoring shots results for a given game. If in practice the clients only need to know about scoring shots of few selected games, then this approach is ok.
But say normally clients need to know about the scoring shots of each and every games. Then they have to call the operation ‘getScoringShots’ multiple times. That’s when the lesson we just learn about the granularity can be applied. We can actually provide another operation, say ‘getGamesDetailed’ that actually bundle the details of scoring shots for all games with other information about the game. Here is snip of the response XML, I’m talking about.

<getGamesDetailedResponse>
   <Game>
      <Venue>
         xxx stadium
      </Venue>
      <Date>
         2008-12-18
      </date>
      <Team1>
          Italy
      </Team1>
      <Team2>
          Sweden
      </Team2>
      <Team1Score>
          34
      </Team1Score>
      <Team2Score>
          33
      </Team2Score>
      <!-- additionally we have ScoringShots element -->
      <ScoringShots>
          <Shot>
              <Time> xxx </Time>
              <ScoringPlayer> xxx </ScoringPlayer>
              <ScoringTeam> xxx </ScoringTeam>
              <Score> xxx </Score>
          </Shot>
          <Shot>
              <Time> yyy </Time>
              <ScoringPlayer> yyy </ScoringPlayer>
              <ScoringTeam> yyy </ScoringTeam>
              <Score> yyy </Score>
          </Shot>
      </ScoringShots>
   </Game>

   <Game>
    <!-- Another game details are mentioned here -->
   </Game>

   <!-- More Games -->
</getGamesDetailedResponse>

You can generate this kind of response using the nested query support of the data services libraries.
You can checkout more details about nested queries in php data services from my old post about php data service API.

Posted in data services, DataServices, design, php, SOA, SQL, Tutorial/Guide, web services, wso2 | Tagged , , , , , | 8 Comments

Sending Encrypted Binary Messages With PHP Web Services

Web services has made the communication between heterogeneous environments (say PHP with .NET  or Java) a reality. It has defines standards for communicate not only with texts but also with binaries. And more importantly you can keep these communication confidential using encrypted messages according to your requirement. In this post, we will look at how we can implement such a system with PHP in one side.

In web services we can send/receive binary messages in two basic forms.

  1. Setting the binary inside the SOAP message. – Binary should be converted to base64 to make sure the SOAP body contains only texts. Since base64 converted data span longer than the binary data, we call this form as non-optimized way of sending binaries.
  2. Setting the binary outside the SOAP message – Binary would be sent as a MIME part in the message. And some element inside SOAP body keeps a reference to the binary using the MIME id. MTOM is a standard for referencing the MIME from inside the SOAP body. Since the binary is encoded, this will keep the message optimum with the binaries.

In WSF/PHP you can use any of these methods as you prefer. Lets forget about the encryption for now. We will check how we can send binaries in both of the above mentioned forms.

// first the request xml. Note tht xop:Include element that is referring the attachment with the id "myid1".
$reqPayloadString = <<<XML
<ns1:upload xmlns:ns1="http://wso2.org/wsfphp/samples/mtom">
               <ns1:fileName>test.jpg</ns1:fileName>
               <ns1:image xmlmime:contentType="image/jpeg" xmlns:xmlmime="http://www.w3.org/2004/06/xmlmime">
                  <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:myid1"></xop:Include>
               </ns1:image>
</ns1:upload>
XML;

try {
    $f = file_get_contents("my_binary_file.jpg");

    // here in the attachments option we define the binaries
    // corresponding to the id defined in the above XML
    $reqMessage = new WSMessage($reqPayloadString,
                                array("to" => "http://localhost/simple_upload_service.php",
                                      "action" => "http://wso2.org/upload",
                                      "attachments" => array("myid1" => $f)));

    // creating the WSClient
    // here the option useMTOM will decide whether the
    // attachment is set MTOM or base64
    $client = new WSClient(array("useWSA" => TRUE,
                                 "useMTOM" => TRUE));

    // sending the message and retrieving the response
    $resMessage = $client->request($reqMessage);

    printf("Response = %s \\n", $resMessage->str);

} catch (Exception $e) {

    if ($e instanceof WSFault) {
        printf("Soap Fault: %s\\n", $e->Reason);
    } else {
        printf("Message = %s\\n",$e->getMessage());
    }
}

As mentioned in the inline comment we can choose the preferred form of sending binary using the “useMTOM” option. if it is true, the binary is set as a MTOM, (referencing from the body) or if it is set false, the binary will be set as a base64 binary within the SOAP body.
To encrypt the message you only need to write few additional lines. First you define your policy that you need to encrypt this message using a WSPolicy object. Then the security token including the service public key and your private key. You need to give these two option as a constructor argument in WSClient. Here is that little additional code you need to write to add the encryption.

    // loading the keys
    $rec_cert = ws_get_cert_from_file("receiving_server.cert");
    $pvt_key = ws_get_key_from_file("my_private_key.pem");

    // here we defines the policies and create WSPolicy object
    $sec_array = array("encrypt" => TRUE,
                       "algorithmSuite" => "Basic256Rsa15",
                       "securityTokenReference" => "IssuerSerial");

    $policy = new WSPolicy(array("security" => $sec_array));

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

    // modifing WSClient with adding WSPolicy and WSSecurityToken object
    $client = new WSClient(array("useWSA" => TRUE,
                                 "useMTOM" => TRUE,
                                 "policy" => $policy,
                                 "securityToken" => $sec_token));

You can implement the receiving side of the message similar to the sending side that we just described above. The most important thing is it doesn’t need to be written in PHP. It can be a Java code or .NET code.If you already have web services that use encrypted binary messaging, the above php code can be use out of the box to communicate with it.

Posted in php, security, SOA, Tutorial/Guide, web services, wsf/php, wso2 | Tagged , , , , , , , | 2 Comments

Calling Simple Web Services From Javascript

If you are a web developer, you may have found many occasions you have to create simple mashups for your web site. There you call web services or data services to fill the content of the web page. Most of the time we call web services from a server side script, since there are many server side technologies like Java, PHP, .NET support web services.

But sometime it is in vain that you call your server scripts for a simple web service request. In fact You can use the famous XMLHttpRequest object to do the same thing from the client side itself. But you may need to prepare the complete SOAP envelope (Yea with SOAP headers, if required) in your hand to send it through XMLHttpRequest.

Another option is to  use the WSRequest script (http://mooshup.com/js/wso2/WSRequest.js). We normally use this script in the WSO2 Mashup Server to call the mashups designed in the serverside using stub. (The server side mashup is also mostly written in Javascript). We can use this script stand alone to call remote web services as well.

It introduce you the WSRequest class. It is exactly similar to the famous XMLHttpRequest class we used in  AJAX. In stead of plain message over HTTP like in the case of XMLHttpRequest, WSRequest send and receive messages in SOAP form. Here is its API in brief.

var WSRequest = function() {
    //----------------------------------------------------
    // the public properties - equivalent to XMLHTTPRequest
    //-----------------------------------------------------
    this.readyState = 0;
    this.responseText = null;
    this.responseXML = null;
    this.error = null;  // equivalent to httpErrorCode
    this.onreadystatechange = null;
    this.proxyAddress = null;
    this.proxyEngagedCallback = null
}

//----------------------------------------------------
// the public operations - equivalent to XMLHTTPRequest
//-----------------------------------------------------

/**
 * @description Prepare a Web Service Request .
 * @method open
 * @param {hash} options,
 *   possible options: possible values for the option
 *            useSOAP : false/true/1.1/1.2
 *            useWSA : true/false/1.0/submission
 *            useWSS : true/false (only for usernametoken & timestamp)
 *
 * @param {string} URL
 * @param {boolean} asyncFlag
 * @param {string} username
 * @param {string} password
 */
WSRequest.prototype.open = function(options, URL, asnycFlag, username, password) {.. }

/**
 * @description Send the payload to the Web Service.
 * @method send
 * @param {dom} response xml payload
 */
WSRequest.prototype.send = function(payload) {.. }

I wrote a simple javascript/html demo which calls the data service that I published for my blog. This service is written using WSF/PHP Data Services. Check the demo and client, service sources  from the following links.

AJAX Tag Search Demo | WSDL | Client | Service Demonstrates how you use SOAP Data Services using WSRequest object to retrieve the data asynchronously from javascript

There You can see, how easy to write an AJAX like page for call web services using the WSRequest javascript class.

Posted in javascript, mashup server, php, SOA, Tutorial/Guide, web services | Tagged , , , | 2 Comments

PHP Data Services with PostgreSQL

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.

Posted in 2 minutes guide, DataServices, php, REST, SOA, SQL, Tutorial/Guide, web services, WSDL, wsf/php, wso2 | Tagged , , , , , , | 2 Comments

Writing Web Apps with Google, Yahoo and Microsoft Maps

Google Maps

Google provides a nice API allowing developers to integrate Google Maps to their web applications. For that you first need to create a Google Map API key from here, http://code.google.com/apis/maps/signup.html. It is free and you can create as many amount of keys as needed for all of your web sites. After generaing the key it will give you a nice piece of sample code. You can use this code to start your work. What you needed to do is include the the Google map API script to your web page and create a GMap2 object. Optionally you can set what should be focused, what controls (navigation, zooming) should be available in the view.

Here is a very simple code I wrote using this API. You can run this code live from here.

    <script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAASLxXDwVRuSoGL8Q-tFgkwBS4YfDDHXLghwcnNbKI3a0b78AiZBS4d4SXNzmv-OUqc8l8T_bziKPHTg"
            type="text/javascript"></script>
    <script type="text/javascript">

   // replace the latitude, logitude, zoom values for your location
   var lat = 8;
   var lon = 80.5;
   var zoom = 8;

    function initialize() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map_canvas"));

        // setting lat lon
        map.setCenter(new GLatLng(lat, lon), zoom);

        // adding the map controls for navigation
        map.addControl(new GSmallMapControl());
      }
    }

    </script>

Yahoo Maps

Yahoo provides two different technologies to add a map to a web page. One is just using Javascript with Ajax and the second is using Javascript with Flash. They both are very simple to use. Similar to Google, you have to have your own app id to run yahoo maps. You can register for an appid from https://developer.yahoo.com/wsregapp/.

Here is the code you may use to have a Flash map. (Click here to view the demo. Remember You need flash to view this).

<script type="text/javascript" src="http://maps.yahooapis.com/v3.5.2/fl/javascript/apiloader.js?appid=CyVSsM_V34GOZUkb9MnakFBTrwVHqfHebJ6LC6nZtoxXMJvbaxczvPh71MXUi_K3"></script>
<script type="text/javascript">

// replace the latitude, logitude, zoom values for your location
var lat = 8;
var lon = 80.5;
var zoom = 10;

// Create a latitude/longitude object 
var latlon = new LatLon(lat, lon);

// Display the map centered on that location. Add your Yahoo! Application
var map = new Map("mapContainer", "CyVSsM_V34GOZUkb9MnakFBTrwVHqfHebJ6LC6nZtoxXMJvbaxczvPh71MXUi_K3", latlon, zoom); 

// Make the map draggable
map.addTool( new PanTool(), true );
</script>

Using Ajax + Javascript Yahoo Map API is very similar to its Flash + javascript API.  Here is the same map is viewed with the Ajax map. (Click here for the live demo of the following code)

<script type="text/javascript"
src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=CyVSsM_V34GOZUkb9MnakFBTrwVHqfHebJ6LC6nZtoxXMJvbaxczvPh71MXUi_K3"></script>
<script type="text/javascript">  

    // replace the latitude, logitude, zoom values for your location
    var lat = 8;
    var lon = 80.5;
    var zoom = 10;

    // geo point from lat and lon
    var point = new YGeoPoint(lat, lon);

    // Create a map object  
    var map = new YMap(document.getElementById('map'));  

    // Add map type control  
    map.addTypeControl();  

    // Add map zoom (long) control  
    map.addZoomLong();  

    // Add the Pan Control  
    map.addPanControl();  

    // Set map type to either of: YAHOO_MAP_SAT, YAHOO_MAP_HYB, YAHOO_MAP_REG  
    map.setMapType(YAHOO_MAP_SAT);  

    // Display the map centered on a geocoded location  
    map.drawZoomAndCenter(point, zoom);
</script>

Microsoft Virtual Earth

Microsoft Virtual Earth also provides a map API. And it has a really cool interactive map SDK. You can get a nice map with just few lines of javascripts.

      <script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
      <script type="text/javascript">
         var map = null;

         // replace the latitude, logitude, zoom values for your location
         var lat = 8;
         var lon = 80.5;
         var zoom = 8;

         function GetMap()
         {
            map = new VEMap('map');
            map.LoadMap(new VELatLong(lat, lon), zoom, 'r', false);
         }
      </script>

Here is how this code run.

All Together with OpenLayers

So now we know how to create web based map applications using each of these providers. But how if you want to create map using all the providers. Actually you can do it with some effort in javascripts. But you don’t need to.

That is when openlayers help. You can add maps from Google, Yahoo, Microsoft or any Map Server as layers in a openlayers map.

See how it is done in the following code. You can view a running instance of this code at here.

<!-- you have to include all the maps provider api script + openlayer script -->
<script src="http://maps.google.com/maps?file=api&amp;v=2&amp;sensor=false&amp;key=ABQIAAAASLxXDwVRuSoGL8Q-tFgkwBS4YfDDHXLghwcnNbKI3a0b78AiZBS4d4SXNzmv-OUqc8l8T_bziKPHTg"
            type="text/javascript"></script>
<script type="text/javascript"
        src="http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=CyVSsM_V34GOZUkb9MnakFBTrwVHqfHebJ6LC6nZtoxXMJvbaxczvPh71MXUi_K3"></script>
<script type="text/javascript" src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>

<script language="javascript">
    // replace the latitude, logitude, zoom values for your location
    var lat = 8;
    var lon = 80.5;
    var zoom = 8;

    var map;

    init();

    function init() {

        // creating the base map
        map = new OpenLayers.Map( 'map' );

        // we will add all the google layers

        gphy = new OpenLayers.Layer.Google(
            "Google Physical",
            {type: G_PHYSICAL_MAP}
        );
        gmap = new OpenLayers.Layer.Google(
            "Google Streets", // the default
            {numZoomLevels: 20}
        );
        gsat = new OpenLayers.Layer.Google(
            "Google Satellite",
            {type: G_SATELLITE_MAP, numZoomLevels: 20}
        );
        ghyb = new OpenLayers.Layer.Google(
            "Google Hybrid",
            {type: G_HYBRID_MAP, numZoomLevels: 20}
        );

        map.addLayers([gphy, gmap, gsat, ghyb]);

        // Now we will add the yahoo layer
        yahooLayer = new OpenLayers.Layer.Yahoo( "Yahoo");
        map.addLayer(yahooLayer);

        // finally adding the MS virtual earth layer
        velayer = new OpenLayers.Layer.VirtualEarth( "VE",
                                {'type': VEMapStyle.Aerial});
        map.addLayer(velayer);

        // adding some control
        map.setCenter(new OpenLayers.LonLat(lon, lat), zoom);
        map.addControl(new OpenLayers.Control.MousePosition());

        // adding the layer switcher
        map.addControl(new OpenLayers.Control.LayerSwitcher());

    }

</script>
Posted in openlayers, Tutorial/Guide | Tagged , , , , , , , , , | Leave a comment

Using AXIOM/C As The XML Object Model

In Apache Axis2/C AXIOM is used as the basic object model to represent XML. AXIOM provide a DOM like API that allows to traverse and build the XML very easily.

Anyway in underneath, AXIOM is different from DOM, as it has used some techniques to optimize the parsing of the XML as suited specially for SOAP message processing in web services. For an example the SOAP processor can validate a SOAP message by reading only some parts of the SOAP header fields, and if it is not valid, they can completely skip processing the body part. And since AXIOM is designed to built from a stream of data retrieved from a transport, sometimes SOAP processors can validate the message without the need of reading the full stream.

Anyway there should be lot of application that needs this optimization in parsing XMLs. They can easily adapt AXIOM/C to their application. Here is an AXIOM/C tutorial that covers both parsing and building XMLs from AXIOM. In this post I’d like to mention a code that can be used to retrieve an AXIOM from a String (char buffer) which we call as deserialization.

    axiom_node_t* AXIS2_CALL
    deserialize_my_buffer (
        const axutil_env_t * env,
        char *buffer)
    {
        axiom_xml_reader_t *reader = NULL;
        axiom_stax_builder_t *builder = NULL;
        axiom_document_t *document = NULL;
        axiom_node_t *payload = NULL;

        reader = axiom_xml_reader_create_for_memory (env,
            buffer, axutil_strlen (buffer),
            AXIS2_UTF_8, AXIS2_XML_PARSER_TYPE_BUFFER);

        if (!reader)
        {
            return NULL;
        }

        builder = axiom_stax_builder_create (env, reader);

        if (!builder)
        {
            return NULL;
        }
        document = axiom_stax_builder_get_document (builder, env);
        if (!document)
        {
            AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI,
                    "Document is null for deserialization");
            return NULL;
        }

        payload = axiom_document_get_root_element (document, env);

        if (!payload)
        {
            AXIS2_LOG_ERROR (env->log, AXIS2_LOG_SI,
                    "Root element of the document is not found");
            return NULL;
        }
        axiom_document_build_all (document, env);

        axiom_stax_builder_free_self (builder, env);

        return payload;
    }

Regardless of the fact this piece of code is been used many time by Axis2 and application that uses Axis2, it has never been identified as a core AXIOM function. I think it is better we have this function as an alternative method to create an axiom.

axiom_node_t *AXIS2_CALL
axiom_node_create_from_buffer(const axutil_env_t *env, axis2_char_t *buffer);

I already suggested this in Axis2/C mailing list and hopefully it will be included from the next release.

Here when we create the axiom tree function from the character buffer, we used “axiom_xml_reader_create_for_memory” function. Anyway whenever transport read data stream from wire it always uses the “axiom_xml_reader_create_for_io” function.

    /**
     * This create an instance of axiom_xml_reader to
     * parse a xml document in a buffer. It takes a callback
     * function that takes a buffer and the size of the buffer
     * The user must implement a function that takes in buffer
     * and size and fill the buffer with specified size
     * with xml stream, parser will call this function to fill the
     * buffer on the fly while parsing.
     * @param env environment MUST NOT be NULL.
     * @param read_input_callback() callback function that fills
     * a char buffer.
     * @param close_input_callback() callback function that closes
     * the input stream.
     * @param ctx, context can be any data that needs to be passed
     * to the callback method.
     * @param encoding encoding scheme of the xml stream
     */
    AXIS2_EXTERN axiom_xml_reader_t *AXIS2_CALL
    axiom_xml_reader_create_for_io(
        const axutil_env_t * env,
        AXIS2_READ_INPUT_CALLBACK read_callback,
        AXIS2_CLOSE_INPUT_CALLBACK close_callback,
        void *ctx,
        const axis2_char_t * encoding);

As you may have noticed it requires us to implement a “read_callback” function. Here is an example function prototype to implement this callback.

    int AXIS2_CALL
    some_function(
            char *buffer,
            int size,
            void *ctx);

This function will be called by the parser as required to parse the XML read from some stream.

So if your application involves reading data from a stream you are always recommended to use this function (i.e. “axiom_xml_reader_create_for_io”) instead of “axiom_xml_read_create_for_buffer” to create the AXIOM model more effectively.

Posted in axiom, axis2/c, DataServices, drupal, php, SOA, Tutorial/Guide, web services | Tagged , , , , | Leave a comment

Writing a Mashup with Maps and Weather

Few weeks back, I did a screencast on how to consume a web service using WSF/PHP demonstrating an application of US National Digital Weather Forecast Database. In that webservice there are operations like “GmlLatLonList” that retrieve a KML for a given longitude and latitude inside USA. I wrote a simple mashup that load this KML from the web service and set it as a layer in a map which is created using openlayers.

There I use the WSO2 Mashup Server to create the stub to invoke the weather forecasting web service. This stub can be easily used to invoke the service from a javascript in a HTML page.

You can visit the mashup from the Mashup Server community site mooshup.com from here, http://mooshup.com/services/Dimuthu/weatherMap/.

Here are the steps I used to create this mashup.

  1. First I wrote a javascript to wrap the web service. It has a function that can be used as a stub to invoke the web service operation just as a javascript function call. Here is the source of the javascript I wrote. It wraps the “GmlLatLonList” service operation in the “fetchWeatherInfo” function. I gave this javascript service the name “weatherMap”.
    this.serviceName = "weatherMap";
    this.scope = "application";
    this.documentation = "Visit the weather information from just a mouse click";
    
    fetchWeatherInfo.documentation = "Retrieve the weather information for the given inputs" ;
    fetchWeatherInfo.inputTypes = {"listLatLon" : "string",
                                   "startTime" : "string",
                                   "endTime" : "string"};
    fetchWeatherInfo.outputType = "xml";
    function fetchWeatherInfo(listLatLon, startTime, endTime){
    
        var url = "http://www.weather.gov/forecasts/xml/SOAP_server/ndfdXMLserver.php";
    
        // setting up the the WSRequest
        var request = new WSRequest();
    
        var options = new Array();
        options.useSOAP = 1.1;
        options.useWSA = false;
    
        // do the request
        request.open(options, url, false);
    
        var reqXml =
            <ns:GmlTimeSeries xmlns:ns="uri:DWMLgen">
                <listLatLon>{listLatLon}</listLatLon>
                <startTime>{startTime}</startTime>
                <endTime>{endTime}</endTime>
                <compType>Between</compType>
                <featureType>Ndfd_KmlPoint</featureType>
                <propertyName></propertyName>
            </ns:GmlTimeSeries>
    
        request.send(reqXml);
    
        return request.responseXML;
    }
  2. Deployed it in the WSO2 Mashup server. I downloaded and setup the mashup server locally. Then I just needed to put the script inside “scripts/dimuthu” directory. There is an online instance of mashup server called mooshup.com in which I later deployed my service. After deployed it in the mashup, it will generate the javascript stub for that service. You can view the generated stub by adding a “?stub” to the mashup url. Here is the stub for the “weatherMap” mashup deployed in the mooshup server, http://mooshup.com/services/Dimuthu/weatherMap?stub. Similarly you can view the try out page for the service from, http://mooshup.com/services/Dimuthu/weatherMap?tryit
  3. Wrote an HTML interface for the service. I used the openlayers javascript library to load google map in to my page. And added a custom control that handles the click. In the click handler, I just call the stub and get the response KML string back using a code similar to this.
    <!-- include the script for the stub -->
    <script type="text/javascript" src="../weatherMap?stub"></script>
    
    <script language="javascript">
    ...
    
    // the code inside the handler of the click control
    
       // preparing the stub call
       weatherMap.fetchWeatherInfo.onError = handleError;
       weatherMap.fetchWeatherInfo.callback = function(response) {
           if(response && response.firstChild.firstChild.nodeValue) {
    
               // handling kml document
               var kmlDoc = response.firstChild.firstChild.nodeValue;
    
               // the code to add the kml layer to the map and render it
               ....
             }
        };
       // preparing the startTime, endTIme, lat, lon values
       ...
    
       // doing the request call
       weatherMap.fetchWeatherInfo(lat + "," + lon, startTime, endTime);
    
    </script>

    The KML style icon will be shown in the map after adding the KML layer to the map. And we can render the KML style details which in this case contain the weather forecast data in detail in some other place easily.

So this way you can create a mashup using openlayers and the data retrieved from different web services. You can find another mashup that shows the twitter updates on a map in real time at here, http://mooshup.com/services/tyrell/TwitterMap/.

Posted in mashup server, openlayers, SOA, Tutorial/Guide, web services, wso2 | Tagged , , , , , , | 1 Comment

Steps to Convert a SQL Query to a Data Service

With WSF/PHP Data Service library, you can convert a SQL query to a Data Service very easily in few steps.

  1. Decide your SQL query first, For the query you may require some input parameters, and you have to decide what should be returned by the query, Say your query is
    $sql_query = "SELECT name, age, email FROM users where country = ?";

    Then the “country” is our input parameter and the name, age, email are our return values.

  2. Define the input Format. For the above query it will be something like,
    $inputFormat = array("country" => "INT");
  3. Define the output format. We are giving the name “Users” for the out most wrapper element and the name “user” for the wrapper element of each user. Here is how we define it,
    $outputFormat = array("resultElement" => "users",
                    "rowElement" => "user",
                    "elements" => array(
                                "name" => "name",
                                "age" => "age",
                                "email" => "email"));

    For this output format, our expected result payload would be like,

    <users>
      <user>
         <name>xxx</name>
         <age>23</age>
         <email>xxx@xxx.xx</email>
      </user>
      <user>
         <name>yyy</name>
         <age>23</age>
         <email>yyy@yyy.yy</email>
      </user>
      ....
    </users>
  4. Define your operation using the sql query, input and output formats.
    $operations = array("getUsersByCountry" => array(
                                  "inputFormat" => $inputFormat,
                                  "sql" => $sql_query,
                                  "outputFormat" => $outputFormat));
  5. Define your database configuration in an array like this,
    $config = array(
        "db" => "mysql", // your db engine
        "username" => "myname", // name & password for the db server
        "password" => "mypasswd",
        "dbname" => "db", // the db
        "dbhost" => "localhost");
  6. Create a DataService instance using the database configuration and the operations we just created. And call DataServices reply method.
    $ds_service = new DataService(array(
                   "config" => $config,
                   "operations" => $operations));
    
    $ds_service->reply();

That is it. You just exposed your query as a web service. The PHP script URL will be the endpoint URL for the web service.

Posted in DataServices, php, SOA, SQL, Tutorial/Guide, web services, wsf/php, wso2 | Tagged , , , , | Leave a comment

WSO2 Carbon Explained In Pictures

WSO2 Carbon is getting ready to come out very soon. You want to know what exactly WSO2 Carbon is?. Just check this samisa’s blog about “Carbon In Pictures”.

Posted in DataServices, SOA, web services, wso2 | Tagged , , | Leave a comment

5 Facts About WS-Addressing Action in WSF/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.

Posted in php, SOA, Tutorial/Guide, web services, WSDL, wsf/php, wso2 | Tagged , , , , , , , | Leave a comment