29 January 2010

Link Adobe Flex 3.5 Chart to ColdFusion webservice

As promised, here is a (not very) short blog about how to get Adobe Flex 3.5 to consume a coldfusion cfc based webservice and display it as a chart.

As mentioned in my previous post it's EPIC that Adobe decided to put charting in the SDK. I use the SDK (coz I'm poor) and with it and a little patience you can achieve some amazing Flex apps.

So to do this you'll need the Flex 3.5 SDK, you'll need the Flex data visualization pack and obviously you'll need coldFusion.

I'm sorry for the code here, Google blogger doesn't make posting code easy.

1)The cfc:


<cfcomponent>

<cffunction name="getPersonByDept" access="remote" returntype="query" output="false">
<cfargument name="deptname1" type="string" required="true" />
<cfargument name="deptname2" type="string" required="true" />
<cfargument name="deptname3" type="string" required="true" />
<cfset var myQuery = queryNew('counttt,deptName') />

<cfquery name="myQuery" datasource="jayLocal">
select count(personid) * 100 as [counttt], [deptName]
from [person]
group by [deptName]
having
[deptName] = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.deptname1#" />
or [deptName] = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.deptname2#" />
or [deptName] = <cfqueryparam cfsqltype="cf_sql_varchar" value="#ARGUMENTS.deptname3#" />
</cfquery>

<cfreturn myQuery />
</cffunction>

</cfcomponent>



I know, I know, the function isn't great, i don't need to pass in 3 separate params, but this is just for illustration purposes. Take this cfc and save it as latestone.cfc in your coldfusion webroot or in a webservices folder. Whatever you fancy. You're going to want to be careful of Application.cfc because it can eat your webservices. You should be able to then open up the wsdl in your browser.
http://localhost/webserrvices/latestone.cfc?wsdl
You should see a bunch of xml data. This is coldfusion doing the hard work for you and describing the webservices offered at this wsdl.
The datasource and query are linked to a ms sql server, a single table called person. It should all be pretty straightforward.



2)The test.cfm:

OK so far so good, lets create a quick test.cfm and make sure the webservice works so far. Create the cfm file and paste in the following code:


<cfobject type="JAVA"
action="Create"
name="factory"
class="coldfusion.server.ServiceFactory">
<cfset RpcService = factory.XmlRpcService />
<cfset RpcService.refreshWebService("http://localhost/webserrvices/latestone.cfc?wsdl")>


<cfinvoke webservice="http://localhost/webserrvices/latestone.cfc?wsdl" method="getPersonByDept" returnvariable="hello2">
<cfinvokeargument name="deptname1" value="development" />
<cfinvokeargument name="deptname2" value="sales" />
<cfinvokeargument name="deptname3" value="marketing" />
</cfinvoke>



<cfdump var="#hello2#" />





OK quick bit of explaining. First and foremost the first paragraph, the JAVA stuff may be the single most useful piece of code when working with webservices in CF. CF does some aggressive caching when it comes to webservices. So if you're in dev mode this code forces CF to keep re-looking. DO NOT leave this code on a production server as it'll slow it right down. But for now it's useful. The second bit of code is a simple cfinvoke based on a webservice consumption.


3)The mxml:

Finally the Flex part. OK So assuming you've downloaded Flex, and tried a helloWorld already you should be able to take the following code and paste it into a .mxml file. Then compile it using the mxmlc command as before. Here's the mxml Flex code:




<?xml version="1.0" encoding="utf-8"?>

<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
viewSourceURL="src/HelloWorld/index.html"
horizontalAlign="center" verticalAlign="middle" initialize="initApp()" backgroundColor="white">


<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import mx.rpc.events.ResultEvent;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.utils.ObjectUtil;
import mx.core.Application;
import mx.validators.Validator;
import mx.managers.CursorManager;
import mx.events.ListEvent;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridListData;
import mx.utils.ArrayUtil;


[Bindable]
private var myDebpts: ArrayCollection;



public function initApp():void {
//onload send webservice
WSgetTasks.getPersonByDept.send();
}


private function server_fault(event:FaultEvent):void{
//on error, show...an error message!
Alert.show(ObjectUtil.toString(event.fault));
}


private function returnLoadTasks(evt:ResultEvent):void {
//when webservice returns, we grab the results and stick it in the bindable myDebpts
myDebpts = WSgetTasks.getPersonByDept.lastResult;
}


]]>
</mx:Script>

//This is the crus of the app, the webservice call. the operation tells it what method to call and the request stuff is the parameters, that simple!
<mx:WebService id="WSgetTasks" wsdl="http://localhost/webserrvices/latestone.cfc?wsdl" fault="server_fault(event);" result="returnLoadTasks(event)">
<mx:operation name="getPersonByDept">
<mx:request>
<deptname1>development</deptname1>
<deptname2>sales</deptname2>
<deptname3>marketing</deptname3>
</mx:request>
</mx:operation>
</mx:WebService>


<mx:Panel title="Users By Department" height="300" width="400">
//the chart
<mx:ColumnChart id="myChart"
dataProvider="{myDebpts}"
height="100%"
width="100%"
showDataTips="true">


//this bit is confusing but it works!
<mx:horizontalAxis>
<mx:CategoryAxis dataProvider="{myDebpts}" categoryField="DEPTNAME" />
</mx:horizontalAxis>

<mx:series>
<mx:ColumnSeries yField="COUNTTT" xField="DEPTNAME" displayName="Department Name" />
</mx:series>
</mx:ColumnChart>


<mx:Legend dataProvider="{myChart}"/>
</mx:Panel>


</mx:Application>





There we go. Hopefully the comments provide some clarity, again I'm sorry Google blogger does such a poor job of showing the code properly. To talk you through it briefly, on app initialize the initApp() is called, this triggers the webservice. The mx:WebService calls the cfc which we defined as a webservice. It uses the mx:operation and the mx:request as parameters, obviously you can bind these to a text field or something. Then on completion the result runs the returnLoadTasks() function which loads the lastresult into the bindable arraycollection. This arraycollection is bound to the chart with the appropriate x and y axis names.

4)Display the generated flash file:

Done. Compile this and flex will spit out a lovely flash file. Copy this to your web directory somewhere and add the following to output the flash file:



<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0" width="100%" height="100%">
<param name="movie" value="wschart.swf">
<param name="quality" value="high">
<embed src="wschart.swf" quality="high" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" width="100%" height="100%"></embed>
</object>




21 January 2010

Update: Charting available in Flex

A while ago i posted an entry saying charting was not available to Flex users of the SDK. While i was upset (charting is cool) I understood that Adobe wanted to attract users to their Flex Builder (purchased) product over the free SDK. Well in the latest version i discovered to my surprise the SDK can now support charting. This is awesome, hats of to Adobe, it works great and looks amazing, and all for free, grata, no money!

Here's a very brief example:

1) Download the SDK and the data visualization pack (currently flex version 3.5):
http://www.adobe.com/cfusion/entitlement/index.cfm?e=flex3sdk

2) Unzip install, etc, rtfm.

3) Create a blank text file with the extension .mxml

4) type the following code:



5) type something along the lines of this in a cmd window

C:\Adobe\Flex3\bin>mxmlc --strict=true --file-specs C:\flexie\chartTest.mxml

**should be obvious the first bit is cmd window telling me what dir i'm in, then the mxmlc is the executable to use for compiling and the rest is jarg, then the last bit is the location of my mxml code file.

6) This should deploy a .swf file to your code location. The swf file is then your flex app with some pretty little charts available!

I'll blog later with how to link these charts to something useful like a cf webservice.

Congrats Adobe on putting charts in the sdk, nice one.