SlideShare a Scribd company logo
Migrate Large GWT Applications
MIGRATE LARGE GWT
APPLICATIONS
Harald Pehl, GWTCon 2017
LESSONS LEARNED
Migrate Large GWT Applications
About Me
Senior Software Engineer at Red Hat
Component Lead of the WildFly Management Console
Working with GWT since 2008
http://hpehl.info
https://github.com/hpehl
@haraldpehl
Migrate Large GWT Applications
HAL - WildFly Management Console
Migrate Large GWT Applications
History
First commit
Feb 8 2011
2.9.14.Final
5.723 commits / 179 releases
Today200k LoC
Migrate Large GWT Applications
Current Version
UI
GWT Stock Widgets
Cell Widgets
No Widget Library
Stack
GWT 2.8
GWTP / GIN
Some Code Generation
⇨ Lots of Repeating Code ⇦
Migrate Large GWT Applications
New Version
UI
No Widgets
PatternFly
3rd Party Libraries
Stack
Latest GWT Version
GWTP / GIN
Lots of Code Generation
⇨ Cleaner Architecture ⇦
Migrate Large GWT Applications
Architecture
SPI
CodeGeneration
Resources
DMR
UI / Ballroom
Core
Metadata
Application
GWTP GuavaRxGWT SLF4J
Migrate Large GWT Applications
Comparison
200k
112k
LoC Full Build
08:11
05:44
GWT Compile
06:51
02:46
Migrate Large GWT Applications
Demo
http://localhost:9090/
Migrate Large GWT Applications
User Interface
Migrate Large GWT Applications
MBUI
Elemento
3rd Party Libs
PatternFly
Migrate Large GWT Applications
PatternFly
UI Framework for Enterprise Web Applications
Pattern Library
● Communication
● Content Views
● Data Visualization
● Forms & Control, Navigation & Widgets
Common Styles, Colors & Icons
Migrate Large GWT Applications
Migrate Large GWT Applications
Elemento
Type Safe Builders and Event Handlers
HTML Templates w/ Expression Support
Helper Methods
Migrate Large GWT Applications
HTMLDivElement div = div().css(progressContainewr)
.add(div().css(progressDescription)
.title(label)
.textContent(label))
.add(div().css(progressCss)
.add(valueBar = div().css(progressBar)
.title(Names.NOT_AVAILABLE)
.attr(ROLE, PROGRESSBAR)
.aria(VALUE_MIN, "0")
.add(valueElement = span().asElement())
.asElement())
.add(remainingBar = div().css(progressBar, progressBarRemaining)
.title(Names.NOT_AVAILABLE)
.add(remainingElement = span().css(srOnly).asElement())
.asElement()))
.asElement();
Migrate Large GWT Applications
public class Breadcrumb implements IsElement<HTMLElement> {
private final HTMLElement root;
public Breadcrumb() {
root = ol().css(breadcrumb).asElement();
}
public void clear() {
Elements.removeChildrenFrom(root);
}
public Breadcrumb append(String segment, SegmentHandler handler) {
root.appendChild(li()
.add(a().css(clickable)
.textContent(segment)
.on(click, e -> handler.onClick()))
.asElement());
return this;
}
@Override
public HTMLElement asElement() {
return root;
}
}
Migrate Large GWT Applications
XML schema for common UI building blocks
Navigation Tables
HTML Forms
CRUD Operations
Annotation Processor
MBUI
Migrate Large GWT Applications
<sub-item id="ejb-thread-pool-item" title="Thread Pool">
<metadata address="/{selected.profile}/subsystem=ejb3/thread-pool=*">
<h1>Thread Pool</h1>
<p>${metadata.getDescription().getDescription()}</p>
<table id="ejb-thread-pool-table" title="Thread Pool" form-ref="ejb-thread-pool-form">
<actions>
<action handler-ref="add-resource"/>
<action handler-ref="remove-resource" scope="selected"
name-resolver="${table.selectedRow().getName()}"/>
</actions>
<columns>
<column name="name" value="${row.getName()}"/>
</columns>
</table>
<form id="ejb-thread-pool-form" title="Thread Pool" auto-save="true" reset="true"
name-resolver="${form.getModel().getName()}"/>
</metadata>
</sub-item>
Migrate Large GWT Applications
@MbuiView
public abstract class EjbView
extends MbuiViewImpl<EjbPresenter>
implements EjbPresenter.MyView {
public static EjbView create(MbuiContext mbuiContext) {
return new Mbui_EjbView(mbuiContext);
}
@MbuiElement("ejb-thread-pool-table") Table<NamedNode> threadPoolTable;
@MbuiElement("ejb-thread-pool-form") Form<NamedNode> threadPoolForm;
EjbView(MbuiContext mbuiContext) {
super(mbuiContext);
}
}
Migrate Large GWT Applications
http://localhost:9090/#ejb3-configuration
Migrate Large GWT Applications
3rd Party Libraries
"dependencies": {
"ace-builds": "^1.2.6",
"datatables.net": "~1.10.13",
"datatables.net-buttons": "~1.2.2",
"datatables.net-keytable": "^2.1.3",
"datatables.net-select": "~1.2.0",
"font-awesome": "~4.7.0",
"js-cookie": "~2.1.3",
"javascript-auto-complete": "1.0.4",
"jquery": "~2.2.4",
"jstree": "~3.3.3",
"patternfly": "~3.26.1",
"tagmanager": "~3.0.2",
"zeroclipboard": "^2.2.0"
}
Migrate Large GWT Applications
@JsType(isNative = true)
public abstract class Modal {
@JsFunction @FunctionalInterface
public interface ModalHandler {
void handle();
}
@JsType(isNative = true, namespace = GLOBAL, name = OBJECT)
public static class ModalOptions {
public boolean keyboard;
@JsOverlay
public static ModalOptions create(boolean closeOnEsc) {
ModalOptions options = new ModalOptions();
options.keyboard = closeOnEsc;
return options;
}
}
@JsMethod(namespace = GLOBAL)
public native static Modal $(@NonNls String selector);
public native void modal(ModalOptions modalOptions);
public native void on(@NonNls String event, ModalHandler handler);
}
Migrate Large GWT Applications
Model View Presenter
Migrate Large GWT Applications
MVP
GWTP
● DI through GIN
● Simple and powerful history management
● Support for nested presenters
● Lifecycle events using GWT eventbus
● Lazy instantiation for presenters and views
● Effortless and efficient code splitting
Widget ↔ Elemental2 Adapter
Migrate Large GWT Applications
Escape From Callback Hell
Migrate Large GWT Applications
RxGWT
GWT specific bindings for RxJava
Turn callbacks into “Rx types”
Developed and maintained by @ibaca
Documentation
● http://reactivex.io/
● https://github.com/ReactiveX/RxJava
● https://github.com/intendia-oss/rxgwt
Migrate Large GWT Applications
interface FooService extends RemoteService {
void prepare();
void main();
void cleanup();
}
interface FooServiceAsync {
void prepare(AsyncCallback<Void> async);
void main(AsyncCallback<Void> async);
void cleanup(AsyncCallback<Void> async);
}
Migrate Large GWT Applications
public class ExecuteInOrder implements EntryPoint {
@Override
public void onModuleLoad() {
FooServiceAsync service = GWT.create(FooService.class);
service.prepare(new AsyncCallback<Void>() {
public void onFailure(Throwable throwable) {
console.log("Failed: " + throwable.getMessage());
}
public void onSuccess(Void aVoid) {
service.main(new AsyncCallback<Void>() {
public void onFailure(Throwable throwable) {
console.log("Failed: " + throwable.getMessage())
}
public void onSuccess(Void aVoid) {
service.cleanup(new AsyncCallback<Void>() {
public void onFailure(Throwable throwable) {
console.log("Failed: " + throwable.getMessage())
}
public void onSuccess(Void aVoid) {
console.log("Finished")
}
});
}
});
}
});
}
}
Migrate Large GWT Applications
public class ExecuteInOrder implements EntryPoint {
@Override
public void onModuleLoad() {
FooServiceAsync service = GWT.create(FooService.class);
Completable prepare = Completable.fromEmitter(em -> service.prepare(callback(em)));
Completable main = Completable.fromEmitter(em -> service.main(callback(em)));
Completable cleanup = Completable.fromEmitter(em -> service.cleanup(callback(em)));
Completable.concat(prepare, main, cleanup)
.doOnError(throwable -> console.log("Failed: " + throwable.getMessage()))
.doOnCompleted(() -> console.log("Finished"))
.subscribe();
}
AsyncCallback<Void> callback(CompletableEmitter emitter) {
return new AsyncCallback<Void>() {
@Override
public void onFailure(Throwable throwable) { emitter.onError(throwable); }
@Override
public void onSuccess(Void aVoid) { emitter.onCompleted(); }
};
}
}
Migrate Large GWT Applications
public class RxDemo implements EntryPoint {
@Override
public void onModuleLoad() {
Observable.interval(1, SECONDS)
.take(10)
.flatMapSingle(this::xhr)
.forEach(timestamp -> console.log(timestamp));
}
Single<String> xhr(long id) {
String url = "http://server.test-cors.org/server?enable=true&id=" + id;
return Single.fromEmitter(emitter -> {
XMLHttpRequest xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = event -> emitter.onSuccess(new Date().toLocaleTimeString());
xhr.send();
});
}
}
Migrate Large GWT Applications
Annotation Processing
Migrate Large GWT Applications
Annotation Processing
Registries
Composite GIN
MBUI
EsDoc
Migrate Large GWT Applications
package org.jboss.hal.processor;
@AutoService(Processor.class)
public class NameTokenProcessor extends AbstractProcessor {
private final Set<TokenInfo> tokenInfos;
public NameTokenProcessor() {
super(NameTokenProcessor.class, TEMPLATES);
tokenInfos = new HashSet<>();
}
@Override
protected boolean onProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element e : roundEnv.getElementsAnnotatedWith(NameToken.class)) {
TypeElement tokenElement = (TypeElement) e;
NameToken nameToken = tokenElement.getAnnotation(NameToken.class);
TokenInfo tokenInfo = new TokenInfo(nameToken.value()[0]);
tokenInfos.add(tokenInfo);
...
}
return false;
}
}
Migrate Large GWT Applications
<#-- @ftlvariable name="generatedWith" type="java.lang.String" -->
<#-- @ftlvariable name="packageName" type="java.lang.String" -->
<#-- @ftlvariable name="className" type="java.lang.String" -->
<#-- @ftlvariable name="tokenInfos"
type="java.util.Set<org.jboss.hal.processor.NameTokenProcessor.TokenInfo>" -->
package ${packageName};
import ...
/*
* WARNING! This class is generated. Do not modify.
*/
@Generated("${generatedWith}")
public class ${className} implements org.jboss.hal.meta.token.NameTokens {
private final Set<String> tokens;
public ${className}() {
this.tokens = new HashSet<>();
<#list tokenInfos as tokenInfo>
this.tokens.add("${tokenInfo.token}");
</#list>
}
@Override
public Set<String> getTokens() { return tokens; }
}
Migrate Large GWT Applications
Annotation Processing
Freemarker Templates
Use 3rd party libraries
● https://github.com/google/auto/tree/master/common
● https://github.com/google/auto/tree/master/service
Test your annotation processor!
● https://github.com/google/compile-testing
Migrate Large GWT Applications
public class FormTest {
@Test
public void simpleForm() {
Compilation compilation = javac()
.withOptions("-proc:only")
.withProcessors(new MbuiViewProcessor())
.compile(JavaFileObjects.forResource("SimpleForm.java"));
assertThat(compilation)
.generatedSourceFile("Mbui_SimpleForm")
.hasSourceEquivalentTo(
JavaFileObjects.forResource("Mbui_SimpleForm.java"));
}
}
Migrate Large GWT Applications
Build Process
Migrate Large GWT Applications
Build & Run
Maven First
3rd Party Libraries: Frontend Maven Plugin
● NPM
● Bower
● Grunt
Build: Maven Plugin for GWT by Thomas Broyer
Run: Browser Dev Tools
Migrate Large GWT Applications
Open Issues
Migrate Large GWT Applications
Open Issues
GIN
Code Splitting
JSNI
GWT.create()
ClientBundle / i18n
Migrate Large GWT Applications
Links
https://github.com/hal/hal.next/
https://github.com/hal/elemento
http://www.patternfly.org/
http://wildfly.org/
Migrate Large GWT Applications
Thanks!
Questions?
Ad

Recommended

PDF
Web components with java by Haijian Wang
GWTcon
 
PDF
"Xapi-lang For declarative code generation" By James Nelson
GWTcon
 
PDF
Mobile Day - React Native
Software Guru
 
PDF
React Native: JS MVC Meetup #15
Rob Gietema
 
PDF
Oleksandr Tolstykh
CodeFest
 
PDF
Angular 2 introduction
Christoffer Noring
 
PDF
JavaCro'14 - Scala and Java EE 7 Development Experiences – Peter Pilgrim
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association
 
KEY
Geotalk presentation
Eric Palakovich Carr
 
PPT
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
Srijan Technologies
 
PDF
How to build to do app using vue composition api and vuex 4 with typescript
Katy Slemon
 
PDF
Integrating React.js with PHP projects
Ignacio Martín
 
PDF
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
Fwdays
 
PPTX
Vue next
Vitalii Ratyshnyi
 
PPTX
ReactJs presentation
nishasowdri
 
PPTX
React и redux
Дмитрий Радыно
 
PDF
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 
PDF
React Lifecycle and Reconciliation
Zhihao Li
 
PPTX
SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato
Sencha
 
PDF
React JS and why it's awesome
Andrew Hull
 
PDF
Intro to ReactJS
Harvard Web Working Group
 
PPTX
The Road To Reactive with RxJava JEEConf 2016
Frank Lyaruu
 
PPTX
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
Sencha
 
PPTX
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
PPTX
Getting started with ReactJS
Krishna Sunuwar
 
PDF
React Native One Day
Troy Miles
 
PDF
Building React Applications with Redux
FITC
 
PPTX
React & redux
Cédric Hartland
 
PPTX
ReactJS for Beginners
Oswald Campesato
 
PDF
Best Practices - By Lofi Dewanto
GWTcon
 
PPT
Google Web Toolkits
Yiguang Hu
 

More Related Content

What's hot (20)

PPT
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
Srijan Technologies
 
PDF
How to build to do app using vue composition api and vuex 4 with typescript
Katy Slemon
 
PDF
Integrating React.js with PHP projects
Ignacio Martín
 
PDF
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
Fwdays
 
PPTX
Vue next
Vitalii Ratyshnyi
 
PPTX
ReactJs presentation
nishasowdri
 
PPTX
React и redux
Дмитрий Радыно
 
PDF
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 
PDF
React Lifecycle and Reconciliation
Zhihao Li
 
PPTX
SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato
Sencha
 
PDF
React JS and why it's awesome
Andrew Hull
 
PDF
Intro to ReactJS
Harvard Web Working Group
 
PPTX
The Road To Reactive with RxJava JEEConf 2016
Frank Lyaruu
 
PPTX
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
Sencha
 
PPTX
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
PPTX
Getting started with ReactJS
Krishna Sunuwar
 
PDF
React Native One Day
Troy Miles
 
PDF
Building React Applications with Redux
FITC
 
PPTX
React & redux
Cédric Hartland
 
PPTX
ReactJS for Beginners
Oswald Campesato
 
[Srijan Wednesday Webinar] Rails 5: What's in It for Me?
Srijan Technologies
 
How to build to do app using vue composition api and vuex 4 with typescript
Katy Slemon
 
Integrating React.js with PHP projects
Ignacio Martín
 
"Full Stack frameworks or a story about how to reconcile Front (good) and Bac...
Fwdays
 
ReactJs presentation
nishasowdri
 
Java9 Beyond Modularity - Java 9 más allá de la modularidad
David Gómez García
 
React Lifecycle and Reconciliation
Zhihao Li
 
SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato
Sencha
 
React JS and why it's awesome
Andrew Hull
 
Intro to ReactJS
Harvard Web Working Group
 
The Road To Reactive with RxJava JEEConf 2016
Frank Lyaruu
 
SenchaCon 2016: Modernizing the Ext JS Class System - Don Griffin
Sencha
 
JavaFX 2 and Scala - Like Milk and Cookies (33rd Degrees)
Stephen Chin
 
Getting started with ReactJS
Krishna Sunuwar
 
React Native One Day
Troy Miles
 
Building React Applications with Redux
FITC
 
React & redux
Cédric Hartland
 
ReactJS for Beginners
Oswald Campesato
 

Similar to "Migrate large gwt applications - Lessons Learned" By Harald Pehl (9)

PDF
Best Practices - By Lofi Dewanto
GWTcon
 
PPT
Google Web Toolkits
Yiguang Hu
 
PPT
GWT MVP Case Study
David Chandler
 
PDF
Easing offline web application development with GWT
Arnaud Tournier
 
PPT
GWT
yuvalb
 
PDF
Javaland 2014 / GWT architectures and lessons learned
pgt technology scouting GmbH
 
PPT
Google Dev Day2007
lucclaes
 
PDF
GWT architecture best practices and lessons learned
pgt technology scouting GmbH
 
PPT
SF JUG - GWT Can Help You Create Amazing Apps - 2009-10-13
Fred Sauer
 
Best Practices - By Lofi Dewanto
GWTcon
 
Google Web Toolkits
Yiguang Hu
 
GWT MVP Case Study
David Chandler
 
Easing offline web application development with GWT
Arnaud Tournier
 
GWT
yuvalb
 
Javaland 2014 / GWT architectures and lessons learned
pgt technology scouting GmbH
 
Google Dev Day2007
lucclaes
 
GWT architecture best practices and lessons learned
pgt technology scouting GmbH
 
SF JUG - GWT Can Help You Create Amazing Apps - 2009-10-13
Fred Sauer
 
Ad

More from GWTcon (12)

PPTX
"Jclays, A global solution for application design and automatic GWT code gene...
GWTcon
 
PDF
In defense of GWT-RPC By Colin Alworth
GWTcon
 
PDF
DIY: Split GWT Applications using TURDUCKEN approach By Alberto Mancini
GWTcon
 
PDF
Unirex Lean tools By Dario Carotenuto
GWTcon
 
PDF
The future of GWT 2.x - By Colin Alworth
GWTcon
 
PDF
UI Framework Development using GWT and HTML Canvas - By Iarosla Kobyliukh
GWTcon
 
PPTX
GWT Development for Handheld Devices
GWTcon
 
PPTX
GWT vs CSS3
GWTcon
 
PDF
WebTram: una WebApp GWT per l'editing di dati cartografici e topologici di un...
GWTcon
 
PDF
GWT Web Socket and data serialization
GWTcon
 
PPTX
GWTcon 2014 - Apertura
GWTcon
 
PPTX
GWT videocall: power-up your mobile & web app with WebRTC
GWTcon
 
"Jclays, A global solution for application design and automatic GWT code gene...
GWTcon
 
In defense of GWT-RPC By Colin Alworth
GWTcon
 
DIY: Split GWT Applications using TURDUCKEN approach By Alberto Mancini
GWTcon
 
Unirex Lean tools By Dario Carotenuto
GWTcon
 
The future of GWT 2.x - By Colin Alworth
GWTcon
 
UI Framework Development using GWT and HTML Canvas - By Iarosla Kobyliukh
GWTcon
 
GWT Development for Handheld Devices
GWTcon
 
GWT vs CSS3
GWTcon
 
WebTram: una WebApp GWT per l'editing di dati cartografici e topologici di un...
GWTcon
 
GWT Web Socket and data serialization
GWTcon
 
GWTcon 2014 - Apertura
GWTcon
 
GWT videocall: power-up your mobile & web app with WebRTC
GWTcon
 
Ad

Recently uploaded (20)

PPTX
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
PDF
Cyber Defense Matrix Workshop - RSA Conference
Priyanka Aash
 
PDF
“MPU+: A Transformative Solution for Next-Gen AI at the Edge,” a Presentation...
Edge AI and Vision Alliance
 
PDF
Database Benchmarking for Performance Masterclass: Session 2 - Data Modeling ...
ScyllaDB
 
PDF
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
PPTX
Securing Account Lifecycles in the Age of Deepfakes.pptx
FIDO Alliance
 
PDF
Oh, the Possibilities - Balancing Innovation and Risk with Generative AI.pdf
Priyanka Aash
 
PDF
A Constitutional Quagmire - Ethical Minefields of AI, Cyber, and Privacy.pdf
Priyanka Aash
 
PDF
Cracking the Code - Unveiling Synergies Between Open Source Security and AI.pdf
Priyanka Aash
 
PDF
Techniques for Automatic Device Identification and Network Assignment.pdf
Priyanka Aash
 
PPTX
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
Fwdays
 
PPTX
You are not excused! How to avoid security blind spots on the way to production
Michele Leroux Bustamante
 
PDF
Python Conference Singapore - 19 Jun 2025
ninefyi
 
PDF
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
revolcs10
 
PDF
AI Agents and FME: A How-to Guide on Generating Synthetic Metadata
Safe Software
 
PDF
Securing AI - There Is No Try, Only Do!.pdf
Priyanka Aash
 
PDF
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
caoyixuan2019
 
PDF
Mastering AI Workflows with FME by Mark Döring
Safe Software
 
PDF
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
PDF
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 
OpenACC and Open Hackathons Monthly Highlights June 2025
OpenACC
 
Cyber Defense Matrix Workshop - RSA Conference
Priyanka Aash
 
“MPU+: A Transformative Solution for Next-Gen AI at the Edge,” a Presentation...
Edge AI and Vision Alliance
 
Database Benchmarking for Performance Masterclass: Session 2 - Data Modeling ...
ScyllaDB
 
Smarter Aviation Data Management: Lessons from Swedavia Airports and Sweco
Safe Software
 
Securing Account Lifecycles in the Age of Deepfakes.pptx
FIDO Alliance
 
Oh, the Possibilities - Balancing Innovation and Risk with Generative AI.pdf
Priyanka Aash
 
A Constitutional Quagmire - Ethical Minefields of AI, Cyber, and Privacy.pdf
Priyanka Aash
 
Cracking the Code - Unveiling Synergies Between Open Source Security and AI.pdf
Priyanka Aash
 
Techniques for Automatic Device Identification and Network Assignment.pdf
Priyanka Aash
 
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
Fwdays
 
You are not excused! How to avoid security blind spots on the way to production
Michele Leroux Bustamante
 
Python Conference Singapore - 19 Jun 2025
ninefyi
 
ReSTIR [DI]: Spatiotemporal reservoir resampling for real-time ray tracing ...
revolcs10
 
AI Agents and FME: A How-to Guide on Generating Synthetic Metadata
Safe Software
 
Securing AI - There Is No Try, Only Do!.pdf
Priyanka Aash
 
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
caoyixuan2019
 
Mastering AI Workflows with FME by Mark Döring
Safe Software
 
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
Quantum AI Discoveries: Fractal Patterns Consciousness and Cyclical Universes
Saikat Basu
 

"Migrate large gwt applications - Lessons Learned" By Harald Pehl

  • 1. Migrate Large GWT Applications MIGRATE LARGE GWT APPLICATIONS Harald Pehl, GWTCon 2017 LESSONS LEARNED
  • 2. Migrate Large GWT Applications About Me Senior Software Engineer at Red Hat Component Lead of the WildFly Management Console Working with GWT since 2008 http://hpehl.info https://github.com/hpehl @haraldpehl
  • 3. Migrate Large GWT Applications HAL - WildFly Management Console
  • 4. Migrate Large GWT Applications History First commit Feb 8 2011 2.9.14.Final 5.723 commits / 179 releases Today200k LoC
  • 5. Migrate Large GWT Applications Current Version UI GWT Stock Widgets Cell Widgets No Widget Library Stack GWT 2.8 GWTP / GIN Some Code Generation ⇨ Lots of Repeating Code ⇦
  • 6. Migrate Large GWT Applications New Version UI No Widgets PatternFly 3rd Party Libraries Stack Latest GWT Version GWTP / GIN Lots of Code Generation ⇨ Cleaner Architecture ⇦
  • 7. Migrate Large GWT Applications Architecture SPI CodeGeneration Resources DMR UI / Ballroom Core Metadata Application GWTP GuavaRxGWT SLF4J
  • 8. Migrate Large GWT Applications Comparison 200k 112k LoC Full Build 08:11 05:44 GWT Compile 06:51 02:46
  • 9. Migrate Large GWT Applications Demo http://localhost:9090/
  • 10. Migrate Large GWT Applications User Interface
  • 11. Migrate Large GWT Applications MBUI Elemento 3rd Party Libs PatternFly
  • 12. Migrate Large GWT Applications PatternFly UI Framework for Enterprise Web Applications Pattern Library ● Communication ● Content Views ● Data Visualization ● Forms & Control, Navigation & Widgets Common Styles, Colors & Icons
  • 13. Migrate Large GWT Applications
  • 14. Migrate Large GWT Applications Elemento Type Safe Builders and Event Handlers HTML Templates w/ Expression Support Helper Methods
  • 15. Migrate Large GWT Applications HTMLDivElement div = div().css(progressContainewr) .add(div().css(progressDescription) .title(label) .textContent(label)) .add(div().css(progressCss) .add(valueBar = div().css(progressBar) .title(Names.NOT_AVAILABLE) .attr(ROLE, PROGRESSBAR) .aria(VALUE_MIN, "0") .add(valueElement = span().asElement()) .asElement()) .add(remainingBar = div().css(progressBar, progressBarRemaining) .title(Names.NOT_AVAILABLE) .add(remainingElement = span().css(srOnly).asElement()) .asElement())) .asElement();
  • 16. Migrate Large GWT Applications public class Breadcrumb implements IsElement<HTMLElement> { private final HTMLElement root; public Breadcrumb() { root = ol().css(breadcrumb).asElement(); } public void clear() { Elements.removeChildrenFrom(root); } public Breadcrumb append(String segment, SegmentHandler handler) { root.appendChild(li() .add(a().css(clickable) .textContent(segment) .on(click, e -> handler.onClick())) .asElement()); return this; } @Override public HTMLElement asElement() { return root; } }
  • 17. Migrate Large GWT Applications XML schema for common UI building blocks Navigation Tables HTML Forms CRUD Operations Annotation Processor MBUI
  • 18. Migrate Large GWT Applications <sub-item id="ejb-thread-pool-item" title="Thread Pool"> <metadata address="/{selected.profile}/subsystem=ejb3/thread-pool=*"> <h1>Thread Pool</h1> <p>${metadata.getDescription().getDescription()}</p> <table id="ejb-thread-pool-table" title="Thread Pool" form-ref="ejb-thread-pool-form"> <actions> <action handler-ref="add-resource"/> <action handler-ref="remove-resource" scope="selected" name-resolver="${table.selectedRow().getName()}"/> </actions> <columns> <column name="name" value="${row.getName()}"/> </columns> </table> <form id="ejb-thread-pool-form" title="Thread Pool" auto-save="true" reset="true" name-resolver="${form.getModel().getName()}"/> </metadata> </sub-item>
  • 19. Migrate Large GWT Applications @MbuiView public abstract class EjbView extends MbuiViewImpl<EjbPresenter> implements EjbPresenter.MyView { public static EjbView create(MbuiContext mbuiContext) { return new Mbui_EjbView(mbuiContext); } @MbuiElement("ejb-thread-pool-table") Table<NamedNode> threadPoolTable; @MbuiElement("ejb-thread-pool-form") Form<NamedNode> threadPoolForm; EjbView(MbuiContext mbuiContext) { super(mbuiContext); } }
  • 20. Migrate Large GWT Applications http://localhost:9090/#ejb3-configuration
  • 21. Migrate Large GWT Applications 3rd Party Libraries "dependencies": { "ace-builds": "^1.2.6", "datatables.net": "~1.10.13", "datatables.net-buttons": "~1.2.2", "datatables.net-keytable": "^2.1.3", "datatables.net-select": "~1.2.0", "font-awesome": "~4.7.0", "js-cookie": "~2.1.3", "javascript-auto-complete": "1.0.4", "jquery": "~2.2.4", "jstree": "~3.3.3", "patternfly": "~3.26.1", "tagmanager": "~3.0.2", "zeroclipboard": "^2.2.0" }
  • 22. Migrate Large GWT Applications @JsType(isNative = true) public abstract class Modal { @JsFunction @FunctionalInterface public interface ModalHandler { void handle(); } @JsType(isNative = true, namespace = GLOBAL, name = OBJECT) public static class ModalOptions { public boolean keyboard; @JsOverlay public static ModalOptions create(boolean closeOnEsc) { ModalOptions options = new ModalOptions(); options.keyboard = closeOnEsc; return options; } } @JsMethod(namespace = GLOBAL) public native static Modal $(@NonNls String selector); public native void modal(ModalOptions modalOptions); public native void on(@NonNls String event, ModalHandler handler); }
  • 23. Migrate Large GWT Applications Model View Presenter
  • 24. Migrate Large GWT Applications MVP GWTP ● DI through GIN ● Simple and powerful history management ● Support for nested presenters ● Lifecycle events using GWT eventbus ● Lazy instantiation for presenters and views ● Effortless and efficient code splitting Widget ↔ Elemental2 Adapter
  • 25. Migrate Large GWT Applications Escape From Callback Hell
  • 26. Migrate Large GWT Applications RxGWT GWT specific bindings for RxJava Turn callbacks into “Rx types” Developed and maintained by @ibaca Documentation ● http://reactivex.io/ ● https://github.com/ReactiveX/RxJava ● https://github.com/intendia-oss/rxgwt
  • 27. Migrate Large GWT Applications interface FooService extends RemoteService { void prepare(); void main(); void cleanup(); } interface FooServiceAsync { void prepare(AsyncCallback<Void> async); void main(AsyncCallback<Void> async); void cleanup(AsyncCallback<Void> async); }
  • 28. Migrate Large GWT Applications public class ExecuteInOrder implements EntryPoint { @Override public void onModuleLoad() { FooServiceAsync service = GWT.create(FooService.class); service.prepare(new AsyncCallback<Void>() { public void onFailure(Throwable throwable) { console.log("Failed: " + throwable.getMessage()); } public void onSuccess(Void aVoid) { service.main(new AsyncCallback<Void>() { public void onFailure(Throwable throwable) { console.log("Failed: " + throwable.getMessage()) } public void onSuccess(Void aVoid) { service.cleanup(new AsyncCallback<Void>() { public void onFailure(Throwable throwable) { console.log("Failed: " + throwable.getMessage()) } public void onSuccess(Void aVoid) { console.log("Finished") } }); } }); } }); } }
  • 29. Migrate Large GWT Applications public class ExecuteInOrder implements EntryPoint { @Override public void onModuleLoad() { FooServiceAsync service = GWT.create(FooService.class); Completable prepare = Completable.fromEmitter(em -> service.prepare(callback(em))); Completable main = Completable.fromEmitter(em -> service.main(callback(em))); Completable cleanup = Completable.fromEmitter(em -> service.cleanup(callback(em))); Completable.concat(prepare, main, cleanup) .doOnError(throwable -> console.log("Failed: " + throwable.getMessage())) .doOnCompleted(() -> console.log("Finished")) .subscribe(); } AsyncCallback<Void> callback(CompletableEmitter emitter) { return new AsyncCallback<Void>() { @Override public void onFailure(Throwable throwable) { emitter.onError(throwable); } @Override public void onSuccess(Void aVoid) { emitter.onCompleted(); } }; } }
  • 30. Migrate Large GWT Applications public class RxDemo implements EntryPoint { @Override public void onModuleLoad() { Observable.interval(1, SECONDS) .take(10) .flatMapSingle(this::xhr) .forEach(timestamp -> console.log(timestamp)); } Single<String> xhr(long id) { String url = "http://server.test-cors.org/server?enable=true&id=" + id; return Single.fromEmitter(emitter -> { XMLHttpRequest xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = event -> emitter.onSuccess(new Date().toLocaleTimeString()); xhr.send(); }); } }
  • 31. Migrate Large GWT Applications Annotation Processing
  • 32. Migrate Large GWT Applications Annotation Processing Registries Composite GIN MBUI EsDoc
  • 33. Migrate Large GWT Applications package org.jboss.hal.processor; @AutoService(Processor.class) public class NameTokenProcessor extends AbstractProcessor { private final Set<TokenInfo> tokenInfos; public NameTokenProcessor() { super(NameTokenProcessor.class, TEMPLATES); tokenInfos = new HashSet<>(); } @Override protected boolean onProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { for (Element e : roundEnv.getElementsAnnotatedWith(NameToken.class)) { TypeElement tokenElement = (TypeElement) e; NameToken nameToken = tokenElement.getAnnotation(NameToken.class); TokenInfo tokenInfo = new TokenInfo(nameToken.value()[0]); tokenInfos.add(tokenInfo); ... } return false; } }
  • 34. Migrate Large GWT Applications <#-- @ftlvariable name="generatedWith" type="java.lang.String" --> <#-- @ftlvariable name="packageName" type="java.lang.String" --> <#-- @ftlvariable name="className" type="java.lang.String" --> <#-- @ftlvariable name="tokenInfos" type="java.util.Set<org.jboss.hal.processor.NameTokenProcessor.TokenInfo>" --> package ${packageName}; import ... /* * WARNING! This class is generated. Do not modify. */ @Generated("${generatedWith}") public class ${className} implements org.jboss.hal.meta.token.NameTokens { private final Set<String> tokens; public ${className}() { this.tokens = new HashSet<>(); <#list tokenInfos as tokenInfo> this.tokens.add("${tokenInfo.token}"); </#list> } @Override public Set<String> getTokens() { return tokens; } }
  • 35. Migrate Large GWT Applications Annotation Processing Freemarker Templates Use 3rd party libraries ● https://github.com/google/auto/tree/master/common ● https://github.com/google/auto/tree/master/service Test your annotation processor! ● https://github.com/google/compile-testing
  • 36. Migrate Large GWT Applications public class FormTest { @Test public void simpleForm() { Compilation compilation = javac() .withOptions("-proc:only") .withProcessors(new MbuiViewProcessor()) .compile(JavaFileObjects.forResource("SimpleForm.java")); assertThat(compilation) .generatedSourceFile("Mbui_SimpleForm") .hasSourceEquivalentTo( JavaFileObjects.forResource("Mbui_SimpleForm.java")); } }
  • 37. Migrate Large GWT Applications Build Process
  • 38. Migrate Large GWT Applications Build & Run Maven First 3rd Party Libraries: Frontend Maven Plugin ● NPM ● Bower ● Grunt Build: Maven Plugin for GWT by Thomas Broyer Run: Browser Dev Tools
  • 39. Migrate Large GWT Applications Open Issues
  • 40. Migrate Large GWT Applications Open Issues GIN Code Splitting JSNI GWT.create() ClientBundle / i18n
  • 41. Migrate Large GWT Applications Links https://github.com/hal/hal.next/ https://github.com/hal/elemento http://www.patternfly.org/ http://wildfly.org/
  • 42. Migrate Large GWT Applications Thanks! Questions?