RIAs Done Right: Grails, Flex, and EXT GWT

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    4 Favorites

    RIAs Done Right: Grails, Flex, and EXT GWT - Presentation Transcript

    1. RIAs Done Right Michael Galpin, eBay @michaelg
    2. Traditional Web Applications
    3. Traditional Web Applications Browser
    4. Traditional Web Applications Request Browser
    5. Traditional Web Applications Request Ser ver Browser
    6. Traditional Web Applications Request HTML Ser ver Browser
    7. Traditional Web Applications Request HTML Ser ver Browser
    8. Welcome to 2009
    9. Welcome to 2009 Browser
    10. Welcome to 2009 Request Browser
    11. Welcome to 2009 Request Web Ser ver Browser
    12. Welcome to 2009 Request Web Ser ver App Browser
    13. Welcome to 2009 Request Web Ser ver App Browser
    14. Welcome to 2009 Request Web Ser ver App Browser
    15. Welcome to 2009 Request Web Ser ver App Request Browser
    16. Welcome to 2009 Request Web Ser ver App Request Browser Data App Server
    17. Why?
    18. Architecture
    19. Architecture client server 1998 pres app “Hello World”
    20. Architecture client server 1998 pres app “Hello World” client server 2003 pres app Ajax
    21. Architecture client server 1998 pres app “Hello World” client server 2003 pres app Ajax client ser ver 2009 pres app RIA
    22. Performance (seriously)
    23. $$$$$$$$$$$$$$$ $$$$$$$$
    24. $$$$$$$$$$$$$$$ $$$$$$$$ Less (Ser ver)Processing Less Ser vers More Money
    25. $$$$$$$$$$$$$$$ $$$$$$$$ Less (Ser ver)Processing More (Client) Processing Less Ser vers More Cores More Money Free! (Thanks Users)
    26. $$$$$$$$$$$$$$$ $$$$$$$$ Less (Ser ver)Processing More (Client) Processing Less Ser vers More Cores More Money Free! (Thanks Users) Less Bandwidth More Money
    27. Mobility
    28. Mobility a.app a.com
    29. Mobility a.app a.app a.com b.com
    30. Mobility a.app a.app a.app a.com b.com facebook.com
    31. Mobility a.app a.app a.app a.com b.com facebook.com a.app a.air
    32. But What About Ajax?
    33. Ajax?
    34. Ajax? Browser
    35. Ajax? Request Browser
    36. Ajax? Request Browser App Server
    37. Ajax? Request Browser App Server
    38. Ajax? Request HTML+JS Browser App Server
    39. Ajax? Request HTML+JS Browser App Server
    40. Ajax? Request HTML+JS XHR Browser App Server
    41. Ajax? Request HTML+JS XHR Browser ??? App Server
    42. Ajax? Request HTML+JS XHR Browser HTML? App Server
    43. Ajax? Request HTML+JS XHR Browser Data? App Server
    44. Ajax? Request HTML+JS XHR Browser Data? App Server
    45. How?
    46. Step 1. Get Serious About SOA
    47. Step 1. Get Serious About SOA
    48. Step 1. Get Serious About SOA X
    49. Step 1. Get Serious About SOA X •REpresentational •State •Transfer •?
    50. Step 2. Get Tools JAX-RS (JSR-311) s ey Jer J Apa che RESTEasy CXF
    51. Domain Model class Story { String link String title String description String tags String category int votesFor int votesAgainst }
    52. Services class SearchService { boolean transactional = false def list() { Story.list() } def listCategory(catName){ Story.findAllWhere(category:catName) } def searchTag(tag){ Story.findAllByTagsIlike(\"%\"+tag+\"%\") } }
    53. class StoryService { Services boolean transactional = true def create(story) { story.votesFor = 0 story.votesAgainst = 0 if(!story.save(flush:true) ) { story.errors.each { log.error(it) } } story } def voteFor(storyId){ def story = Story.get(storyId) story.votesFor += 1 if(!story.save(flush:true) ) { story.errors.each { log.error(it) } } story } def voteAgainst(storyId){ // .... } }
    54. class ApiController { Controllers // injected services def searchService def storyService def search = { def results= null def tagResults = null if (params.tag){ tagResults = searchService.searchTag(params.tag) } def catResults = null if (params.category){ catResults = searchService.listCategory(params.category) } if (params.tag && params.category){ def tagMap = [:] tagResults.each{ story -> tagMap[story.id] = story } results = catResults.findAll { tagMap[it.id] != null} } else { if (params.category){ results = catResults } else { results = tagResults } } render results as JSON } def digg = { def story = storyService.voteFor(params.id) render story as XML } }
    55. Step 3
    56. Step 3a. Just Pick One
    57. GWT in Action public class DiggApp implements EntryPoint { private HorizontalPanel createSearchForm() { HorizontalPanel panel = new HorizontalPanel(); panel.setTitle(\"Search for Stories\"); Label tagLabel = new Label(\"Tag:\"); final TextBox tagBox = new TextBox(); panel.add(tagLabel); panel.add(tagBox); Label catLabel = new Label(\"Category:\"); final ListBox catBox = new ListBox(); catBox.addItem(\"\"); for (String[] category : CATEGORIES){ catBox.addItem(category[0],category[1]); } panel.add(catLabel); panel.add(catBox); Button searchBtn = new Button(\"Search\"); searchBtn.addClickListener(new ClickListener(){ public void onClick(Widget sender) { search(tagBox.getText(), catBox.getValue(catBox.getSelectedIndex())); } }); panel.add(searchBtn); return panel; } }
    58. Mo’ GWT public class DiggApp implements EntryPoint { private final void search(String tag, String category){ resultsPanel.clear(); Story.search(tag, category, new RequestCallback(){ public void onError(Request request, Throwable exception) { Label label = new Label(\"Sorry there was an error\"); resultsPanel.add(label); } public void onResponseReceived(Request request, Response response) { List<Story> stories = Story.fromJson(response.getText()); //SearchTable grid = new SearchTable(stories); StoryGrid grid = new StoryGrid(stories); resultsPanel.add(grid); } }); } }
    59. public class Story { GWT Models public Story(JSONObject obj){ id = (int) obj.get(\"id\").isNumber().doubleValue(); link = obj.get(\"link\").isString().stringValue(); title = obj.get(\"title\").isString().stringValue(); description = obj.get(\"description\").isString().stringValue(); tags = obj.get(\"tags\").isString().stringValue(); category = obj.get(\"category\").isString().stringValue(); votesFor = (int) obj.get(\"votesFor\").isNumber().doubleValue(); votesAgainst = (int) obj.get(\"votesAgainst\").isNumber().doubleValue(); } public static void search(String tag, String category, RequestCallback callback){ String url = buildRequest(tag, category); RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url); try { builder.sendRequest(null, callback); } catch (RequestException e) { callback.onError(null, e); } } public static List<Story> fromJson(String jsonText){ JSONValue val = JSONParser.parse(jsonText); JSONArray array = val.isArray(); List<Story> stories = new ArrayList<Story>(array.size()); for (int i=0;i<array.size();i++){ Story story = new Story(array.get(i).isObject()); stories.add(story); } return stories; } }
    60. Plain ‘Ol GWT Table public class SearchTable extends FlexTable { private List<Story> stories; public SearchTable(List<Story> stories) { super(); this.stories = stories; this.buildTable(); } private void buildTable(){ this.setBorderWidth(2); this.setText(0, 0, \"story\"); this.setText(0, 1, \"category\"); this.setText(0, 2, \"description\"); if (stories.size() == 0){ showMessage(\"Sorry there were no results\"); } else { for (int i=0;i<stories.size();i++){ Story story = stories.get(i); setWidget(i+1, 0, story.getTitleLink()); setText(i+1, 1, story.getCategory()); setText(i+1, 2, story.getDescription()); } } } private void showMessage(String msg){ setText(1,0, msg); getFlexCellFormatter().setColSpan(1, 0, 3); } }
    61. Pimp my GWT public class StoryGrid extends LayoutContainer { public StoryGrid(List<Story> stories){ this.setLayout(new FlowLayout(10)); this.setSize(750, 300); ListStore<BaseModelData> store = this.buildDataModel(stories); Grid<BaseModelData> grid = new Grid<BaseModelData>(store, createColumnModel()); grid.setBorders(true); add(grid); } private ColumnModel createColumnModel(){ List<ColumnConfig> configs = new ArrayList<ColumnConfig>(); ColumnConfig column = new ColumnConfig(); column.setId(\"titleLink\"); column.setHeader(\"Story\"); column.setWidth(200); configs.add(column); //... return new ColumnModel(configs); } private ListStore<BaseModelData> buildDataModel(List<Story> stories){ ListStore<BaseModelData> data = new ListStore<BaseModelData>(); for (Story story : stories){ BaseModelData model = new BaseModelData(story.properties()); data.add(model); } return data; } }
    62. I Want Your Flex
    63. MmmmXML <ctrl:DiggController xmlns:mx=\"http://www.adobe.com/2006/mxml\" layout=\"vertical\" xmlns:works=\"components.*\" xmlns:ctrl=\"controllers.*\"> <mx:Script> <![CDATA[ import org.developerworks.digg.Story; private function digg():void { this.diggStory(results.selectedItem as Story); } private function bury():void { this.buryStory(results.selectedItem as Story); } ]]> </mx:Script> <ctrl:states> <mx:State name=\"SubmitStory\"> <mx:AddChild relativeTo=\"{buttons}\" position=\"after\"> <works:StoryEditor successHandler=\"{this.submissionHandler}\"/> </mx:AddChild> </mx:State> </ctrl:states> <mx:DataGrid id=\"results\" dataProvider=\"{stories}\" doubleClickEnabled=\"true\" doubleClick=\"openStory(results.selectedItem as Story)\"/> <mx:HBox id=\"buttons\"> <mx:Button label=\"Digg the Story!\" click=\"digg()\"/> <mx:Button label=\"Bury the Story!\" click=\"bury()\"/> <mx:Button label=\"{this.subBtnLabel}\" click=\"toggleSubmitStory()\"/> </mx:HBox> </ctrl:DiggController>
    64. Components <mx:VBox xmlns:mx=\"http://www.adobe.com/2006/mxml\" width=\"100%\" height=\"100%\"> <mx:Script> <![CDATA[ [Bindable] private var story:Story = new Story(); public var successHandler:Function; private function submitStory():void { story.addEventListener(DiggEvent.ON_STORY_SUBMIT_SUCCESS, successHandler); story.addEventListener(DiggEvent.ON_STORY_SUBMIT_FAILURE, errorHandler); story.save(); // reset story = new Story(); } ]]> </mx:Script> <mx:Form> <mx:FormHeading label=\"Submit a New Story\"/> <mx:FormItem label=\"What's the URL?\" required=\"true\"> <mx:TextInput id=\"linkBox\" toolTip=\"Keep it Short and Sweet\" text=\"{story.link}\"/> </mx:FormItem> <mx:FormItem label=\"Give it a Title\" required=\"true\"> <mx:TextInput id=\"titleBox\" text=\"{story.title}\"/> </mx:FormItem> <mx:FormItem label=\"Pick a Category\" required=\"true\"> <mx:ComboBox dataProvider=\"{Story.CATEGORIES}\" id=\"categoryBox\" selectedIndex=\"0\"/> </mx:FormItem> <mx:FormItem label=\"Give a Short Description\"> <mx:TextArea height=\"60\" width=\"320\" id=\"descripBox\" text=\"{story.description}\"/> </mx:FormItem> <mx:FormItem label=\"Tag It\"> <mx:TextInput id=\"tagBox\" text=\"{story.tags}\"/> </mx:FormItem> <mx:Button label=\"Submit It!\" click=\"submitStory()\"/> </mx:Form> <mx:Binding source=\"linkBox.text\" destination=\"story.link\"/> <mx:Binding source=\"titleBox.text\" destination=\"story.title\"/> <mx:Binding source=\"categoryBox.selectedItem.data\" destination=\"story.category\"/> <mx:Binding source=\"descripBox.text\" destination=\"story.description\"/> <mx:Binding source=\"tagBox.text\" destination=\"story.tags\"/>
    65. Flex Models public class Story extends EventDispatcher { public function Story(data:XML=null) { if (data) { id = data.@id; title = data.title; link = data.link; category = data.category; description = data.description; tags = data.tags; votesFor = Number(data.votesFor); votesAgainst = Number(data.votesAgainst); } } public function save():void { var req:URLRequest = new URLRequest(SUBMIT_URL); req.method = URLRequestMethod.POST; var params:URLVariables = new URLVariables(); params.title = title; params.link = link; params.category = category; params.description = description; params.tags = tags; req.data = params; submitStoryLoader = new URLLoader(req); submitStoryLoader.addEventListener(Event.COMPLETE, submitSuccessHandler); submitStoryLoader.addEventListener(IOErrorEvent.IO_ERROR, submitErrorHandler); submitStoryLoader.load(req); }
    66. Now Is The Time Questions Protests Cries for Help Confessions Donations

    + michael.galpinmichael.galpin, 5 months ago

    custom

    2599 views, 4 favs, 2 embeds more stats

    Your users want a more advanced user interface. You more

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 2599
      • 2561 on SlideShare
      • 38 from embeds
    • Comments 0
    • Favorites 4
    • Downloads 100
    Most viewed embeds
    • 36 views on http://fupeg.blogspot.com
    • 2 views on http://kimsiapp:8080

    more

    All embeds
    • 36 views on http://fupeg.blogspot.com
    • 2 views on http://kimsiapp:8080

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories