Friday 17 July 2009

Flex,Domino and Web Services 101

Okay Dokey, the last 2 Flex posts used JSON from a Web Agent, which is fine if that is your cup of tea, but Domino comes complete with easy to use and deploy WebServices and it would be a shame not to use them.

I will take it as read you know all about web services but for those that don't a Web Service is a way of letting applications written in languages like FLEX's MXML or Java interact with your data with the minimum of fuss and bother. You define the webservice and it gets published by domino as a WSDL which is a formal XML data stream. Your application then knows what methods and data your webservice offers for getting data, posting data etc and you app can use the methods it finds in the WSDL data to interact with the back end data.

Anyway I have a simple Notes database with 1 form called STOCK with the following fields
ItemKey
Category
SubCategory
ItemName
OnHandQuantity

I have a view sorted (but not categorised) by ItemKey the view is called MyStockView

So I go to the CODE section in the DDE and open the "Web Services Providers Section"

On the Web Services Properties Dialog I do the following:

I Give the WebService a NAME of StockService
I give it a PORT TYPE CLASS of getStock
I give it a PROGRAMMING MODEL of RPC
I give it SOAP MESSAGE FORMAT of DOC/LITERAL
I include "Operational Name in SOAP Action"
The PORT TYPE NAME is getStock
The SERVICE ELEMENT NAME is getStockService
The SERVICE PORT NAME is Domino

In the "Declarations" section i put this code
Dim ThisSession As NotesSession
Dim ThisDB As NotesDatabase
Dim StockDoc As NotesDocument
Dim StockView As NotesView

Class getStock
Sub New
Set ThisSession = New NotesSession
End Sub

Public Function getStock(stockKey As String) As String

If StockDoc Is Nothing Then
result=getStockDoc(stockKey)
getStock=result
End If
End Function

End Class
This is a VERY VERY basic web service!
Web Services are defined in CLASS objects and this service contains one class called getStock, it contains 1 method that instansiated the getStock object. It is passed one parameter stockKey
which is passed to a function called getStockDoc which does the actual work of geting and returning data.

I then have to create the getStockDoc() function in the Web Service object .. like this
Private Function GetStockDoc(stockKey As String) As String
Set ThisDB = ThisSession.CurrentDatabase
If Not (ThisDB.IsOpen) Then
GetStockDoc= "Error opening database"
Exit Function
End If
'Check that view exists in the database
Set StockView = ThisDB.GetView("StockByKey")
If StockView Is Nothing Then
GetStockDoc = "Error in search"
Exit Function
End If
'Get a document by provided search key
Set StockDoc = StockView.GetDocumentByKey(stockKey, True)
If StockDoc Is Nothing Then
GetStockDoc = "Cannot find Stock"
Exit Function
End If
GetStockDoc= StockDoc.ItemName(0)
End Function
This does what it says on the tin.. it checkes the DB exists, the view exists and then goes and gets the document found using the stock key. the function returns either an error message if something goes wrong or the Item Name if it succeeds.

Having done all this I try out my webservice by going to this URL

http://www.unseenuni.com/mystock.nsf/StockService?wsdl

And if every thing goes according to plan i should get some nicely formatted XML. The content of the XML is very interesting if you are a real geek, but the domino server does all the interesting shit so as long as you get lots of XML your web service is working and you can they create applications that can "consume" it.

OH very important this.. DOMINO will take all the important bits of your server and make them UPPER CASE!! so getStock will become GETSTOCK

OK I fire up the other side of the coin now and create my MXML file called WS1.mxml in this case and i open the application with the normal Application tags
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
</mx:application>
inside these tags I create my webservice definition
<mx:WebService
id='myservice'
wsdl="http://www.unseenuni.com/mystock.nsf/stockservice?wsdl">
</mx:WebService>
You will not that i have given it an ID so i can refer to it in my MX code later on
and I define where the web service object can get the WSDL XML from the server. This will be loaded from the server automatically when the application is loaded at run time.

Inside the mx:WebService tag i create the following code
<mx:operation name='GETSTOCK' result='myresult(event)'>
<mx:request>
<STOCKKEY>
{mykey.text}
</STOCKKEY>
</mx:request>
</mx:operation>


Although the WSDL defines the method GETSTOCK in the webservice I have to define an MX object to interact with it. So I create an mx:operation which has the same name as the WSDL (note the upper case !!) and it also defines an mx function myresult(event) which will be fired when the webservice operation returns data.

The STOCKEY tag defines the data that will be passed to the method again note the UPPERCASE! In this case I have defined this as the bindable value of a Text input box which I will define in a moment... but first i will define the script for the result handler myresult();

<mx:Script>
<![CDATA[
import mx.controls.Text;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent
[Bindable]
private var msg:String
private function myresult(event:ResultEvent):void
{
msg = (event.result as String)
mx.controls.Alert.show(msg)
}
]]>
</mx:Script>


As you can see when the myresult() function is triggered it will display the content s of the Event result as text in an alert box.. not very exciting i know but I want to keep the code down to a minimum.

lastly I create a text input box and button.

<mx:TextInput x="25" y="10" id="mykey"/>
<mx:Button x="25" y="40" label="Button" click='myservice.GETSTOCK.send()'/>
The text input box is called mykey and use {mykey.text} in the STOCKKEY tag of the Webservice Operation definition earlier..

The Button calls the Webservice's GETSTOCK's method by calling .send(), this then calls the webservice method passes it to the server and waits for some data to come back when the function myresult() will be triggered and processed.

So when i compile up my flex project it looks like this on the screen



and if i type in a valid Item Key and click the button .. this happens



Easy Peasy!

Now webservices are usually way way way more complex than this one, but you get the idea :-) and it only took 31 lines of MXML to define the process that consumed it. In the next post I will use Web Services to Update data on the server.

Disqus for Domi-No-Yes-Maybe