Comparing GWT Transport Mechanisms

Post on 11-Nov-2014

1.878 views 0 download

Tags:

description

Presentation about transport mechanisms in GWT, held at GWT.create 2013 in San Francisco and Frankfurt.

Transcript of Comparing GWT Transport Mechanisms

Leif ÅstrandSenior Vaadin Expert

Comparing GWT Transport Mechanisms

torsdag 19 december 13

public class Contact { private String name; private int yearOfBirth;

private List<String> emailAddresses;

private Address address; public static class Address { private String street; private String city; }

// + Getters and setters

}

Contact

torsdag 19 december 13

AJAX

torsdag 19 december 13

Good

• It just works

Bad

• Low level

RequestBuilder

torsdag 19 december 13

Real world usage

11 %torsdag 19 december 13

RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);try { builder.sendRequest(requestData, new RequestCallback() {

@Override public void onResponseReceived(Request request, Response response) { int statusCode = response.getStatusCode(); String text = response.getText(); }

@Override public void onError(Request request, Throwable exception) { // TODO Handle asynchronous problems

} });} catch (RequestException e) { // TODO Handle synchronous problems}

RequestBuilder

torsdag 19 december 13

Contact

String

torsdag 19 december 13

String data = contact.getName();data += "," + contact.getYearOfBirth();

String[] parts = data.split(",");contact.setName(parts[0]);contact.setYearOfBirth(Integer.parseInt(parts[1]));

String conversion

torsdag 19 december 13

String data = contact.getName();data += "," + contact.getYearOfBirth();

String[] parts = data.split(",");contact.setName(parts[0]);contact.setYearOfBirth(Integer.parseInt(parts[1]));

String conversion

torsdag 19 december 13

<?xml version="1.0" encoding="UTF-8"?><contact name="John Doe" yearOfBirth="1900"> <address street="HappyStreet 1" city="Turku" /> <email address="john@doe.com" /> <email address="johndoe@gmail.com" /></contact>

XML

torsdag 19 december 13

Document document = XMLParser.parse(string);Element contactElement = document.getDocumentElement();

contact.setName(contactElement.getAttribute("name"));contact.setYearOfBirth(Integer.parseInt(

contactElement.getAttribute("yearOfBirth")));contact.setAddress(parseAddress(

contactElement.getElementsByTagName("address").item(0)));

NodeList emailTags = contactElement.getElementsByTagName("email");for (int i = 0; i < emailTags.getLength(); i++) { contact.getEmailAddresses().add(

((Element) emailTags.item(i)).getAttribute("address"));

}

XML parsing

torsdag 19 december 13

Good

• It’s “standard”• Lots of server-side

libraries

Bad

• Verbose data• Verbose code• Document markup

language• Not so common in

the GWT ecosystem• Not typesafe

XML

torsdag 19 december 13

{ name: "John Doe", yearOfBirth: 1900, address: { street: "Happy Street 1", city: "Turku" }, emailAddresses: ["john@doe.com", "johndoe@gmail.com"]}

JSON

torsdag 19 december 13

JSONObject json = JSONParser.parseStrict(string).isObject();

contact.setName(json.get("name").isString().stringValue());contact.setYearOfBirth(

(int) json.get("yearOfBirth").isNumber().doubleValue());contact.setAddress(

parseAddress(json.get("address").isObject()));

JSONArray emailAddresses = json.get("emailAddresses").isArray(); for (int i = 0; i < emailAddresses.size(); i++) { contact.getEmailAddresses().add(

emailAddresses.get(i).isString().stringValue()); }}

JSONValue parsing

torsdag 19 december 13

Good

• It’s “standard”• Extensive library

support• Compact format

Bad

• Not completely typesafe

• JSONValue parsing code is verbose

JSON

torsdag 19 december 13

public class ContactJso extends JavaScriptObject { public native String getName() /*-{ return this["name"]; }-*/;

public native int getYearOfBirth() /*-{ return this["yearOfBirth"]; }-*/;

public native AddressJso getAddress() /*-{ return this["address"]; }-*/;

public native JsArrayString getEmailAddresses() /*-{ return this["emailAddresses"]; }-*/;}

JavaScriptObject

torsdag 19 december 13

Good

• Very efficient• Very little boilerplate

Bad

• /*-{ ... }-*/; syntax• Can’t share code

with the server

JavaScriptObject

torsdag 19 december 13

What about the server?

torsdag 19 december 13

JAX-RS

torsdag 19 december 13

Good

• It’s “standard”• Full control

Bad

• About as verbose as JSONValue

• Not suitable for GWT

• The Software shall be used for Good, not Evil.

org.json

torsdag 19 december 13

ObjectMapper mapper = new ObjectMapper();try { Contact contact = mapper.readValue(string, Contact.class);} catch (VariousExceptions e) { // Do something sensible}

Jackson on the server

torsdag 19 december 13

ReflectionCode generation

torsdag 19 december 13

public static interface ContactMapper extends ObjectMapper<Contact> {}

public Contact parseContact(String string) { ContactMapper mapper = GWT.create(ContactMapper.class); Contact contact = mapper.read(string); return contact;}

gwt-jackson

torsdag 19 december 13

Good

• Minimal boiler plate• Can share code

between server and client

• Plugin for JAX-RS

Bad

• You’re still just sending objects

Jackson

torsdag 19 december 13

Using interfaces instead of objects

torsdag 19 december 13

public interface Contact { public void setName(String name); public String getName();

public void setYearOfBirth(int yearOfBirth); public int getYearOfBirth();

public void setAddress(Address address); public Address getAddress();

public void setEmailAddresses(List<String> addresses); public List<String> getEmailAddresses();}

Contact interface

torsdag 19 december 13

interface AddressBookFactory extends AutoBeanFactory { public AutoBean<Contact> contact(); }

public void autobeanExample() { AddressBookFactory factory = GWT.create(AddressBookFactory.class); AutoBean<Contact> contactBean = factory.contact(); Contact contact = contactBean.as();

contact.setName("John Doe"); contact.setYearOfBirth(1900); contact.setEmailAddresses(Arrays.asList("john@doe.com", "johndoe@gmail.com"));

String json = AutoBeanCodex.encode(contactBean).getPayload();

AutoBean<Contact> bean = AutoBeanCodex.decode(factory, Contact.class, json);

contact = bean.as(); }

AutoBean

torsdag 19 december 13

Good

• Flexible foundation for custom implementations of interface methods

Bad

• Can’t use classes

AutoBean

torsdag 19 december 13

Intercepting interface methods allows us to...

Send partial updates

Manage entity identity

Use instance methods for RPC

torsdag 19 december 13

public interface AddressBookRequestFactory extends RequestFactory { public ContactRequest contactRequest();}

@Service(Contact.class)public interface ContactRequest extends RequestContext { public Request<List<ContactProxy>> getContacts(); public InstanceRequest<ContactProxy, Void> update();}

public void setupRequestFactory() { this.factory = GWT.create(AddressBookRequestFactory.class); this.eventBus = new SimpleEventBus(); this.factory.initialize(this.eventBus);}

RequestFactory - setting it up

torsdag 19 december 13

public void contactRequest() { ContactRequest contactRequest = factory.contactRequest(); contactRequest.getContacts().with("address").fire( new Receiver<List<ContactProxy>>() { @Override public void onSuccess(List<ContactProxy> contacts) { updateUI(contacts); } });}

public void updateContact(ContactProxy proxy) { ContactRequest contactRequest = factory.contactRequest(); contactRequest.update().using(proxy).fire();}

RequestFactory -client-side usage

torsdag 19 december 13

public class Contact { // + fields, setters and getters public Integer getId() { return this.id; }

public Integer getVersion() { return this.version; }

public void update() { ContactDAO.update(this); }

public static List<Contact> getContacts() { return ContactDAO.fetchContacts(); }}

RequestFactory - server-side

torsdag 19 december 13

Good

• Entities do not need to be GWT compatible

• Combines RPC and entity management

• Automatic request handling

Bad

• Complex setup• Heavy coupling with

the server

RequestFactory

torsdag 19 december 13

Real world usage

7 %torsdag 19 december 13

Why not just send Java objects?

torsdag 19 december 13

public Object[] sendAndReceive(Object[] objects);

Send and receive objects

public interface ContactService { public void saveContact(Contact contact); public List<Contact> getContacts();}

torsdag 19 december 13

public interface ContactService { public AsyncResult<Void> saveContact(Contact contact); public AsyncResult<List<Contact>> getContacts();}

Asynchronousity

public interface ContactServiceAsync { public void saveContact(Contact contact, AsyncCallback<Void> callback); public void getContacts(AsyncCallback<List<Contact>> callback);}

torsdag 19 december 13

Good

• Simple but powerful concept

• The default solution

Bad

• You (almost) always send the entire object graph

GWT-RPC

torsdag 19 december 13

Most popular!

53 %torsdag 19 december 13

[-4, 2, 42, [“Foo”, “Bar”]]

2 | Foo | Bar | 42 | 2 | -4

torsdag 19 december 13

What if we put the server in control?

torsdag 19 december 13

torsdag 19 december 13

State synchronization

torsdag 19 december 13

public class ContactState extends SharedState { public String name;

@DelegateToWidget public int yearOfBirth;}

@Overridepublic TextButtonState getState() { return (TextButtonState) super.getState();}

addStateChangeHandler("name", new StateChangeHandler() { @Override public void onStateChanged(StateChangeEvent stateChangeEvent) { String name = getState().name; doSomethingWithTheName(name); }});

Reacting to state changes

torsdag 19 december 13

Events

torsdag 19 december 13

public interface ContactRpc extends ServerRpc { public void deleteContact(int id);}

// Sending RPC from the clientpublic void sendDelete(int contactId) { getRpcProxy(ContactRpc.class).deleteContact(contactId);}

//Registering RPC handler on the serverregisterRpc(new ContactRpc() { @Override public void deleteContact(int id) { ContactDAO.deleteById(id); }});

RPC

torsdag 19 december 13

Good

• Stateful server• Server push

Bad

• Stateful server

Vaadin

torsdag 19 december 13

Real world usage

6 %torsdag 19 december 13

What if we completely hide the transport?

torsdag 19 december 13

Local? Remote? It’s all the same!

torsdag 19 december 13

// Fire event from the client or the server @InjectEvent<Contact> contactEvent;

public void updateContact(Contact contact) { contactEvent.fire(contact);}

// Listen to event on the client or the serverpublic void contactUpdateObserver(@Observes Contact contact) { ContactDAO.updateContact(contact);}

Errai CDI events

torsdag 19 december 13

Good

• Transparent communication

• Different protocols• Server push

Bad

• Transparent communication

Errai Bus

torsdag 19 december 13

Which one should I use?

torsdag 19 december 13

Did I get some detail wrong?

Questions?

Please rate the talk at gwtcreate.com/agenda? leif@vaadin.com

torsdag 19 december 13