Saturday 18 July 2009

Really clever music mash up - Christina Milan and Jim Hendrix "Dip it Joe"

Almost seamless.... fantastic



and probably the weirdest mash of the year to date that I have heard with way to many folk to mention including the late great Bill Hicks

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.

Tuesday 14 July 2009

More Flexy loveliness = Categorized with Summaries

In the last post I popped up an example of categorized views and in this we will add the additional functionality of Summaries.

To recap the last post

01. Create a GroupCollection object

02. Assign a source property of the Group Collection object to the AdvancedDataGrid's dataProvider

03. Create a New Grouping Object

04. Create a new GroupingField Object or Objects that specify the field(s) on which to group

05. Assign the Grouping property of the GroupingCollection to the Grouping Object

06. Refresh the Grouping Collection

07. Assign the GroupingCollection to the Dataprovider or the AdvancedDataGrid.

But what if you want to have some summarised .. well that is relatively easy too. Lets try for this.. With summary data at the end of each category


Ok Lets go.

01. I go to the GroupingField definitions I created yesterday
Originally it looked like this <mx:GroupingField name="cat"/>

02. I drop the / from the end and create a tag pair
<mx:GroupingField name="cat">
&lt/mx:GroupingField>

03. Inside this tag pair I create a <mx:summaries> and </mx:summaries> tag pair

04. Inside the summaries Tags i create a <mx:SummaryRow summaryPlacement="last"> tag pair.. Note the SummaryPlacement attribute. "last" will place it at the end of the category and "first" will put it and the start.

05. Inside the SummaryRow i create a <mx:fields> tag pair

06. Inside the fields tag pair i create
<mx:SummaryField dataField="qty" operation="SUM" label="summary" />
The source of the data is set in dataField which in this case is the "qty" field in the XML pulled from the domino agent.
The Operation is "SUM" (or totalise all the QTY values in the category) other options can be MIN, MAX, AVG and COUNT

07. I repeat 1-6 for the other field "subcat" that I am summarising on

08. Your code will now look like this.

<mx:Grouping>
<mx:GroupingField name="cat">
<mx:summaries>
<mx:SummaryRow summaryPlacement="last">
<mx:fields>
<mx:SummaryField
dataField="qty"
operation="SUM"
label="summary" />
</mx:fields>
</mx:SummaryRow>
</mx:summaries>
</mx:GroupingField>
<mx:GroupingField name="subcat">
<mx:summaries>
<mx:SummaryRow summaryPlacement="last">
<mx:fields>
<mx:SummaryField dataField="qty" operation="SUM" label="summary" />
</mx:fields>
</mx:SummaryRow>
</mx:summaries>
</mx:GroupingField>
</mx:Grouping>
09. Now i am going to use a flex function called a rendererProvider, which is a MXML component that is used to render a particular item in your project.

10. I create a new MXML file called SummaryText.mxml in a subdirectory called Renderers off the directory i have my main MXML file in.

11. The code looks like this and basically all it is , is a LABEL component the which will display the total that is calculated for the category. Note the {data.summary} the .summary refers back to the LABEL I used in the <mx:SummaryField> statement above

<?xml version="1.0" encoding="utf-8"?>
<mx:Label xmlns:mx="http://www.adobe.com/2006/mxml"
text="Total Quantity {data.summary}">
</mx:Label>
12. Having saved the SummaryText.mxml file I return to the AdvancedDataGrid definition in my main MXML file. Just above the closing </mx:AdvancedDataGrid> tag I create a new set of tags that attach the renderer to the AdvancedDataGrid. the code looks like this

<mx:rendererProviders>
<mx:AdvancedDataGridRendererProvider
dataField="summary"
columnIndex="1"
columnSpan="2"
renderer="Renderers.SummaryText"/>
</mx:rendererProviders>
Of note here is the the dataField attribute points at LABEL I used in the <mx:SummaryField> definition (and beware it IS case sensitive)
Also if i set the columnSpan to "0" it will span all columns in the grid. I have chosen 2 here cos it looks better in the finished application.
Also the renderer attribute is made up of [the path to the renderer MXML file].[File name without extenstion] beware this too is case sensitive.

13. Once that is done ... compile up your app and there you have it.. summary values in your view. Note this is all done by FLEX as I have NOT changed the agent that supplies the data from the Domino application.

I have Popped this into a NSF and zipped it up with the Flex Builder 3 project files if you want to have a look see.. This is the same file as yesterday.. except the summarised page is FlexView2 ad the SWF is called CategoryView2.swf.. you can get it here .. Same provisio as yesterday, This will NOT work on your server as you need to change the URL for the HTTPService object and recompile the SWF for it to work!!! Enjoy and again if you have any questions drop me an email :-)

Categorised Views in Flex - It's really easy

OK .. a Flex Post for youse in Domino land.

First some stuff about the what I used.

Flex 3 SDK
Notepad ++
Domino 8.5.0 server
Domino 8.5.0 DDE

I was asked recently how I would FLEX a multi-category expand/collapsible view which is admittedly dead easy in the Notes Client. Well it is almost as easy in Flex.

This is what I did to illustrate the method.

01. I created a form that looks like this


02. I created a view that looks like this

03. I created an agent that does this
04. I opened Notepad++ and created a file called CategoryView1.mxml and typed up these 47 lines of code
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="myData.send()">
<mx:HTTPService id="myData"
url="http://www.unseenuni.com:81/flexview.nsf/getdata?openagent"
result="dataResult(event)"/>
<mx:Script>
<![CDATA[
import mx.controls.Text;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent
import mx.collections.ArrayCollection
[Bindable]
private var items:ArrayCollection = new ArrayCollection
private var msg:String
private function dataResult(event:ResultEvent):void
{
items= event.result.items.item;
myGroup.refresh(true)
}
private function dostuff(event:MouseEvent):void
{
if(event.target.data.key)
{
msg = event.target.data.key
mx.controls.Alert.show(msg)
}
}
]]>
</mx:Script>

<mx:AdvancedDataGrid x="10" y="10" id="Grid1" designViewDataType="tree" width="719" height="343" creationComplete="myGroup.refresh()">
<mx:dataProvider>
<mx:GroupingCollection id="myGroup" source="{items}">
<mx:Grouping>
<mx:GroupingField name="cat"/>
<mx:GroupingField name="subcat"/>
</mx:Grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Item" dataField="item"/>
<mx:AdvancedDataGridColumn headerText="Qty" dataField="qty"/>
<mx:AdvancedDataGridColumn headerText="Price" dataField="price"/>
</mx:columns>
</mx:AdvancedDataGrid>

</mx:Application>

05. I compiled up the mxml to a SWF using the SDK (a lot easier if you use FLEX BUILDER!)

06. I Imported the resulting file CategoryView1.swf as a File Resource in my NSF

07. I created a Page in my NSF with this Passthru HTML
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="CategoryView1" width="100%" height="100%"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie" value="CategoryView1.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="CategoryView1.swf" quality="high" bgcolor="#869ca7"
width="100%" height="100%" name="CategoryView1" align="middle"
play="true"
loop="false"
quality="high"
allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed>
</object>

08. I fired up a browser and went to the page's I just created URL and this is what appeared.



It really is that easy... So lets look at this in detail.

The Domino agent returns nice simple XML - have a look at ../flexdata.nsf/getdata?openagent and you will see it in "raw" form, althought the parent view is sorted it is not categorised it is an ordinary flat view. We will let Flex do the sorting and grouping once it gets the data.

The MXML is only 47 lines long and was created as follows :-
(replace [] with < adn >)
01. I created an application

[mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"]

[/mx:Application]


This defines the application and it is always like this, note the tag pair is closed!


02. Inside the application tags I place a definition of the HTTPService I am going to use to provide the data to the application


[mx:HTTPService id="myData"
url="http://www.unseenuni.com:81/flexview.nsf/getdata?openagent"
result="dataResult(event)"/]


This breaks down into
id this is the id by which I will refer to the service later in the code
url this is the URL which will provide the data
result this is the actionscript code that will run when data is recieved from the url

03. The next section is the Actionscript code that my flex application will use

<mx:Script>
<![CDATA[
import mx.controls.Text;
import mx.controls.Alert;
import mx.rpc.events.ResultEvent
import mx.collections.ArrayCollection
[Bindable]
private var items:ArrayCollection = new ArrayCollection
private var msg:String
private function dataResult(event:ResultEvent):void
{
items= event.result.items.item;
myGroup.refresh(true)
}
]]>
</mx:Script>


Firstly I import the various Adobe Supplied libaries that i will need
Then I create a Bindable ArrayCollection object call items, this will store the returned data.
Then I define the dataResult() function that I attached to the HTTPService object. Remember this code gets executed when the URL in the HTTPService recieves data from the URL. In this instance the items ArrayCollection is loaded with the data returned from the URL. FLEX will see it as XML and I can access it through the event.result object by name.

04. Now I define my on screen objects

<mx:AdvancedDataGrid x="10" y="10" id="Grid1" designViewDataType="tree" width="719" height="343" creationComplete="myGroup.refresh()">
<mx:dataProvider>
<mx:GroupingCollection id="myGroup" source="{items}">
<mx:Grouping>
<mx:GroupingField name="cat"/>
<mx:GroupingField name="subcat"/>
</mx:Grouping>
</mx:GroupingCollection>
</mx:dataProvider>
<mx:columns>
<mx:AdvancedDataGridColumn headerText="Item" dataField="item"/>
<mx:AdvancedDataGridColumn headerText="Qty" dataField="qty"/>
<mx:AdvancedDataGridColumn headerText="Price" dataField="price"/>
</mx:columns>
</mx:AdvancedDataGrid>


I use the AdvancedDataGrid because it has support for Grouped (read Categorised Objects) you will not I do not ascribe a datasource to the AdvancedDataGrid Object. Instead I create a DataProvider object INSIDE the AdvancedDataGrid Tag pair! very important than!

Inside the DataProvider Object I create first a GroupingCollection object, I would do this even if I had only one category. Inside that I define a Grouping object and then as manu GroupingField objects as I need. In this instance the Fields Cat and SubCat.

I then define the Columns I want to display. Note i do NOT include the columns that will be my groups!

And that is it... compile it up, stick it in your NSF and Robert is your mother's brother.

I have uploaded the NSF and FLEX BUILDER PROJECT here.. but the NSF will not work on your server unless you change the URL in the MXML from my server to your own, recompile the SWF and delete the orginal SWF from the NSF and attach the new one as a new file resource.. i include it only so you can see the code not run it :-)

If you have any questions just drop me a line ... enjoy

Sunday 12 July 2009

Tinariwen - New Album Companions - 5 Star wonderful!

I discovered the Tuareg Poet / Guitarist legends Tinariwen last year and YIPEE a new album is out.. This is Lulla from the new album "Companions" If you like new exciting sounds give it a listen close your eyes and think desert ... enjoy

Some thoughts on Tradition

I have recently returned from a business trip to the far east and arrived back just in time for the annual tradition of the 12th of July. The "Glorious Twelfth" as it is known in some circles is the traditional celebration of the The Battle of Boyne in 1690 when the Protestant King William of Orange gave the Catholic King James a bloody nose. Now it was far from the simple matter of two denominations of Christianity being belligerent, it was more about the power of the royal families in Europe at the time. In fact Pope Alexander VIII lent King William troops for the war against King James. King William and the Pope and several other countries were in the League of Ausburg which was set up to defend the Palatinate of the Rhine from the French. A fact sadly lacking from the history expounded by organisations like the Orange Order who much prefer the world view that the Battle of the Boyne was a "Protestant Victory for a Protestant People" which is in fact a load of revisionist knob cheese, but what is a bit of revisionism when it is the absolute right given by God and justified by Luther, Calvin, Knox and the tooth fairy to be a raving bigot at the drop of a bowler hat each July.

I overheard a conversation at the airport where a grandmother was telling her grandchildren of the "good old days" when her grandfather paid her 1 old penny each time she sat on his knee and shouted "To hell and the flames with the pope and all Catholics". Ah yes the good old days of vitriol and hatred ... such a fine gift to pass on to one's children!

When I was a teenager if you travelled outside the streets where you were known it was inevitable that you would be asked "What are you?". Now for other traditional forms of hatred like racism it is easy to pick your targets by visual cues alone. Picking which person to abuse is harder when based on religion hence the blunt interrogative method. It became second nature for most to quickly work out who was doing the asking and switch sides accordingly, this whilst being ethically suspect was a sure fire way to avoid getting a black eye or worse. Needless to say one had to learn the responses to the follow up questions of "Well sing the Sash" or "Say the hail Mary" but that was a small price to pay.

You could not answer "neither", that was not an option, you could not sit on the fence. You had to plant yourself firmly on one side or the other and be prepared to defend that position from all comers, needless to say expressions of distrust or outright hatred of the "other" side were mandatory if you were to be believed.

As a callow youth the painful experience of having to fight off both sides soon lead to the my questionable position of variable allegiance, although in hindsight I was put in the position of having to repeat parrot like the vitriol of one side or the other, something I could not and hopefully would not allow myself to do now.

Now do not get me wrong, tradition can be a wonderful thing. The traditions of openness, friendship, philanthropy and generosity of spirit are fine things to pass on to the next generation. Such traditions are the glue that holds societies together and makes them work. However on the other side of the coin are the traditions that are divisive, that are driven by the sure and certain knowledge that your tradition is the ONLY one that is right, the only one that is useful and in this case that it is the only one that is God Given to you and your side only.

Traditions are dangerous when they are the only thing that defines who you are. I do not define myself by the country that I live in, nor do I wrap myself in the dubious comfort of a flag, as this only succeeds in hiding me from others. If I was holding that tightly onto a flag how could I hug a stranger or extend them the hand of friendship?.. and there is the rub ... i do not think that is part of the traditions I see unfolding each July. There are no hands of friendship, no hugs expect for those in your tribe. It is all inward looking, incestuous, foetid reinforcement of generationally transmitted regligious hatred and distrust.

Tomorrow, tens of thousands of bowler hatted, white gloved men will march behind banners that display their commitment to the British monarch (but ONLY with the strict condition that the monarch is Protestant, or more exactly, not Catholic) and commitment to the Bible (the protestant one not the catholic one). The banners they march behind will be flanked by men carrying swords and pikestaffs in rememberance of those that were killed and the fact that they needed to be killed to protect the faith. There will be marching bands playing military marching tunes mixed with sectarian anthems, some of which will have words that call the listener to arms to defend with violence the God given right to be Protestant. There will be acts of worship in which ministers will pillory the "church of rome" and declaimed it as the worst evil in the world. There will be speeches where the leaders of the Orange tribes will extole their members to stick together for God and Country at all and any cost.

This is not a tradition I want any part of.

Disqus for Domi-No-Yes-Maybe