GWT server library (port from https://code.google.com/p/gwt-sl/)
The GWT Server Library is a collection of Java server side components for the Google Web Toolkit AJAX framework with the current focus on the Spring framework by facilitating publishing of Spring beans as RPC services.
Features
This project used to be hosted at Sourceforge as part of the GWT Widget Library, later at Google Code and has now moved to Github.
java.lang.NoClassDefFoundError
although the class/jar is there!ClassFormatError
java.lang.reflect.InvocationTargetException
404
but no exception in the server logNullPointerException
in GenericServlet
GWTRPCServiceExporter now throws undeclared exceptions to the servlet container. Can be switched off.
Thanks to David Durham.
Upgraded dependencies:
Java 1.5
GWT 1.7
Gilead 1.2.2.598
jboss-serialization 1.0.3GA
trove 2.0.5
Removed support for SerializationException, use regular Exceptions implementing java.io.Serializable.
upgraded dependencies:
gwt 1.5.3
spring 2.5.6
hibernate 3.3.1
junit 4.4
log4j 1.2.15
hibernate4gwt replaced with gilead 1.2.029
commons logging 1.1.1
aspectj 1.6.2
commons collections 3.2
added javassist 3.4GA, new dependency for hibernate
added slf4j 1.5.0, new dependency for hibernate
new ant target “all” - alias of “package”
New features:
The Server Library for GWT (in short SL) is a collection of Java server side components for the Google Web Toolkit AJAX framework
with the current focus on the Spring framework by facilitating publishing of Spring beans as RPC services. The main
binary dependencies are GWT 2.7.0 and Spring 4.2.5 (other versions may work too).
The Spring Framework is an established component framework for web applications that span
authentication, database access and complex page flow. Through its aspect oriented approach
it is unobtrusive and cleanly separates the presentation layer from the business logic and
the data model, allowing for back end services which are agnostic towards the way the
presentation is rendered. This is the ideal base for a GWT application, which also separates the
presentation (widgets that run in the browser) from the business logic (RPC services
running on the web server) from the data model (the objects serialized over RPC).
GWT binds Java methods to RPC calls by using the Servlet API so that
each service you write is a servlet. The Servlet API however is rather crude and the servlet
container (like Tomcat) is a gross environment providing little assistance to elaborate tasks
like transaction management, AOP tasks (authentication, logging, per-task caching) etc. Also
the notoriously scarce configuration abilities are by far inferior to Spring’s XML
configuration and bean injection which allows even the most complex configurations by
plugging objects together in XML. With the SL you can easily write Spring managed beans
which act as GWT services, taking full advantage of both frameworks.
The binary can be downloaded here. At the time of this writing the SL isn’t available on a central artifact repository, but there
is a private repository on Github:
<repositories>
<repository>
<id>gwt-sl-mvn-repo</id>
<url>https://raw.github.com/ggeorgovassilis/gwt-sl/mvn-repo/</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
</snapshots>
</repository>
</repositories>
And this dependency:
<dependency>
<groupId>net.sf.gwt-widget</groupId>
<artifactId>gwt-sl</artifactId>
<version>1.7</version>
</dependency>
We’ll briefly cover the steps necessary to publish a simple Spring managed bean so that a GWT client can communicate with it over RPC. There are several ways of
exporting a bean to RPC, here we shall follow the simplest one, namely the GWTHandler
. Details follow in Chapter 3.
We start off with the definition of the service interface. Our service will perform a simple arithmetic addition. Since
the client application running in a browser will access this interface also (its Async version, to be precise), the service interface must extend GWT’sRemoteService
interface.
ServiceTest.java :
package org.gwtwidgets.server.spring.test.server;
import com.google.gwt.user.client.rpc.RemoteService;
public interface ServiceTest extends RemoteService{
public int add(int a, int b);
}
The implementation is free of any dependencies on Spring, GWT or the servlet API.
ServiceTestImpl.java :
package org.gwtwidgets.server.spring.test.serverimpl;
import org.gwtwidgets.server.spring.test.server.ServiceTest;
public class ServiceTestImpl implements ServiceTest{
public int add(int a, int b) {
return a + b;
}
}
This is a Spring application, so we load the Spring servlet which will export our service bean under the url http://localhost:8080/gwtWebApp/handler/rpctest
web.xml :
<web-app>
<!--
Mapping an RPC service defined in handler-servlet.xml
-->
<servlet>
<servlet-name>handler</servlet-name>`
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>handler</servlet-name>
<url-pattern>/handler/*</url-pattern>
</servlet-mapping>
</web-app>
Last, we define a URL handler mapping like we’d do with any regular Spring MVC application, only that we won’t use a SimpleUrlHandlerMapping
but a GWTHandler
which knows how to translate RPC calls to method invocations on POJOs.
handler-servlet.xml :
<beans>
<bean class="org.gwtwidgets.server.spring.GWTHandler">
<property name="mappings">
<map>
<entry key="/rpctest" value-ref="RPCTest" ></entry>
</map>
</property>
</bean>
<bean id="RPCTest" class="org.gwtwidgets.server.spring.test.serverimpl.ServiceTestImpl" ></bean>
</beans>
The SL creates RPC services following different implementation strategies, from extending a base
class similar to the default way services are created in GWT to publishing POJOs as services without
dependencies on any class, interface or even annotation. It is common to all approaches that eventually
a RemoteServiceServlet
is generated (usually at runtime) automatically which delegates
RPCs to method invocations to a specified service bean. The following sections describe the different
approaches towards creating services which can be used alone or together.
There are always three common steps and you always need a service interface, an asynchronous callback version
of that interface and a service implementation.
RemoteService
and AsyncCallback
interfaces from the service interface1. | Browser encodes objects to RPC string | |
2. | Browser makes HTTP request to the designated RPC URL on the server | |
3. | Web server forwards the HTTP request to the web application which is bound to that URL | |
4. | Based on the servlet mapping in web.xml the request is routed to the corresponding servlet | |
5. | The RemoteServiceServlet decodes the RPC payload and invokes the service method | |
6. | The service response is encoded as an RPC response payload and send as an HTTP response back to the browser | |
7. | Browser decodes the RPC payload and invokes the service callback |
1. | Browser encodes objects to RPC string | |||
2. | Browser makes HTTP request to the designated RPC URL on the server | |||
3. | Web server forwards the HTTP request to the web application which is bound to that URL | |||
4. | Based on the servlet mapping in web.xml the request is routed to the corresponding servlet | |||
5. | Spring routes the request based on its mapping (i.e. the SimpleUrlHandlerMapping ) to the corresponding controller | |||
5.1 | SL’s GWTRPCServiceExporter decodes the RPC request into Java objects | |||
5.2 | The GWTRPCServiceExporter forwards the request to a specified service bean | |||
5.3 | The GWTRPCServiceExporter encodes the service bean’s response into an RPC payload | |||
6. | Spring sends the response back to the servlet container and back to the Browser | |||
7. | Browser decodes the RPC payload and invokes the service callback |
The GWTRPCServiceExporter
is the purist’s take at developing services since it does not introduce any API and compile
time dependency to your service. Essentially it is a wrapper which exports any POJO as an RPC service. In order for theGWTRPCServiceExporter
to know which methods to bind to RPC, the service bean should either implement a RemoteService
interface or you should provide it in the configuration. If no interface is specified, all methods are published to RPC
which should be avoided - even fundamental methods like wait()
can provide backdoors for various denial of service
attacks.
Let’s create a simple bean which we will later publish as a service. This example is taken from the unit
test web application and it shows a trivial bean with a method that adds two integers. Note that
the bean is really a POJO, it does not extend or implement any class or interface.
package org.gwtwidgets.server.spring.test.serverimpl;
public class ServiceTestPOJO {
public int add(int a, int b) {
return a + b;
}
...
}
Next we need an interface which extends RemoteService
and declares the methods which should be exposed
to RPC. Since in our example we have only one, this is an easy task:
package org.gwtwidgets.server.spring.test.server;
public interface ServiceTest extends RemoteService{
public int add(int a, int b);
}
That leaves only the correct bean creation and URL mapping in the Spring servlet XML:
<!--
Create POJO version of the Test service: implements only methods but does not expose any RPC interfaces
-->
<bean id="ServiceTestPOJO" class="org.gwtwidgets.server.spring.test.serverimpl.ServiceTestPOJO" ></bean>
<!--
Declaration of RPC service with the RPCServiceExporter which behaves very similar to
a Spring controller and needs to be mapped to URLs the same way any other Spring
controller is mapped...
-->
<bean id="RPCTestPOJO" class="org.gwtwidgets.server.spring.GWTRPCServiceExporter">
<!--
Reference to the service bean which should be exported via RPC to the web.
-->
<property name="service" ref="ServiceTestPOJO" ></property>
<!--
If our Test service was not a 100% pure POJO but also implemented the ServiceTest interface then
we wouldn't have to specify it here. Note that you can provide multiple interface names, as long as
your service has the corresponding methods with a matching signature.
-->
<property name="serviceInterfaces">
<value>
org.gwtwidgets.server.spring.test.server.ServiceTest
</value>
</property>
</bean>
<!--
... with a SimpleUrlHandlerMapping for instance:
-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/service" value-ref="RPCTestPOJO" ></entry>
</map>
</property>
</bean>
The GWTHandler
allows you to quickly map multiple RPC service beans to different URLs
very similar to the way Spring’s SimpleUrlHandlerMapping
maps URLs to controllers. The
mapped beans are internally wrapped into [GWTRPCServiceExporter](#GWTRPCServiceExporter)
instances, with the notable difference that you cannot specify a service interface in the configuration
and the service beans must implement the RemoteService
interface (as a matter of fact there is
a workaround even for that by providing your own implementation of a RPCServiceExporter
).
First we need the service interface from our previous example:
package org.gwtwidgets.server.spring.test.server;
public interface ServiceAdd extends RemoteService{
public int add(int a, int b);
}
And the corresponding implementation:
package org.gwtwidgets.server.spring.test.serverimpl;
public class ServiceAddImpl implements ServiceAdd{
public int add(int a, int b) {
return a + b;
}
}
Finally the mapping:
<bean id="urlMapping" class="org.gwtwidgets.server.spring.GWTHandler">
<!-- Supply here mappings between URLs and services. Services must implement the RemoteService interface but
are not otherwise restricted.-->
<property name="mappings">
<map>
<!-- Other mappings could follow -->
<entry key="/add.rpc" value-ref="ServiceAdd" ></entry>
</map>
</property>
</bean>
<!-- Declare service -->
<bean id="ServiceAdd" class="org.gwtwidgets.server.spring.test.serverimpl.ServiceAddImpl" ></bean>
Annotations can also be used to publish services to URLs. Beans in the current application context
featuring the GWTRequestMapping
annotation on their service interface will be picked
up by the GWTHandler
and mapped to the specified URL. Please note that the URL is relative
to URL which the GWTHandler
is already servicing:
<beans>
<bean class="org.gwtwidgets.server.spring.GWTHandler"></bean>
<bean id="annotatedService" class="org.gwtwidgets.server.spring.test.serverimpl.AnnotatedServiceTestImpl"></bean>
</beans>
@GWTRequestMapping("/service")
public interface AnnotatedService extends ServiceTest{
}
You can optionally export annotated beans from a parent application context by enabling thescanParentApplicationContext
property.
A sidenote on method interceptors and AOP advice: advice applied on the GWTHandler
is
applied on the servlet request/response level and not the method invocation level of a particular service.
In this case it is applied before/after/around the RPC request handling and not around the service method
invocation. You should carefully distinguish between advice applied on the GWTHandler
(i.e. access
authorisation based on session attributes) and advice applied on services (i.e. logging or transaction management).
If you require a different functionality (for example with exception translation) to be
wrapped around your services than the one provided by the default GWTRPCServiceExporter
which is used
by the GWTHandler
you can inject your own implementation of a RPCServiceExporter
by providing
a RPCServiceExporterFactory
.
The GWTSpringController
is the SL’s oldest yet best-performing approach towards integrating GWT with Spring
and it requires an RPC service to extend the org.gwtwidgets.server.spring.GWTSpringController
class.
While you are usually better off with any of the previous strategies, the GWTSpringController
is lighter
than the other implementations, relies less on reflection and consumes less processing time.
The service extends GWTSpringController
:
package org.gwtwidgets.server.spring.test.serverimpl;
public class ControllerAdd extends GWTSpringController implements ServiceAdd{
public int add(int a, int b) {
return a+b;
}
}
And the mapping:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/add.rpc" value-ref="ControllerAdd" ></entry>
</map>
</property>
</bean>
<bean id="ControllerAdd" class="org.gwtwidgets.server.spring.test.serverimpl.ControllerAdd"></bean>
In this chapter we will discuss common cases in a Spring web application and how the SL
deals with them - yet, since it uses the basic Spring building blocks and conventions we hope
that you will find little surprises and hardly any unexpected behaviour.
The term Exception translation in general refers to the task of converting one exception
instance to an other of a different class as the program execution passes through different application
layers which nest the original exception in an exception relevant to the current layer. Exceptions
are usually nested so that the root cause lies deep in the stack trace while the exception at the
bottom of the stack trace is an entirely different one, generated by the various program layers the
method invocation went through.
By default the GWTHandler
and the GWTRPCServiceExporter
unwrap the immediate root
cause of any exception and propagate it back to the client.
In this regard they behave slightly different from previous versions which would propagate the firstSerializableException
found in the stack trace to the client, regardless how deep in the
stack trace it was.
Exception translation is important for RPC services because only SerializableException
s are
propagated through the RPC protocol back to the client and all other exceptions will usually result in
terminating the current request with the client not getting any meaningful message. In previous versions
you could switch off exception translation, now this it possible by overriding methods in theGWTRPCServiceExporter
.
SerializableException
is a checked exception and as such it does not cause
transactions in the exception-throwing service to be rolled back. This is best tackled either from
inside the service implementation (since you may want the transaction to be committed) or by declaring
the conditions under which a transaction should be rolled back by the transaction proxy - for details on
how to attain both please consult the
Spring Reference Manual.
In v0.1.4c the GWTRPCServiceExporter
was refactored to move exception handling into
separate methods. By extending GWTRPCServiceExporter
and overriding these methods you can
influence substantially the way target services are invoked and the way exceptions are handled.
For instance, imagine that you are trying to handle exceptions in your Spring applications in a common way.
You want to catch all exceptions before they reach the console (or the user), possibly filter out the long traces that
are often introduced by runtime class weaving (such as with CGLIB), filter out InvocationTargetException
traces which are appended to exceptions during reflective invocation and want to repackage these exceptions
into other, more friendly and application specific exceptions. You would do that with the Spring AOP or aMethodInterceptor
, catch there any exceptions, inspect them and throw new exceptions.
The exceptions you throw from within the advice would be RuntimeException
s, because they cause
Springs transaction management to roll-back by default any transactions and because they do not violate the
signature of the invoked method. If the last statement looks puzzling, think of this scenario:
class MathService {
public double divide(double a, double b){
return a / b;
}
}
And an obvious advice:
class DivisionByZero extends Exception{
}
class MathAdvice {
public Object doAround(Object target, Method method, Object[] args){
double b = (double)args[1];
if (b == null) throw new DivisionByZero();
return method.invoke(target, args);
}
}
This means trouble: although you have a MathService
instance at hand (more precicely, an advised
proxy - but that is not the invoker’s concern), calling divide(3,0)
will throw a checked
exception, namely DivisionByZero
. If DivisionByZero
was a RuntimeException
the call would be fine, but now divide
‘s method signature contract is violated. Because the JVM
will not allow that, it will wrap the exception into an
UndeclaredThrowableException
which is a RuntimeException
and does not violate the method signature when thrown. But you may have
your reasons for throwing checked exceptions (i.e. because you don’t want a transaction to be rolled back) theGWTRPCServiceExporter
can be overridden to handle exceptions. The particular case discussed can be
tackled by catching an UndeclaredThrowableException
and propagating the enclosed exception to the
client :
public class MyGWTRPCServiceExporter extends GWTRPCServiceExporter{
@Override
protected String handleUndeclaredThrowableException(Exception e, Method targetMethod, RPCRequest rpcRequest) throws Exception {
Throwable cause = e.getCause();
String failurePayload = RPC.encodeResponseForFailure(rpcRequest.getMethod(), cause);
return failurePayload;
}
}
While not 100% in tune with the MVC pattern, it is often convenient to access the servlet
container, the HTTP session or the current HTTP request from the business layer. The SL
provides several strategies to achieve this which pose a compromise in the amount of configuration
required to set up and the class dependencies introduced to the business code.
The easiest way to obtain the current HTTP request is by using the ServletUtils
class
which provides convenience methods for accessing the HttpServletRequest
andHttpServletResponse
instances. Please note that it makes use of thread local variables
and will obviously not return correct values if used in any other than the invoking thread.
A simple example:
package org.gwtwidgets.server.spring.test.serverimpl;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.gwtwidgets.server.spring.ServletUtils;
public class ServiceTestPOJO {
...
public String replaceAttribute(String name, String value) {
HttpSession session = ServletUtils.getRequest().getSession(true)
String oldValue = (String) session.getAttribute(name);
session.setAttribute(name, value);
return oldValue;
}
}
It is also possible to inject the request/response pair in an IoC manner, when compile-time
dependency on the SL API is not desired. This approach sets the request and response to the service
as a thread local variable. Thus, the service implementation could look similar to:
package org.gwtwidgets.server.spring.test.serverimpl;
public class ServiceHttpRequestTestPOJOImpl{
private static ThreadLocal`<HttpServletRequest>` servletRequest = new ThreadLocal`<HttpServletRequest>`();
private static ThreadLocal`<HttpServletResponse>` servletResponse = new ThreadLocal`<HttpServletResponse>`();
...
// These two setters...
public void setRequest(HttpServletRequest request) {
servletRequest.set(request);
}
// ... must be public
public void setResponse(HttpServletResponse request) {
servletResponse.set(request);
}
protected HttpServletRequest getRequest() {
return servletRequest.get();
}
// That's a service method exposed to RPC
public String test2(String newValue) {
HttpSession session = getRequest().getSession();
return (String) session.getAttribute(attrName);
}
}
Now we have to create the bean that will perform the actual injection of the servlet request and response
and glue it to the service:
<!-- Target service bean -->
<bean id="ServiceTestHTTPTarget" class="org.gwtwidgets.server.spring.test.serverimpl.ServiceHttpRequestTestImpl" ></bean>
<!-- Create request setter -->
<bean id="requestSetter" class="org.gwtwidgets.server.spring.RequestInjection">
<property name="requestSetterName" value="setRequest"></property>
<property name="responseSetterName" value="setResponse"></property>
</bean>
<!-- Create Servlet API aware service -->
<bean id="ServiceTestHTTP" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="ServiceTestHTTPTarget"></property>
<property name="autodetectInterfaces" value="true"></property>
<property name="interceptorNames">
<list>
<value>requestSetter</value>
</list>
</property>
</bean>
Tweaking HTTP headers is a useful technique when it comes to performance tuning your GWT application. The SL
contains the ResponseHeaderFilter
which is a servlet filter used to alter response headers.
It was inspired by an article
written by Jason Falkner which discusses many interesting applications of HTTP headers.
init-param
entries for the ResponseHeaderFilter
are HTTP header names and values and are not further interpreted,
except for the special parameter ResponseHeaderFilter.UrlPattern
which can be used to specify a regular expression which,
when specified, applies headers only to the subset of request URLs which match the provided pattern.
Some HTTP headers describe the validity period of a web resource and can be used to enable caching of resources in a browser.
In an GWT application this will usually be the .cache.html
, the module entry HTML page, CSS and images.
To enable caching for a resource, something along the lines of
<filter>
<filter-name>CachingFilter</filter-name>
<filter-class>org.gwtwidgets.server.filters.ResponseHeaderFilter</filter-class>
<init-param>
<param-name>Expires</param-name>
<param-value>Sun, 17 Jan 2038 19:14:07 GMT</param-value>
</init-param>
</filter>
could be used in web.xml
A further interesting application is compressing of static resources such as scripts and static HTML pages. These do not have to be
compressed again for every request but can reside in an already compressed format on the file system. It then suffices to add the appropriate
headers to the HTTP response in order to instruct the browser to inflate the transmitted resource:
<filter>
<filter-name>GzipFilter</filter-name>
<filter-class>org.gwtwidgets.server.filters.ResponseHeaderFilter</filter-class>
<init-param>
<param-name>Content-Type</param-name>
<param-value>text/html; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>Content-Encoding</param-name>
<param-value>gzip</param-value>
</init-param>
<init-param>
<param-name>ResponseHeaderFilter.UrlPattern</param-name>
<param-value>.*?\.html</param-value> <!-- Match only *.html URLs -->
</init-param>
</filter>
A few versions ago GWT’s RemoteServiceServlet
started checking certain X-GWT-
headers
generated by the client (more). As this is
a breaking change with ealier SL versions, this check can be enabled optionally in the GWTRPCServiceExporter
(and extending classes) or GWTHandler
with the shouldCheckStrongPermutationName
flag.
If you’ve ever inspected an RPC payload you would notice that it contains the complete class names of the DTOs used. GWT also has a not-so-well
known generator which can produce payloads without these class names, significantly reducing the payload. In order to use it you must:
com.google.gwt.user.RemoteServiceObfuscateTypeNames
in your module xmlGWTRPCServiceExporter.setSerializationFlags()
) on your exporter, which currently (GWT 2.1.1) is AbstractSerializationStream.FLAG_ELIDE_TYPE_NAMES
As of 1.2 you can implement the SL SerializationPolicyProvider
interface (not the GWT one!) and inject it
into your favorite flavour of RPCServiceExporters. Your implementation will then be consulted for each and every
request about the serialization policy to use.
In case you’d like to use multiple serialization policies at the same time, I strongly recommend Alex Moffat’s excellent
LINK_MISSING on that matter which also provides ready to be used code for your use case.
java.lang.NoClassDefFoundError
although the class/jar is there!" class="reference-link">I am seeing a java.lang.NoClassDefFoundError
although the class/jar is there!The most common cause of this error is that not all related classes are loaded by the same class loader. If, for example, the spring library,
GWT, CGLib and your project classes are partially deployed in WEB-INF/lib and common/lib a NoClassDefFoundError
may be thrown.
This is a configuration detail of the concrete servlet container you are using and is often solved by placing all libraries into the same location,
though that may not always be easy because of your web server’s dependencies. A very good overview of how class loading is dealt with can be read
at the Commons Logging project site.
java.lang.reflect.InvocationTargetException
" class="reference-link">I am getting a java.lang.reflect.InvocationTargetException
InvocationTargetException
s are envelopes that contain other exceptions - it occurs when an exception is thrown in a method
which is invoked via reflection and it is the most common exception you will see when your GWT services throw unintentionally an exception.
This is because RPC joins object methods with HTTP requests by relying on method invocation through reflection. The true cause of the exception
then lies deeper in the stack trace and is nested inside the InvocationTargetException
. You may also want to read up on
Exception Translation which discusses the special case of not treating SerializableException
s
as exceptions but propagating them properly back to the client.
ClassFormatError
" class="reference-link">My application runs on a 1.4 JRE and I’m getting a ClassFormatError
Since 0.1.5 the SL requires Java 1.5. If you have to use Java 1.4, consider using a 0.1.4 release of the SL which
includes Java 1.4 support. For this, please consult the corresponding documentation in the 0.1.4 SL.
404
but no exception in the server log" class="reference-link">RPCs to my services don’t work, I’m getting a 404
but no exception in the server logIf you can rule out any other errors and you are not seeing any exceptions in the server log (let’s supposed that logs are working
OK) your URL mappings may be incorrect. The SL hosts multiple RPC services under one or more Spring managed servlets, thus a good
start is to check the URL mappings in web.xml
:
<servlet>
<servlet-name>myRPCServices</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myRPCServices</servlet-name>
<url-pattern>/myRPCServicesURL/*</url-pattern>
</servlet-mapping>
This maps /myRPCServicesURL/...
to a spring servlet which is defined in myRPCServices-servlet.xml
.
Note that the /myRPCServicesURL
part of the URL is already ‘consumed’ by the servlet container and you should not duplicate it in
the subsequent Spring mappings:
<bean id="urlMapping" class="org.gwtwidgets.server.spring.GWTHandler">
<property name="mappings">
<map>
<-- Attention: We don't repeat the servlet URL, so it's not /myRPCServicesURL/service1 but just /service1 -->
<entry key="/service1" value-ref="FirstServiceBean" ></entry>
<entry key="/service2" value-ref="SecondServiceBean" ></entry>
<entry key="/service3" value-ref="ThirdServiceBean" ></entry>
...
</map>
</property>
</bean>
Very basic stand-alone unit test can be run with ant test
. In order to run the demo unit test web application,
first compile it with ant war
and deploy it to a servlet container, it is then accessible under http://myServer:port/gwt-sl
.
It runs a series of automated tests and should conclude with ‘Finished tests’ and no error messages.
The short answer: understand and use the hosted browser’s -noserver
option.
Some background: The embedded tomcat server that comes with the hosted mode browser is intended as a simple aid
when making your first steps with GWT, so that you can focus on client development and so that you do not
have to worry about server configuration. An applications’s ability to run with the hosted mode browser is not
affected by the SL, simply because the SL is a server side framework, while the browser runs the client
side portion of the application code.
Where problems do occur is when you run the browser together with the embedded tomcat server: your application
requires Spring and a mapping of URLs to the RPC services to be set up, but the embedded tomcat starts with
its own configuration instead of yours. Hence it is simpler to setup your own development server, as
you would do with every traditional web application and treat the GWT compiler output as a bunch of static
resources. For an example of such a setup run the package
task of build.xml
and
inspect the contents of the target/webapp
directory or check the equivalent demo WAR in the
project’s download area (sources are in src/test
).
An RPC is nothing but an HTTP request to the server - depending on the HTTP headers returned by the server’s response
it can happen that the browser decides that the response can be cached. This means that future similar requests (with the same URL)
may be served from the browser’s cache. The best way to avoid caching RPC responses is by modifying the HTTP headers of the response
in such a way that browser caching is disabled - for an example of how to do this consult the HTTP Headers chapter.
An alternative solution is to make sure that each request is dispatched to an unique URL, i.e. by appending to each RPC request a parameter
with a random, unique value.
Also note that the SL’s RPC implementations (see chapter 3) attempt to disable response caching by default.
Don’t export services in the application context, always export them in a -servlet.xml
file. GWT’s RPC mechanism expects
a servlet environment into which it logs information. The application context does not provide this
environment (namely the serlvet configuration), which causes GWTRPCServiceExporter
instances
declared in the application context to lack the servlet configuration and thus procude NPEs.
Project homepage https://github.com/ggeorgovassilis/gwt-sl
User group http://groups.google.com/group/gwt-sl/topics
Spring project homepage http://spring.io/
GWT homepage http://www.gwtproject.org/