SlideShare une entreprise Scribd logo
1  sur  75
RIAs Done Right
   Michael Galpin, eBay
       @michaelg
Traditional Web
  Applications
Traditional Web
        Applications




Browser
Traditional Web
        Applications
          Request




Browser
Traditional Web
        Applications
          Request



                    Ser ver
Browser
Traditional Web
        Applications
          Request



            HTML
                    Ser ver
Browser
Traditional Web
        Applications
          Request



            HTML
                    Ser ver
Browser
Welcome to 2009
Welcome to 2009




Browser
Welcome to 2009
          Request




Browser
Welcome to 2009
          Request   Web Ser ver




Browser
Welcome to 2009
          Request   Web Ser ver

            App




Browser
Welcome to 2009
          Request   Web Ser ver

            App




Browser
Welcome to 2009
          Request   Web Ser ver

            App




Browser
Welcome to 2009
          Request   Web Ser ver

            App



          Request


Browser
Welcome to 2009
          Request   Web Ser ver

            App



          Request


Browser      Data
                    App Server
Why?
Architecture
Architecture
client        server          1998
         pres       app   “Hello World”
Architecture
client            server          1998
             pres       app   “Hello World”

 client            server        2003
          pres          app      Ajax
Architecture
client            server           1998
             pres       app    “Hello World”

 client            server         2003
          pres          app       Ajax

    client           ser ver      2009
     pres              app         RIA
Performance
  (seriously)
$$$$$$$$$$$$$$$
    $$$$$$$$
$$$$$$$$$$$$$$$
    $$$$$$$$



Less (Ser ver)Processing
      Less Ser vers
      More Money
$$$$$$$$$$$$$$$
    $$$$$$$$



Less (Ser ver)Processing   More (Client) Processing
      Less Ser vers              More Cores
      More Money            Free! (Thanks Users)
$$$$$$$$$$$$$$$
    $$$$$$$$



Less (Ser ver)Processing                    More (Client) Processing
      Less Ser vers                               More Cores
      More Money                             Free! (Thanks Users)

                           Less Bandwidth
                            More Money
Mobility
Mobility

a.app

a.com
Mobility

a.app     a.app

a.com    b.com
Mobility

a.app     a.app      a.app

a.com    b.com    facebook.com
Mobility

a.app     a.app      a.app

a.com    b.com    facebook.com


          a.app

          a.air
But What About Ajax?
Ajax?
Ajax?




Browser
Ajax?
          Request




Browser
Ajax?
          Request




Browser             App Server
Ajax?
          Request




Browser             App Server
Ajax?
          Request

           HTML+JS




Browser              App Server
Ajax?
          Request

           HTML+JS




Browser              App Server
Ajax?
          Request

           HTML+JS



           XHR


Browser              App Server
Ajax?
          Request

           HTML+JS



           XHR


Browser       ???    App Server
Ajax?
          Request

           HTML+JS



           XHR


Browser     HTML?
                     App Server
Ajax?
          Request

           HTML+JS



           XHR


Browser      Data?
                     App Server
Ajax?
          Request

           HTML+JS



           XHR


Browser      Data?
                     App Server
How?
Step 1. Get Serious
    About SOA
Step 1. Get Serious
    About SOA
Step 1. Get Serious
    About SOA


X
Step 1. Get Serious
    About SOA


X
          •REpresentational
          •State
          •Transfer
          •?
Step 2. Get Tools
JAX-RS (JSR-311)


    s ey
 Jer
                               J

            Apa
               che
 RESTEasy            CXF
Domain Model
class Story {
    String link
    String title
    String description
    String tags
    String category
    int votesFor
    int votesAgainst
}
Services
class SearchService {

    boolean transactional = false

    def list() {
        Story.list()
    }

    def listCategory(catName){
        Story.findAllWhere(category:catName)
    }

    def searchTag(tag){
        Story.findAllByTagsIlike(quot;%quot;+tag+quot;%quot;)
    }
}
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){
        // ....
    }
}
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
    }
}
Step 3
Step 3a. Just Pick One
GWT in Action
public class DiggApp implements EntryPoint {

    private HorizontalPanel createSearchForm() {
        HorizontalPanel panel = new HorizontalPanel();
        panel.setTitle(quot;Search for Storiesquot;);
        Label tagLabel = new Label(quot;Tag:quot;);
        final TextBox tagBox = new TextBox();
        panel.add(tagLabel);
        panel.add(tagBox);
        Label catLabel = new Label(quot;Category:quot;);
        final ListBox catBox = new ListBox();
        catBox.addItem(quot;quot;);
        for (String[] category : CATEGORIES){
            catBox.addItem(category[0],category[1]);
        }
        panel.add(catLabel);
        panel.add(catBox);
        Button searchBtn = new Button(quot;Searchquot;);
        searchBtn.addClickListener(new ClickListener(){
            public void onClick(Widget sender) {
                search(tagBox.getText(), catBox.getValue(catBox.getSelectedIndex()));
            }
        });
        panel.add(searchBtn);
        return panel;
    }
}
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(quot;Sorry there was an errorquot;);
                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);
            }
        });
    }
}
public class Story {
                             GWT Models
    public Story(JSONObject obj){
        id = (int) obj.get(quot;idquot;).isNumber().doubleValue();
        link = obj.get(quot;linkquot;).isString().stringValue();
        title = obj.get(quot;titlequot;).isString().stringValue();
        description = obj.get(quot;descriptionquot;).isString().stringValue();
        tags = obj.get(quot;tagsquot;).isString().stringValue();
        category = obj.get(quot;categoryquot;).isString().stringValue();
        votesFor = (int) obj.get(quot;votesForquot;).isNumber().doubleValue();
        votesAgainst = (int) obj.get(quot;votesAgainstquot;).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;
    }
}
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, quot;storyquot;);
        this.setText(0, 1, quot;categoryquot;);
        this.setText(0, 2, quot;descriptionquot;);
        if (stories.size() == 0){
            showMessage(quot;Sorry there were no resultsquot;);
        } 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);
    }
}
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(quot;titleLinkquot;);
        column.setHeader(quot;Storyquot;);
        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;
    }
}
I Want Your Flex
MmmmXML
<ctrl:DiggController xmlns:mx=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;verticalquot;
    xmlns:works=quot;components.*quot; xmlns:ctrl=quot;controllers.*quot;>
    <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=quot;SubmitStoryquot;>
            <mx:AddChild relativeTo=quot;{buttons}quot; position=quot;afterquot;>
                 <works:StoryEditor successHandler=quot;{this.submissionHandler}quot;/>
            </mx:AddChild>
        </mx:State>
    </ctrl:states>
    <mx:DataGrid id=quot;resultsquot; dataProvider=quot;{stories}quot; doubleClickEnabled=quot;truequot;
        doubleClick=quot;openStory(results.selectedItem as Story)quot;/>
    <mx:HBox id=quot;buttonsquot;>
        <mx:Button label=quot;Digg the Story!quot; click=quot;digg()quot;/>
        <mx:Button label=quot;Bury the Story!quot; click=quot;bury()quot;/>
        <mx:Button label=quot;{this.subBtnLabel}quot; click=quot;toggleSubmitStory()quot;/>
    </mx:HBox>
</ctrl:DiggController>
Components
<mx:VBox xmlns:mx=quot;http://www.adobe.com/2006/mxmlquot; width=quot;100%quot; height=quot;100%quot;>
    <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=quot;Submit a New Storyquot;/>
        <mx:FormItem label=quot;What's the URL?quot; required=quot;truequot;>
            <mx:TextInput id=quot;linkBoxquot; toolTip=quot;Keep it Short and Sweetquot;
                text=quot;{story.link}quot;/>
        </mx:FormItem>
        <mx:FormItem label=quot;Give it a Titlequot; required=quot;truequot;>
            <mx:TextInput id=quot;titleBoxquot; text=quot;{story.title}quot;/>
        </mx:FormItem>
        <mx:FormItem label=quot;Pick a Categoryquot; required=quot;truequot;>
            <mx:ComboBox dataProvider=quot;{Story.CATEGORIES}quot; id=quot;categoryBoxquot; selectedIndex=quot;0quot;/>
        </mx:FormItem>
        <mx:FormItem label=quot;Give a Short Descriptionquot;>
            <mx:TextArea height=quot;60quot; width=quot;320quot; id=quot;descripBoxquot;
                text=quot;{story.description}quot;/>
        </mx:FormItem>
        <mx:FormItem label=quot;Tag Itquot;>
            <mx:TextInput id=quot;tagBoxquot; text=quot;{story.tags}quot;/>
        </mx:FormItem>
        <mx:Button label=quot;Submit It!quot; click=quot;submitStory()quot;/>
    </mx:Form>
    <mx:Binding source=quot;linkBox.textquot; destination=quot;story.linkquot;/>
    <mx:Binding source=quot;titleBox.textquot; destination=quot;story.titlequot;/>
    <mx:Binding source=quot;categoryBox.selectedItem.dataquot; destination=quot;story.categoryquot;/>
    <mx:Binding source=quot;descripBox.textquot; destination=quot;story.descriptionquot;/>
    <mx:Binding source=quot;tagBox.textquot; destination=quot;story.tagsquot;/>
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);
   }
Now Is The Time
Questions
Protests
Cries for Help
Confessions
Donations

Contenu connexe

Tendances

Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateKiev ALT.NET
 
Restful App Engine
Restful App EngineRestful App Engine
Restful App EngineRyan Morlok
 
JSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than TwilightJSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than TwilightDonny Wals
 
Wcf data services
Wcf data servicesWcf data services
Wcf data servicesEyal Vardi
 
The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210Mahmoud Samir Fayed
 
Java script advance-auroskills (2)
Java script advance-auroskills (2)Java script advance-auroskills (2)
Java script advance-auroskills (2)BoneyGawande
 
ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2RORLAB
 
Julio Capote, Twitter
Julio Capote, TwitterJulio Capote, Twitter
Julio Capote, TwitterOntico
 
The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!Donny Wals
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testingVincent Pradeilles
 
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/RailsFinding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/RailsMichael Reinsch
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with JasmineTim Tyrrell
 
Designing a Functional GraphQL Library
Designing a Functional GraphQL LibraryDesigning a Functional GraphQL Library
Designing a Functional GraphQL LibraryPierre Ricadat
 
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark ApplicationsFuture Processing
 
Javascript And J Query
Javascript And J QueryJavascript And J Query
Javascript And J Queryitsarsalan
 
Kotlin Introduction with Android applications
Kotlin Introduction with Android applicationsKotlin Introduction with Android applications
Kotlin Introduction with Android applicationsThao Huynh Quang
 
apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...apidays
 
Sane Sharding with Akka Cluster
Sane Sharding with Akka ClusterSane Sharding with Akka Cluster
Sane Sharding with Akka Clustermiciek
 

Tendances (20)

Micro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicateMicro-ORM Introduction - Don't overcomplicate
Micro-ORM Introduction - Don't overcomplicate
 
Restful App Engine
Restful App EngineRestful App Engine
Restful App Engine
 
JSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than TwilightJSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than Twilight
 
Graphql, REST and Apollo
Graphql, REST and ApolloGraphql, REST and Apollo
Graphql, REST and Apollo
 
Wcf data services
Wcf data servicesWcf data services
Wcf data services
 
The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210The Ring programming language version 1.9 book - Part 54 of 210
The Ring programming language version 1.9 book - Part 54 of 210
 
Java script advance-auroskills (2)
Java script advance-auroskills (2)Java script advance-auroskills (2)
Java script advance-auroskills (2)
 
ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2ActiveRecord Query Interface (2), Season 2
ActiveRecord Query Interface (2), Season 2
 
Julio Capote, Twitter
Julio Capote, TwitterJulio Capote, Twitter
Julio Capote, Twitter
 
The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!The Testing Games: Mocking, yay!
The Testing Games: Mocking, yay!
 
An introduction to property-based testing
An introduction to property-based testingAn introduction to property-based testing
An introduction to property-based testing
 
Firebase ng2 zurich
Firebase ng2 zurichFirebase ng2 zurich
Firebase ng2 zurich
 
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/RailsFinding the right stuff, an intro to Elasticsearch with Ruby/Rails
Finding the right stuff, an intro to Elasticsearch with Ruby/Rails
 
Testing Javascript with Jasmine
Testing Javascript with JasmineTesting Javascript with Jasmine
Testing Javascript with Jasmine
 
Designing a Functional GraphQL Library
Designing a Functional GraphQL LibraryDesigning a Functional GraphQL Library
Designing a Functional GraphQL Library
 
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
[QE 2018] Łukasz Gawron – Testing Batch and Streaming Spark Applications
 
Javascript And J Query
Javascript And J QueryJavascript And J Query
Javascript And J Query
 
Kotlin Introduction with Android applications
Kotlin Introduction with Android applicationsKotlin Introduction with Android applications
Kotlin Introduction with Android applications
 
apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...apidays LIVE Australia - Building distributed systems on the shoulders of gia...
apidays LIVE Australia - Building distributed systems on the shoulders of gia...
 
Sane Sharding with Akka Cluster
Sane Sharding with Akka ClusterSane Sharding with Akka Cluster
Sane Sharding with Akka Cluster
 

En vedette

辛亥革命
辛亥革命辛亥革命
辛亥革命Vintone
 
Camiño Inglés en Vilar Do Colo
Camiño Inglés en Vilar Do ColoCamiño Inglés en Vilar Do Colo
Camiño Inglés en Vilar Do Colobngcabanas
 
Mobile Showcase Moblin2
Mobile Showcase Moblin2Mobile Showcase Moblin2
Mobile Showcase Moblin2Tomas Bennich
 
How To Keep Men Women Happy
How To Keep Men Women HappyHow To Keep Men Women Happy
How To Keep Men Women Happyagek2005
 
Virtual Research Environments
Virtual Research EnvironmentsVirtual Research Environments
Virtual Research EnvironmentsJoss Winn
 
Pointing Your Domain Name To Your Website
Pointing Your Domain Name To Your WebsitePointing Your Domain Name To Your Website
Pointing Your Domain Name To Your Websitepahmah
 
1.2 Estimating With Whole #S And Decimals
1.2 Estimating With Whole #S And Decimals1.2 Estimating With Whole #S And Decimals
1.2 Estimating With Whole #S And DecimalsAmy Langelli
 
zen and the art of SQL optimization
zen and the art of SQL optimizationzen and the art of SQL optimization
zen and the art of SQL optimizationKaren Morton
 
Phoenix Az Dept Of Commerce Rural Renewable Presentations
Phoenix   Az Dept Of Commerce Rural Renewable PresentationsPhoenix   Az Dept Of Commerce Rural Renewable Presentations
Phoenix Az Dept Of Commerce Rural Renewable PresentationsICF_HCD
 
Phoenix Hope VI And Green Building Presentation
Phoenix   Hope VI And Green Building PresentationPhoenix   Hope VI And Green Building Presentation
Phoenix Hope VI And Green Building PresentationICF_HCD
 

En vedette (20)

Unit 2.2 Part 1
Unit 2.2 Part 1Unit 2.2 Part 1
Unit 2.2 Part 1
 
辛亥革命
辛亥革命辛亥革命
辛亥革命
 
Eemn1
Eemn1Eemn1
Eemn1
 
Camiño Inglés en Vilar Do Colo
Camiño Inglés en Vilar Do ColoCamiño Inglés en Vilar Do Colo
Camiño Inglés en Vilar Do Colo
 
Work Contracts
Work ContractsWork Contracts
Work Contracts
 
Mobile Showcase Moblin2
Mobile Showcase Moblin2Mobile Showcase Moblin2
Mobile Showcase Moblin2
 
MeshU Cloud Camp
MeshU Cloud CampMeshU Cloud Camp
MeshU Cloud Camp
 
M02 un07 p02
M02 un07 p02M02 un07 p02
M02 un07 p02
 
Women
WomenWomen
Women
 
How To Keep Men Women Happy
How To Keep Men Women HappyHow To Keep Men Women Happy
How To Keep Men Women Happy
 
Virtual Research Environments
Virtual Research EnvironmentsVirtual Research Environments
Virtual Research Environments
 
M02 un10 p01
M02 un10 p01M02 un10 p01
M02 un10 p01
 
Unit 2.6 Link
Unit 2.6 LinkUnit 2.6 Link
Unit 2.6 Link
 
Pointing Your Domain Name To Your Website
Pointing Your Domain Name To Your WebsitePointing Your Domain Name To Your Website
Pointing Your Domain Name To Your Website
 
1.2 Estimating With Whole #S And Decimals
1.2 Estimating With Whole #S And Decimals1.2 Estimating With Whole #S And Decimals
1.2 Estimating With Whole #S And Decimals
 
Unit 2.6
Unit 2.6Unit 2.6
Unit 2.6
 
zen and the art of SQL optimization
zen and the art of SQL optimizationzen and the art of SQL optimization
zen and the art of SQL optimization
 
Phoenix Az Dept Of Commerce Rural Renewable Presentations
Phoenix   Az Dept Of Commerce Rural Renewable PresentationsPhoenix   Az Dept Of Commerce Rural Renewable Presentations
Phoenix Az Dept Of Commerce Rural Renewable Presentations
 
Phoenix Hope VI And Green Building Presentation
Phoenix   Hope VI And Green Building PresentationPhoenix   Hope VI And Green Building Presentation
Phoenix Hope VI And Green Building Presentation
 
Trinity 020908
Trinity 020908Trinity 020908
Trinity 020908
 

Similaire à RIAs Done Right: Grails, Flex, and EXT GWT

Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineAndy McKay
 
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...BradNeuberg
 
Adopting F# at SBTech
Adopting F# at SBTechAdopting F# at SBTech
Adopting F# at SBTechAntya Dev
 
Ajax tutorial
Ajax tutorialAjax tutorial
Ajax tutorialKat Roque
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Sven Efftinge
 
JavaScript ∩ WebAssembly
JavaScript ∩ WebAssemblyJavaScript ∩ WebAssembly
JavaScript ∩ WebAssemblyTadeu Zagallo
 
Open Source Ajax Solution @OSDC.tw 2009
Open Source Ajax  Solution @OSDC.tw 2009Open Source Ajax  Solution @OSDC.tw 2009
Open Source Ajax Solution @OSDC.tw 2009Robbie Cheng
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme SwiftMovel
 
Google Back To Front: From Gears to App Engine and Beyond
Google Back To Front: From Gears to App Engine and BeyondGoogle Back To Front: From Gears to App Engine and Beyond
Google Back To Front: From Gears to App Engine and Beyonddion
 
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...PHP Conference Argentina
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The HoodWO Community
 
How to make Ajax work for you
How to make Ajax work for youHow to make Ajax work for you
How to make Ajax work for youSimon Willison
 
Post Sharp Talk
Post Sharp TalkPost Sharp Talk
Post Sharp Talkwillmation
 
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...Guillaume Laforge
 
Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...
Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...
Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...Amazon Web Services
 

Similaire à RIAs Done Right: Grails, Flex, and EXT GWT (20)

Cross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App EngineCross Domain Web
Mashups with JQuery and Google App Engine
Cross Domain Web
Mashups with JQuery and Google App Engine
 
huhu
huhuhuhu
huhu
 
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
Beyond Cookies, Persistent Storage For Web Applications Web Directions North ...
 
Adopting F# at SBTech
Adopting F# at SBTechAdopting F# at SBTech
Adopting F# at SBTech
 
Android dev 3
Android dev 3Android dev 3
Android dev 3
 
Ajax tutorial
Ajax tutorialAjax tutorial
Ajax tutorial
 
Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]Getting the most out of Java [Nordic Coding-2010]
Getting the most out of Java [Nordic Coding-2010]
 
JavaScript ∩ WebAssembly
JavaScript ∩ WebAssemblyJavaScript ∩ WebAssembly
JavaScript ∩ WebAssembly
 
Open Source Ajax Solution @OSDC.tw 2009
Open Source Ajax  Solution @OSDC.tw 2009Open Source Ajax  Solution @OSDC.tw 2009
Open Source Ajax Solution @OSDC.tw 2009
 
Rack Middleware
Rack MiddlewareRack Middleware
Rack Middleware
 
Extreme Swift
Extreme SwiftExtreme Swift
Extreme Swift
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
Google Back To Front: From Gears to App Engine and Beyond
Google Back To Front: From Gears to App Engine and BeyondGoogle Back To Front: From Gears to App Engine and Beyond
Google Back To Front: From Gears to App Engine and Beyond
 
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
2013 - Nate Abele: HTTP ALL THE THINGS: Simplificando aplicaciones respetando...
 
Coding Ajax
Coding AjaxCoding Ajax
Coding Ajax
 
Ajax Under The Hood
Ajax Under The HoodAjax Under The Hood
Ajax Under The Hood
 
How to make Ajax work for you
How to make Ajax work for youHow to make Ajax work for you
How to make Ajax work for you
 
Post Sharp Talk
Post Sharp TalkPost Sharp Talk
Post Sharp Talk
 
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
JavaOne 2008 - TS-5793 - Groovy and Grails, changing the landscape of Java EE...
 
Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...
Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...
Simpler by Design: Build a Better GraphQL API for Your Next App by Writing Le...
 

Plus de Michael Galpin

Android lessons you won't learn in school
Android lessons you won't learn in schoolAndroid lessons you won't learn in school
Android lessons you won't learn in schoolMichael Galpin
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesMichael Galpin
 
Scala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump TechnologiesScala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump TechnologiesMichael Galpin
 
That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryMichael Galpin
 
Persistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesPersistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesMichael Galpin
 
Mobile Development 101
Mobile Development 101Mobile Development 101
Mobile Development 101Michael Galpin
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java DevelopersMichael Galpin
 

Plus de Michael Galpin (12)

Android lessons you won't learn in school
Android lessons you won't learn in schoolAndroid lessons you won't learn in school
Android lessons you won't learn in school
 
Design Patterns for Tablets and Smartphones
Design Patterns for Tablets and SmartphonesDesign Patterns for Tablets and Smartphones
Design Patterns for Tablets and Smartphones
 
Android workshop
Android workshopAndroid workshop
Android workshop
 
Scala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump TechnologiesScala on Android: Experiences at Bump Technologies
Scala on Android: Experiences at Bump Technologies
 
That’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your BatteryThat’s My App - Running in Your Background - Draining Your Battery
That’s My App - Running in Your Background - Draining Your Battery
 
Mobile Web 5.0
Mobile Web 5.0Mobile Web 5.0
Mobile Web 5.0
 
Persistent Data Structures And Managed References
Persistent Data Structures And Managed ReferencesPersistent Data Structures And Managed References
Persistent Data Structures And Managed References
 
Scala on Your Phone
Scala on Your PhoneScala on Your Phone
Scala on Your Phone
 
Mobile Development 101
Mobile Development 101Mobile Development 101
Mobile Development 101
 
Eclipse @eBay 2009
Eclipse @eBay 2009Eclipse @eBay 2009
Eclipse @eBay 2009
 
Introduction to Scala for Java Developers
Introduction to Scala for Java DevelopersIntroduction to Scala for Java Developers
Introduction to Scala for Java Developers
 
Eclipse@eBay
Eclipse@eBayEclipse@eBay
Eclipse@eBay
 

Dernier

Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningLars Bell
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxhariprasad279825
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionDilum Bandara
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DaySri Ambati
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek SchlawackFwdays
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfPrecisely
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr BaganFwdays
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLScyllaDB
 

Dernier (20)

Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
DSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine TuningDSPy a system for AI to Write Prompts and Do Fine Tuning
DSPy a system for AI to Write Prompts and Do Fine Tuning
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Artificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptxArtificial intelligence in cctv survelliance.pptx
Artificial intelligence in cctv survelliance.pptx
 
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptxE-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
E-Vehicle_Hacking_by_Parul Sharma_null_owasp.pptx
 
Advanced Computer Architecture – An Introduction
Advanced Computer Architecture – An IntroductionAdvanced Computer Architecture – An Introduction
Advanced Computer Architecture – An Introduction
 
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo DayH2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
H2O.ai CEO/Founder: Sri Ambati Keynote at Wells Fargo Day
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
"Subclassing and Composition – A Pythonic Tour of Trade-Offs", Hynek Schlawack
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdfHyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
Hyperautomation and AI/ML: A Strategy for Digital Transformation Success.pdf
 
Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan"ML in Production",Oleksandr Bagan
"ML in Production",Oleksandr Bagan
 
Developer Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQLDeveloper Data Modeling Mistakes: From Postgres to NoSQL
Developer Data Modeling Mistakes: From Postgres to NoSQL
 

RIAs Done Right: Grails, Flex, and EXT GWT

  • 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
  • 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?
  • 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
  • 23.
  • 24.
  • 25. $$$$$$$$$$$$$$$ $$$$$$$$
  • 26. $$$$$$$$$$$$$$$ $$$$$$$$ Less (Ser ver)Processing Less Ser vers More Money
  • 27. $$$$$$$$$$$$$$$ $$$$$$$$ Less (Ser ver)Processing More (Client) Processing Less Ser vers More Cores More Money Free! (Thanks Users)
  • 28. $$$$$$$$$$$$$$$ $$$$$$$$ Less (Ser ver)Processing More (Client) Processing Less Ser vers More Cores More Money Free! (Thanks Users) Less Bandwidth More Money
  • 31. Mobility a.app a.app a.com b.com
  • 32. Mobility a.app a.app a.app a.com b.com facebook.com
  • 33. Mobility a.app a.app a.app a.com b.com facebook.com a.app a.air
  • 34. But What About Ajax?
  • 35. Ajax?
  • 37. Ajax? Request Browser
  • 38. Ajax? Request Browser App Server
  • 39. Ajax? Request Browser App Server
  • 40. Ajax? Request HTML+JS Browser App Server
  • 41. Ajax? Request HTML+JS Browser App Server
  • 42. Ajax? Request HTML+JS XHR Browser App Server
  • 43. Ajax? Request HTML+JS XHR Browser ??? App Server
  • 44. Ajax? Request HTML+JS XHR Browser HTML? App Server
  • 45. Ajax? Request HTML+JS XHR Browser Data? App Server
  • 46. Ajax? Request HTML+JS XHR Browser Data? App Server
  • 47. How?
  • 48. Step 1. Get Serious About SOA
  • 49. Step 1. Get Serious About SOA
  • 50. Step 1. Get Serious About SOA X
  • 51. Step 1. Get Serious About SOA X •REpresentational •State •Transfer •?
  • 52. Step 2. Get Tools JAX-RS (JSR-311) s ey Jer J Apa che RESTEasy CXF
  • 53.
  • 54.
  • 55. Domain Model class Story { String link String title String description String tags String category int votesFor int votesAgainst }
  • 56. Services class SearchService { boolean transactional = false def list() { Story.list() } def listCategory(catName){ Story.findAllWhere(category:catName) } def searchTag(tag){ Story.findAllByTagsIlike(quot;%quot;+tag+quot;%quot;) } }
  • 57. 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){ // .... } }
  • 58. 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 } }
  • 60. Step 3a. Just Pick One
  • 61.
  • 62. GWT in Action public class DiggApp implements EntryPoint { private HorizontalPanel createSearchForm() { HorizontalPanel panel = new HorizontalPanel(); panel.setTitle(quot;Search for Storiesquot;); Label tagLabel = new Label(quot;Tag:quot;); final TextBox tagBox = new TextBox(); panel.add(tagLabel); panel.add(tagBox); Label catLabel = new Label(quot;Category:quot;); final ListBox catBox = new ListBox(); catBox.addItem(quot;quot;); for (String[] category : CATEGORIES){ catBox.addItem(category[0],category[1]); } panel.add(catLabel); panel.add(catBox); Button searchBtn = new Button(quot;Searchquot;); searchBtn.addClickListener(new ClickListener(){ public void onClick(Widget sender) { search(tagBox.getText(), catBox.getValue(catBox.getSelectedIndex())); } }); panel.add(searchBtn); return panel; } }
  • 63. 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(quot;Sorry there was an errorquot;); 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); } }); } }
  • 64. public class Story { GWT Models public Story(JSONObject obj){ id = (int) obj.get(quot;idquot;).isNumber().doubleValue(); link = obj.get(quot;linkquot;).isString().stringValue(); title = obj.get(quot;titlequot;).isString().stringValue(); description = obj.get(quot;descriptionquot;).isString().stringValue(); tags = obj.get(quot;tagsquot;).isString().stringValue(); category = obj.get(quot;categoryquot;).isString().stringValue(); votesFor = (int) obj.get(quot;votesForquot;).isNumber().doubleValue(); votesAgainst = (int) obj.get(quot;votesAgainstquot;).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; } }
  • 65. 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, quot;storyquot;); this.setText(0, 1, quot;categoryquot;); this.setText(0, 2, quot;descriptionquot;); if (stories.size() == 0){ showMessage(quot;Sorry there were no resultsquot;); } 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); } }
  • 66.
  • 67. 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(quot;titleLinkquot;); column.setHeader(quot;Storyquot;); 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; } }
  • 68.
  • 69.
  • 70. I Want Your Flex
  • 71. MmmmXML <ctrl:DiggController xmlns:mx=quot;http://www.adobe.com/2006/mxmlquot; layout=quot;verticalquot; xmlns:works=quot;components.*quot; xmlns:ctrl=quot;controllers.*quot;> <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=quot;SubmitStoryquot;> <mx:AddChild relativeTo=quot;{buttons}quot; position=quot;afterquot;> <works:StoryEditor successHandler=quot;{this.submissionHandler}quot;/> </mx:AddChild> </mx:State> </ctrl:states> <mx:DataGrid id=quot;resultsquot; dataProvider=quot;{stories}quot; doubleClickEnabled=quot;truequot; doubleClick=quot;openStory(results.selectedItem as Story)quot;/> <mx:HBox id=quot;buttonsquot;> <mx:Button label=quot;Digg the Story!quot; click=quot;digg()quot;/> <mx:Button label=quot;Bury the Story!quot; click=quot;bury()quot;/> <mx:Button label=quot;{this.subBtnLabel}quot; click=quot;toggleSubmitStory()quot;/> </mx:HBox> </ctrl:DiggController>
  • 72. Components <mx:VBox xmlns:mx=quot;http://www.adobe.com/2006/mxmlquot; width=quot;100%quot; height=quot;100%quot;> <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=quot;Submit a New Storyquot;/> <mx:FormItem label=quot;What's the URL?quot; required=quot;truequot;> <mx:TextInput id=quot;linkBoxquot; toolTip=quot;Keep it Short and Sweetquot; text=quot;{story.link}quot;/> </mx:FormItem> <mx:FormItem label=quot;Give it a Titlequot; required=quot;truequot;> <mx:TextInput id=quot;titleBoxquot; text=quot;{story.title}quot;/> </mx:FormItem> <mx:FormItem label=quot;Pick a Categoryquot; required=quot;truequot;> <mx:ComboBox dataProvider=quot;{Story.CATEGORIES}quot; id=quot;categoryBoxquot; selectedIndex=quot;0quot;/> </mx:FormItem> <mx:FormItem label=quot;Give a Short Descriptionquot;> <mx:TextArea height=quot;60quot; width=quot;320quot; id=quot;descripBoxquot; text=quot;{story.description}quot;/> </mx:FormItem> <mx:FormItem label=quot;Tag Itquot;> <mx:TextInput id=quot;tagBoxquot; text=quot;{story.tags}quot;/> </mx:FormItem> <mx:Button label=quot;Submit It!quot; click=quot;submitStory()quot;/> </mx:Form> <mx:Binding source=quot;linkBox.textquot; destination=quot;story.linkquot;/> <mx:Binding source=quot;titleBox.textquot; destination=quot;story.titlequot;/> <mx:Binding source=quot;categoryBox.selectedItem.dataquot; destination=quot;story.categoryquot;/> <mx:Binding source=quot;descripBox.textquot; destination=quot;story.descriptionquot;/> <mx:Binding source=quot;tagBox.textquot; destination=quot;story.tagsquot;/>
  • 73. 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); }
  • 74.
  • 75. Now Is The Time Questions Protests Cries for Help Confessions Donations

Notes de l'éditeur