JavaFX and Scala in the Cloud

Post on 15-Jan-2015

998 views 1 download

Tags:

description

Talk about an end-to-end application leveraging JavaFX, Scala, Java DB, and cloud technologies. Given at the JAX conference in San Francisco.

Transcript of JavaFX and Scala in the Cloud

Stephen Chin | OracleAndrew 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 PlatformImmersive 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 DSLpublic 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 Lines2622 Characters

88 Lines1452 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}

DATABASEBy 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-RelationalMapping)

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

Embedded DB Config

orm.connection.driver= org.apache.derby.jdbc.EmbeddedDriverorm.connection.url=jdbc:derby:conferenceDataorm.connection.username=user1orm.connection.password=user1orm.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

concernso Outperforms many native SDKso GAE compatibleo 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 providerso also supports offline/local testing

@jclouds

Why jclouds?

• Location metadatao Don’t get locked in to a provider’s deployment policy

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

jclouds

• Strong & active communityo ~65 contributors, commercial support

Conference App Demo

Stephen Chin <stephen.chin@oracle.com> | Oracle @steveonjava

Andrew Phillips <andrew@jclouds.org> | jclouds @jclouds

Thank You!