Architecting your GWT applications with GWT-Platform - Lesson 02
1. Architecting your GWT
application with GWT-
Platform
Juan Manuel Rojas R.
http://rhemsolutions.com/ Lima, Perú 26/10/2012
2. Architecting your GWT application
Google found that a Model-view-presenter
(MVP) architecture works best when
developing GWT apps
https://developers.google.com/web-toolkit/articles/mvp-
architecture
Model View Presenter Frameworks
Mvp4g
gwt-dispatch
gwt-platform
3. GWT-Platform
It's an open source MVP framework, that
supports many nice features of GWT, including
code splitting and history management, with a
simple annotation-based API.
5. Google Plugin for Eclipse
Update sites
Eclipse 4.2 (Juno)
http://dl.google.com/eclipse/plugin/4.2
6. GWTP Eclipse Plugin
To install the GWTP Eclipse Plugin, from
Eclipse go to Help > Install New Software
Click on Add...
Name: GWTP
Location: http://plugin.gwt-platform.googlecode.com/hg/update
7. Clean example code
1. Delete theme lines from Module.gwt.xml
2. Delete files from
Entry point
client package
GreetingService package com.example.client;
GreetingServiceAsync
server package, import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Window;
GreetingServiceImpl
shared packaged public class FirstProject implements EntryPoint {
FieldVerifier
src/test/java public void onModuleLoad() {
GwtTestFirstProject Window.alert("empty project");
}
src/test/resources
}
FirstProjectJUnit.gwt.xml
3. Clean Css file and html table code src/main/webapp
4. Delete servlet definition from web.xml src/main/webapp/WEB-INF
8. Dependency injection (DI)
Separate behavior from dependency resolution.
Injects the dependent element (object or value
etc) to the destination automatically.
Reduction of boilerplate code in the application
objects since all work to initialize or set up
dependencies is handled by a provider
component.
http://en.wikipedia.org/wiki/Dependency_injection
9. Dependency injection for GWT
google-gin
GIN is built on top of Guice and uses (a subset
of) Guice's binding language.
<!-- google-gin -->
<dependency>
<groupId>com.google.gwt.inject</groupId>
<artifactId>gin</artifactId>
<version>2.0.0</version>
<exclusions>
<exclusion>
<groupId>com.google.gwt</groupId>
<artifactId>gwt-servlet</artifactId>
</exclusion>
</exclusions>
</dependency>
10. Dependency injection for Java 5
google-guice
Think of Guice's @Inject as the new new.
Guice embraces Java's type safe nature using
generics and annotations.
<!-- google guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
11. Dependency injection GIN
Constructor injection Field injection
public class ClientPlaceManager { public class ColaboradorPresenter {
@Inject @Inject Messages messages;
public ClientPlaceManager(final EventBus eventBus,
final TokenFormatter tokenFormatter) { public ColaboradorPresenter() {
//eventBus and tokenFormatter are not null //messages is null
}
}
} protected void onBind() {
//messages is not null
}
}
12. Dependency injection GIN (Continuation)
@Provides Methods
When you need create and initialize an object.
public class ClientModule extends AbstractPresenterModule {
@Provides
@Singleton
public AppRequestFactory createRequestFactory(EventBus eventBus, MyDefaultRequestTransport
requestTransport) {
AppRequestFactory factory = GWT.create(AppRequestFactory.class);
factory.initialize(eventBus, requestTransport);
return factory;
}
}
public class ColaboradorPresenter {
private final AppRequestFactory factory;
How to inject @Inject
public ColaboradorPresenter(Provider<AppRequestFactory> provider){
factory = provider.get();
}
}
14. Setting GWTP Create the directories
com.example.client
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER; |--presenter
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|--view
|--place
@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD }) public class NameTokens {
@Retention(RUNTIME)
public @interface DefaultPlace { }
}
import com.google.web.bindery.event.shared.EventBus;
public class ClientPlaceManager extends PlaceManagerImpl {
private final PlaceRequest defaultPlaceRequest;
@Inject
public ClientPlaceManager(final EventBus eventBus,
final TokenFormatter tokenFormatter,
@DefaultPlace final String defaultPlaceNameToken) {
super(eventBus, tokenFormatter);
this.defaultPlaceRequest = new PlaceRequest(defaultPlaceNameToken);
}
public void revealDefaultPlace() {
revealPlace(defaultPlaceRequest, false);
}
15. Setting GIN for GWTP
Inheriting the GIN module
<inherits name="com.google.gwt.inject.Inject"/>
Create a gin package in the client side
public class ClientModule extends AbstractPresenterModule {
Define objects
@Override available for
protected void configure() { injection
install(new DefaultModule(ClientPlaceManager.class));
}
}
import com.google.web.bindery.event.shared.EventBus; Getters methods
@GinModules(ClientModule.class)
public interface ClientGinjector extends Ginjector {
for get objects
EventBus getEventBus();
PlaceManager getPlaceManager();
}
If GIN can't find a binding for a class, it falls back to calling GWT.create() on that
class.
16. Setting GIN for GWTP(Continuation)
Configure your EntryPoint
public class FirstProject implements EntryPoint {
private final ClientGinjector ginjector = GWT.create(ClientGinjector.class);
public void onModuleLoad() {
// This is required for Gwt-Platform proxy's generator
DelayedBindRegistry.bind(ginjector);
ginjector.getPlaceManager().revealCurrentPlace();
}
}
Add the next properties to your Module.gwt.xml
<module>
...
<define-configuration-property name='gin.ginjector' is-multi-valued='false' />
<set-configuration-property name='gin.ginjector' value='com.example.client.gin.ClientGinjector' />
</module>
18. GWT-Platform and GXT3(Continuation)
Tokens
Most presenters have a token so the user can navigate.
When there is not token the default presenter is shown.
You can navigate from one presenter to another by:
● Typing another url PlaceRequest request = new PlaceRequest("inicio");
● Using a Hyperlink Widget placeManager.revealPlace(request);
● Using a PlaceRequest
21. GWT-Platform and GXT3(Continuation)
Popup Presenters
Is a presenter widget
that is shown inside
a popup dialog.
For create Popup Presenters with GXT Window you need
the following classes
GXTPopupViewImpl.java
GXTPopupViewWithUiHandlers.java
22. GWT-Platform and GXT3(Continuation)
All presenters are composed of three files if you will use
UIBinder
All presenters have a inner interface that view implements.
24. GWT-Platform and GXT3(Continuation)
Presenter lifecycle
1. Presenters are Singleton so it is instantiated once.
2. prepareFromRequest(): Is where you can get url
parameters.
3. onBind(): Is called when the presenter is instantiated.
4. onReveal(): Is called whenever the Presenter was not
visible on screen and becomes visible.
5. onHide(): Is called whenever the Presenter was visible
on screen and is being hidden.
6. onReset(): Is called whenever the user navigates to a
page that shows the presenter, whether it was visible or
not.
27. First Presenter LayoutPresenter
(Continuation)
Deprecated shared.EventBus
GWTP Eclipse Plugin use EventBus from event.shared
next this package was deprecated and change to web.
bindery.event.shared.
* Is important to do the next in every presenter you create
with GWTP Eclipse Plugin
Delete
import com.google.gwt.event.shared.EventBus
Replace by
import com.google.web.bindery.event.shared.EventBus;
28. First Presenter LayoutPresenter
(Continuation)
Add the next field to LayoutPresenter
import com.google.gwt.event.shared.GwtEvent.Type;
//for nested presenters
@ContentSlot public static final Type<RevealContentHandler<?>> SLOT_content =
new Type<RevealContentHandler<?>>();
Modify LayoutView.ui.xml
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder'
xmlns:g='urn:import:com.google.gwt.user.client.ui'
xmlns:gxt= "urn:import:com.sencha.gxt.widget.core.client"
xmlns:container= "urn:import:com.sencha.gxt.widget.core.client.
container" >
<container:Viewport>
<!--for nested presenter -->
<gxt:ContentPanel ui:field="contentPanel" borders="false"
headerVisible= "false" bodyBorder= "false" />
</container:Viewport>
</ui:UiBinder>
31. First Presenter LayoutPresenter
(Continuation)
Add the next field to LayoutView
@UiField ContentPanel contentPanel;//for nested presenter
Add the next method to LayoutView
@Override
public void setInSlot(Object slot, Widget content) {
if(slot == LayoutPresenter.SLOT_content){
contentPanel.clear();
if(content != null){
contentPanel.add(content);
contentPanel.forceLayout();
}
return;
}
super.setInSlot(slot, content);
}
32. Default Presenter
WelcomePresenter
Options
● Use UiBinder
● RevealContentEvent
● Content Slot
(from parent presenter)
● Is a Place
● CodeSplit (recommended)
● Token: #welcome
● DefaultPlace
34. reset.css
Download reset.css
put this css in your HTML header
<head>
...
<link type="text/css" rel="stylesheet" href="reset.css">
...
</head>
In your Module.css file
*{
font-family: arial, helvetica, tahoma, sans-serif;
}