Flex For Java Developers - SDForum Java SIG
Upcoming SlideShare
Loading in...5
×
 

Flex For Java Developers - SDForum Java SIG

on

  • 7,950 views

One day Chris Richardson, in need of a rich UI and deeply frustrated with Javascript and CSS, sat on his couch and downloaded FlexBuilder. This is what he found out.

One day Chris Richardson, in need of a rich UI and deeply frustrated with Javascript and CSS, sat on his couch and downloaded FlexBuilder. This is what he found out.

Statistics

Views

Total Views
7,950
Views on SlideShare
7,927
Embed Views
23

Actions

Likes
2
Downloads
113
Comments
0

2 Embeds 23

http://www.slideshare.net 22
http://ig.gmodules.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Flex For Java Developers - SDForum Java SIG Flex For Java Developers - SDForum Java SIG Presentation Transcript

  • Flex for Java developers: My quest for pain-free UI development Chris Richardson Author of POJOs in Action www.chrisrichardson.net chris@chrisrichardson.net @crichardson Cinco de Mayo 2009
  • About Chris Grew up in England and live in Oakland • Over 20+ years of software • development experience including 12 years of Java Started Java architecture consulting • company and sold it to BEA Speaker at JavaOne, SpringOne, etc. • Java Champion • Run a consulting and training company • that helps organizations reduce g development costs and i d l d increase effectiveness cloudtools.org www.cloudfoundry.com Slide 2 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Developing Flex Applications Pushing data to the client g Building and testing Flex applications Slide 3 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Arms race: Frameworks vs. UI complexity p y 1998 1998- 2000 2000- 2002 2002- 2005 2005- 2007 2008 1999 2002 2005 2006 Really Really More More More simply Simple Complex Complex complex Rich UIs pages Pages Pages Pages pages Home Spring Spring grown MVC Struts Struts Spring MVC/Web frame 1.0 1.0 MVC WebFlow Flow work Dojo /☺ ☺ Slide 4 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cloud Foundry y Slide 5
  • Cloud Foundry UI y Single page application Dojo toolkit Uses DWR to push events to browser p End result is quite nice But getting there was painful Slide 6 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Why is building RIAs so painful? y g p Open-source JavaScript projects Variable quality q y Some are poorly documented Built on a shaky foundation of web technologies JavaScript p Dynamic ⇒ limited IDE support Prototype-based ⇒ simulated classes No packages ⇒ build your own … CSS layout Difficult to learn Relies on “hacks” to accomplish basic layout tasks Lack of portability across browsers Easier to use tables? Numerous b N browser incompatibilities i tibiliti Slide 7 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Today's web = multi-layer hack y y Was – a straightforward Hacks to enable offline hypertext browsing system applications Now – an application … delivery platform Fake class system ⇒Time for a Javascript change Hypertext Slide 8 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • GWT is an option p Treats JavaScript as the runtime environment Develop and debug in Java quot;Swing-stylequot; programming model But my social network liked Flex … Slide 9 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • So I downloaded Flex Builder and wrote some Flex code… d l d Slide 10 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Developing Flex Applications pg pp Pushing data to the client Building and testing Flex applications Slide 11 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • What is Flex? Open-source framework for building Rich Internet Applications Current version is Flex 3 (Flex 4 in 4Q09) Flex apps run on the ubiquitous Flash pp q player In the browser On the desktop with Adobe AIR Excellent documentation Develop applications in MXML – declaratively define UI ActionScript 3 – handle events, invoke backend services, dynamically construct UI ,y y Slide 12 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • ActionScript 3 – the scripting language for the Flash p y gg player Class-based, object-oriented language Compile-time type checking Packages Dynamic vs. sealed classes Dynamic – add properties/methods at runtime ti Method closures High Hi h performance AVM2 with JIT f ith compiler Dialect Di le t of ECMAS ipt (like J ECMAScript JavaScript) S ipt) Slide 13 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • ActionScript XML support ( p pp (E4X) ) var x : XML = <createAlbumRequest> <title>{title}</title> var albums : XML = <albums> <album> <creationDate> <id>id1</id> {creationDate.time} <title>t1</title> / </creationDate> <thumbnail>xyz<thumbnail> <notes>{notes}</notes> </album> <album> </createAlbumRequest> <id>id2</id> <title>t2</title> <thumbnail>abc</thumbnail> var title : String = x.title; </album> var notes : String = x.notes; ….. </albums> var notes : XMLList = albums.album.notes var albums2: XMLList = ablums.album.(title = “t1”) Slide 14 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Comprehensive component library p p y Components have properties and methods generate events Visual components Controls: Button, TextField, … Container: TabContainer, Form, Box, … Can be styled with CSS Non-Visual Data access components, e.g. HTTP, Web Services Validators Formatters Slide 15 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Declaratively define UI in MXML y <mx:Application > <mx:Form> <mx:FormItem label=quot;Symbolquot; fontWeight=quot;boldquot;> label= Symbol fontWeight= bold > <mx:TextInput id=quot;symbolquot; text=quot;AAPLquot; fontWeight=quot;normalquot;/> </mx:FormItem> <mx:FormItem label=quot;quot;> <mx:Button label=quot;Get Quotequot; click=quot;handleClick(event)quot;/> </mx:FormItem> / </mx:Form> <mx:DataGrid dataProvider=quot;{quotes}quot; width=quot;100%quot;> <mx:columns> <mx:DataGridColumn headerText=quot;Symbolquot; dataField=quot;symbolquot;/> <mx:DataGridColumn headerText=quot;Pricequot; dataField=quot;pricequot;/> </mx:columns> / l </mx:DataGrid> </mx:Application> Equivalent to creating component tree in ActionScript Slide 16 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Events Components generate events Handled by ActionScript code <mx:Button l b l quot;G t Q t quot; click=quot;handleClick(event)quot;/> < B tt label=quot;Get Quotequot; li k quot;h dl Cli k( t)quot;/> private function handleClick(event :Event) : void { … } Slide 17 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Data Binding g Control is updated whenever variable changes [Bindable] private var quotes : Array = []; <mx:DataGrid dataProvider=quot;{quotes}quot; width=quot;100%quot;> dataProvider= {quotes} width= 100% > <mx:columns> <mx:DataGridColumn headerText=quot;Symbolquot; dataField=quot;symbolquot;/> <mx:DataGridColumn headerText=quot;Pricequot; dataField=quot;pricequot;/> </mx:columns> </mx:DataGrid> Slide 18 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Custom components p Define <mx:GridItem > AlbumThumbnail.mxml <mx:Script> subclasses in <![CDATA[ [Bindable] MXML or public var album : XML; p public function viewAlbum() : void { ….} () } ActionScript A ti S i t ]]> </mx:Script> Use to <mx:VBox width=quot;100quot; height=quot;125quot;> modularize dl i <mx:Image id quot;i I id=quot;imgquot; click=quot;viewAlbum()quot; quot; li k quot; i Alb ()quot; source=quot;{album.thumbnail}quot; /> </mx:Box> application <mx:Text width=quot;100quot; height=quot;25quot; text=quot;{album.title}quot;/> 3rd party d </mx:VBox> components </mx:GridItem> <components:AlbumThumbnail album=quot;{rp.currentItem}quot;/> Slide 19 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Flex security sandbox y Uses the Flash Player security model By default, a Flex application can only access resources on the site that it was downloaded from Cross-domain policy files on remote server grants access to Flex applications from other domains Slide 20 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Flex Tools from Adobe Flex SDK Free, open-source F Compilers and command-line debugger FlexBuilder – Cheap ($249) Eclipse-based IDE For Mac and Windows MXML and ActionScript editors – completion, renaming and validation Drag and drop UI builder Good debugging: breakpoints, Comprehensive h l C h i help Slide 21 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Flex Stock Quote Demo Q Slide 22 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Flex back-end integration g BlazeDS Open-source project O j Allows Flex clients to talk to server-side Java applications RPC Server-push over HTTP p LiveCycle Data Services ES Commercial Superset of BlazeDS More scalable Client/Server d t synchronization Cli t/S data h i ti Slide 23 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Flex Application Architecture pp Blaze DS SOFEA = Service-Oriented Front-End Architecture Service Oriented Front End Slide 24 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Building Flex Applications The Cairngorm framework Cloud Photos Example Application Scenario: displaying albums S i di l i lb Scenario: creating a new album Scenario: copying photos between albums Pushing data to the client Building and testing Flex applications Slide 25 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Tangled code g <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:Application xmlns:mx=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;absolutequot; implements=quot;mx.rpc.IResponderquot; backgroundColor=quot;#ffffffquot;> <mx:Script> Data [Bindable] private var quote : String; private function handleClick(event :Event) : void { var service : HTTPService = new HTTPService(); Data … Access } Logic public function result(data:Object):void { …. } p public function fault(info:Object):void { } ( j ) ]]> </mx:Script> <mx:VDividedBox width=quot;414quot; height=quot;217quot; Presentation logic …. </mx:VDividedBox> </mx:Application> Slide 26 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cairngorm framework g MVC framework for Flex Model – data View – Flex components that display the model (through binding) Controller – implements quot;business logicquot; logicquot;, i.e. accessing backend services and update the model Encourages: Separation of concerns Separation of development roles: front-end and b k d back-endd Avoids big ball of mud An alternative is PureMVC Slide 27 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cairngorm classes and roles g Views Display the model The code has a cookie- ModelLocator cutter feel to it but I Provides access to the model like the structure “Business” Events Generated by Views Front Controller Routes events to Commands Commands Handle events Contain quot;business logicquot;/data access logic g/ g Invoke delegates Delegates Proxy for remote services Contract between front-end and back-end team Calls b k t C ll back to command d ServiceLocator Centralized registry of (supposedly) all data access components Used by delegates Slide 28 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cairngorm flow g Slide 29 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Building Flex Applications The Cairngorm framework Cloud Photos Example Application Scenario: displaying albums S i di l i lb Scenario: creating a new album Scenario: copying photos between albums Pushing data to the client Building and testing Flex applications Slide 30 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cloud Photos Application pp Tomcat RESTful web services Flex Client Scala/Spring MVC /p g Events Java/Spring/JMS Manage your photos online Upload and p view photos Simple DB Organize S3 photos into Amazon Web Services albums … Slide 31 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cloud Photos – screenshots Slide 32 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Cloud Photo – web services http://localhost:8080/webapp/api/album <albums> <album> <id>e778769a-8432-46ca-b0f1-5c92f33a8710</id> <title>Pictures of kids</title> <thumbnail>https://s3.amazonaws.com/…</thumbnail> </album> / <album> <id>1ff7528a-65aa-4300-a5bb-c5b7e6eba985</id> <title>Some birds</title> <thumbnail>https://s3.amazonaws.com…</thumbnail> p // / </album> ….. </albums> Slide 33 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Application structure pp Slide 34 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Model – a Singleton g package net.chrisrichardson.cloudphotos.ui.model { import com.adobe.cairngorm.model.IModelLocator; Metadata tag enables binding for all public properties [Bindable] public class CloudPhotosModelLocator implements IModelLocator { private static var modelLocator:CloudPhotosModelLocator; public var viewState : String = quot;displayAlbumsquot;; public var albums : XMLList; public var currentAlbum : XML bli tAlb XML; public static function getInstance():CloudPhotosModelLocator{ if (modelLocator == null) { Singleton modelLocator = new CloudPhotosModelLocator();(); } return modelLocator; } } } Slide 35 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • View - Main application pp <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:Application layout=quot;verticalquot; layout vertical xmlns:ns1=quot;net.chrisrichardson.cloudphotos.ui.components.*quot; xmlns:control=quot;net.chrisrichardson.cloudphotos.ui.control.*quot; xmlns:business=quot;net.chrisrichardson.cloudphotos.ui.business.*quot; width=quot;100%quot; height=quot;100%quot;> idth quot;100%quot; h i ht quot;100%quot; <business:Services id=quot;servicesquot; /> bus ess Se ces d se ces / <control:Controller id=quot;controllerquot; /> <mx:Label text=quot;Cloud Photosquot; fontSize=quot;33quot;/> <ns1:HomePage width=quot;100%quot; height=quot;100%quot;> width quot;100%quot; height quot;100%quot;> </ns1:HomePage> </mx:Application> Slide 36 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • View - HomePage g <mx:Vbox …> <mx:Binding destination=quot;currentStatequot; destination currentState source=quot;{CloudPhotosModelLocator.getInstance().viewState}quot;/> <mx:states> <mx:State name=quot;displayAlbumsquot;> <mx:SetProperty name=quot;selectedIndexquot; target=quot;{viewStack}quot; value=quot;{0}quot;/> </mx:State> <mx:State name=quot;displayAlbumquot;> <mx:SetProperty name=quot;selectedIndexquot; target=quot;{viewStack}quot; value=quot;{1}quot;/> </mx:State> </mx:states> <mx:TabNavigator id=quot;tabNavigatorquot; …> id= tabNavigator > <mx:ViewStack id=quot;viewStackquot; width=quot;100%quot; height=quot;100%quot; label=quot;My Albumsquot; > <components:AlbumList id=quot;albumListquot; width=quot;100%quot; height=quot;100%“/> <components:AlbumView id=quot;albumViewquot; width=quot;100%quot; height=quot;100%“/> </mx:ViewStack> … </mx:TabNavigator> CloudPhotosModelLocator.getInstance().viewState </mx:VBox> determines whether we are viewing albums or an album Slide 37 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Building Flex Applications The Cairngorm framework Cloud Photos Example Application Scenario: di l i S i displaying albums lb Scenario: creating a new album Scenario: copying photos between albums Pushing data to the client Building and testing Flex applications Slide 38 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Display Albums Flow py Slide 39 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • View dispatches event p <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:Vbox … creationComplete=quot;displayAlbums()quot;> <mx:Script> <![CDATA[ private function displayAlbums():void { var event : DisplayAlbumsEvent = new DisplayAlbumsEvent(); event.dispatch(); } private function createAlbum() : void { PopUpManager.centerPopUp(PopUpManager.createPopUp(this, CreateAlbumPopup, true)); } ]]> </mx:Script> <mx:HBox width=quot;100%quot; height=quot;10%quot;> <mx:Button label=quot;Create Newquot; click=quot;createAlbum()quot;/> </mx:HBox> <mx:Tile id=quot;albumGridquot; width=quot;100%quot; height=quot;90%quot;> <mx:Repeater id quot; quot; d t P R t id=quot;rpquot; dataProvider=quot;{CloudPhotosModelLocator.getInstance().albums}quot;> id quot;{Cl dPh t M d lL t tI t () lb }quot; <components:AlbumThumbnail album=quot;{rp.currentItem}quot;/> </mx:Repeater> </mx:Tile> </mx:VBox> Slide 40 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Controller executes command package net.chrisrichardson.cloudphotos.ui.control { import com.adobe.cairngorm.control.FrontController; import net.chrisrichardson.cloudphotos.ui.command.*; import net.chrisrichardson.cloudphotos.ui.event.*; public class Controller extends FrontController { public function Controller() { initializeCommands(); } public function initializeCommands() : void { addCommand( CreateAlbumEvent.CREATE_ALBUM, CreateAlbumCommand); addCommand( DisplayAlbumsEvent.DISPLAY_ALBUMS, DisplayAlbumsCommand); addCommand( DisplayAlbumEvent.DISPLAY_ALBUM, DisplayAlbumCommand); addCommand( CopyPhotoToAlbumEvent.COPY_PHOTO, CopyPhotoToAlbumCommand); } } } Slide 41 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Command calls delegate g public class DisplayAlbumsCommand implements ICommand, IResponder { public function execute( event:CairngormEvent ):void { var delegate : DisplayAlbumsDelegate = new DisplayAlbumsDelegate(this); delegate.displayAlbums(); } public function result( event : Object ):void { var albums : XMLList = event.result.album; var model : Cl dPh t M d lL d l CloudPhotosModelLocator = Cl dPh t M d lL t CloudPhotosModelLocator.getInstance(); t tI t () model.albums = albums } p public function fault( event : Object ) : void { ( j // handle error } } Slide 42 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Delegate invokes service g public class DisplayAlbumsDelegate { private var responder : IResponder; private var service : HTTPService; public function DisplayAlbumsDelegate( responder : IResponder ) { this.service = ServiceLocator.getInstance().getHTTPService( quot;displayAlbumsquot; ); displayAlbums this.responder = responder; } public function displayAlbums() : void { var call : Obj t = service.send() ll Object i d() call.addResponder(responder); } } Slide 43 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Service definition <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <cairngorm:ServiceLocator xmlns:mx=quot;http://www.adobe.com/2006/mxmlquot; xmlns:cairngorm http://www.adobe.com/2006/cairngorm > xmlns:cairngorm=quot;http://www adobe com/2006/cairngormquot;> <mx:HTTPService id=quot;displayAlbumsquot; url=quot;http://.../api/albumquot; resultFormat=quot;e4xquot; ltF t quot;4quot; useProxy=quot;falsequot; method=quot;GETquot; > </mx:HTTPService> / </cairngorm:ServiceLocator> Slide 44 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Command updates model p public class DisplayAlbumsCommand implements ICommand, IResponder { public function execute( event:CairngormEvent ):void { var delegate : DisplayAlbumsDelegate = new DisplayAlbumsDelegate(this); delegate.displayAlbums(); } public function result( event : Object ):void { var albums : XMLList = event.result.album; var model : Cl dPh t M d lL d l CloudPhotosModelLocator = Cl dPh t M d lL t CloudPhotosModelLocator.getInstance(); t tI t () model.albums = albums } p public function fault( event : Object ) : void { ( j <albums> // handle error <album>…</album> } <album>…</album> } … </albums> Slide 45 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • View displays model py <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:Vbox … creationComplete=quot;displayAlbums()quot;> <mx:Script> <![CDATA[ private function displayAlbums():void { var event : DisplayAlbumsEvent = new DisplayAlbumsEvent(); event.dispatch(); } private function createAlbum() : void { PopUpManager.centerPopUp(PopUpManager.createPopUp(this, CreateAlbumPopup, true)); } ]]> </mx:Script> <mx:HBox width=quot;100%quot; height=quot;10%quot;> <mx:Button label=quot;Create Newquot; click=quot;createAlbum()quot;/> </mx:HBox> <mx:Tile id=quot;albumGridquot; width=quot;100%quot; height=quot;90%quot;> <mx:Repeater id quot; quot; d t P < R t id=quot;rpquot; dataProvider=quot;{CloudPhotosModelLocator.getInstance().albums}quot;> id quot;{Cl dPh t M d lL t tI t () lb }quot;> <components:AlbumThumbnail album=quot;{rp.currentItem}quot;/> </mx:Repeater> </mx:Tile> </mx:VBox> Slide 46 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • View component p <album> <mx:GridItem > <id>e778769a-8432-46ca-b0f1-5c92f33a8710</id> <mx:Script> <title>Pictures of kids</title> / <thumbnail>https://s3.amazonaws.com/…</thumbnail> <![CDATA[ </album> [Bindable] public var album : XML; p public function viewAlbum() : void { () new DisplayAlbumEvent(album.id).dispatch(); CloudPhotosModelLocator.getInstance().viewState = quot;displayAlbumquot;; } ]]> </mx:Script> / S it <mx:Box width=quot;100quot; height=quot;125quot;> <mx:Image id=quot;imgquot; click=quot;viewAlbum()quot; source=quot;{album.thumbnail}quot; /> </mx:Box> <mx:Text width=quot;100quot; height= 25 text= {album.title} /> width= 100 height=quot;25quot; text=quot;{album title}quot;/> </mx:VBox> </mx:GridItem> Slide 47 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Building Flex Applications The Cairngorm framework Cloud Photos Example Application Scenario: displaying albums S i di l i lb Scenario: creating a new album Scenario: copying photos between albums Pushing data to the client Building and testing Flex applications Slide 48 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Points of interest Uses a popup window Uploads files Command publishes a Cairngorm p g event to notify view that upload is complete Slide 49 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Displaying a popup window p y g ppp <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:Vbox … creationComplete=quot;displayAlbums()quot;> <mx:Script> <![CDATA[ private function displayAlbums():void { var event : DisplayAlbumsEvent = new DisplayAlbumsEvent(); event.dispatch(); } private function createAlbum() : void { PopUpManager.centerPopUp(PopUpManager.createPopUp(this, CreateAlbumPopup, true)); } ]]> </mx:Script> <mx:HBox width=quot;100%quot; height=quot;10%quot;> <mx:Button label=quot;Create Newquot; click=quot;createAlbum()quot;/> </mx:HBox> <mx:Tile id=quot;albumGridquot; width=quot;100%quot; height=quot;90%quot;> <mx:Repeater id quot; quot; d t P R t id=quot;rpquot; dataProvider=quot;{CloudPhotosModelLocator.getInstance().albums}quot;> id quot;{Cl dPh t M d lL t tI t () lb }quot; <components:AlbumThumbnail album=quot;{rp.currentItem}quot;/> </mx:Repeater> </mx:Tile> </mx:VBox> Slide 50 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • CreateAlbum popup window ppp <mx:TitleWindow> <mx:Form width=quot;100%quot;> <mx:FormItem label=quot;Album Titlequot;> <mx:TextInput id quot; lb T I id=quot;albumTitlequot; change=quot;enableDisableCreateButton()quot;/> Ti l quot; h quot; bl Di bl C B ()quot;/ </mx:FormItem> <mx:FormItem label=quot;Album Datequot;> <mx:DateChooser id=quot;datequot; change=quot;enableDisableCreateButton()quot;/> </mx:FormItem> <mx:FormItem label=quot;Notesquot;> <mx:TextArea id=quot;notesquot;/> </mx:FormItem> <mx:FormItem label=quot;quot;> <mx:Button label=quot;Select Images...quot; click=quot;selectFiles()quot;/> </mx:FormItem> <mx:FormItem label=quot;quot;> <Form> provides <mx:Label text=quot;{photosToUpload.length} imagesquot;/> </mx:FormItem> / an easy way to <mx:FormItem label=quot;Selected Filesquot; width=quot;100%quot;> layout the form <mx:DataGrid dataProvider=quot;{photosToUpload}quot; width=quot;100%quot;> <mx:columns> fields <mx:DataGridColumn headerText=quot;Namequot; dataField=quot;namequot;/> <mx:DataGridColumn headerText=quot;Datequot; dataField=quot;creationDatequot;/> </mx:columns> </mx:DataGrid> </mx:FormItem> </mx:Form> <mx:ControlBar> <mx:Button id=quot;createButtonquot; label=quot;Create Album click= createAlbum(event) enabled= false /> id= createButton label= Create Albumquot; click=quot;createAlbum(event)quot; enabled=quot;falsequot;/> <mx:Button label=quot;Cancelquot; click=quot;cancelCreateAlbum()quot;/> </mx:ControlBar> </mx:TitleWindow> Slide 51 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Selecting files to upload g p private var myFileReference:FileReferenceList = new FileReferenceList(); [Bindable] private var photosToUpload : Array; private function selectFiles():void { myFileReference.addEventListener(quot;selectquot;, selectHandler); myFileReference.browse(); } private function selectHandler(event:Event):void { photosToUpload = myFileReference.fileList.slice(); enableDisableCreateButton(); } private function enableDisableCreateButton() : void { createButton.enabled = titl V lid t t B tt bl d titleValidator.validate().type ! quot;invalidquot; lid t () t != quot;i lidquot; && dateValidator.validate().type != quot;invalidquot; && filesSupplied() } p private function filesSupplied() : Boolean { pp () return photosToUpload != null && photosToUpload.length > 0 } Slide 52 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Displaying progress and dispatching Cairngorm event p g g <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:TitleWindow> <mx:Script> <![CDATA[ private var uploadProgressWindow : PhotoUploadProgressWindow; private function createAlbum(event:Event) : void { uploadProgressWindow = PhotoUploadProgressWindow(PopUpManager.createPopUp(this, PhotoUploadProgressWindow, true)); PopUpManager.centerPopUp(uploadProgressWindow); var ev : C CreateAlbumEvent = new C t Alb E t CreateAlbumEvent() t Alb E t() ev.album = new Album(albumTitle.text, notes.text, date.selectedDate) ev.photosToUpload = photosToUpload ev.dispatch() } </mx:Script> </mx:TitleWindow> Slide 53 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Uploading a file p g public class CreateAlbumDelegate { var photo : FileReference; public function notePhotoAdded(photoId : String) : void { … photoIndex = photoIndex + 1; var ur : URLRequest = new URLRequest(); ur.url = Env.getRootUrl() + quot;api/album/quot; + album.id + quot;/photo/quot; + p photoId; ; this.photo.addEventListener(Event.COMPLETE, completeHandler); this.photo.upload(ur, quot;photoquot;); } public function completeHandler(event: Event) : void { … } } Slide 54 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • CreateAlbumCommand package net.chrisrichardson.cloudphotos.ui.command { public class CreateAlbumCommand implements ICommand, IResponder { public function CreateAlbumCommand() {} public function execute( event:CairngormEvent ):void { var delegate : CreateAlbumDelegate = new CreateAlbumDelegate(this); var album : Album = (event as CreateAlbumEvent).album var photosToUpload : Array = (event as CreateAlbumEvent).photosToUpload delegate.createAlbum(album, photosToUpload); } Long running public function result( event : Object ):void { new AlbumCreatedEvent((event as Album).id).dispatch(); - publishes a } Cairngorm public function fault( event : Object ) : void { … } event when finished } Slide 55 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • CreateAlbumPopup pp <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> View subscribes to <mx:TitleWindow creationComplete=quot;creationComplete()quot;> AlbumCreatedEvent – <mx:Script> easier than binding to <![CDATA[ model private function creationComplete() : void { CairngormEventDispatcher.getInstance() .addEventListener(quot;albumCreatedquot;, albumCreated); } public function albumCreated(event : CairngormEvent) : void { PopUpManager.removePopUp(uploadProgressWindow); CloudPhotosModelLocator.getInstance().viewState = quot;displayAlbumquot;; new DisplayAlbumsEvent().dispatch(); new DisplayAlbumEvent((event as AlbumCreatedEvent).albumId).dispatch(); PopUpManager.removePopUp(this); } } ]]> </mx:Script> / p </mx:TitleWindow> Slide 56 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex O i f Fl Building Flex Applications The Cairngorm framework Cloud Photos Example Application Scenario: displaying albums pyg Scenario: creating a new album Scenario: copying photos between albums Pushing data to the client Building and testing Flex applications Slide 57 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Points of interest Uses drag and drop to copy a photo to an album Slide 58 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Initiating a drag g g <mx:VBox width=quot;100quot; height=quot;175quot;> <mx:Script> PhotoThumbnail.mxml <![CDATA[ [Bindable] var photo : XML; private function mouseMoveHandler(event:MouseEvent):void { var dragInitiator:Image=Image(event.currentTarget); var ds:DragSource = new DragSource(); ds.addData(photo.id, 'photoId'); DragManager.doDrag(dragInitiator, ds, event); } … ]]> </mx:Script> <mx:Image id=quot;imgquot; width=quot;100%quot; height=quot;100%quot; mouseMove=quot;mouseMoveHandler(event)quot; source=quot;{photo.thumbnail}quot;/> </mx:VBox> Slide 59 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Handling a drop g p <mx:VBox width=quot;100quot; height=quot;175quot;> <mx:Script> AlbumSummaryThumbnail.mxml y <![CDATA[ [Bindable] [Bi d bl ] public var album : XML ; private function dragEnterHandler(event:DragEvent):void { if (event.dragSource.hasFormat('photoId')) { var dropTarget:Image=Image(event.currentTarget); DragManager.acceptDragDrop(dropTarget); } } private function dragDropHandler(event:DragEvent):void { var photoId : Object = event.dragSource.dataForFormat('photoId'); p j g (p ); new CopyPhotoToAlbumEvent(album.id, String(photoId)).dispatch(); } ]]> </mx:Script> <mx:Box width=quot;100quot; height=quot;125quot; verticalScrollPolicy=quot;offquot; horizontalScrollPolicy=quot;offquot;> <mx:Image dragEnter=quot;dragEnterHandler(event);quot; dragDrop=quot;dragDropHandler(event);quot; source=quot;{album.thumbnail}quot;/> </mx:Box> <mx:Text id=quot;titlequot; width=quot;100quot; height=quot;25quot; text=quot;{album.title}quot;/> </mx:VBox> Slide 60 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Developing Flex Applications pg pp Pushing data to the client Building and testing Flex applications Slide 61 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Why events? y Cloud Photos server asynchronously uploads photos to S3 Client might display photo before it is available ⇒ Notify client when a photo is available Client can reload the image Slide 62 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • BlazeDS Open-source project Connects Flex and AIR clients to Java backend services Client-side Flex components Server-side components, E.g. Servlet RPC services Proxying for remote (web) services Invoke server-side Java object Publish-Subscribe messaging Supports integration with JMS Spring BlazeDS project for simplified development Slide 63 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • BlazeDS messaging components gg p Client Server receives messages from JMS Queue/ Consumer Destination Adapter Topic using Channel Endpoint corresponds to http://localhost:8080/webapp/messagebroker/amfpolling Slide 64 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Channel/Endpoint options / p p HTTP Options: Simple polling with piggyback Long polling – message/connection Streaming – many messages/connection Formats: AMF – efficient binary format AMFX – XML format Slide 65 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Example client-side consumer p <?xml version=quot;1.0quot; encoding=quot;utf-8quot;?> <mx:Canvas creationComplete=quot;creationComplete()quot;> <mx:Script> <![CDATA[ ![CDATA[ public function creationComplete() : void { consumer.subscribe();} private function messageHandler(event:MessageEvent):void { for each (var photoThumbnail : PhotoThumbnail in thumbnailContainer.getChildren()) { photoThumbnail.reloadIfNecessary(event.message.body.toString()); } } Server publishes a JMS event when it has uploaded an image ]]> </mx:Script> to S3. Client subscribes and reloads <mx:Consumer id=quot;consumerquot; destination=quot;message-destinationquot; images if required message=quot;messageHandler(event)quot; …/> <mx:Tile id=quot;thumbnailContainerquot; width=quot;100%quot; height=quot;90%quot;> <mx:Repeater id=quot;rpquot; id rp dataProvider=quot;{CloudPhotosModelLocator.getInstance().currentAlbum.photos.photo}quot;> <components:PhotoThumbnail photo=quot;{rp.currentItem}quot;/> </mx:Repeater> </mx:Tile> </mx:Canvas> Slide 66 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Spring beans for messaging pg gg <amq:topic id=quot;destinationquot; physicalName=quot;org.apache.activemq.spring.Test.spring.embeddedquot;/> <bean id=quot;consumerJmsTemplatequot; class=quot;org.springframework.jms.core.JmsTemplatequot;> <property name=quot;connectionFactoryquot; ref=quot;jmsFactoryquot;/> </bean> <bean id=quot;producerquot; class=quot;net.chrisrichardson.kickstart.backend.services.SpringProducerquot;> <property name=quot;templatequot; ref=quot;myJmsTemplatequot;/> <property name=quot;destinationquot; ref=quot;destinationquot; /> </bean> public class SpringProducer { private JmsTemplate template; private Destination destination; public void send(String message) { template.convertAndSend(destination, message); } } Slide 67 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • BlazeDS MessageBrokerServlet g <servlet> <servlet-name>MessageBrokerServlet</servlet-name> <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class> l l fl i kS l / l l <init-param> <param-name>services.configuration.file</param-name> <param-value>/WEB-INF/flex/services-config.xml</param-value> </init-param> /i i <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> lt i <servlet-name>MessageBrokerServlet</servlet-name> <url-pattern>/messagebroker/*</url-pattern> </servlet-mapping> Slide 68 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • services-config.xml g Shared by client and server Messaging Service One or more adapters One or more destinations One or more channels Destinations Referenced by client Source/sink of messages g Has an adapter, e.g. JMSAdapter Channels Used by a Flex component to communicate with the BlazeDS server Bl DS Communicate with server-side endpoints Endpoints URLs that URL th t are mapped t M d to MessageBroker servlet Bk lt Slide 69 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Channels and endpoints p <services-config> <channel-definition id quot; h l d fi i i id=quot;my-polling-amfquot; lli fquot; class=quot;mx.messaging.channels.AMFChannelquot;> <endpoint url=quot;http://localhost:8080/webapp/messagebroker/amfpollingquot; class=quot;flex.messaging.endpoints.AMFEndpointquot;/> l quot;fl i di AMFE d i quot;/ <properties> <polling-enabled>true</polling-enabled> <polling-interval-seconds>4</polling-interval-seconds> </properties> / ti </channel-definition> </services-config> / i fi Slide 70 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Messaging service gg <service id=quot;message-servicequot; class=quot;flex.messaging.services.MessageServicequot;> <adapters> <adapter-definition id=quot;actionscriptquot; class=quot;flex.messaging.services.messaging.adapters.ActionScriptAdapterquot; default=quot;truequot; /> <adapter-definition id=quot;jmsquot; class=quot;flex.messaging.services.messaging.adapters.JMSAdapterquot; /> </adapters> <default-channels> <channel ref=quot;my-polling-amfquot; /> ref my polling amf </default-channels> <destination id=quot;message-destinationquot;> <properties> <jms> j <destination-jndi-name>topicjndiname</destination-jndi-name> … </jms> </properties> /p p <adapter ref=quot;jmsquot; /> </destination> </service> Slide 71 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Agenda g The joy and pain of UI development Overview of Flex Developing Flex Applications pg pp Pushing data to the client Building and testing Flex applications Slide 72 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Using Flex Mojos g j Open source project Maven Mojos for building and testing flex applications http://code.google.com/p/flex-mojos/ Badly documented but they work y y Slide 73 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Building a Flex client p j g project <project> … <pluginRepositories> <pluginRepository> l iR i <id>pia-repository</id> <url>http://repository.sonatype.org/content/groups/flexgroup/</url> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>cairngorm</groupId> “mvn install” builds SWF <artifactId>cairngorm</artifactId> <version>2_2_1</version> <type>swc</type> </dependency> /p y </dependencies> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <groupId>info.flex mojos</groupId> <groupId>info.flex-mojos</groupId> <artifactId>flex-compiler-mojo</artifactId> </plugin> …. </plugins> </build> </project> Slide 74 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Adding the SWF to y g your WAR <project> <packaging>war</packaging> … <dependencies> d d i <dependency> <groupId>net.chrisrichardson</groupId> <artifactId>kickstart-webapp</artifactId> Input = SWF + Existing WAR file <version>1.0-SNAPSHOT</version> <type>war</type> Output = new WAR file containing SWF </dependency> <dependency> <groupId>net.chrisrichardson</groupId> <artifactId>photoflexui</artifactId> <version>1.0-SNAPSHOT</version> <type>swf</type> yp / yp </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.sonatype.flexmojos</groupId> <artifactId>flexmojos-maven-plugin</artifactId> <executions> <execution> <goals><goal>copy-flex-resources</goal></goals> </execution> </executions> </plugin> … Slide 75 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Automated testing g $$: HP QTP, RIATest FlexUnit Focused on unit tests Record UI tests with FlexMonkey Encountered a licensing error during compilation! Fluint Supposedly better than FlexUnit Not supported by Flex Mojos Slide 76 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Selenium-Flex Looks the most familiar/promising selenium.flexClick() selenium flexClick() selenium.flexWaitForElement() … Selenium extensions invoke ActionScript functions via External interface Include SeleniumFlexAPI.swc in your application External interface seems not to work in IE6 Tricky to get working in FireFox y g g Launching SeleniumServer via Java API didn’t work – extensions not loaded maven-selenium-plugin worked pg Slide 77 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Example Selenium-Flex test p public class WebIntegrationTest extends TestCase { @Override protected void setUp() throws Exception { selenium = new DefaultSeleniumFlex(quot;localhostquot;, 4444, browserType, quot;http://localhost:8080quot;); selenium.start(); } public void test() throws Exception { selenium.open(quot;http://localhost:8080/webapp/photoflexui.htmlquot;); waitForFlexApplicationToLoad(quot;createAlbumButtonquot;); selenium.flexWaitForElement(quot;albumThumbnail[1]quot;); selenium.flexClick(quot;albumThumbnail[1]quot;); selenium.flexWaitForElementVisible(quot;backToAlbumsButtonquot;); selenium.flexClick( backToAlbumsButtons ); selenium flexClick(quot;backToAlbumsButtonsquot;); selenium.flexWaitForElementVisible(quot;createAlbumButtonquot;); selenium.flexClick(quot;createAlbumButtonquot;); } } Slide 78 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • My next steps y p Write some automated tests Investigate Spring ActionScript Dependency injection framework Promotes loose coupling “Inject stubs for services” Investigate ExternalInterface ActionScript JavaScript Slide 79 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Summary Flex HTML/Javascript/CSS p Better paradigm (Open-source) testing tools are more Easier to develop mature Slide 80 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Final thoughts g Download or contribute to Cloud Tools today : y www.cloudtools.org Checkout Cloud Foundry: www.cloudfoundry.com www cloudfoundry com Buy my book ☺ Send email: chris@chrisrichardson.net Visit my website: www.chrisrichardson.net Talk to me about consulting and training Phone: 510 904 9832 Slide 81 Copyright (c) 2009 Chris Richardson. All rights reserved.
  • Resources http://www.actionscript.org/ http://www.adobe.com/devnet/actionscript/articl es/actionscript3_overview.html http://www.adobe.com/devnet/flex/ http://www.adobe.com/devnet/flash/ http://www.infoq.com/articles/java-flex-blazeds Intro link: http://www.adobe.com/devnet/flex/articles/intro ducing_cairngorm.html http://dispatchevent.org/roger/as3-e4x- rundown/ / http://myflex.org/presentations/ComparingFlexFr ameworks.pdf http://code.google.com/p/flexlib/ p // gg /p/ / Slide 82 Copyright (c) 2009 Chris Richardson. All rights reserved.