In my last post I gave an example based on the Google Webtool Kit (GWT) Starter Application using MVP, dependency injection, event bus and command patterns. The command pattern made use of the excellent gwt-dispatch library and used Google Guice at the server side for wiring the service handlers together. My current project uses JBoss Seam for implementing services and this requires a slightly different configuration so that the server side command handlers are properly injected with Seam managed components.
Therefore the aim of this post is to demonstrate those changes involved so you can integrate your own gwt-dispatch based applications with Seam. I expect that most of the changes here will also apply to services implemented using other server frameworks such as Spring. Naturally, you'll need to appropriately tailor the steps for the Seam specific parts but it should serve as a good starting point nonetheless.
Note 1: I should also point out that the code here demonstrates the bare minimum to get the client talking to GWT and does not take into account how security or validation exceptions from the Seam framework might be handled etc.
Note 2: JBoss Seam does in fact support integration with Guice 1.0. However, since I am writing code from fresh rather than integrating with existing code I feel it is better to produce the command handlers as first class Seam citizens.
I'm assuming that you already have a Seam project configured to talk to GWT via regular RPC (if not, then see the Seam docs on how to do this), you've got the code from the MVP example copied into the project and wish to talk to Seam services instead of the Guice versions.
The approach we'll take is to create our own implementation of the command (a.k.a. Action) dispatch mechanism using standard RPC calls to Seam and then extend the gwt-dispatch default dispatcher implementation to create an ActionHandler instance that has been suitably wrapped by Seam's interceptors. Once this boiler plate code is in place, the original Action and Result code and (more importantly) the calls to them remain unchanged while the action handlers can be modified to use Seam components.
Changes to the Client
- 1. Define a RPC service to process our commands;
- 2. Point the client to Seam friendly URLs;
- 3. Wire it all up.
First up, we need to define an RPC call to carry the command to the server using standard RPC:
DispatchService.javaDispatchServiceAsync.java
package co.uk.hivedevelopment.greet.client.gin;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;
import com.google.gwt.user.client.rpc.RemoteService;
public interface DispatchService extends RemoteService {
Result execute(Action<?> action) throws Exception;
}
package co.uk.hivedevelopment.greet.client.gin;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface DispatchServiceAsync {
void execute(Action<?> action, AsyncCallback<Result> callback);
}
Now we need to change the RPC service URL to a Seam friendly one. By default, gwt-dispatch will look to go to a servlet located at the URL http://<host>/<context>/dispatcher. Seam requires the URL point to http://<host>/<context>/seam/resource/gwt.
SeamDispatchAsync.java
package co.uk.hivedevelopment.greet.client.gin;
import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
public class SeamDispatchAsync implements DispatchAsync {
private static final DispatchServiceAsync realService;
static {
realService = GWT.create( DispatchService.class );
final String endpointURL = getModuleBaseURL() + "seam/resource/gwt";
((ServiceDefTarget) realService).setServiceEntryPoint(endpointURL);
}
public static String getModuleBaseURL() {
// Make sure that communication is with the server that served the containing
// web page and not where the GWT resources came from (which is the case with
// GWT.getHostPageBaseURL)
final String url = GWT.getHostPageBaseURL();
return url;
}
public SeamDispatchAsync() {
}
public <A extends Action<R>, R extends Result> void execute( final A action, final AsyncCallback<R> callback ) {
realService.execute(action, new AsyncCallback<Result>() {
public void onFailure(final Throwable caught) {
callback.onFailure( caught );
}
@SuppressWarnings("unchecked")
public void onSuccess(final Result result) {
callback.onSuccess((R) result);
}
} );
}
}
All standard RPC stuff so far. Finally, to wire everything together we define a new Gin module called SeamDispatchModule and modify the annotation @GinModules on the GreetingGinjector class to use the new SeamDispatchModule rather than the default ClientDispatchModule:
SeamDispatchModule.javaGreetingGinjector.java
package co.uk.hivedevelopment.greet.client.gin;
import net.customware.gwt.dispatch.client.DispatchAsync;
import com.google.gwt.inject.client.AbstractGinModule;
import com.google.inject.Singleton;
public class SeamDispatchModule extends AbstractGinModule {
@Override
protected void configure() {
bind( DispatchAsync.class ).to( SeamDispatchAsync.class ).in( Singleton.class );
}
}
package co.uk.hivedevelopment.greet.client.gin;
import net.customware.gwt.presenter.client.place.PlaceManager;
import com.google.gwt.inject.client.GinModules;
import com.google.gwt.inject.client.Ginjector;
import co.uk.hivedevelopment.greet.client.mvp.AppPresenter;
@GinModules({ SeamDispatchModule.class, GreetingClientModule.class })
public interface GreetingGinjector extends Ginjector {
AppPresenter getAppPresenter();
PlaceManager getPlaceManager();
}
That's it for the client. The existing GreetMvp code was written to use dispatcher interfaces so once we gave Gin an alternative implementation anywhere that uses the dispatcher is injected with new version. Ahhh, good old dependency injection.
Configuration for the Server
Under the GreetMvp example application, all code under the co.uk.hivedevelopment.greet.server.guice package is no longer required. Also if you were already making GWT RPC calls to Seam then there are no changes necessary to your existing Seam web.xml or components.xml. Just make sure that gwt-dispatch jars (aopalliance.jar and gwt-dispatch-1.0.0-SNAPSHOT.jar) are deployed with the application WAR file (i.e. add them to your Eclipse project and edit deployed-jars.list).
At the server we'll:
- Define the server RPC dispatch implementation;
- Create a Seam registry for handlers;
- Modify the SendGreetingHandler for Seam injection.
The following is a standard Seam RPC end point. Notice how the component name matches the fully qualified client side DispatchService remote service interface - this is a key part of any Seam GWT integration:
DispatchServiceImpl.javaGwtActionDispatcher.java
package co.uk.hivedevelopment.greet.server.seam;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.remoting.WebRemote;
import co.uk.hivedevelopment.greet.client.gin.DispatchService;
@Name("co.uk.hivedevelopment.greet.client.gin.DispatchService")
public class DispatchServiceImpl implements DispatchService {
@In GwtActionDispatcher gwtActionDispatcher;
@WebRemote
@Override
public Result execute(final Action<? extends Result> action) throws Exception {
return gwtActionDispatcher.execute(action);
}
}
SeamActionHandlerRegistry.java
package co.uk.hivedevelopment.greet.server.seam;
import net.customware.gwt.dispatch.server.DefaultDispatch;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.ActionException;
import net.customware.gwt.dispatch.shared.Result;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.Create;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import co.uk.hivedevelopment.greet.server.handler.SendGreetingHandler;
@Name("gwtActionDispatcher")
@Scope(ScopeType.APPLICATION)
@AutoCreate
public class GwtActionDispatcher {
private SeamActionHandlerRegistry actionHandlerRegistry;
@Create
public void init() {
actionHandlerRegistry = new SeamActionHandlerRegistry();
addHandlers();
}
private void addHandlers() {
// TODO: Add all your handlers here.
actionHandlerRegistry.addHandler(new SendGreetingHandler());
}
public Result execute(final Action<? extends Result> action) throws ActionException {
final DefaultDispatch dd = new DefaultDispatch(actionHandlerRegistry);
return dd.execute(action);
}
}
package co.uk.hivedevelopment.greet.server.seam;
import net.customware.gwt.dispatch.server.ActionHandler;
import net.customware.gwt.dispatch.server.DefaultActionHandlerRegistry;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;
import org.jboss.seam.Component;
public class SeamActionHandlerRegistry extends DefaultActionHandlerRegistry {
@SuppressWarnings("unchecked")
@Override
public <A extends Action<R>, R extends Result> ActionHandler<A, R> findHandler(final A action) {
final ActionHandler<A, R> handler = super.findHandler(action);
if (handler == null) {
return null;
}
// The crucial part to the Seam dispatch implementation is to create handlers using getInstance
final ActionHandler<A, R> handler_ = (ActionHandler<A, R>) Component.getInstance(handler.getClass());
return handler_;
}
}
That completes the server side boiler plate code. The main bit to focus on is the SeamActionHandlerRegistry which extends the default gwt-dispatch implementation to create handlers via Seam's getInstance() method which ensures that appropriate Seam bijection takes place. Remember to add all your new handlers to GwtActionDispatcher.addHandlers().
Finally, here is the version of SendGreetingHandler amended for Seam:
SendGreetingHandler.java
package co.uk.hivedevelopment.greet.server.seam;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import net.customware.gwt.dispatch.server.ActionHandler;
import net.customware.gwt.dispatch.server.ExecutionContext;
import net.customware.gwt.dispatch.shared.ActionException;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.log.Log;
import org.jboss.seam.web.ServletContexts;
import co.uk.hivedevelopment.greet.shared.rpc.SendGreeting;
import co.uk.hivedevelopment.greet.shared.rpc.SendGreetingResult;
@Name("sendGreetingHandler")
@Scope(ScopeType.STATELESS)
public class SendGreetingHandler implements ActionHandler<SendGreeting, SendGreetingResult> {
@Logger Log logger;
@In("org.jboss.seam.web.servletContexts") ServletContexts servletContexts;
@Override
public SendGreetingResult execute(final SendGreeting action,
final ExecutionContext context) throws ActionException {
final String name = action.getName();
try {
final HttpServletRequest request = servletContexts.getRequest();
final ServletContext sc = request.getSession().getServletContext();
final String serverInfo = sc.getServerInfo();
final String userAgent = request.getHeader("User-Agent");
final String message = "Hello, " + name + "! I am running " + serverInfo + ". It looks like you are using:" + userAgent;
return new SendGreetingResult(name, message);
}
catch (Exception cause) {
logger.error("Unable to send greeting", cause);
throw new ActionException(cause);
}
}
@Override
public void rollback(final SendGreeting action,
final SendGreetingResult result,
final ExecutionContext context) throws ActionException {
// Nothing to do here
}
@Override
public Class<SendGreeting> getActionType() {
return SendGreeting.class;
}
}
Good luck!
While this sounds very interesting, I just dont get why gwt-dispatch has any effect on the server at all.
ReplyDeleteIn the slides from Ray Ryan (http://dl.google.com/io/2009/pres/Th_0200_GoogleWebToolkitArchitecture-BestPracticesForArchitectingYourGWTApp.pdf ) he clearly uses a client side command-pattern only. Therefore he can use standard gwt-rpc to invoke services.
Why does gwt-dispatch propagate itself to the server?
Big data is a term that describes the large volume of data – both structured and unstructured – that inundates a business on a day-to-day basis. big data projects for students But it’s not the amount of data that’s important.Project Center in Chennai
DeletePython Training in Chennai Python Training in Chennai The new Angular TRaining will lay the foundation you need to specialise in Single Page Application developer. Angular Training Project Centers in Chennai
gwt-dispatch is a very lightweight library with a narrow focus that basically boils down to the RPC example given in the talk:
ReplyDeleteinterface Action<T extends Response> { }
interface Response { }
interface ContactsService extends RemoteService {
<T extends Response> T execute(Action<T> action);
}
interface ContactsServiceAsync {
<T extends Response> void execute(Action<T> action, AsyncCallback<T> callback);
}
At the server you'll have an RPC endpoint which implements ContactsService. Assuming your app is reasonably interesting, then you'll have several commands and associated handlers and only one RPC endpoint (execute). When a command arrives you'll need to work out how to execute it - gwt-dispatch just saves you the time of writing this dispatch code.
So it is used to match Actions with ActionHandlers and execute the appropriate functionality, I guess.
ReplyDeleteThx.
Hi Daniel,
ReplyDeleteYes, that's pretty much it. Once your integration is done then adding actions and handlers becomes trivial and there is no more RPC plumbing to be done. I find it very convenient.
Keep the feedback coming!
Chris.
If anyone's interested in some proper Spring integration instructions then there is a link on a previous post comment which will probably help.
ReplyDeleteThere is a less invasive way of using the dispatch lib with spring.
ReplyDeleteHave a look here:
http://pgt.de/2009/09/16/use-spring-with-gwt-dispatch/
Comments are welcome!
Additional to the spring comments here, the trunk of gwt-dispatch has been refactored a bit to a) remove Guice dependencies where not necessary and b) added some basic Spring support classes, based on P.G. Taboada's example.
ReplyDeletejordan 6 black infrared
ReplyDeletenorth face coats
hermes belt
fitflop outlet store usa
under armour outlet
burberry scarf
gucci shoes
coach handbags
burberry sale
kevin durant shoes
north face jackets
converse shoes sale
coach factory outlet
air jordan 14
coach factory outlet online
louboutin outlet
fitflop sale
nike nfl jerseys 2015
north face outlet store
ugg boots
reebok outlet
michael kors handbags
christian louboutin sale
north face jackets clearance
new kevin durant shoes
nike clearance
toms outlet
dior handbags
michael kors outlet store
fitflops clearance
kate spade sale
jordan 12
ugg boots
coach purses sale
gucci outlet
wholesale jordans
canada goose clearance
1030wjl
1 columbia outlet
ReplyDeletenike air max
polo shirts
polo shirts for women
north face outlet 70% off
cheap michael kors handbags
air jordan retro 6
salvatore ferragamo outlet
north face clearance
mbt shoes clearance outlet
reebok shoes outlet
polo ralph lauren factory store
celine handbags
christian louboutin shoes
michael kors handbags
fitflops online
jordan 6
ralph lauren extra 25% off
michael kors outlet
air jordan 11
coach factory online sale
jordan shoes
kd shoes
coach handbags outlet
coach shoes for women
gucci outlet
abercrombie and fitch outlet
ferragamo shoes outlet
air jordan 11 legend blue
michael kors factory outlet online
michael kors store
all jordan shoes
ugg boots sale
fitflop sandals for women
gucci outlet
cheap canada goose coats
nike running shoes
1030wjl
burberry outlet online
ReplyDeleteralph lauren outlet
coach outlet
cheap oakleys
canada goose jackets
cheap oakley sunglasses
air force 1
coach purses
louis vuitton outlet
coach factory outlet
running shoes
rolex watches uk
babyliss flat iron
cheap jordan shoes
coach factory outlet online
polo ralph lauren
polo ralph lauren
cheap jordans
oakey sunglasses wholesale
louis vuitton pas cher
air max 90 black
birkenstock outlet
asics gel nimbus
coach outlet store
the north face outlet
michael kors outlet clearance
nike tn
rolex replica watches
nike air max
true religion outlet store
wholesale nike shoes
polo ralph lauren
kobe bryant shoes
louis vuitton outlet online
lacoste outlet
louboutin shoes
louis vuitton outlet online
red bottoms outlet online
abercrombie outlet
2016614yuanyuan
ray ban sunglasses outlet
ReplyDeleteoakley sunglasses outlet
converse outlet
gucci belts
polo ralph lauren uk
adidas yeezy boost 350
christian louboutin shoes
fitflop shoes
nfl jerseys cheap
chicago bulls jerseys
2017.2.25xukaimin
pandora charms
ReplyDeletetrue religion jeans
birkenstock sandals
adidas uk
beats by dr dre
chicago cubs jerseys
michael kors
louis vuitton canada
adidas yeezy boost 350
cheap nfl jerseys
0509shizhong
ralph lauren outlet
ReplyDeleteugg boots clearance
ugg boots clearance
nfl jerseys wholesale
adidas outlet store
lebron shoes
pandora outlet
ugg boots
adidas outlet online
true religion outlet
yaoxuemei20171222
vans shoes
ReplyDeleteair max 97
christian louboutin outlet
pandora charms sale
asics shoes
coach outlet
michael kors outlet online
cheap ray bans
coach factory outlet
ralph lauren uk
clb0309
It is great to have visited your website. Thanks for sharing useful information. And also visit my website about health. God willing it will be useful too
ReplyDeleteCara Mengobati Cacingan pada Anak
Cara Mengobati Usus Buntu
Obat Benjolan di Belakang Telinga
Obat Telinga Berkerak dan Berair
Cara Membersihkan flek di paru-paru
Obat Koreng Bernanah Alami
Obat Sakit perut melilit paling Ampuh
Obat Pelancar Haid paling Ampuh
black desert system requirements
ReplyDeleteblack desert pc requirements
black desert online system requirements
black desert online
https://newyear2019love.com/ is not so far
ReplyDeleteugg outlet
ReplyDeletenfl jerseys wholesale
michael kors outlet
true religion outlet
michael kors outlet
michael kors outlet
coach outlet online
coach outlet
michael kors outlet clearance
nike outlet
yaoxuemei20180820
Development is love <3 I developed this online columbus day cards
ReplyDeleteLive scores and ball to ball update of PSL 2019 livepsldigital.com
ReplyDeleteValentines Day 2019 wallpapers, messages and much more
ReplyDeletejust information we only provide information for those who need it cara menggugurkan kandungan
ReplyDeleteA. obat telat datang bulan
B. posisi berhubungan agar cepat hamil
C. makanan dan minuman agar cepat hamil
D. panduan agar cepat hamil
E. cara agar cepat hamil
F. cara agar cepat hamil setelah selesai haid
G. cara alami untuk segera mendapat kehamilan
canada goose jackets
ReplyDeleteasics running shoes
christian louboutin outlet
michael kors outlet
christian louboutin outlet
polo ralph lauren
coach outlet
chaussures christian louboutin
ugg outlet
canada goose outlet
yaoxuemei20181113
nike sb
ReplyDeletevans shoes
mac makeup
prada handbags
nike air max 2018
ralph lauren outlet
michael kors taschen
ugg australia
supreme clothing
onitsuka tiger
chenlina20181117
teacher appreciation week ideas
ReplyDeleteneww download free
Nice thoughts with great helping content. I have also been seeking such thoughfull content to learn and appy in the life. We have also created such type of content on our site. You can refer out site for more ideas.
ReplyDeleteHappy New Year 2019 Wishes Messages Sms in Bengali
Merry Christmas 2018 SMS, Wishes, Messages, Greetings in Bengali
Merry Christmas 2018 Wishes Messages in Marathi,funny christmas text sms
neww download free.
ReplyDeletepip camera new version 2019
Nice thoughts with great helping content. I have also been seeking such thoughfull content to learn and appy in the life.
ReplyDeleteSketch Maker new version 2019
Get the best version of valentine's day exchange cards
ReplyDeleteBy reading the article material very very well and this is very useful.
ReplyDeletecara menggugurkan hamil
aktivitas penyebab keguguran
penyebab telat haid dan solusinya
tanda tanda kehamilan
kalkulator masa subur wanita
masa subur wanita
valentines day cards for dads best dads
ReplyDeleteI loved the article, keep updating interesting articles. I will be a regular reader… I am offering assignment help to students over the globe at a low price.
ReplyDeleteclick here
click here
click here
click here
click here
click here
click here
click here
click here
click here
This article is actually a nice one it helps new internet viewers, who are wishing in favor of blogging. For more information click here latest news and I absolutely love your blog and find almost all of your post’s to be just what I’m looking for. Does one offer guest writers to write content to suit your needs? click here
ReplyDeleteHi,
ReplyDeleteYour article is very informative and has a lot of information. I really like your effort, keep posting.
hungrysharkevolutionmodapk
I have read your blog its very attractive and impressive. I like it your blog.
ReplyDeletesports online
iptv athletics
http://blog.hivedevelopment.co.uk/2009/08/integerating-gwt-dispatch-with-jboss.html
ReplyDeletehttp://www.pygbook.com/groups/topic/view/group_id/9/topic_id/64/post_id/64
http://lunas-island.blogspot.com/2006/09/hard-to-say-i-love-you.html
http://blog.donavon.com/2009/09/okcancel-buttons-and-web.html
http://www.msp430launchpad.com/2011/03/devbo-is-born.html
http://www.thequinoxfashion.com/2013/11/my-new-partner-firmoo-eyewear.html
http://gsjy.cersp.com/forum.php?mod=viewthread&tid=646
http://dare2sayit.blogspot.com/2007/01/jimmy-carter-continues-to-embarrass.html
http://blog.lukashmayyn.com/2011/06/social-media-news-weekly-roundup.html
http://kerstinrosalia.blogspot.com/2009/05/havet-ar-djupt.html
curry 4
ReplyDeletejordan shoes
nike shoes
curry 6
supreme clothing
hermes belts for men
russell westbrook shoes
coach outlet
100% real jordans for cheap
coach outlet
kd shoes
ReplyDeletepandora jewelry official site
nike epic react
lebron 16
yeezy
birkin bag
supreme t shirt
curry 8
longchamp
off white shoes
Superbly written article, if only all bloggers offered the same content as you, the internet would be a far better place.. 網站設計
ReplyDeleteI am always searching online for storys that can accommodate me. There is obviously a multiple to understand about this. I feel you made few salubrious points in Attributes moreover. Detain busy, awesome career! scrape emails from facebook
ReplyDeleteDo watch winders actually wind rolex watch winder price up a watch?
ReplyDeleteThere is a common misconception that a watch winder will wind a watch. This is not true. A watch winder will keep the watch wound at the level the mainspring was wound at when it was placed in the winder. Normally, an unwound watch will need about 30-40 manual winds to fully wind the mainspring. During the day, depending on how much movement and activity there has been, the watch should generally stay wound and at optimal performance. A watch winder will keep the watch operating at that level. Every now and again, the watch will benefit from a few extra winds of watch winder with storage the crown.