javafx and scala in the cloud: stephen chin

39
Stephen Chin | Oracle Andrew Phillips | jclouds JavaFX and Scala in the Cloud @steveonjava @jclouds

Upload: jaxconf

Post on 17-Jul-2015

1.079 views

Category:

Technology


2 download

TRANSCRIPT

Stephen Chin | Oracle Andrew Phillips | jclouds

JavaFX and Scala in the Cloud

@steveonjava

@jclouds

+

Heaven

Photo by Alberto Fernandez Fernandez

When This Architecture Makes Sense

•  Data is mostly read-only –  Transactional updates still require a server (but

can be simpler/smaller) •  User's view of data is small to medium

–  Initial DB download of < 10K records is reasonable –  Not total DB size, but subset of data visible to user

Conference App has 3K large records and compresses to only 330KB DB size

Cloud Data Advantages

•  Offline Operation –  Once DB is cached, application works 100% offline

•  Responsive Client Performance –  All DB queries are fast and local

•  High Availability & Scalability –  99.99% Availability –  Easily scales up to 100s of requests per second

But, with proper hashes scales up to millions of requests per second!

Cloud Data Advantages (continued)

•  Insanely cheap server costs!

Number of Users Monthly Cost*

3,000 Free (S3 free tier)

10,000 $0.28

100,000 $3.84

1,000,000 $39.48

* For 330KB of hosted data in Amazon S3

Cloud Data Advantages (continued)

•  Insanely cheap server costs!

Number of Users Monthly Cost*

3,000 Free (S3 free tier)

10,000 $0.28

100,000 $3.84

1,000,000 $39.48

* For 330KB of hosted data in Amazon S3

Cloud Data Advantages (continued)

•  Insanely cheap server costs!

Number of Users Monthly Cost*

3,000 Free (S3 free tier)

10,000 $0.28

100,000 $3.84

1,000,000 $39.48

* For 330KB of hosted data in Amazon S3

Cloud Data Advantages (continued)

•  Insanely cheap server costs!

Number of Users Monthly Cost*

3,000 Free (S3 free tier)

10,000 $0.28

100,000 $3.84

1,000,000 $39.48

* For 330KB of hosted data in Amazon S3

UI

JavaFX 2.0 Platform Immersive Application Experience

Leverage your Java skills with modern JavaFX APIs

•  Cross-platform Animation, Video, Charting

•  Integrate Java, JavaScript, and HTML5 in the same application

•  New graphics stack takes advantage of hardware acceleration for 2D and 3D applications

•  Use your favorite IDE: NetBeans, Eclipse, IntelliJ, etc.

What is Scala

•  Started in 2001 by Martin Odersky •  Compiles to Java bytecodes •  Pure object-oriented language •  Also a functional programming language

2001 •  Scala Started

2003/2004 •  Scala v1.0

2006 •  Scala v2.0

2011 •  Scala 2.9.2 (latest)

Why Scala?

•  Shares many language features with JavaFX Script that make GUI programming easier: – Static Type Checking – Catch your errors

at compile time – Closures – Wrap behavior and pass it by

reference – Declarative – Express the UI by describing

what it should look like

Why Scala?

•  Scala also supports Type Safe DSLs! –  Implicit Conversions – type safe class

extension – Operator Overloading – with standard

precedence rules – DelayedInit / @specialized – advanced

language features

(continued)

Java vs. Scala DSL public  class  JavaFXEEDemo  extends  Application  {            public  static  void  main(String[]  args)  {  

               launch(JavaFXEEDemo.class,  args);          }            

       private  SpeakerModel  speakerModel  =  getInstance();          private  TextField  filter;          private  ChoiceBox<String>  items;  

                 @Override          public  void  start(Stage  primaryStage)  {  

               primaryStage.setTitle("JavaOne  Speaker  List");                  speakerModel.load();                  EventHandler<ActionEvent>  filterAction  =  new  EventHandler<ActionEvent>()  {  

                       public  void  handle(ActionEvent  event)  {                                  String  field  =  items.selectionModelProperty().getValue().getSelectedItem();                                  String  text  =  filter.getText();  

                               speakerModel.filter(field,  text);                          }                  };                  primaryStage.setScene(SceneBuilder.create()  

                       .width(625)                          .height(700)                          .fill(Color.web("#fcfcfc"))  

                       .root(StackPaneBuilder.create().children(                                  //  Background  image  and  gradient                                  VBoxBuilder.create().children(  

                                       ImageViewBuilder.create()                                                  .image(new  Image(getClass().getResourceAsStream("JavaOneLogo.png"))).build(),                                          RectangleBuilder.create().width(625).height(50).fill(LinearGradientBuilder.create().endX(0).stops(  

                                               StopBuilder.create().color(Color.WHITE).offset(0).build(),                                                  StopBuilder.create().color(Color.web("#d0cbc8")).offset(1).build()                                          ).build()).build()  

                               ).build(),                                  //  Foreground  controls                                  VBoxBuilder.create()  

                                       .padding(new  Insets(100,  20,  20,  20))                                          .spacing(30)                                          .children(HBoxBuilder.create()  

                                               .alignment(Pos.BASELINE_LEFT)                                                  .spacing(15)                                                  .children(  

                                                       items  =  new  ChoiceBox<String>(                                                                  FXCollections.observableArrayList(FIRST_NAME,  LAST_NAME,  JOB_TITLE,  COMPANY)                                                          ),  

                                                       filter  =  TextFieldBuilder.create().prefColumnCount(20).onAction(filterAction).build(),                                                          ButtonBuilder.create().text("Filter").onAction(filterAction).build(),                                                          ButtonBuilder.create().text("Clear").onAction(new  EventHandler<ActionEvent>()  {                                                                  public  void  handle(ActionEvent  event)  {  

                                                                       speakerModel.clearFilter();                                                                  }                                                          }).build(),  

                                                       ButtonBuilder.create().text("Reload").onAction(new  EventHandler<ActionEvent>()  {                                                                  public  void  handle(ActionEvent  event)  {                                                                          speakerModel.load();  

                                                               }                                                          }).build()                                                  ).build(),  

                                               TableViewBuilder.<Speaker>create().items(speakerModel.getFilteredData()).prefHeight(1000).columns(                                                          TableColumnBuilder.<Speaker,  String>create()                                                                  .text(FIRST_NAME)  

                                                               .cellValueFactory(new  PropertyValueFactory<Speaker,  String>(FIRST_NAME_FIELD)).build(),                                                          TableColumnBuilder.<Speaker,  String>create()                                                                  .text(LAST_NAME)  

                                                               .cellValueFactory(new  PropertyValueFactory<Speaker,  String>(LAST_NAME_FIELD)).build(),                                                          TableColumnBuilder.<Speaker,  String>create()                                                                  .text(JOB_TITLE)  

                                                               .prefWidth(200)                                                                  .cellValueFactory(new  PropertyValueFactory<Speaker,  String>(JOB_TITLE_FIELD)).build(),                                                          TableColumnBuilder.<Speaker,  String>create()  

                                                               .text(COMPANY)                                                                  .prefWidth(212)                                                                  .cellValueFactory(new  PropertyValueFactory<Speaker,  String>(COMPANY_FIELD)).build()                                                  ).build()  

                                       ).build()                                  ).build()                          ).build()  

               );                  items.getSelectionModel().selectFirst();                  primaryStage.show();  

       }  }  

object  ConferenceUI  extends  JFXApp  {      val  model  =  ConferenceModel      stage  =  new  Stage  {  

       width  =  625          height  =  700          scene  =  new  Scene(new  StackPane())  {  

           fill  =  "#fcfcfc"              children  =  Seq(                  new  VBox  {  

                   children  =  Seq(                          new  ImageView  {                              image  =  new  Image(getClass().getResourceAsStream("JavaOneLogo.png"))  

                       },                          new  Rectangle  {                              width  =  625  

                           height  =  50                              fill  =  new  LinearGradient(                                  endX  =  0,  

                               stops  =  Stops(WHITE,  "#d0cbc8")                              )                          }                      )  

               },                  new  VBox  {                      padding  =  Insets(100,  20,  20,  20)  

                   spacing  =  30                      children  =  Seq(                          new  HBox  {  

                           val  filter  =  new  TextField();                              val  items  =  new  ChoiceBox[ruco.TextField[Speaker]]()  {                                  items  =  ObservableBuffer(Speaker.firstName,  Speaker.lastName,  Speaker.jobTitle,  Speaker.company)  

                               converter  =  StringConverter.toStringConverter({s:ruco.TextField[Speaker]  =>  s.name})                              }                              alignment  =  Pos.BASELINE_LEFT  

                           spacing  =  15                              children  =  Seq(                                  items,  

                               filter,                                  new  Button("Filter")  {                                      onAction  =  {  e:ActionEvent  =>  

                                       model.filter(items.selectionModel().getSelectedItem(),  filter.text())                                      }                                  },  

                               new  Button("Clear")  {                                      onAction  =  {  e:ActionEvent  =>                                          filter.text  =  ""  

                                       model.clear()                                      }                                  },                                  new  Button("Reload")  {  

                                   onAction  =  {  e:ActionEvent  =>                                          filter.text  =  ""                                          model.load()  

                                   }                                  }                              )  

                           items.selectionModel().selectFirst()                          },                          new  TableView[Speaker](model.filteredSpeakers)  {  

                           columns  =  Seq(                                  new  TableColumn[Speaker,  String]  {                                      text  =  "First  Name"  

                                   converter  =  {_.firstName()}                                  },                                  new  TableColumn[Speaker,  String]  {  

                                   text  =  "Last  Name"                                      converter  =  {_.lastName()}                                  },  

                               new  TableColumn[Speaker,  String]  {                                      text  =  "Job  Title"                                      converter  =  {_.jobTitle()}  

                                   prefWidth  =  200                                  },                                  new  TableColumn[Speaker,  String]  {                                      text  =  "Company"  

                                   converter  =  {_.company()}                                      prefWidth  =  212                                  }  

                           )                              prefHeight  =  1000                          }  

                   )                  }              )  

       }          onCloseRequest  =  {_:Any  =>  Platform.exit}      }  

}  

83 Lines 2622 Characters

88 Lines 1452 Characters

ScalaFX Application object  ConferenceUI  extends  JFXApp  {      val  model  =  ConferenceModel      stage  =  new  Stage  {          width  =  625          height  =  700          scene  =  new  Scene(new  StackPane())  {              fill  =  "#fcfcfc"              children  =  Seq(                  //  create  background                  //  create  foreground              )          }      }  }  

Loading Images

new  ImageView  {      image  =  new  Image(          getClass().getResourceAsStream(              "JavaOneLogo.png"          )      )  }  

Creating Buttons new  Button("Filter")  {      onAction  =  {  e:ActionEvent  =>          model.filter(items.selectionModel().getSelectedItem(),                                    filter.text())      }  }    new  Button("Clear")  {      onAction  =  {  e:ActionEvent  =>          filter.text  =  ""          model.clear()      }  }  

ScalaFX Table Construction new  TableView[Speaker](model.filteredSpeakers)  {      columns  =  Seq(          new  TableColumn[Speaker,  String]  {              text  =  "First  Name"              converter  =  {_.firstName()}          },          new  TableColumn[Speaker,  String]  {              text  =  "Last  Name"              converter  =  {_.lastName()}          }          …      )      prefHeight  =  1000  }  

DATABASE By RRZEicons (Own work) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons

Java DB / Apache Derby

•  Embedded Database •  Small Footprint (2.7MB) •  Standards Based (Java, JDBC, SQL) •  Extremely Easy to Configure

– With JDBC 4 / SE 6, just drop in the jar!

Circumflex ORM

•  Scala-based ORM (Object-Relational Mapping)

•  SQL-based Query Syntax •  DSL for Domain Object Definition •  Lazy and Eager Fetch Strategies

Embedded DB Config orm.connection.driver=      org.apache.derby.jdbc.EmbeddedDriver  orm.connection.url=jdbc:derby:conferenceData  orm.connection.username=user1  orm.connection.password=user1  orm.defaultSchema=APP  

Speaker Domain Object class  Speaker  extends  Record[String,  Speaker]  {      val  id  =  "id".VARCHAR(255).NOT_NULL      val  company  =  "company".VARCHAR(255)      val  firstName  =  "firstName".VARCHAR(255)      val  jobTitle  =  "jobTitle".VARCHAR(255)      val  lastName  =  "lastName".VARCHAR(255)        def  PRIMARY_KEY  =  id      def  relation  =  Speaker  }  object  Speaker  extends  Speaker  with  Table[String,  Speaker]    

Query the Database def  clear()  {      val  speakers  =  Speaker.criteria.list()      filteredSpeakers.setAll(speakers)  }    def  filter(field:  TextField[Speaker],                        filterString:  String)  {      val  speakers  =  Speaker.criteria.add(          field  LIKE  "%"  +  filterString  +  "%").list()      filteredSpeakers.setAll(speakers)  }  

CLOUD

@jclouds

An OSSM Persistence Store

• On-demand • Self-service • Scalable • Measurable

•  ™ Dave Nielsen, CloudCamp

open source"

simple: feels like java (and clojure)unit testable"

tested across multiple clouds"

vibrant community"

BlobStore LoadBalancer

Compute What do you want?

Portable APIs

Embeddable Provider-Specific Hooks

github jclouds-examples

@jclouds

Anatomy of a BlobStore Project

1. Create context 2. Get BlobStore API 3. Do stuff 4. Close context

jclouds modularity"

APIs are software focused Providers are offering focused"API + location + defaults = Provider"

Cloud Access in Scala val  context  =  ContextBuilder.newBuilder("aws-­‐s3")      .credentials("identity",  "secret")      .buildView(classOf[BlobStoreContext])    def  loadFromCloud(container:String,                                      resource:String):InputStream  =  {      val  blobStore  =  context.getBlobStore      val  blob  =  blobStore.getBlob(container,  resource)      blob.getPayload.getInput  }    def  close()  {      context.close()  }  

@jclouds

Why jclouds? •  Data Portability

o APIs are not as compatible as they might appear •  Code Portability

o Currently 33 cloud providers •  Enterprise-grade

o Move petabytes of data •  Parallel operations without threading

concerns o Outperforms many native SDKs o GAE compatible o Many tuning options

@jclouds

Why jclouds? •  OSGi compatible •  Clojure binding •  “Invented” many standard SDK features

o e.g. sync/async APIs

•  Tested! o “official” TCK for a number of cloud providers o also supports offline/local testing

@jclouds

Why jclouds? •  Location metadata

o Don’t get locked in to a provider’s deployment policy

•  Does the hard work so you don’t have to o Multi-part in native SDKs vs. .multipart() in

jclouds

•  Strong & active community o ~65 contributors, commercial support

Conference App Demo

Stephen Chin <[email protected]> | Oracle @steveonjava Andrew Phillips <[email protected]> | jclouds @jclouds

Thank You!