html5 communication
DESCRIPTION
With the advent of HTML5, browser applications are becoming more and more independent of server side frameworks. The user interface and its rendering are often decoupled from the server and new ways of communication become handy. This talk aims to cover some techniques how HTML applications can communicate with the server. Besides raw communication techniques the talk presents an approach on how the user interface can be plumped together with an http communication technology of choice by declaring a clean client side architecture.TRANSCRIPT
© Zühlke 2011
marcbaechinger
HTML5 communications
© Zühlke 2011HTML5 communications | marcbaechinger
Classic web application
12. August 2011
HTTP App-Server DBWebbrowse
r
• display markup• request pages• send form data
• serve page assets
• authentication• authorization• access data storage• enterprise integration
• maintain user state• process business logic• process UI logic• render markup
• process CRUD• (stored procedures)
HTTP GET/POST SQL
Slide 2
© Zühlke 2011HTML5 communications | marcbaechinger
Lifecycle of modern HTML application
12. August 2011
GET /index.html HTTP/1.1onload
application use cases state synchronization
onbeforeunload
• (HTTP GET/POST)
• XHR GET/POST• JSONP
• XHR POST• JSON/XML
REST• Websockets• Local storage
DOMContentLoaded
UI setup
onunload
• JSON/XML REST
• Websockets• Local storage• File I/O
• HTTP GET• XHR GET/POST
Slide 3
© Zühlke 2011HTML5 communications | marcbaechinger
Modern HTML5 web application
12. August 2011
HTTP App-Server DBWebbrowse
r
• display markup• request pages• send form data
• access remote data• access local data
• maintain user sstate• process business logic• process UI logic• render markup
• serve page assets
• authentication• authorization• access data storage• enterprise integration
• provide services
• process CRUD
HTTP SQL
Slide 4
© Zühlke 2011
marcbaechingerXMLHttpRequest and friends
12. August 2011Slide 5
© Zühlke 2011HTML5 communications | marcbaechinger
‘native’ JavaScriptvar xhr = new XMLHttpRequest(); xhr.open("GET", url, true);
xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status < 300) { document.querySelector("#main").innerHTML =
encodeHTML(xhr.responseText); } }}; xhr.send(null);
XMLHttpRequest
12. August 2011 Slide 6
© Zühlke 2011HTML5 communications | marcbaechinger
Benefits• Abstracts browser deviations (from standard)• Clean and handy API• Implementation of common techniques (TEXT, XML,
JSON(P), SCRIPT)• Implementations of common Ajax patterns• Support for global error handling and user feedback• Shortcuts and syntax sugar
• all major libraries provide most of these features
Library support for xhr and friends
12. August 2011 Slide 7
© Zühlke 2011HTML5 communications | marcbaechinger
Dasselbe mit jQuery
$("#main").load(url);
XMLHttpRequest
12. August 2011 Slide 8
© Zühlke 2011HTML5 communications | marcbaechinger
• onreadystatechange (XHR Level 1)
• onloadstart
• onprogress
• onabort
• ontimeout
• onerror
• onload (on success only)• onloadend (on success or error)
XHR2 – event handlers
12. August 2011 Slide 9
© Zühlke 2011HTML5 communications | marcbaechinger
• full REST support (GET, POST, PUT, DELETE)• FormData API• Upload control by event handlers of xhr.upload• Download and upload of binary data• Connect with BLOBs und URL.createObjectURL()
XHR2 – new features
12. August 2011 Slide 10
© Zühlke 2011
marcbaechingerData formats and protocols
12. August 2011Slide 11
© Zühlke 2011HTML5 communications | marcbaechinger
• plain text (HTML)• XML• XmlHttpRequest.responseXML
• XML parser, XSLT transformer• data, markup fragments , UI templates
• JSON (JavaScript Object Notation)• JSON.parse(string) , JSON.stringify(obj)
• tightly integrated with JavaScript• ease of use on client side• good support on server side (eg. JAX-RS, Rails, PHP)
Dataformats
12. August 2011 Slide 12
© Zühlke 2011
marcbaechinger
Websockets
© Zühlke 2011HTML5 communications | marcbaechinger
• bi-directional communication channel• send and retrieve messages to and from the server• usually boils down to some kind of publish-subscribe
approach
• usually required for server push only• may be used to keep network latency low (multi-user)
• Desktop: support by browsers not widely available• web-socket-js@github: flash fallback for all desktop
browsers
Websockets
12. August 2011 Slide 14
© Zühlke 2011HTML5 communications | marcbaechinger
var connection = new WebSocket(url);
connection.onopen = function () { $(‘#send-button’).click(function() { // send a message when button clicked
connection.send('Ping'); });};
connection.onmessage = function (e) { // simply log the message retrieved console.log('Server: ' , e.data); };
Accessing an echo service via websocket
12. August 2011 Slide 15
© Zühlke 2011HTML5 communications | marcbaechinger
• node.js• prominent server side JavaScript server (V8)• Open source licence• excellent socket.io library for client and server
• Kaazing WebSocket Gateway• advanced implementation• client library for JavaScript, Java, .Net, Flex, Silverlight• Commercial licence; free developer licences
• Glassfish• EE6 reference implementation driven by Oracle
• Pusher.com
Server side implementations
12. August 2011 Slide 16
© Zühlke 2011HTML5 communications | marcbaechinger
• Multi-User map• node.js (connect/socket.io), Google maps• broadcast map interactions
• Call-agent user support• node.js (connect/socket.io)• custom HTML/JS/CSS• allow a user agent to remote-control a widget/application
• SlideIt• node.js (connect/socket.io), jQuery• remote control presentation via mobile browser
Websocket demos
12. August 2011 Slide 17
© Zühlke 2011
marcbaechingerjQuery and JAX-RS example
Slide 18
© Zühlke 2011HTML5 communications | marcbaechinger
JavaScript und REST
12. August 2011
Webbrowser
JAX-RS
Integration layer
Application server
Service layer
HTTP GET/POST/PUT/DELETE
Slide 19
© Zühlke 2011HTML5 communications | marcbaechinger
$.ajax( { type: "PUT", contentType: "application/json; charset=utf8",
data: JSON.stringify(contact), // request body
url: url, dataType: "json", success: function(data) { // parsed JSON resp. if (callback) { callback(data.contacts); } }});
REST with JSON and jQuery
12. August 2011 Slide 20
© Zühlke 2011HTML5 communications | marcbaechinger
Monitoring REST with JSON
12. August 2011 Slide 21
© Zühlke 2011HTML5 communications | marcbaechinger
$.ajax( { type: "PUT", contentType: "application/json; charset=utf8",
data: JSON.stringify(contact), // request body
url: url, dataType: "json", success: function(data) { // parsed JSON resp. if (callback) { callback(data.contacts); } }});
REST with JSON and jQuery
12. August 2011 Slide 22
© Zühlke 2011
var AddressService = function() { this.getAddresses = function(callback) { $.ajax({type: "GET", …}); }; this.addAddress = function(addr, callback) { $.ajax({type: "POST",…}); }; this.updateAddress = function(addr, callback) { $.ajax({type: "PUT"…}); }; this.deleteAddress = function(addr, callback) { $.ajax({type: "DELETE"…}); };};
Encapsulate remote communicationwith a client side service
HTML5 communications | marcbaechinger 12. August 2011 Slide 23
© Zühlke 2011
var DataService = function() { this.get = function(type, [id,] callback) { $.ajax({type: "GET", …}); }; this.add = function(type, obj, callback) { $.ajax({type: "POST",…}); }; this.update = function(type, obj, callback) { $.ajax({type: "PUT"…}); }; this.delete = function(type, obj, callback) { $.ajax({type: "DELETE"…}); };};
Generic client side service
HTML5 communications | marcbaechinger 12. August 2011 Slide 24
© Zühlke 2011
@Path("/contacts")public class AddressBookService {
@GET @Produces(MediaType.APPLICATION_JSON) public AddressBookResponse getContacts() throws Exception { // fetch data return new AddressBookResponse("ok", ALL_CONTACTS); }
@POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public AddressBookResponse createContact(Contact contact) { // create contact and set id return new AddressBookResponse("ok", contact); }}
REST with JSON and JAX-RS
HTML5 communications | marcbaechinger 12. August 2011 Slide 25
© Zühlke 2011
marcbaechingerServer side architecture
12. August 2011Slide 26
© Zühlke 2011HTML5 communications | marcbaechinger
JAX-RS and EE6
12. August 2011
Webbrowser
Presentation layer
Integration layer
REST framework
Application server
HTTP
HTTP
HTTP
Business layer
Slide 27
© Zühlke 2011HTML5 communications | marcbaechinger
Remoting with Direct Web Remoting (DWR)
12. August 2011
Webbrowser
Presentation layer
Integration layer
DWR
Application server
DWR
HTTP
DWR
HTTP
HTTP
Business layer
DWR service (JS)
Slide 28
© Zühlke 2011HTML5 communications | marcbaechinger
JSF JavaScript API
12. August 2011
Webbrowser
JSF
Integration layer
Application server
Business layer
HTTP GET/POST
Slide 29
© Zühlke 2011HTML5 communications | marcbaechinger
Include JSF JavaScript file into facelets pages<h:outputScript library="javax.faces" name="jsf.js"/>
APIaddOnError(callback)
addOnEvent(callback)
request(source, event, options)
response(request, context)
JSF 2.0 JavaScript library
12. August 2011 Slide 30
© Zühlke 2011HTML5 communications | marcbaechinger
JSF component<h:inputText...> <f:ajax event="blur"
render="nameError«onevent="com.corejsf.showProgress"/>
</h:inputText>
JavaScriptjsf.ajax.request(this, event, {
render: ‘target', onevent: showProgress
});
Trigger Ajax behaviours with JavaScript
12. August 2011 Slide 31
© Zühlke 2011HTML5 communications | marcbaechinger
• global error handling• global Ajax event listener (begin, complete, success)• decorate jsf.ajax.request • decorate jsf.ajax.response• trigger JSF events programmatically (requires JSF
component)• send additional parameters• <h:commandButton onclick="doit();" value="OK"/>
JSF 2.0 JavaScript opportunities
12. August 2011 Slide 32
© Zühlke 2011HTML5 communications | marcbaechinger
• No JavaScript integration beyond the component model• No REST support• simple HTML fragment replacements
• workaround to hook in with JavaScript: use hidden input fields
• conservative communication programming model• good backward compatibility
• Solution: expose business service with REST and inject in JSF bean with CDI
• JAX-RS, JSF, CDI, JSR303: solid, powerful and flexible Ajax-Framework
JavaScript integration of JSF 2.0
12. August 2011 Slide 33
© Zühlke 2011HTML5 communications | marcbaechinger
JAX-RS and JSF 2.0
12. August 2011
Webbrowser
JSF 2.0
Integration layer
JAX-RS
Application server
HTTP
HTTP
HTTP
Business layer
Slide 34
© Zühlke 2011
marcbaechinger
THX!
Q&A
© Zühlke 2011
marcbaechinger
Backup slides
12. August 2011Slide 36
© Zühlke 2011HTML5 communications | marcbaechinger
• backbone.js (MVC)• Model (Collections), View and Routers• Event system for arbitrary objects• Model synchronization via REST• templating and databinding of choice
• knockout.js (MVVM)• ViewModel with Observables and dependent Observables• ModelView with templating and databinding
• JavaScript MVC• meta-library collecting symbiotic jQuery plugins• MVC, scaffolding, testing
Library support for MVC
12. August 2011 Slide 37
© Zühlke 2011
marcbaechinger
Client side architecture
Slide 38
© Zühlke 2011HTML5 communications | marcbaechinger
Model View Controller derivates
12. August 2011
ListView
observesController
ViewModel
maintainsdatabinding
create and initialize
ModelView
action binding
maintains
DataService
use
Slide 39
© Zühlke 2011HTML5 communications | marcbaechinger
Page loading
12. August 2011 Slide 40
© Zühlke 2011HTML5 communications | marcbaechinger
function upload(url, blob, f) { var r = new XMLHttpRequest(); r.open("POST", url); r.send(blob); // XHR2 r.upload.onprogress = f;
} function uploadFiles(url, files) {
var r = new XMLHttpRequest(); r.open("POST", url); var fd = new FormData(); // XHR2 for(var i=0; i < files.length; i++) {
fd.append(files[i].name, files[i]);
}r.send(fd); // multipart/form-data
}
XHR2 – Blob und Form data
12. August 2011 Slide 41
© Zühlke 2011HTML5 communications | marcbaechinger
function getBlobWithXhr2(url, callback) { var r = new XMLHttpRequest(); r.open("GET", url); // Or use "arraybuffer" r.responseType = "blob" // XHR2 r.send(null); r.onload = function() {// XHR2
if (callback) {callback(r.response); // XHR2
} }
}
XHR2 – download binary blob
12. August 2011 Slide 42
© Zühlke 2011HTML5 communications | marcbaechinger
• style and layout system (CSS)• template/render engine
• connect UI triggers to event handlers/model functions• update views (eg. data binding)
• process user events• validate user input
• back button and deep linking support• remote or local I/O
Functional client side requirements
12. August 2011
MVC
Slide 43
© Zühlke 2011HTML5 communications | marcbaechinger 12. August 2011
ListViewobserves Controller
Model
maintains
databinding
creates/handle events
DataService
use
Slide 44
© Zühlke 2011HTML5 communications | marcbaechinger
• usually boils down to a publish/subscribe pattern• polyvalent nature of pub/sub fits most ws requirements• publish/subscribe matches with event driven JavaScript
apps
remoteEventRegistry.bind(‘foo’, function(){});
connection.onmessage = function (e) { var ev = e.data; if (ev.type) { remoteEventRegistry.fireEvent(ev.type, ev); }};
Websocket client integration
12. August 2011 Slide 45
© Zühlke 2011HTML5 communications | marcbaechinger
• All-in-one• A single all-purpose library• jQuery (UI)/jQuery mobile, extJS, Dojo toolkit, Sencha
touch
• Micro libraries• < 5kb (minified & gzipped) • Each task a library (UNIX tools philosophy)• script management (getsprockets.org)• microjs.com• Example: underscore, backbone, moustache, qwery,
reqwest
JS libraries -All-in-one vs. micro libraries
12. August 2011 Slide 46
© Zühlke 2011
(function(global) { var Observable = function() { this.observers = []; return this; }; Observable.prototype.bind = function(type, observerCallback) { if (type && observerCallback) { if (!this.observers[type]) { this.observers[type] = []; } this.observers[type].unshift(observerCallback); } return this; }; Observable.prototype.unbind = function(type, observerCallback) { var i; if (type && observerCallback && this.observers[type]) { for (i = 0; i < this.observers[type].length;i++) { if (observerCallback === this.observers[type][i]) { this.observers[type].splice(i,1); break; } } } return this; }; Observable.prototype.emit = function(type, event) { var i; if (type && event && this.observers[type]) { if (!event.type) { event.type = type; } for (i = 0; i < this.observers[type].length;i++) {
this.observers[type][i](event); } } return this; }; global.Observable = Observable;}(this));
Simple Observable implementation
HTML5 communications | marcbaechinger 12. August 2011 Slide 47