Ok,
your fresh new GWT user interface is ready, it works great with GWTShell's internal Tomcat and with server-side stubs,
but as you compile and deploy it on your web-app there are problems.
Of course you can debug with a JavaScript debugger (Venkman or Microsoft's Script Debugger),
but generated JavaScript is really complex, for people and for those unstable debuggers.
But, wait, we have a debugger, is our state-of-the-art debugger,
integrated in our IDE and GWT can use it, if only you could run client
into the Shell and server side into your preferred development
envinroment !!!
We could deploy our web-app into the integrated Tomcat, but it's not easy to do (and an hell to mantain)
and also can be that you don't want (or you can't) use Tomcat for your Web Application.
I think that everyone should do his work, so let's Google Shell do
the client, and your application server run the server side code. It's
not difficult, you only need to follow these few steps.
First thing do to it's a little (I promise really little and only
one) change to your GWT code, so that the client will always use
absolute urls for your web-app, allowing us to use the ContextPath
without problems, whatever it's the relative position of your Google
client inside your root context.
To do that we have to register this way the end-point of the remote service:
endpoint.setServiceEntryPoint( GWT.getModuleBaseURL()+"/myRemoteService" );
now we must also remember to change our servlet path inside the GWT module file (*.gwt.xml)
putting the complete service name at the top, in this case /mypackage.google.GWTClient:
<servlet path="/mypackage.google.GWTClient/myRemoteService" class="mypackage.google.server.MyRemoteServiceImpl"/>
No other change to your client side code, I promise again.
Now let's start to modify the web-app to run our services. The first thing is to include in our WEB-INF/lib the gwt-user.jar.
Unfortunately the one supplied by Google doesn't work, because it
includes the javax.servlet.* classes to simplify the automatic
generation of development projects.
We must strip that out (with an ANT Task obviously):
Now we can also add that to our IDE build-path.
Everything is ready to begin the configuration of our web-app,
beginning with the registration of the remote service inside web.xml,
remembering the module name we used in the *.gwt.xml file:
We don't have yet finished, we must also "simulate" one of the call
implemented by GWTServlet, registering its path into web.xml and with
the help of a JSP::
the
gwt-hosted.jsp JSP it's only a simple script with a row of scriptlet that export our web-app context to the GWT client::
We did it !!!!The good thing is that we don't even have to "Compile" our
JavaScript in the destination context during debug. Infact the GWT Shell
callback will always call our Java classes and not the JavaScript code.
So we have together maximum flexibility on client-side project for our debugging purposes,
and only at the very finish of the development cycle we will produce the JavaScript code.
Could we be in a better position as web developer ?
Now some tips about GWT's Shell:
Are we in debug mode or not ? The answer is yes, so we should
configure the Shell log to a more verbose level (if you have used
GWT.log in your code):
-logLevel ERROR|WARN|INFO|TRACE|DEBUG|SPAM|ALL
We should also disable the integrated Tomcat:
-noserver
and configure the Shell to generate JavaScript code directly inside our web-app project:
-out <web-app-project-dir>
Also can be useful to open directly the Shell browser to our web-app
at startup, simply putting the http url as the last parameter of the
command line that start the Shell.
But what if all this it's not enough to solve our problems, may be because the generated JavaScript is not working fine ?
Well, together with much luck, we can try to switch the generation code to DETAILED:
-style DETAILED
and use traditional JavaScript debugging tecnique.
Integrate Google Web Toolkit with Struts/Tiles
Ok, now everything it's integrated with your web-application and
you're in love with GWT. You did really a great work, a prototype that
it's working fine and looks pretty. But when time comes that you must
put it into your old fashioned Struts/Tiles web-application it stops
working and sure you can't write everything from scratch again, but do
a step after another and start with a single functionality done with
GWT.
Well, I don't know you, but I suffered from this problem, but at the
end, thank to some little tips, I was able to let Struts and GWT not
only to live together, but to cooperate to make my application look
better.
It was like having an old fashioned B&W TV Set and a new HDMI on the same bench, side by side !!!
Well, to achieve this, we have to do some simple steps:
- In web.xml add another Struts action mapping, this time it must be extension based, for instance I choosed *.gwt:
- In struts-config.xml write the new Struts action
that will render the GWT page, taking care to put at the top of the
path the complete GWT's module name, so that the script will be able to
find internal files with no problems:
- (only if you use Tiles as view)Add a Tiles definition that will include GWT's (in my example into the body of the layout JSP):
- (if you used filters for Struts Action mapping)Update
your filters so that they will be able to do their work also with the
new GWT module:
That's all, the game is made.
P.S.:the same applies if you used Spring MVC.
Integrating it also with Spring/Hibernate
The life-cycle of a GWT's Service is managed by your
servlet-container, because as a design choice Google opted for the
portabily and simplicity of the Servlet model.
In our code this mean that our service implementations will all inherit (indirectly) from HttpServlet. This means also that to integrate them in our Spring managed container we have to play dirty. I decided to use static property inside our Google Service implementation, so that Spring will be able to assign it at startup time.
Pratically, if we want to inject something in GWT's service mypackage.google.server.MyRemoteServiceImpl's myProperty property, it's enough to declare it static:
Then to let Spring works, we also need an instance setter:
In our applicationContext.xml we can inject the myPropertyBean Bean simply with a dummy bean declaration of the GWT implementation class:
This works because at startup Spring will instantiate an
instance of the MyRemoteServiceImpl class, this instance will never be
used by the servlet-container, but the bean property is contained into
a static variable, so every instance will have it !!!
Now, if your business bean myPropertyBean uses Hibernate and you usually use Spring's OpenSessionInViewFilter/Interceptor
to manage your Session, you need a further step and use an AOP
Interceptor. But we are lucky in this, because all is done by Spring
out-of-the-box only with few lines of configuration::
With this configuration, if myPropertyBean is used
outside a transaction scope, a new Hibernate transaction will be
created and assigned to it. In our case this is also the span of the
Hibernate's Session (thanks to HibernateTransactionManager). The myHibernateInterceptor will also take charge of eventually close the Session at the end of the business method.
continue here...