Escolar Documentos
Profissional Documentos
Cultura Documentos
Jeff Dwyer
Currently: (rails)
Today
• What and Why GWT?
• Demo ToCollege.net
• Real Apps
• Integration Patterns
• Hibernate
• Security
• Gears
Goal
YUI Flex
Dojo Silverlight
Rico Echo GWT
Script.aclo.us Lazlo
jMaki JSF
Why GWT
• GWT Brings Java Software Development
Best Practices to AJAX HTML
• GWT is DHTML + JavaScript
• JavaScript doesn’t scale... with increased
development staff.
• Best Practices: i18n, History, ImageBundle
Features
• Easy RPC: Single domain for client & server
• History Mechanism
• Extremely Cacheability
• Browser Compatibility
• Real Debugging & JUnit & I18N
Benefits & Joys
• One Domain Model
• Static Typing
• IDE Refactoring, Code Completion
• FindBugs, PMD, Checkstyle, Metrics
• Hosted Mode. Real Debugging.
• Maven
Tradeoffs?
• Code Size?
• Think HttpRequests > size
• Cache Forever
• Debugable w/ Firebug?
• Use pretty mode or real debugger
• Script.aculo.us?
• JSNI is great, or whip together yourself.
• SEO...
How it Works
• Swing + CSS
• Java to JavaScript compiler
• Compressed and Obfuscated by default
• Include in HTML with <script> and <div>
• Locale Specific Compilation
Demo
• www.ToCollege.net
• http://code.google.com/p/tocollege-net/
ToCollege.net Stack
• MySQL / Hibernate
• Compass
• Spring MVC 2.5
• Acegi & OpenID
• SiteMesh & FreeMarker
• GWT 1.5 Integration SEO, Security
• Also: Facebook, Maven
VerticalLabel
VerticalLabel.java
public class VerticalLabel extends Composite {
public interface LetterImages extends ImageBundle {
AbstractImagePrototype A();
AbstractImagePrototype B();
AbstractImagePrototype sY();
AbstractImagePrototype sZ();
AbstractImagePrototype SPACE();
}
private FlowPanel mainPanel;
private HashMap<Character, AbstractImagePrototype> allImages;
private static final LetterImages images =
(LetterImages) GWT.create(LetterImages.class);
public VerticalLabel(String text) {
if (allImages == null) {
createMap();
}
mainPanel = new FlowPanel();
mainPanel.setStylePrimaryName("vertical-label");
setText(text);
initWidget(mainPanel);
}
private void setText(String text) {
mainPanel.clear();
for (int i = text.length() - 1; i >= 0; i--) {
char c = text.charAt(i);
mainPanel.add(getImage(c));
}
}
}
Deferred Binding
• The Joy of IE6 w/ Apologies to Joel Webber
Interface:
public abstract boolean compare(Element e1, Element e2);
Standard:
public native boolean compare(Element e1, Element e2) /*-{
return (e1 == e2);
}-*/;
IE6:
public native boolean compare(Element e1, Element e2) /*-{
if (!e1 && !e2)
return true;
else if (!e1 || !e2)
return false;
return (e1.uniqueID == e2.uniqueID);
}-*/;
public class ForumApp extends GWTApp implements
HistoryListener {
public ForumApp(int pageID) {
History
if (initToken.length() > 0) {
onHistoryChanged(initToken);
(Back Button)
}
History.addHistoryListener(this);
}
// #School~486~20
// #UserForumPost~12~0
// #UserForumPost~12
public void onHistoryChanged(String historyToken) {
ForumCommand fc = new ForumCommand();
fc.setId(Long.parseLong(tok[1]));
if (tok.length == 3) {
fc.setStart(Integer.parseInt(tok[2]));
}
fc.setType(tok[0]);
load(fc);
}
}
http://www.tocollege.net/forums.html#SchoolForumPost~112
JRE SampleApp.java
Emulation 1.5 Source
GWT
Compiler
IE (Fr)
function gGd(a){return (this==null?null:this)===(a==null?null:a)}
function hGd(){return gmb}
function iGd(){return this.$H||(this.$H=++Cvc)}
Gecko Gecko
IE (En) ... (...)
(Fr) (En)
JRE SampleApp.java
Emulation 1.5 Source
GWT
Compiler
IE
JRE SampleApp.java
Emulation 1.5 Source
GWT
Compiler
Spring <html>
<script language='javascript'
MVC src='com.apress.progwt.Sample
PHP App.nocache.js'></script>
<div id=”gwt-slot”></div>
Rails </html> IE
Simple GWT Integration
protected void loadError(Exception e) {
panel.add(new Label("Error"));
panel.add(new Label(e.getMessage()));
RootPanel.get(“gwt-preload”).setVisible(false);
RootPanel.get(“gwt-slot”).add(panel);
}
Real Applications
• Integration
• JavaScript & FreeMarker Macros
• Hibernate
• Command Pattern
• Security
• XSRF & Command Pattern
• Gears
Integration
• div id == Java Code
• What about multiple component talking to
each other?
• What about re-use?
• This is where people screw up. Many
modules, etc.
• Solution? Leverage JavaScript.
Spring MVC Integration
GWTDispatcher
•
Hibernate4GWT
GWT Client Server
GWT
User RPC User
&
Application Hib4GWT
Application
1..1 1..1
School School
School School
Overhead.
Can’t simply call save()
Cons Must implement
Lazy collections != null
Hibernate4GWT
RPC Service
public interface GWTSchoolService extends RemoteService {
Spring Security
Server
PostsList getForum(String tagname, int start, int max)
throws SiteException;
Command
Spring Security
XSRF Protection
Server
SiteCommand executeAndSaveCommand(SiteCommand comm)
throws SiteException;
Command Pattern
• Hibernate Integration
• Authorization
• XSRF
• Gears / Offline
save(Object o)
• Dangerous
• Client can modify anything.
Command Pattern
•
Gears (1)
public class SimpleGearsDatabase extends Database implements ClientDB {
public SimpleGearsDatabase(String databaseName) throws GearsException {
super(databaseName);
}
public ResultSet execute(String statement, Object... args) {
String[] strs = new String[args.length];
//convert args -> strs
return execute(statement, strs);
}
public void createKeyedStringStore(String tableName) {
execute("drop table if exists " + tableName);
execute("create table if not exists " + tableName
+ " (key varchar(255), json text )");
}
public void addToKeyedStringStore(String tableName, String key,
String value) {
execute("insert into " + tableName + " values (?, ?)", key, value);
}
}
}
Gears (2)
public <T> List<T> query(String sql, GearsRowMapper<T> mapper,
Object... args) {
this.schoolService = gwtApp.getSchoolService();
this.userService = gwtApp.getUserService();
if (Gears.isInstalled()) {
try {
db = new SimpleGearsDatabase("tocollege.net");
db.createKeyedStringStore(MATCH);
db.createKeyedStringStore(PROCESSTYPE);
} catch (GearsException e) {
Log.warn("No Gears " + e.getMessage());
}
}
if (db == null) {
Log.info("Creating Empty Client DB");
db = new EmptyClientDB();
}
}
public void matchSchool(final String query,
final AsyncCallback<List<String>> origCallback) {
List<String> stored = db.getFromKeyedStringStore(MATCH, query,
stringMapper);
if (stored != null && !stored.isEmpty()) {
origCallback.onSuccess(stored);
return;
} else {
schoolService.getSchoolsMatching(query,
new AsyncCallback<List<String>>() {
public void onFailure(Throwable caught) {
origCallback.onFailure(caught);
}
public void onSuccess(List<String> result) {
origCallback.onSuccess(result);
for (String string : result) {
db.addToKeyedStringStore(MATCH, query,
string);
}
}
});
}
}
Thanks!
• ToCollege.net &
• http://code.google.com/p/tocollege-net/