easing offline web application development with gwt
DESCRIPTION
At this current time, HTML5 APIs are mature enough so that the web browser can now be a very good platform for applications that were before only implemented as native applications : offline applications with locally stored data, embedded SQL engines, etc. Although there are many good Javascript frameworks out there, the Java language allows to build, maintain, debug and work with ease on really big applications (> 100,000 LOC). You'll discover in this presentation all the tools we assembled to make an application available with its data 100% of the time, even without internet!TRANSCRIPT
Easing Offline web
application development
with GWTArnaud Tournier, LTE Consulting
Speaker : Arnaud Tournier
Developper, Architect and CEO at LTE Consulting. 10 years experience with
C/C++ on Windows. Since 5 years+ : GWT and Web technologies.
GWT and AppEngine trainer
Offline HTML5 apps with GWT 2
Why Offline applications ?
For mobility:
3G throughput sometimes is not enough (ex: offline blog reader)
Mitigate innoportune disconnections (ex: emails)
Moving out of covered zones
Offline HTML5 apps with GWT 3
And because Web is the plateform
HTML5 opens up lots of new possibilities, that were before only accessible to native applications.
Accessible concepts to HTML5 applications:
Data storage,
Application cache,
File system,
Worker thread,
Web sockets, WebRTC,
Web GL, Audio,
Devices access (webcam, microphone, gps, …),
…
Benefits : lower the development cost for a multiplatform application.
Offline HTML5 apps with GWT 4
It’s also about User experience
Online / Offline, users want the same experience !
Connection is a technical concept, not for user…
Thus the most connected application works also offline !
Offline HTML5 apps with GWT 5
Summary
HTML5 APIs for Offline applications
Application Cache
Local data storage
Offline problems
Login
Local DBMS
Data synchronization
Demo
Conclusion
Offline HTML5 apps with GWT 6
HTML 5 APIs for Offline
applicationsIntroduction to APIs and GWT integration
Application Cache
Tell the browser to store necessary resources for the application to work
when internet is down
A « manifest » file describing the list of resources to cache
Cache management and event API
Offline HTML5 apps with GWT 8
Application Cache - GWT GWT manages every application resources « out-of-the-box ». We just need to
write a « linker » to generate the manifest file :
All your application resources, including images, css, js, and so on, are
automatically added to the manifest: we can work offline !
Code G
enera
tor
Offline HTML5 apps with GWT 9
Our Application Cache linker
// Executes in the context of the GWT compilation
@Shardable
@LinkerOrder( Order.POST )
public class AppCacheLinker extends AbstractLinker {…
@Override
public ArtifactSet link( LinkerContext context, … ) {
for( Artifact artifact : artifacts )
sb.append( artifact.getPartialPath() );
emitString( logger, sb.toString(), ontext.getModuleName() + ".appcache" );
}
}
Offline HTML5 apps with GWT 10
Application Cache dynamics
Offline HTML5 apps with GWT 11
Server
.html
.manifest
Reloading .html
.manifest
UPDATE READYNOUPDATEDOWNLOADING
CACHED
NEW MANIFEST FILE
Initial
loading
Application Cache – GWT
Cache API integration in GWT (using JSNI / Elemental).
The browser checks if a new manifest is available when loading the app. We
can ask for further checks with the update() function.
Upon receiving an application update, we can tell the user to refresh the
page to get the latest app version.
Offline HTML5 apps with GWT 12
In JavaScript, we use the object :
window.applicationCache
Application Cache – Events managementpublic final class AppCache extends JavaScriptObject {
// call Javascript from Java
public static final native AppCache get()
/*-{
return $wnd.applicationCache;
}-*/;
// launch an app cache update
public final native void update()
/*-{
this.update();
}-*/;
public interface Callback {
void handleEvent( AppCacheEvent event );
}
// register to App Cache events
public final native void registerEvents( Callback callback )
/*-{
this.addEventListener('cached', function( s ) {
// Call Java from Javascript
callback
[email protected]::handleEvent(Lpackage/AppCacheEvent;)
(@package.AppCacheEvent::CACHED);
} );
…
}-*/;
}
public enum AppCacheEvent
{
// Application en cache
CACHED,
// Vérification en cours
CHECKING,
// Téléchargement en cours
DOWNLOADING,
// Une erreur s’est produite
ERROR,
// Pas de mise à jour
NOUPDATE,
// Le fichier manifest n’existe plus
OBSOLETE,
// Mise à jour en cours
PROGRESS,
// Mise à jour prête à être déployée
UPDATEREADY;
}13
Local data Storage
Locally store data in the browser (user scope !).
Many standards exist (WebSQL, IndexedDB, FileSystem ) but only one is really
multiplatform: LocalStorage
It’s a Map<String, String>.
GWT provides a LocalStorage API wrapper « out of the box », no JSNI to write.
POJO serialization into the storage space might be done with JSON (since it’s
really fast on browsers).
Data is persistent accross page refresh !
5 Mega bytes max (spec) ! (But browsers allow for more…)
Offline HTML5 apps with GWT 14
Summary
HTML5 API for Offline applications
Application Cache
Local data Storage
Offline problems
Login
Local DBMS
Data synchronization
Demo
Conclusion
Offline HTML5 apps with GWT 15
Problems you might
encounter…
A typical wish-list…
Authenticate the user (even offline).
User should be able to manipulate data even when offline.
Application should transparently synchronize its data with the server.
For our awesome developpers : they need a local DBMS (and if we can a JPA
provider).
Offline HTML5 apps with GWT 17
Offline Authentication
When online, authentication is done by the server.
We should then be able to re-authenticate him/her without the server.
Be careful ! Local storage completely unsecure !
We thus store the user’s password in the browser, salted and crypted with
SHA-3.
Find a Java SHA-3 implementation, copy-paste in the project :
String shaEncoded = SHA3.digest( String clearString );
Offline HTML5 apps with GWT 18
An in-browser DBMS ?
Complex data queries, we’re not going to implement that again (complexity,
performance, index, joints, transactions, …) !
Database oriented HTML 5 APIs are not implemented on every browser, except
Local Storage which is just a String to String map…
Jboss ERRAI is a really interesting project, aiming to implement JPA, but it is
too light for majority of cases (no joins, tx, dynamic queries…).
SQL.js is a javascript compiled version of SQLite. Done with the emscripten
compiler from Alon Zhakai. Emscripten = C/C++ to Javascript cross-compiler
based on the LLVM compiler toolkit. Is that a good idea ?
Offline HTML5 apps with GWT 19
SQL.js and GWT
SQLite is the most deployed embedded DBMS in the world (~500 millions)
SQL.js API :
a JavaScript object : window.SQL
3 functions : open(data), execute(statement), exportData(). Talks in JSON.
How to persist the DB ? With Local Storage !
JSNI code to bind the sql.js API
A mini ORM to bind SQL results to our POJOs (we like comfort a bit)
That gives us…
Offline HTML5 apps with GWT 20
SQL.js with GWT
public class SQLite extends JavaScriptObject
{
public static final native SQLite open( JsArrayInteger data )
/*-{
return $wnd.SQL.open( data );
}-*/;
public final native JavaScriptObject execute( String statement )
/*-{
return this.exec( statement );
}-*/;
public final native JsArrayInteger exportData()
/*-{
return this.exportData();
}-*/;
public final native void close()
/*-{
this.close();
}-*/;
}List<Item> items = db.query( « select {Item:i}
from Item i
left join Brand b on i.brandId=b.id
where b.id=42 » ).getResultList();
class DbHelper {
SQLite db;
public <T>
List<T> query( String query ) {
// parse query and generate select
…
// execute query
JavaScriptObject jso = db.execute( transformedQuery );
JSON json = new JSONObject( jso );
// generate List<T> from JSON
return list;
}
}
SQL.js creates a « SQL » global
variable
var result = window.SQL.exec( « select… »);
// result holds the results in JSON
Offline HTML5 apps with GWT
21
Homogeneous service contracts
public class SQLiteBusinessLogic {
BusinessLogic businessLogic =
new BusinessLogic( new SQLiteDAO() );
public List<Article> searchArticles( int id,
AsyncCallback<List<Article>> callback ) {
// simply delegate to local service
callback.onSuccess( business.searchArticles(…) );
}
}
// Le même code métier appelle cette fois le DAO SQLite
return db.query( « … » );
public class BusinessLogicFacade
{
public ListItem> searchItems( int id,
AsyncCallback<ListItem>> callback ) {
return currentImplementation.searchArticles( … );
}
public void switchImplementation( impl ) {
currentImplementation = impl
}
}
public class RemoteBusinessLogic {
private static ApplicationServiceAsync proxy =
GWT.create(ApplicationService.class);
public List<Item> searchItems( int id,
AsyncCallback<List<Item> callback ) {
// simply delegate to remote service
return proxy.searchArticles( … );
}
}
… On the server …
businessLogic = BusinessLogic( new JPADAO() );
// Servlet delegates the délègue au code métier
return business.searchArticles( … );
// le code métier appelle son DAO …
class BusinessLogic {
DAO dao;
…
}
// … qui utilise ici JPA
return em.createQuery( « … » ).getResultList();
Offline HTML5 apps with GWT
22
Server
Client
Data Synchronization
Three offline access, three difficulty levels
Local data access mode Related problematic
Read Only Continuous Synchronization
Read + Add Sending inserts to the server
Read, Add, Modification,
Suppression
Conflict management
Offline HTML5 apps with GWT 23
Continuous downstream
synchronization
Continuously feeding the local database,
Can use server-side counters or timestamps,
Client asks for unknown data,
For server-side deletes, a trigger feeds a log table.
Offline HTML5 apps with GWT 24
Offline
access in
READ ONLY
Sending local new records to the
server
Managing new local records Ids:
Local new records are associated to negative Ids,
Send them when going back to online mode,
Reconciliate local Ids with the server ones.
Offline HTML5 apps with GWT 25
Offline
access in
READ + ADD
Sending changes to the server
Worst scenarios are possible! Similar problems as for distributed systems.
Version vectors for causality tracking.
Conflict management, several resolution policies :
Last writer wins,
Source wins,
Destination wins,
Specified replica wins,
Merge, automatic or manual ?
Log and deffer, etc.
Offline HTML5 apps with GWT 26
Full offline
access
READ WRITE
So what about out Wish-list?
Ideally, we’d had a fully compliant JPA implementation, enabling us to fully
share data access code between server and client.
ERRAI may be enough in some situations,
Or an home made mini-ORM.
We are building a fully JPA compliant implementation for GWT
http://www.lteconsulting.fr/jpa-for-gwt.html
We didn’t explore security.
Quite a big impedance between HTML5 platform potential and tools we have.
Community needs better tools.
BUT, our goal is fulfilled!
An application running offline, with the same functionalities as online. User
doesn’t need to know whether he is connected or not.
Offline HTML5 apps with GWT 27
Demonstration !
Used stack
GUI
Business facade
RPC Services
Business layerSynchro
DAO JPA DAO SQL.JS/GWT
JDBC compliant DBMS SQLite/Local storage
Synchro
Server Client
Server watchdog
AppCache management
Applis Offlines HTML5 avec GWT 29
Online mode
Applis Offlines HTML5 avec GWT 30
GUI
Business facade
RPC Services
Business layerSynchro
DAO JPA DAO SQL.JS/GWT
JDBC compliant DBMS SQLite/Local storage
Synchro
Server Client
Server watchdog
AppCache management
Offline mode
Applis Offlines HTML5 avec GWT 31
GUI
Business facade
RPC Services
Business layerSynchro
DAO JPA DAO SQL.JS/GWT
JDBC compliant DBMS SQLite/Local storage
Synchro
Server Client
Server watchdog
AppCache management
Unreachable
Server
Transition to Online mode
Applis Offlines HTML5 avec GWT 32
GUI
Business facade
RPC Services
Business layerSynchro
DAO JPA DAO SQL.JS/GWT
JDBC compliant DBMS SQLite/Local storage
Synchro
Server Client
Server watchdog
AppCache management
Server
replies
Send local changes to
the server
Online mode
Applis Offlines HTML5 avec GWT 33
GUI
Business facade
RPC Services
Business layerSynchro
DAO JPA DAO SQL.JS/GWT
JDBC compliant DBMS SQLite/Local storage
Synchro
Server Client
Server watchdog
AppCache management
Démonstration…
Offline HTML5 apps with GWT 34
Questions?
Offline HTML5 apps with GWT 35
Thanks, and see you soon!
Links :
GWT
SQL.JS
SQLITE
EMSCRIPTEN
HTML5Rocks
JBOSS ERRAI
CANIUSE.COM
Offline HTML5 apps with GWT 36
Twitter: @ltearno
Email: [email protected]