So if your a Java developer and not been hiding under a rock recently, you’ve probably heard of the Google Web Toolkit (GWT). It’s been around for a few years, and it provides some wonderful capabilities to develop applications in Java that get compiled to Javascript and are cross-compatible on all browsers.
GWT 2.1 is still under development but GWT 2.1 RC 1 was released a few days ago and we’re well excited. They’ve got some wonderful new classes and interfaces like Activities, Places and EventBuses which help manage complex applications.
I won’t get into all the detail, but there are some great articles to start you off which can be found here:
- GWT MVP Development with Activities and Places
- Large scale application development and MVP (Part 1)
- Large scale application development and MVP (Part 2)
The only thing is about the above articles is that the first one identifies how to use Activities & Places using the new GWT 2.1 architecture. However, the second and third articles, although brilliant, are using a slightly different architecture and are focusing on event buses, rather than GWT 2.1. The second and third ones do however provide a lovely Contact Details example code which works straight out the box and shows how the events work.
As a little bit of help to the community, I applied the GWT MVP in 2.1 (Places, Activities and a Client Factory) with the Contact Details example which was brilliantly provided by Chris Ramsdale from the Google Developer team. My updated code can be downloaded here.
In case you’re interested in the original Contact Details example from google, that file can be found here.
The changes I’ve made are as follows:
- Integrated the new ClientFactory class required to pass the EventBus and PlaceController around
- ClientFactory can also be used to get references to the views
- I’ve replaced the HandlerManager with the new EventBus class used in GWT 2.1
- I’ve ditched the AppController class for the new GWT 2.1 PlaceController
- Presenters are no longer called presenters, instead they use Activities
- Added the AppActivityMapper and the AppPlaceHistoryMapper classes recommended for GWT 2.1
- Created three new places ContactPlace, EditContactPlace and NewContactPlace which can be used for accessing the url based locations
- No longer use events to jump from url to url, now use the PlaceController to go to new Place
So that’s it. I hope you have found that useful. If you have – please let me know by adding a comment and I’ll gladly answer any questions you may have.
Hi, I am quite new in gwt but i managed to use mvp4g or gwtp for my mvp applications. Now I am trying to use default mvp from google. It seems it is ready for production. I see you a using a Flex Table to render the data in your view. I also see you are using the useful option display.getClickedRow(event);
My question is just to see your pont of view of using the new CellTable (or other CellWidgets) and to know the benefits to use them insted the Grid and FlexTable widgets. Could you implement the same example but with one of those CellWidgets. THANKYOU!!! this example is really amazing and could improve others to understand MVP. Ramon
Thanks rsallar! To be honest, I must give credit that the initial example was the one from google, I just modified it to take into account the new ClientFactory usage. I didn’t put the code together for the Flex Table and CellTable (though I can have a more thorough look at it when I have time and get back to you)
If you’re interested in the GWT example, i’d recommend also checking out the next post I wrote which integrates GWT 2.1 activities with GIN. GIN is a Dependency injection framework which does a great job of helping unit testing. Take a look and tell me what you think –
http://www.bright-creations.com/blog/gwt-2-1-mvp-gin-example/
it’s just an example to have out there until GWT produces it’s own examples specifically with GIN. If you’re more interested in this discussion, check out the forum topic which helped me put it together.
http://groups.google.com/group/google-web-toolkit/browse_thread/thread/2ed199a42c500156/d64b0d748eedf225?lnk=gst&q=hellomvp#d64b0d748eedf225
Hi Mahamad,
I tried to compile your project and I got this error:
Compiling module com.google.gwt.sample.contacts.Contacts
Resolving com.google.gwt.sample.contacts.client.mvp.AppPlaceHistoryMapper
Found type ‘com.google.gwt.sample.contacts.client.mvp.AppPlaceHistoryMapper’
[ERROR] Annotation error: cannot resolve com.google.gwt.sample.contacts.client.place.NewContactPlace$Tokenizer
java.lang.ClassNotFoundException: com.google.gwt.sample.contacts.client.place.NewContactPlace$Tokenizer
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
[...]
Mahamad, thanks a lot for your example. I am currently writing an article about GWT MVP and I mention you and provide a link to this blog.
Hi Kai – glad the post could help. I’d love to read your article once it’s published, please let me know the link once it’s out.
HI Aurel – did you manage to solve the compilcation problem?
Hello, Mahamad El Tanahy! I’ve got the same problem with the Aurel…
Compiling module com.google.gwt.sample.contacts.Contacts
Resolving com.google.gwt.sample.contacts.client.mvp.AppPlaceHistoryMapper
Found type ‘com.google.gwt.sample.contacts.client.mvp.AppPlaceHistoryMapper’
[ERROR] Annotation error: cannot resolve com.google.gwt.sample.contacts.client.place.NewContactPlace$Tokenizer
java.lang.ClassNotFoundException: com.google.gwt.sample.contacts.client.place.NewContactPlace$Tokenizer
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source) …
…….
Could you please help us to solve this problem ? It would be great )))
@Aurel : This is happening because places are not GWT compiled. Add the ‘place’ package to translatable paths by adding to Contacts.gwt.xml
Thanks a lot for your example. One thing puzzles me. You reuse the views through the ClientFactory, but I can’t seem to find any cleanup code for the views. For each newly created activity you call the ‘bind’ method where all the handlers are registered, but you do not care for the handlers already registered. Am I missing something here ?
Hi Mahamad, thanks for your tutorial, i see client factory in gwt tutorials too, but how can i organize a client factory with a big project such as CRM / ERP ? if i write all Views in a client factory, then it is a large client factory class, is it not problem ? Or is it a good solution for a big project?
yours sincerely.
Hi Deniz,
To be honest, on our projects, we didn’t find the Client Factory very scalable. What we did instead was use GIN and GUICE for Independency Injection and didn’t use the client factory in the end. See my other blog post for information (http://www.bright-creations.com/blog/gwt-2-1-mvp-gin-example/)
We’ve been trying to modularise our projects a bit more, as we ourselves also do large scale projects. Our approach was to split code into separate modules and use gin modules for each GWT module. It helped loosely couple of the projects together. My suggestion might be to have a separate clientFactory class for each different module.
Hope that helps.
Thanks a lot for the code!
But i still have one problem: when i import your project to Eclipse. It is marked as there are some errors in there, but there are no errors in the code. When i try to run the app i get (Is there any way around?) :
java.lang.ClassNotFoundException: com.google.gwt.sample.contacts.server.ContactsServiceImpl
at java.lang.ClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:352)
at org.mortbay.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:337)
at org.mortbay.util.Loader.loadClass(Loader.java:91)
at org.mortbay.util.Loader.loadClass(Loader.java:71)
at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:73)
at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:233)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:616)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1220)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload.doStart(JettyLauncher.java:447)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.handler.RequestLogHandler.doStart(RequestLogHandler.java:115)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:222)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at com.google.gwt.dev.shell.jetty.JettyLauncher.start(JettyLauncher.java:542)
at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:431)
at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1053)
at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:795)
at com.google.gwt.dev.DevMode.main(DevMode.java:282)
[WARN] failed contactsServiceServlet
javax.servlet.UnavailableException: com.google.gwt.sample.contacts.server.ContactsServiceImpl
at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:79)
at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:233)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:616)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1220)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload.doStart(JettyLauncher.java:447)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.handler.RequestLogHandler.doStart(RequestLogHandler.java:115)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:222)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at com.google.gwt.dev.shell.jetty.JettyLauncher.start(JettyLauncher.java:542)
at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:431)
at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1053)
at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:795)
at com.google.gwt.dev.DevMode.main(DevMode.java:282)
[WARN] Failed startup of context com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload@110fe28{/,D:\CPprojects\Eclipse\workspace\ContactsClientFactory\war}
javax.servlet.UnavailableException: com.google.gwt.sample.contacts.server.ContactsServiceImpl
at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:79)
at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:233)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:616)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:140)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1220)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload.doStart(JettyLauncher.java:447)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.handler.RequestLogHandler.doStart(RequestLogHandler.java:115)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:222)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at com.google.gwt.dev.shell.jetty.JettyLauncher.start(JettyLauncher.java:542)
at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:431)
at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1053)
at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:795)
at com.google.gwt.dev.DevMode.main(DevMode.java:282)
Nikita, download Gin from here: http://code.google.com/p/google-gin/downloads/detail?name=gin-1.0.zip&can=2&q=
And extract the 3 jars (gin, guice, aopalliance) to the war/WEB-INF/lib directory.
Also, Nikita, if you’re like me just now, you’ll want to replace gwt-servlet.jar with a newer one from the original Contacts project (downloadable from MVP part 2 above) or else GWT will complain that it’s too old.
Hi Mahamad,
I m new in this area and if my question does not sound very logical please excuse me. Here is it.
Why should we use ClientFactory? what is the advantage it over the other approaches?
And also if i want to use Activities i m force to implement ClientFactory, right ? or i have mistaken?
Thanks in advance!
Thanks for the great article. One question, as Luise pointed out “you reuse the views through the ClientFactory, but I can’t seem to find any cleanup code for the views. For each newly created activity you call the ‘bind’ method where all the handlers are registered.
I think Luise is correct. When I run the code I can see the handlers are registered each time an activity is created. After clicking a few times I can see that events are firing multiple times.
Can you please set me straight on how to deal with this? Many thanks!
hi mahamad,thanks for your post, i’m new to this technology,I write the program that is illustrated in http://code.google.com/webtoolkit/doc/latest/DevGuideMvpActivitiesAndPlaces.html page, and i’m getting error [ERROR] [hellomvp] – Deferred binding result type ‘com.google.client.ClientFactory’ should not be abstract please help me in finding solution
Hello Mahamad.
I have go through your tutorial but i want to integrate GWT,MVP and Hibernate ..
Is that possible ?
Thanks
thanks for the post ….. great effort