Stephen Chin | Oracle @steveonjava Andrew Phillips | jclouds @jclouds JavaFX and Scala in the Cloud
+
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 2001 2006 • Scala Started • Scala v2.0 2003/2004 2011 • Scala v1.0 • Scala 2.9.2 (latest) • Started in 2001 by Martin Odersky • Compiles to Java bytecodes • Pure object-oriented language • Also a functional programming language
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? (continued) • Scala also supports Type Safe DSLs! – Implicit Conversions – type safe class extension – Operator Overloading – with standard precedence rules – DelayedInit / @specialized – advanced language features
Java vs. Scala DSL public class JavaFXEEDemo extends Application { object ConferenceUI extends JFXApp { val model = ConferenceModel public static void main(String[] args) { stage = new Stage { launch(JavaFXEEDemo.class, args); width = 625 } height = 700 scene = new Scene(new StackPane()) { private SpeakerModel speakerModel = getInstance(); fill = "#fcfcfc" private TextField filter; children = Seq( private ChoiceBox<String> items; new VBox { children = Seq( @Override new ImageView { public void start(Stage primaryStage) { image = new Image(getClass().getResourceAsStream("JavaOneLogo.png")) primaryStage.setTitle("JavaOne Speaker List"); }, speakerModel.load(); new Rectangle { EventHandler<ActionEvent> filterAction = new EventHandler<ActionEvent>() { width = 625 public void handle(ActionEvent event) { height = 50 String field = items.selectionModelProperty().getValue().getSelectedItem(); fill = new LinearGradient( String text = filter.getText(); endX = 0, speakerModel.filter(field, text); stops = Stops(WHITE, "#d0cbc8") } ) }; } primaryStage.setScene(SceneBuilder.create() ) .width(625) }, .height(700) new VBox { .fill(Color.web("#fcfcfc")) padding = Insets(100, 20, 20, 20) .root(StackPaneBuilder.create().children( spacing = 30 // Background image and gradient children = Seq( VBoxBuilder.create().children( new HBox { ImageViewBuilder.create() val filter = new TextField(); 83 Lines 88 Lines .image(new Image(getClass().getResourceAsStream("JavaOneLogo.png"))).build(), val items = new ChoiceBox[ruco.TextField[Speaker]]() { RectangleBuilder.create().width(625).height(50).fill(LinearGradientBuilder.create().endX(0).stops( items = ObservableBuffer(Speaker.firstName, Speaker.lastName, Speaker.jobTitle, Speaker.company) StopBuilder.create().color(Color.WHITE).offset(0).build(), converter = StringConverter.toStringConverter({s:ruco.TextField[Speaker] => s.name}) StopBuilder.create().color(Color.web("#d0cbc8")).offset(1).build() } ).build()).build() alignment = Pos.BASELINE_LEFT ).build(), spacing = 15 // Foreground controls children = Seq( VBoxBuilder.create() items, 2622 Characters 1452 Characters .padding(new Insets(100, 20, 20, 20)) filter, .spacing(30) new Button("Filter") { .children(HBoxBuilder.create() onAction = { e:ActionEvent => .alignment(Pos.BASELINE_LEFT) model.filter(items.selectionModel().getSelectedItem(), filter.text()) .spacing(15) } .children( }, items = new ChoiceBox<String>( new Button("Clear") { FXCollections.observableArrayList(FIRST_NAME, LAST_NAME, JOB_TITLE, COMPANY) onAction = { e:ActionEvent => ), filter.text = "" filter = TextFieldBuilder.create().prefColumnCount(20).onAction(filterAction).build(), model.clear() ButtonBuilder.create().text("Filter").onAction(filterAction).build(), } ButtonBuilder.create().text("Clear").onAction(new EventHandler<ActionEvent>() { }, public void handle(ActionEvent event) { new Button("Reload") { speakerModel.clearFilter(); onAction = { e:ActionEvent => } filter.text = "" }).build(), model.load() ButtonBuilder.create().text("Reload").onAction(new EventHandler<ActionEvent>() { } public void handle(ActionEvent event) { } speakerModel.load(); ) } items.selectionModel().selectFirst() }).build() }, ).build(), new TableView[Speaker](model.filteredSpeakers) { TableViewBuilder.<Speaker>create().items(speakerModel.getFilteredData()).prefHeight(1000).columns( columns = Seq( TableColumnBuilder.<Speaker, String>create() new TableColumn[Speaker, String] { .text(FIRST_NAME) text = "First Name" .cellValueFactory(new PropertyValueFactory<Speaker, String>(FIRST_NAME_FIELD)).build(), converter = {_.firstName()} TableColumnBuilder.<Speaker, String>create() }, .text(LAST_NAME) new TableColumn[Speaker, String] { .cellValueFactory(new PropertyValueFactory<Speaker, String>(LAST_NAME_FIELD)).build(), text = "Last Name" TableColumnBuilder.<Speaker, String>create() converter = {_.lastName()} .text(JOB_TITLE) }, .prefWidth(200) new TableColumn[Speaker, String] { .cellValueFactory(new PropertyValueFactory<Speaker, String>(JOB_TITLE_FIELD)).build(), text = "Job Title" TableColumnBuilder.<Speaker, String>create() converter = {_.jobTitle()} .text(COMPANY) prefWidth = 200 .prefWidth(212) }, .cellValueFactory(new PropertyValueFactory<Speaker, String>(COMPANY_FIELD)).build() new TableColumn[Speaker, String] { ).build() text = "Company" ).build() converter = {_.company()} ).build() prefWidth = 212 ).build() } ); ) items.getSelectionModel().selectFirst(); prefHeight = 1000 primaryStage.show(); } } ) } } ) } onCloseRequest = {_:Any => Platform.exit} } }
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
An OSSM Persistence Store • On-demand • Self-service • Scalable • Measurable • ™ Dave Nielsen, CloudCamp @jclouds
open source simple: feels like java (and clojure)unit testable tested across multiple clouds vibrant community
Portable APIs BlobStore LoadBalancer What do you Compute want? Provider-Specific Hooks Embeddable github jclouds-examples
Anatomy of a BlobStore Project 1.Create context 2.Get BlobStore API 3.Do stuff 4.Close context @jclouds
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() }
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 @jclouds
Conference App Demo
Stephen Chin <stephen.chin@oracle.com> | Oracle @steveonjava Andrew Phillips <andrew@jclouds.org> | jclouds @jclouds Thank You!

JavaFX and Scala in the Cloud

  • 1.
    Stephen Chin |Oracle @steveonjava Andrew Phillips | jclouds @jclouds JavaFX and Scala in the Cloud
  • 2.
  • 3.
    Heaven Photo by AlbertoFernandez Fernandez
  • 6.
    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
  • 7.
    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!
  • 8.
    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
  • 9.
    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
  • 10.
    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
  • 11.
    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
  • 12.
  • 13.
    JavaFX 2.0 Platform ImmersiveApplication 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.
  • 14.
    What is Scala 2001 2006 • Scala Started • Scala v2.0 2003/2004 2011 • Scala v1.0 • Scala 2.9.2 (latest) • Started in 2001 by Martin Odersky • Compiles to Java bytecodes • Pure object-oriented language • Also a functional programming language
  • 15.
    Why Scala? • Sharesmany 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
  • 16.
    Why Scala? (continued) • Scala also supports Type Safe DSLs! – Implicit Conversions – type safe class extension – Operator Overloading – with standard precedence rules – DelayedInit / @specialized – advanced language features
  • 17.
    Java vs. ScalaDSL public class JavaFXEEDemo extends Application { object ConferenceUI extends JFXApp { val model = ConferenceModel public static void main(String[] args) { stage = new Stage { launch(JavaFXEEDemo.class, args); width = 625 } height = 700 scene = new Scene(new StackPane()) { private SpeakerModel speakerModel = getInstance(); fill = "#fcfcfc" private TextField filter; children = Seq( private ChoiceBox<String> items; new VBox { children = Seq( @Override new ImageView { public void start(Stage primaryStage) { image = new Image(getClass().getResourceAsStream("JavaOneLogo.png")) primaryStage.setTitle("JavaOne Speaker List"); }, speakerModel.load(); new Rectangle { EventHandler<ActionEvent> filterAction = new EventHandler<ActionEvent>() { width = 625 public void handle(ActionEvent event) { height = 50 String field = items.selectionModelProperty().getValue().getSelectedItem(); fill = new LinearGradient( String text = filter.getText(); endX = 0, speakerModel.filter(field, text); stops = Stops(WHITE, "#d0cbc8") } ) }; } primaryStage.setScene(SceneBuilder.create() ) .width(625) }, .height(700) new VBox { .fill(Color.web("#fcfcfc")) padding = Insets(100, 20, 20, 20) .root(StackPaneBuilder.create().children( spacing = 30 // Background image and gradient children = Seq( VBoxBuilder.create().children( new HBox { ImageViewBuilder.create() val filter = new TextField(); 83 Lines 88 Lines .image(new Image(getClass().getResourceAsStream("JavaOneLogo.png"))).build(), val items = new ChoiceBox[ruco.TextField[Speaker]]() { RectangleBuilder.create().width(625).height(50).fill(LinearGradientBuilder.create().endX(0).stops( items = ObservableBuffer(Speaker.firstName, Speaker.lastName, Speaker.jobTitle, Speaker.company) StopBuilder.create().color(Color.WHITE).offset(0).build(), converter = StringConverter.toStringConverter({s:ruco.TextField[Speaker] => s.name}) StopBuilder.create().color(Color.web("#d0cbc8")).offset(1).build() } ).build()).build() alignment = Pos.BASELINE_LEFT ).build(), spacing = 15 // Foreground controls children = Seq( VBoxBuilder.create() items, 2622 Characters 1452 Characters .padding(new Insets(100, 20, 20, 20)) filter, .spacing(30) new Button("Filter") { .children(HBoxBuilder.create() onAction = { e:ActionEvent => .alignment(Pos.BASELINE_LEFT) model.filter(items.selectionModel().getSelectedItem(), filter.text()) .spacing(15) } .children( }, items = new ChoiceBox<String>( new Button("Clear") { FXCollections.observableArrayList(FIRST_NAME, LAST_NAME, JOB_TITLE, COMPANY) onAction = { e:ActionEvent => ), filter.text = "" filter = TextFieldBuilder.create().prefColumnCount(20).onAction(filterAction).build(), model.clear() ButtonBuilder.create().text("Filter").onAction(filterAction).build(), } ButtonBuilder.create().text("Clear").onAction(new EventHandler<ActionEvent>() { }, public void handle(ActionEvent event) { new Button("Reload") { speakerModel.clearFilter(); onAction = { e:ActionEvent => } filter.text = "" }).build(), model.load() ButtonBuilder.create().text("Reload").onAction(new EventHandler<ActionEvent>() { } public void handle(ActionEvent event) { } speakerModel.load(); ) } items.selectionModel().selectFirst() }).build() }, ).build(), new TableView[Speaker](model.filteredSpeakers) { TableViewBuilder.<Speaker>create().items(speakerModel.getFilteredData()).prefHeight(1000).columns( columns = Seq( TableColumnBuilder.<Speaker, String>create() new TableColumn[Speaker, String] { .text(FIRST_NAME) text = "First Name" .cellValueFactory(new PropertyValueFactory<Speaker, String>(FIRST_NAME_FIELD)).build(), converter = {_.firstName()} TableColumnBuilder.<Speaker, String>create() }, .text(LAST_NAME) new TableColumn[Speaker, String] { .cellValueFactory(new PropertyValueFactory<Speaker, String>(LAST_NAME_FIELD)).build(), text = "Last Name" TableColumnBuilder.<Speaker, String>create() converter = {_.lastName()} .text(JOB_TITLE) }, .prefWidth(200) new TableColumn[Speaker, String] { .cellValueFactory(new PropertyValueFactory<Speaker, String>(JOB_TITLE_FIELD)).build(), text = "Job Title" TableColumnBuilder.<Speaker, String>create() converter = {_.jobTitle()} .text(COMPANY) prefWidth = 200 .prefWidth(212) }, .cellValueFactory(new PropertyValueFactory<Speaker, String>(COMPANY_FIELD)).build() new TableColumn[Speaker, String] { ).build() text = "Company" ).build() converter = {_.company()} ).build() prefWidth = 212 ).build() } ); ) items.getSelectionModel().selectFirst(); prefHeight = 1000 primaryStage.show(); } } ) } } ) } onCloseRequest = {_:Any => Platform.exit} } }
  • 18.
    ScalaFX Application object ConferenceUIextends JFXApp { val model = ConferenceModel stage = new Stage { width = 625 height = 700 scene = new Scene(new StackPane()) { fill = "#fcfcfc" children = Seq( // create background // create foreground ) } } }
  • 19.
    Loading Images new ImageView{ image = new Image( getClass().getResourceAsStream( "JavaOneLogo.png" ) ) }
  • 20.
    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() } }
  • 21.
    ScalaFX Table Construction newTableView[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 }
  • 22.
    DATABASE By RRZEicons (Ownwork) [CC-BY-SA-3.0 (http://creativecommons.org/licenses/by-sa/3.0)], via Wikimedia Commons
  • 23.
    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!
  • 24.
    Circumflex ORM • Scala-basedORM (Object-Relational Mapping) • SQL-based Query Syntax • DSL for Domain Object Definition • Lazy and Eager Fetch Strategies
  • 25.
    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
  • 26.
    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]
  • 27.
    Query the Database defclear() { 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) }
  • 28.
  • 29.
    An OSSM PersistenceStore • On-demand • Self-service • Scalable • Measurable • ™ Dave Nielsen, CloudCamp @jclouds
  • 30.
    open source simple: feelslike java (and clojure)unit testable tested across multiple clouds vibrant community
  • 31.
    Portable APIs BlobStore LoadBalancer What do you Compute want? Provider-Specific Hooks Embeddable github jclouds-examples
  • 32.
    Anatomy of aBlobStore Project 1.Create context 2.Get BlobStore API 3.Do stuff 4.Close context @jclouds
  • 33.
    jclouds modularity APIs aresoftware focused Providers are offering focused API + location + defaults = Provider
  • 34.
    Cloud Access inScala 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() }
  • 35.
    Why jclouds? • DataPortability 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
  • 36.
    Why jclouds? • OSGicompatible • 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
  • 37.
    Why jclouds? • Locationmetadata 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 @jclouds
  • 38.
  • 39.
    Stephen Chin <stephen.chin@oracle.com>| Oracle @steveonjava Andrew Phillips <andrew@jclouds.org> | jclouds @jclouds Thank You!

Editor's Notes