Download Taming the Spaghetti: Rich Web Applications With Errai

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Taming the Spaghetti: Rich
Web Applications With Errai
Christian Sadilek (@csadilek)
Lincoln Baxter III (@lincolnthree)
JBoss / Red Hat
Another Java Web Framework?
Photo by: darkuncle From: Flickr
What has changed?
Fast execution
Consistent runtime
Spec compliant
More application logic in the browser
Photo by: Kyle Nishioka (madmarv00) From: Flickr
Large talent pool
Great tooling
Amazing ecosystem
Photo by: jeffeaton
From: Flickr
Java-to-JavaScript Compiler
Cross-browser support
Forc
ed
into
Serv
er-s
ide
Heavy up-front optimizations
prog
ram
m
com
atic
U
pilat
ion
Development Mode
I co
mpo
nen
at ru
ntim
e
Code and Refresh development
Debug client and server as Java code in your IDE
ts
Project mantras
Declarative rocks
Boilerplate sucks
Code it once
Project features
Java EE 6 APIs
Unintrusive marshalling
Peer to peer communication
Example project layout
src/main/java
HelloWorld.gwt.xml
client
HelloWorldClient.java
shared
HelloWorldEntity.java
server
HelloWorldService.java
src/main/webapp
HelloWorld.html
WEB-INF
web.xml
src/main/resources
ErraiApp.properties
}
Compiled to JavaScript
Photo by: CORE-Materials
From: Flickr
CDI in the browser
Injecting and firing events
@Inject @Updated
private Event<Document> updatedDocEvent;
...
button.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
updatedDocEvent.fire(document);
}
});
CDI in the browser
Observing events
public void onUpdatedDocument(@Observes @Updated Document doc) {
// received updated document
}
On the client
On the server
Or both (events are sent across the wire)
Uniform programming model on the client and server
CDI in the browser
Producers
@Produces @Supported
public MyBaseWidget createWidget() {
return (Canvas.isSupported()) ? new MyHtml5Widget() : new MyDefaultWidget();
}
@Inject @Supported
private MyBaseWidget widget;
Remote Calls
Errai RPC
@Remote
public interface HappyService {...}
shared
@Service
public class HappyServiceImpl implements HappyService {
public boolean isEveryoneHappy() {
return true; // this could be a lie!
}
}
server
@Inject
private Caller<HappyService> happyService;
...
happyService.call(new RemoteCallback<Boolean>() {
public void callback(Boolean response) {
// process response
}
}).isEveryoneHappy();
client
Browser
Browser
Web Sockets
Browser
Long Polling
Long Polling
Server
Long Polling
Long Polling
Browser
Browser
Web Sockets
Browser
Remote Calls
Errai JAX-RS
@Path("customers")
public interface CustomerService {
@POST
@Consumes("application/json")
@Produces("text/plain")
public long createCustomer(Customer customer);
}
@Inject
private Caller<CustomerService> customerService;
...
customerService.call(new RemoteCallback<Long>() {
public void callback(Long response) {
Window.alert(response);
}
}).createCustomer(customer);
Marshalling
@Portable on simple entities
@Portable
public class Person {
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
}
Marshalling
@Portable on simple entities
@Portable
public class Person {
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
}
Marshalling
@Portable on immutable entities
@Portable
public class Person {
private final String name;
private final int age;
private Person(String name, int age) {
this.name = name;
this.age = age;
}
public static Person create(@MapsTo("name") String name, @MapsTo("age") int age) {
return new Person(name, age);
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Demo!
JPA in the browser
public class RecordStoreView extends Composite {
...
@Inject
private EntityManager em;
public void onSaveButtonClicked(ClickEvent event) {
em.persist(album);
em.flush();
}
}
JPA in the browser
@Entity
@NamedQuery(name="selectAlbumByName",
query="SELECT a FROM Album a WHERE a.name=:name")
public class Album {
@GeneratedValue @Id
private Long id;
private Date releaseDate;
private String name;
@ManyToOne
private Artist artist;
}
Errai UI - HTML5
<!DOCTYPE html>
<link href="css/bootstrap.css" rel="stylesheet">
<form data-field="form">
<legend>Log in to your account</legend>
<label for="username">Username</label>
<input data-field="username" id="username" type="text" placeholder="Username">
<label for="password">Password</label>
<input data-field="pass" id="password" type="password" placeholder="Password">
<button data-field="submit">Log in</button>
<button>Cancel</button>
</form>
Errai UI - HTML5
@Templated
public class LoginForm extends Composite {
@Inject @DataField
private TextBox username;
@Inject @DataField("pass")
private PasswordTextBox password;
@DataField
private Button submit = new Button();
@EventHandler("submit")
private void onLogin(ClickEvent e) {
// send login request
}
}
Errai UI - Data Binding
@Templated
public class LoginForm extends Composite {
@Inject @Bound @DataField
private TextBox username;
@Inject @Bound @DataField("pass")
private PasswordTextBox password;
@Inject @Model
private User user;
@EventHandler("submit")
private void onLogin(ClickEvent e) {
login(user);
}
}
Errai UI - Navigation
@Templated
public class LoginForm extends Composite {
...
@Inject
private TransitionTo<WelcomePage> welcomePage;
public onLoginSuccessful() {
welcomePage.go()
}
}
@Templated @Page
public class WelcomePage extends Composite {
}
Behind the Scenes:
How does it all work?
java.lang.reflect
Class.forName()
Deferred Binding
A feature of the GWT compiler that allows to
replace or generate types at runtime
<replace-with class="com.google.gwt.user.client.ui.impl.PopupImplMozilla">
<when-type-is class="com.google.gwt.user.client.ui.impl.PopupImpl"/>
<when-property-is name="user.agent" value="gecko1_8"/>
</replace-with>
<generate-with class="org.jboss.errai.bus.rebind.RpcProxyLoaderGenerator">
<when-type-assignable
class="org.jboss.errai.bus.client.framework.RpcProxyLoader"/>
</generate-with>
Don’t write this by hand!
// SELECT a FROM Album a WHERE a.name=:name
super.namedQueries.put("selectAlbumByName", new TypedQueryFactory(this, Album.class,
new ErraiParameter[] { new ErraiParameter("name", 0, String.class) }) {
protected TypedQuery createQuery() {
return new ErraiTypedQuery(entityManager, actualResultType, parameters) {
protected Comparator getComparator() {
return null;
}
public boolean matches(JSONObject candidate) {
return Comparisons.nullSafeEquals(
JsonUtil.basicValueFromJson(
candidate.get("name"), String.class),
getParameterValue("name"));
}
};
}
});
Photo by: Tim Bartel (avatar-1) From: Flickr
Photo by: Michelle Lowry From: Wikimedia Commons
Future Work
Data synchronization (JPA and OT)
Security Framework
Errai mobile
JRebel support
Photo by: Mike Lewis (pescatello)
From: Flickr
Get in touch!
Website: http://jboss.org/errai
IRC: #errai on freenode
Twitter: @jbosserrai
Photo by: CHIN.DENG
From: Flickr
http://github.com/errai
Related documents