Integrating Spring managed services without extending a base class

24 views
Skip to first unread message

georgeuoa

unread,
Sep 2, 2006, 1:49:38 PM9/2/06
to Google Web Toolkit
While integrating Spring managed services with GWT can be done with the
GWTSpringController, some people argue that extending this controller
limits them in their choices - point taken, java does not have multiple
inheritance and that makes the choice tough.

I came up with a solution that:

- Allows creation of services that don't depend on any API
- Does not change the code of RemoteServiceServlet

And so the DelegatingFactoryBean [1], [2] was born.

It allows you to create POJO services and wrap GWT around them, having
it RPC method calls forward to your service. It is more a proof of
concept, both in design and implementation, the performance is mediocre
and I have not given any thought to the prototype/singleton
distinction.

The idea behind it is that the DelegatingFactoryBean creates via the
excellent CGLIB in runtime a class which extends the
GWTSpringController, wraps around an object (your service) and then
proxies any number of interfaces (important: your service interface
extending RemoteService). So, in the end, the DelegatingFactoryBean
creates GWTSpringController instances which:
- Extend the RemoteServiceServlet (per default)
- Implement your Service interface
- Wrap around an instance of your service
- Forward calls for the Service interface to your wrapped service
implementation

Things to do:
- Make thorough use of the CGLIB to invoke the wrapped service via
method calls instead of reflection
- Look into singleton/prototype generation
- Infer the implemented interfaces from the wrapped object instead of
supplying them

I am looking forward to your comments
G.

P.S: Please note that you will need a patched GWTSpringController [3],
the one in the 1.0 widget library is unaware of the application context
.
[1].

ackage gwtspring.serverimpl;

import java.lang.reflect.Method;
import java.util.List;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

public class DelegatingFactoryBean extends GWTSpringController
implements FactoryBean, InitializingBean {
private Object target;
private Enhancer enhancer;
private Class objectType;
private Class[] proxyInterfaces;

private Class[] getClasses(Object[] objects)
{
if (objects == null)
return null;
Class[] classes = new Class[objects.length];
for (int i = 0; i < objects.length; i++)
classes[i] = objects[i].getClass();
return classes;
}
private MethodInterceptor callback = new MethodInterceptor() {
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable
{
try
{
Method methodToInvoke =
target.getClass().getMethod(method.getName(), getClasses(args));
return methodToInvoke.invoke(target, args);
}
catch (NoSuchMethodException e)
{
return proxy.invokeSuper(obj, args);
}
}
};

public Object getObject() throws Exception
{
return enhancer.create();
}

public Class getObjectType()
{
return objectType;
}

public boolean isSingleton()
{
return true;
}

public void setTarget(Object parentObject)
{
this.target = parentObject;
}

public void afterPropertiesSet() throws Exception
{
enhancer = new Enhancer();
enhancer.setSuperclass(GWTSpringController.class);
enhancer.setInterfaces(proxyInterfaces);
enhancer.setCallbackType(MethodInterceptor.class);
objectType = enhancer.createClass();
enhancer.setCallback(callback);
}

public void setProxyInterfaces(List<String> proxyInterfaces) throws
Exception
{
this.proxyInterfaces = new Class[proxyInterfaces.size()];
for (int i = 0; i < proxyInterfaces.size(); i++)
{
String interfaceName = proxyInterfaces.get(i);
this.proxyInterfaces[i] = Class.forName(interfaceName);
}
}
}


[2]
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/GWTSpring.rpc">TestController</prop>
</props>
</property>
</bean>

<bean id="TestServiceImpl"
class="gwtspring.serverimpl.TestServiceImpl" />
<bean id="GWTSpringController"
class="gwtspring.serverimpl.GWTSpringController" />
<bean id="PropagatingAdvice"
class="gwtspring.serverimpl.PropagatingAdvice">
<property name="wrappedObject" ref="TestServiceImpl"/>
</bean>


<bean id="TestController"
class="gwtspring.serverimpl.DelegatingFactoryBean">
<property name="target" ref="TestServiceImpl"/>
<property name="proxyInterfaces">
<list>
<value>gwtspring.server.TestService</value>
</list>
</property>
</bean>

</beans>

[3] public class GWTSpringController extends
org.gwtwidgets.server.rpc.GWTSpringController implements Controller,
ServletContextAware {

private ServletContext context;

public void setServletContext(ServletContext context)
{
this.context = context;
}

public ServletContext getServletContext()
{
return context;
}
}

rlogman

unread,
Sep 3, 2006, 10:50:15 AM9/3/06
to Google Web Toolkit
Congratulations. I think this is THE way, so let's have it done.

My only concern is what you say about this solution's "mediocre"
performance.

To be honest, I'm a newbie with Spring and I haven't used CGLIB before,
but what I understand is that the overhead would be specially in
startup time (while initializing proxyInterfaces), which I consider
completely acceptable for a serious application.

And during runtime, the most time consuming operation would be defining
methodToInvoke. Wouldn't it be better to scan all interface's methods
in setProxyInterfaces and build some sort of cache to have them ready
to use? This would make startup even more expensive, but would improve
runtime performance.

Does it make sense?

Rodrigo.

georgeuoa

unread,
Sep 3, 2006, 4:03:04 PM9/3/06
to Google Web Toolkit
Thank you :-)

Allow me to briefly explain why I consider this approach slow. Consider
this example where I have a base class C (= the GWTSpringController),
an Interface I (= your service interface), an class IImpl (your
service) which implements I. And now we need a run-time generated class
CnI which extends C (we want it to have all the abilities of the
GWTSpringController) and I (we also want it to be a service) but
forward all method invocations on I to IImpl:

Class C{
...
}

Interface I{
public Object m1(...);
public Object m2(...);
...
}

class IImpl implements I{
...
}

If you were to hand-code the CnI class you would do smth like:

Class CnI extends C implements I{

private I implementationOfI;

public Object m1(...){
return I.m1(...);
}

public Object m2(...){
return I.m2(...);
}
}

This leads to optimum performance (I suspect the VM will flatten out
the method wrappings anyway) and no CPU cycle is wasted. But look at
the solution I provided: _every_ method invocation goes through a
reflexive lookup. Even if we get around that and store the methods in a
hashmap, that is still a lookup in runtime compared to the hard-wired
invocation made in compile time. I am quite certain that there is a
solution using CGLIB, but quite like yourself I have not used CGLIB for
too long and do not yet know how to solve this.

I favour this approach particularily over having the GWT team open
their RemoteServiceServlet and letting people register their services
with it, because the RemoteServiceServlet will have to lookup the
methods via reflection - while the GWTSpringController can do it in
compile time.

I'm counting on your help here :-)
G.

ijuma

unread,
Sep 3, 2006, 6:45:56 PM9/3/06
to Google Web Toolkit
georgeuoa wrote:
> This leads to optimum performance (I suspect the VM will flatten out
> the method wrappings anyway) and no CPU cycle is wasted. But look at
> the solution I provided: _every_ method invocation goes through a
> reflexive lookup.

I would just like to mention that even though a call using reflection
is generally slower than a direct method call, its performance is quite
respectable with recent VMs. For example,Hotspot already speeds up
reflective calls by bytecode generation internally[1].

Regards,
Ismael

[1] http://blogs.sun.com/sundararajan/entry/invokespecialdynamic

georgeuoa

unread,
Sep 4, 2006, 2:31:32 AM9/4/06
to Google Web Toolkit
Hi ismael. Thanks for pointing this out. Well you are both wrong and
right :-)
Reflexion is indeed fast, but it is much slower than direct method
invocation, try running [1].

That's about the wrong side. The right side is, even like this, it's
fast enough. Considering that atop of a reflective method invocation
we'll still have HTTP traffic, RPC serialisation and the whole business
logic (DB access?) it is indeed negligible.

+ and much important, I forgot that the GWTSpringController (as
extending the RemoteServiceServlet) would access the implemented
interface via reflexion anyway! So, yes, there is no imminent
requirement for fully cglib-ing the controller - but I'd like to do it
just for the fun of it and the psychological impact of knowing that no
pulse of your GHz CPU is wasted :-)

G.


[1] import java.lang.reflect.Method;

public class PerfTest {

public int inc(int a) {
return a + 1;
}

public static void main(String... strings) throws Exception {

for (int warmup = 100; warmup >= 0; warmup--) {
PerfTest ttest = new PerfTest();
Object test = ttest;
long start = System.currentTimeMillis();
int a = 0;
Object args[] = new Object[] { a };
for (int i = 0; i < 100000; i++) {
Method method = test.getClass().getMethod("inc", new Class[] {
int.class });
args[0] = a;
a = (Integer) method.invoke(test, args);
}

long end = System.currentTimeMillis();

if (warmup == 0) {
System.out.println(a);
System.out.println("Reflexive invocation: " + (end - start));
}

start = System.currentTimeMillis();
a = 0;
for (int i = 0; i < 100000; i++) {
a = ttest.inc(a);
}
if (warmup == 0) {
System.out.println(a);
end = System.currentTimeMillis();
System.out.println("Direct invocation: " + (end - start));
}
}
}
}

ijuma

unread,
Sep 4, 2006, 5:56:21 AM9/4/06
to Google Web Toolkit
georgeuoa wrote:
> Hi ismael. Thanks for pointing this out. Well you are both wrong and
> right :-)
> Reflexion is indeed fast, but it is much slower than direct method
> invocation, try running [1].

I never said reflection was faster than direct calls. In fact, I said
it was slower, but with respectable performance. :)

Micro-benchmarks are dangerous. :) Anyway, if you want to make your
benchmark a little bit more realistic even if it's still a
microbenchmark that is not really useful for most scenarios, try this:

1) Change the inc(int) method to inc(String) and return a String. This
way the reflection code doesn't have to do boxing and unboxing.
2) Cache the method object in a map.

With these two changes, I actually get about the same performance for
direct and reflection based calls. But again, this is just a
microbenchmark and running short loops like that several times allows
an optimising VM like HotSpot (I am using the latest jdk6 snapshot) to
optimise it greatly.

> That's about the wrong side. The right side is, even like this, it's
> fast enough. Considering that atop of a reflective method invocation
> we'll still have HTTP traffic, RPC serialisation and the whole business
> logic (DB access?) it is indeed negligible.
>
> + and much important, I forgot that the GWTSpringController (as
> extending the RemoteServiceServlet) would access the implemented
> interface via reflexion anyway!

Exactly.

> So, yes, there is no imminent
> requirement for fully cglib-ing the controller - but I'd like to do it
> just for the fun of it and the psychological impact of knowing that no
> pulse of your GHz CPU is wasted :-)

That is a different story altogether. :)

Regards,
Ismael

tiepi

unread,
Sep 4, 2006, 8:15:49 PM9/4/06
to Google Web Toolkit
Hi George:

I believe your idea is excellent! Could u polish DelegatingFactoryBean
and put it in GwtWidget next release? that would benefit a lot of
developer.

WangQi.

IamRobe...@gmail.com

unread,
Sep 5, 2006, 10:52:18 AM9/5/06
to Google Web Toolkit
I am a Spring user, but I don't consider myself a power-user, so please
feel free to tell me that I have no idea what I am talking about.

My question is, does the proposed Spring configuration
(http://groups.google.com/group/Google-Web-Toolkit/msg/e8a58aad7a8c867f)
need to be so complicated?

<beans>
<bean class="gwtspring.GWTServiceMapping">
<property name="mappings">
<props>
<prop key="/GWTSpring.rpc" value="TestServiceImpl"/>
</props>
</property>
</bean>

<bean id="TestServiceImpl"
class="gwtspring.serverimpl.TestServiceImpl" />

</beans>

I expect the argument against this idea is that the solution will lose
a lot of it's flexibility. I am just thinking that maybe simplifying
the config is worth the trade-off.

Flames welcome.

Rob

georgeuoa

unread,
Sep 5, 2006, 11:32:42 AM9/5/06
to Google Web Toolkit
Hello Robert

The configuration you propose seems very compact and I am not sure I
completely understand it. If I am correct, you propose that a
HandlerMapping instance intercepts the HTTPRequest, deserialises RPC
and invokes based on this the correct method of the TestServiceImpl
bean... interesting! It seems indeed to be the simplest possible
configuration.

I am however somewhat concerned over the bindings of these things:
Currently the RemoteServiceServlet expects a descendant of it self to
implement the service interface (it looks that up via reflection on
'this'). Thus, unless we want to be really creative, the outcome has
always to be a class that :

a) extends RemoteServiceServlet
b) implements an interface extending the RemoteService interface
c) and, since this whole discussion is about using POJOs, delegates the
interface methods to a (wrapped or cglib enhanced) instance of your
service.

Somewhere hidden in the mapper we'd need a RemoteServiceServlet
instance which we must 'merge' with the TestServiceImpl (we provide it
as a mapping in runtime thus the 'merging' takes place in runtime), so
again we can't avoid cglib-style class enhancing.
I will look into the conventions of handler mappings, but if you're
right, that will lead to a vastly improved configuration.

Regards
G.

Robert Hanson

unread,
Sep 5, 2006, 2:54:29 PM9/5/06
to Google-We...@googlegroups.com
On 9/5/06, georgeuoa <g.georgo...@gmail.com> wrote:
> The configuration you propose seems very compact and I
> am not sure I completely understand it.

George, I think you got the basic idea. The only thing I was trying
to infer was ease of configuration. The less steps I need to remember
when configuring a new service, the better.

Rob

georgeuoa

unread,
Sep 8, 2006, 8:29:20 PM9/8/06
to Google Web Toolkit
Dear All

Following your suggestions I implemented the GWTHandler which maps URLs
to RemoteService implementations. The novelty lies in that from now on
you do not have to extends either the RemoteServiceServlet nor the
GWTSpringController yourself - that is done by the GWTHandler through
the CGLIB transparently and in runtime so that you can write plain POJO
services.

The source code is here [1]
The source code with dependencies (spring, cglib, gwt) is here [2]

The usage is as simple [3] as suggested by Robert. Please note that I
consider this a functional draft with several remaining issues such as:

- Providing correct setup for the GWTSpringController part (servlet
context)
- Ensuring correct interface lookup via reflection (cases like method
visibility, overloading, interface inheritance etc)
- Have the GWTHandler implement only the service interfaces extending
RemoteService for security
- Implementing delegate's interfaces via bytecode instrumentation
rather than dynamic proxying

Also, unless you get there before me, I plan on writing a short example
article on how to use it.

Best wishes for the weekend ahead
G.

[1] http://g.georgovassilis.googlepages.com/GWTHandler.nolib.tar.gz
[2] http://g.georgovassilis.googlepages.com/GWTHandler.tar.gz
[3] Usage example:

<bean id="urlMapping"
class="org.gwtwidgets.server.rpc.GWTHandler">
<property name="mapping">
<map>
<entry key="/GWTSpring/add.rpc" value-ref="ServiceAdd"/>
<entry key="/GWTSpring/sub.rpc" value-ref="ServiceSub"/>
</map>
</property>
</bean>

<bean id="ServiceAdd" class="gwtspring.serverimpl.ServiceAddImpl"/>
<bean id="ServiceSub" class="gwtspring.serverimpl.ServiceSubImpl"/>

tiepi

unread,
Sep 13, 2006, 2:57:44 AM9/13/06
to Google Web Toolkit
thanks, george!

I try it and it works perfectly.

WangQi

georgeuoa

unread,
Sep 13, 2006, 5:31:29 AM9/13/06
to Google Web Toolkit
I'm glad it works :-)

A somewhat more configurable, better documented and more performant
version will be included is announced [1] for the next gwt-widget
library, I hope to be able to write a short introduction blog about it
though it's usage is indeed very simple.

Best regards
G.

[1]
http://groups.google.com/group/Google-Web-Toolkit/browse_thread/thread/a9a39d4ea37e95c5/6d16f90a3e5802b0?

rlogman

unread,
Sep 13, 2006, 9:51:24 AM9/13/06
to Google Web Toolkit
Superb solution!

Thanks for your contribution.

georgeuoa

unread,
Sep 25, 2006, 3:50:01 AM9/25/06
to Google Web Toolkit
Dear All

I wrote a short introduction & user manual for the GWTHandler included
with the GWT Server Library as well as a small demo application [1].

BR
G.

[1] http://g.georgovassilis.googlepages.com/usingthegwthandler

François

unread,
Sep 25, 2006, 10:31:31 AM9/25/06
to Google-We...@googlegroups.com
George:

Many thanks,

François

-----Message d'origine-----
De : Google-We...@googlegroups.com
[mailto:Google-We...@googlegroups.com] De la part de georgeuoa
Envoyé : 25 septembre 2006 03:50
À : Google Web Toolkit
Objet : Re: Integrating Spring managed services without extending a base
class

Reply all
Reply to author
Forward
0 new messages