Quick Start
MyEmailService example
Consider the example provided by Google in their Remote
Procedure Calls documentation. The
service interface is MyEmailService, and is defined as follows:
public interface
MyEmailService extends RemoteService
{
void emptyMyInbox( String username,
String password );
}
|
The corresponding asynchronous service looks like this:
public interface
MyEmailServiceAsync
{
void emptyMyInbox( String username,
String password, AsyncCallback callback );
}
|
And the client-side call is similar to the following:
public void
menuCommandEmptyInbox()
{
MyEmailServiceAsync emailService =
( MyEmailServiceAsync ) GWT.create(
MyEmailService.class );
ServiceDefTarget endpoint = ( ServiceDefTarget
) emailService;
String moduleRelativeURL = GWT.getModuleBaseURL()
+ "email";
endpoint.setServiceEntryPoint(
moduleRelativeURL );
AsyncCallback callback = new
AsyncCallback()
{
public void onSuccess(
Object result )
{
// do some
UI stuff to show success
}
public void onFailure(
Throwable caught )
{
// do some
UI stuff to show failure
}
};
emailService.emptyMyInbox( username,
password, callback );
}
|
To implement the server-side service, you would create a
class that extends RemoteServiceServlet and implements MyEmailService. The problem with this approach is that you
cannot create the service as a POJO, which means you cannot create your own
inheritance structure, and you cannot take advantage of dependency injection
using the Spring application context.
Step 1: Create your remote service
implementation class
GWTSpringRPC allows you to define your remote services as
POJO’s created and managed by the Spring application context. The client-side code remains identical to
the example provided by Google. The
server-side code only needs to implement the service interface. In the below example, the MyEmailService
implementation is created and has a reference to the MyEmailSession EJB
injected into it:
public class
MyEmailServiceImpl implements MyEmailService
{
private
MyEmailSession myEmailSession;
public void emptyMyInbox(
String username, String password )
{
myEmailSession.emptyMyInbox(
username, password );
}
public void
setMyEmailSession( MyEmailSession myEmailSession )
{
this.myEmailSession
= myEmailSession;
}
}
|
Note that the remote service implementation class implements
your remote service interface, but does not extend RemoteServiceServlet.
Step 2: Add your remote service to
your GWT module XML
To define your remote service to GWT, you add your servlet
definition to your GWT module XML.
However, rather than specifying your remote service implementation
class, you use the DelegatingRemoteServiceServlet from GWTSpringRPC:
<module>
. . .
<servlet path="/email"
class="net.sf.gwtspringrpc.servlet.DelegatingRemoteServiceServlet"/>
. . .
</module>
|
This servlet will accept requests from many remote services
and delegate the requests to your POJO remote services.
Step 3: Define your remote service
in the Spring bean configuration
The final step is to define your bean that the
DelegatingRemoteServiceServlet will delegate requests to. An example bean configuration is as follows:
. . .
<bean id="email"
class="com.example.MyEmailServiceImpl">
<property name="myEmailSession"
ref="myEmailSession"/>
</bean>
. . .
|
Accessing servlet API objects
Because your remote service implementations are now detached
from the servlet API, you will not be able to access HttpServletRequest and
HttpServletRespone from GWT’s ThreadLocal objects or ServletContext and
ServletConfig from the servlet API. In
order to access these objects from your remote service POJO, a set of dynamic
proxies has been provided that allow you to treat them as singleton objects.
For example, if our MyEmailService requires the use of the
HttpServletRequest for accessing session attributes, it can be injected using
the Spring application context. First,
we need to declare the variable in the MyEmailServiceImpl class and write a
setter:
public class
MyEmailServiceImpl implements MyEmailService
{
private
MyEmailSession myEmailSession;
private
HttpServletRequest request;
public void emptyMyInbox(
String username, String password )
{
request.getSession().setAttribute(
"emptied", Boolean.TRUE );
myEmailSession.emptyMyInbox(
username, password );
}
public void
setMyEmailSession( MyEmailSession myEmailSession )
{
this.myEmailSession
= myEmailSession;
}
public void setRequest(
HttpServletRequest request )
{
this.request = request;
}
}
|
Then we need to declare the HttpServletRequest dynamic proxy
and inject it into the email bean:
. . .
<bean id="request"
class="net.sf.gwtspringrpc.http.SingletonHttpServletRequestFactoryBean"/>
<bean id="email"
class="com.example.MyEmailServiceImpl">
<property name="myEmailSession"
ref="myEmailSession"/>
<property name="request"
ref="request"/>
</bean>
. . .
|
There are dynamic proxies available for accessing the
following servlet classes:
Servlet Class
|
Dynamic Proxy
|
javax.servlet.ServletContext
|
net.sf.gwtspringrpc.http.SingletonServletContextFactoryBean
|
javax.servlet.ServletConfig
|
net.sf.gwtspringrpc.http.SingletonServletConfigFactoryBean
|
javax.servlet.http.HttpServletRequest
|
net.sf.gwtspringrpc.http.SingletonHttpServletRequestFactoryBean
|
javax.servlet.http.HttpServletResponse
|
net.sf.gwtspringrpc.http.SingletonHttpServletResponseFactoryBean
|
How it works
When the DelegatingRemoteServiceServlet receives the request
to process the remote procedure call, it does the following:
- Stores
the servlet API objects in ThreadLocal objects so that they are accessible
by the dynamic proxies.
- Resolves
the bean name using a BeanNameResolver instance. The default instance will use the servlet path as the bean
name; in our above example, the servlet path is “/email”, so the bean name
is “email”. The BeanNameResolver
can be overridden to determine the bean name in a different fashion.
- Retrieves
a web application context using a WebApplicationContextRetriever instance,
and retrieves the bean from the web application context. The default
WebApplicationContextRetriever instance retrieves a servlet context
attribute named “org.springframework.web.context.WebApplicationContext.ROOT”,
but can be overridden to retrieve the application context in a different
fashion.
- Decodes
the RPC request and invokes the method on the delegated bean.