GWTHandler Startup Exceptions

70 views
Skip to first unread message

cho.cabot

unread,
Oct 27, 2006, 1:09:34 PM10/27/06
to Google Web Toolkit
I am trying to use the GWTHandler in my Spring environment. I have the
latest version of the handler (0.1.1) and Spring (2.0). When I start
the server (Tomcat), I get the following exception when using CGLIB:

org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'urlMapping' defined in ServletContext resource
[/WEB-INF/c1-servlet.xml]: Invocation of init method failed; nested
exception is net.sf.cglib.core.CodeGenerationException:
java.lang.reflect.InvocationTargetException-->null
Caused by:
net.sf.cglib.core.CodeGenerationException:
java.lang.reflect.InvocationTargetException-->null
at
net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237)
at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:285)
at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:676)
at
org.gwtwidgets.server.spring.enhancer.CGLIBEnhancer.createController(CGLIBEnhancer.java:38)...

And I get this exception when trying to use javassist:

org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'urlMapping' defined in ServletContext resource
[/WEB-INF/c1-servlet.xml]: Invocation of init method failed; nested
exception is java.lang.RuntimeException:
javassist.CannotCompileException: by java.lang.IllegalAccessError:
class
org.gwtwidgets.server.spring.enhancer.GWTSpringDelegatingController7369094552623412725
cannot access its superclass
org.gwtwidgets.server.spring.enhancer.GWTSpringDelegatingController
Caused by:
java.lang.RuntimeException: javassist.CannotCompileException: by
java.lang.IllegalAccessError: class
org.gwtwidgets.server.spring.enhancer.GWTSpringDelegatingController7369094552623412725
cannot access its superclass
org.gwtwidgets.server.spring.enhancer.GWTSpringDelegatingController
at
org.gwtwidgets.server.spring.enhancer.JavassistEnhancer.createController(JavassistEnhancer.java:191)...

Any help in resolving these problems would be greatly appreciated.
Thanks

-DLC

georgeuoa

unread,
Oct 27, 2006, 4:39:13 PM10/27/06
to Google Web Toolkit
Hello DLC

Unfortunately I can't trace the error... if I had to guess I would
ascertain that my webapp's libraries are all in the WEB-INF/lib folder
and not partially situated in the servlet context's classloader.

If could you post or mail me with your web.xml, application context and
c1-servlet.xml I would do my best to reproduce your case and maybe be
of better assistance.

Regards
G.

JM

unread,
Oct 28, 2006, 12:20:30 AM10/28/06
to Google Web Toolkit
One thing I would check is to make sure you have the asm jars in your
WEB-INF/lib. I've seen this error before running a normal standalone
spring app. The exception that's produced is pretty misleading. Hope
that's the problem.

ash

unread,
Oct 28, 2006, 8:47:22 AM10/28/06
to Google Web Toolkit
george,

i dont think that there is anything wrong with your gwt handler
implementations. i have just updated to r78 from trunk and recompiled
the gwt-petstore[1] application and all is fine.

the only problem that i have not been able to resolve is using
javassist instead of cglib in _hosted mode_. maybe the asm jars that JM
describes might do the trick, dont know - havent tried. i have used
javassist in the past and preferred that impl, but have not bothered
with it for the gwt-handler b/c cglib seemed to work consistently.

there is one thing that i think would be helpful though. is it possible
to inject the httpservletrequest?

eg. you can see in my shopping rpc controller example[2] that i inject
the PetStoreFacade. but suppose i wanted to maintain state on my
server-side controller. from this context i have effectively lost a
handle to the httpservletrequest from
RemoteServiceServlet#getThreadLocalRequest(). can u suggest an approach
to get a handle to it?

btw, you will also notice that i distribute your lib identified as
"gwt-widgets-spring.jar"[3]. at this stage i dont want to have a
dependency on anything other than your gwt-handler. also, i havent got
around to adding your license to the distro. its on my todo list.

1 - http://code.google.com/p/gwtpetstore/
2 -
http://gwtpetstore.googlecode.com/svn/trunk/src/au/com/gworks/gwt/petstore/server/ShoppingRpcControllerImpl.java
3 - http://gwtpetstore.googlecode.com/svn/trunk/lib/

rgds ash
http://www.gworks.com.au

cho.cabot

unread,
Oct 28, 2006, 9:06:14 AM10/28/06
to Google Web Toolkit
I initially had all my jars in the common/lib directory, but I moved
them all to the WEB-INF/lib directory and now everything works fine
(both cglib and javassist). Thanks for everyone's input.

BTW, I would second the request for injecting the httpservletrequest,
if possible.

georgeuoa

unread,
Oct 29, 2006, 4:08:25 AM10/29/06
to Google Web Toolkit
Thank you for your comments gentlemen

DLC, I am glad to hear that putting your classes in the application
classloader solved the issue you were observing. As a matter of fact
this occasionally obstructs development in other (non GWT) web
applications as well... I'm thinking here of spring/hibernate residing
in different classloaders from cglib, JTA et al, not seeing each other
classes... you'd see the most unbelievable errors like ClassNotFound
errors on classes sitting right in front of you!

Ash, DLC, about getting the ServletRequest: I added two static methods
to the GWTSpringController (yes, they are also valid in GWTHandler
managed services) which give access to the request/response... though
I'm not sure if the latter is of any practical use. It is done by the
usual thread local trick, thus the implementation is susceptible to
asynchronous invocation techniques - normally you wouldn't care, I
mention this just in case you do. Changes committed in the project's
svn.

I also think that Spring 2.0 has some utility class giving away the
servlet request.

BR
G.

georgeuoa

unread,
Oct 30, 2006, 2:09:05 AM10/30/06
to Google Web Toolkit

ash

unread,
Oct 30, 2006, 4:39:55 AM10/30/06
to Google Web Toolkit
hey george,

thx for that and it does indeed satisfy the requirements.

however, at the moment my pojo rpc impls have no dependency on spring.
my preference is to keep it that way.

i havent put much thought into this and i havent spent the time
understanding your enchancer package, but i was thinking about
something along the following lines:

before execution context is passed to the target delegate method, a
check is made as to whether the impl has a "setHttpServletRequest()"
method, and if so the value is injected using that method.

i hope that made sense. please let me know if you have a better
suggestion.

rgds ash
http://www.gworks.com.au

georgeuoa

unread,
Oct 30, 2006, 6:45:09 AM10/30/06
to Google Web Toolkit
Repost, first submission failed. My appologies if this is a duplicate.

Hi Ash

What you propose is a practice Spring uses alot, think of the
ApplicationContextAware, BeanNameAware etc interfaces which, once
implemented by the bean will cause a setXYZ() to be performed on the
bean during its initialisation.

In your case you cannot really use that because it's neither reentrant
nor thread safe - two simultaneous requests would simply overwrite the
request on your service. And, nag nag, if your service is proxied a lot
(mine are!) this is also much slower than packaging the request in a
thread local. Whatever solution implemented in the end, must probably
operate on a method-invocation level and not on the object level.

Looking forward to your comments
G.

ash

unread,
Oct 30, 2006, 10:56:59 PM10/30/06
to Google Web Toolkit
mate,

here are some mods that i have made to your code. i tried to optimise
it a bit more, but really couldnt do much better than what you had
already achieved.

it shits me that all methods are being intercepted. i would prefer to
just intercept those target methods on the interface and let all
google's RemoteServiceServlet methods simply pass through.

anyway, let me know what you think. i have commented my changed with
<<ash>> tags so that u can review diffs more easily.

/*
* Copyright 2006 George Georgovassilis <g.georgovassilis[at]gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gwtwidgets.server.spring.enhancer;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.gwtwidgets.server.spring.GWTHandler;
import org.gwtwidgets.server.spring.GWTSpringController;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializableException;


/**
* Callback for CGLIB which determines wether the method invoked
belongs to the
* delegate object or the CGLIB-enhanced {@link GWTSpringController}.
This
* class is for internal use of the {@link GWTHandler}.
*
* @author g.georgovassilis[at]gmail.com
*
*/
class DelegatingCallback implements MethodInterceptor {
final static public Class[] setThreadLocalHttpServletRequestParams =
{HttpServletRequest.class};

private RemoteService target;

private Map<Method, Method> methodsOnTarget = new HashMap<Method,
Method>();

private Map<Method, Method> methodsOnExtendedClass = new
HashMap<Method, Method>();

private Method setThreadLocalHttpServletRequestMethod; // <<ash>>

private boolean unwrapExceptions;

/**
* Wrap this callback around a service
*
* @param target
* @param true
* if you want {@link SerializableException} instances to
be
* unwrapped
*/
DelegatingCallback(RemoteService target, boolean unwrapExceptions) {
this.target = target;
this.unwrapExceptions = unwrapExceptions;
prepareCallInterface(); // <<ash>> - upfront prep
}


private synchronized Method getMethodToInvoke(Object target,
Object[] arguments, Method prototypeMethod,
Map<Method, Method> lookup) {
Method methodToInvoke = null; // <<ash>> see all cache check
Class targetClass = target.getClass();
Class[] parameterTypes = prototypeMethod.getParameterTypes();
String methodName = prototypeMethod.getName();

try {
methodToInvoke = targetClass.getMethod(methodName, parameterTypes);
lookup.put(prototypeMethod, methodToInvoke);
return methodToInvoke;
} catch (Exception e) {
}

try {
methodToInvoke = targetClass.getDeclaredMethod(methodName,
parameterTypes);
lookup.put(prototypeMethod, methodToInvoke);
return methodToInvoke;
} catch (Exception e) {
}
return null;
}

private Method getInvokerFromCaches(Method prototype, boolean[]
targetCache) {
Method ret = methodsOnTarget.get(prototype);
if (ret != null)
targetCache[0] = true;
else {
ret = methodsOnExtendedClass.get(prototype);
targetCache[0] = false;
}
return ret;
}

/**
* {@inheritDoc}
*/
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
boolean[] inTargetCache = new boolean[1];
Method methodToInvoke = getInvokerFromCaches(method, inTargetCache);
try {
// <<ash>> - refactored for optimisation
if (methodToInvoke == null) { // Method cached on target?
methodToInvoke = getMethodToInvoke(target, args, method,
methodsOnTarget);
if (methodToInvoke != null)
inTargetCache[0] = true;
else // Method cached on cglib's class ?
methodToInvoke = getMethodToInvoke(obj, args, method,
methodsOnExtendedClass);
}
if (methodToInvoke != null) {
if (inTargetCache[0]) {
if (setThreadLocalHttpServletRequestMethod != null) {
Object[] raArgs = new Object[]
{GWTSpringController.getRequest()};
setThreadLocalHttpServletRequestMethod.invoke(target, raArgs);
}
return methodToInvoke.invoke(target, args);
} else
return proxy.invokeSuper(obj, args);
}
} catch (Throwable e) {
if (!unwrapExceptions) throw e;
Throwable cause = e;
while (true){
if (cause == null) throw e;
if (cause instanceof SerializableException) throw cause;
cause = cause.getCause();
}
}
throw new NoSuchMethodException(method.getName() + " on " +
obj.getClass());
}

private void prepareCallInterface() { // <<ash>> - get handle to
setThreadLocalHttpServletRequest method if available
Class targClz = target.getClass();
try {
setThreadLocalHttpServletRequestMethod =
targClz.getDeclaredMethod("setThreadLocalHttpServletRequest",
setThreadLocalHttpServletRequestParams);
} catch (NoSuchMethodException err) {
// its ok, not all rpc impls will declare one
}
}
}

// --------------------------

package com.mycompany.project.server;

import javax.servlet.http.HttpServletRequest;

import com.mycompany.project.client.TestRpc;

public class SpringTestRpcImpl implements TestRpc {
private ThreadLocal<HttpServletRequest> threadsHttpServletRequest =
new ThreadLocal<HttpServletRequest>();

public SpringTestRpcImpl() {
System.out.println("SpringTestRpcImpl created");
}

public String test() {
return "Hello World";
}

public void setThreadLocalHttpServletRequest(HttpServletRequest req) {
threadsHttpServletRequest.set(req); // this gets called prior to the
method
}
}


let me know if i have broken some contract without realizing it.

rgds ash
http://www.gworks.com.au

georgeuoa

unread,
Nov 1, 2006, 6:00:48 PM11/1/06
to Google Web Toolkit
Hello Ash

Thank you for taking all the time and coming up with this solution!
Your code seems fine, from a technical standpoint sound and passes the
tests without a problem. I was surprised by the modest impact of these
changes on the outcome. During the standart 1sec test your solution
outperforms the default DelegatingCallback on my machine by about 10%.
What completely knocked me over was what happened once the test
duration is increased to 30sec: your code performs then actually worse
than the current implementation, but again about the same marginally
difference. My results in invocations/sec for the 30sec run:

client vm
ash : 1334508
cglib : 1439809
javassist : 34106509

server vm
ash : 2745261
cglib : 2938247
javassist : 58745240

I think that your intuition is right though, I must find a way to short
circuit method invocations with fewer and more effective lookups...
though there is probably no better way than what javassist does :(

G.

ash

unread,
Nov 2, 2006, 6:35:00 AM11/2/06
to Google Web Toolkit
hey george,

> Thank you for taking all the time and coming up with this solution!

no worries.

i was determined to create a solution such that rpc impls had no
dependencies on either:
1. spring
2. gwt-widgets server lib / gwt handler

i've been creating pojo based rpc impls since 1.0.21. my gems-v1
solution hacked the gwt RemoteServiceServlet. i needed specific methods
openned up, i needed to ignore serialization signature checking; it was
a _real_ hack and i suffered for it. each gwt distro caused me
migration pain. my only savour would be if the gwt team openned up
their apis - but that was never going to happen.

your solution was always abstracted from gwt release issues. however,
it was not until u released the gwthandler version, that it is
satisfied my motivations. afaik, u created a better version of what i
was doing in gems-v1. i personally consider it a great contribution to
the gwt community and promote it as much as i can. well done man.

> I think that your intuition is right though, I must find a way to short
> circuit method invocations with fewer and more effective lookups...
> though there is probably no better way than what javassist does :(

indeed, the short circuit is where i believe we will achieve the
greatesst performance gain. i also think that more could be done
upfront in prepareCallInterface().


rgds ash
http://www.gworks.com.au

ash

unread,
Nov 5, 2006, 2:27:07 AM11/5/06
to Google Web Toolkit
george,

when u presented to performance metrics to me, ive now decided to go
with a cglib impl for development and a javassist impl for production.

i still cant get javassist to work in hosted mode and dont want to give
up my new found freedom.

anyway, i decided to revisit both impl today and here are the results.
both impls now support the setThreadLocatHttpServletRequest()
injection.

once again, let me know what u think.

i will place each impl in a separate post to help with clarity

rgds ash
http://www.gworks.com.au

ash

unread,
Nov 5, 2006, 2:28:30 AM11/5/06
to Google Web Toolkit
RE: CGLIB impl

package org.gwtwidgets.server.spring.enhancer;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.gwtwidgets.server.spring.GWTHandler;
import org.gwtwidgets.server.spring.GWTSpringController;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializableException;


/**
* Callback for CGLIB which determines wether the method invoked
belongs to the
* delegate object or the CGLIB-enhanced {@link GWTSpringController}.
This
* class is for internal use of the {@link GWTHandler}.
*

* notes: - simplified & short circuited lookup
* @author Ashin Wimalajeewa (ash)


*
*/
class DelegatingCallback implements MethodInterceptor {

private RemoteService target;
private boolean unwrapExceptions;

private Method setThreadLocalHttpServletRequestMethod;
private Class targetClass;
private Map<Method, Method> callInterfaceMethods = new HashMap<Method,
Method>();

/**


* Wrap this callback around a service
*
* @param target
* @param true
* if you want {@link SerializableException} instances to
be
* unwrapped
*/
DelegatingCallback(RemoteService target, boolean unwrapExceptions) {
this.target = target;
this.unwrapExceptions = unwrapExceptions;
prepareCallInterface();
}

public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
boolean isAbs = Modifier.isAbstract(method.getModifiers());
if (!isAbs)
return proxy.invokeSuper(obj, args);
try {
return invokeCallInterfaceMethod(method, args);


} catch (Throwable e) {
if (!unwrapExceptions) throw e;
Throwable cause = e;
while (true){
if (cause == null) throw e;
if (cause instanceof SerializableException) throw cause;
cause = cause.getCause();
}
}
}

private Object invokeCallInterfaceMethod(Method method, Object[] args)
throws Throwable {
Method invoker = callInterfaceMethods.get(method);


if (setThreadLocalHttpServletRequestMethod != null) {
Object[] raArgs = new Object[] {GWTSpringController.getRequest()};
setThreadLocalHttpServletRequestMethod.invoke(target, raArgs);
}

if (invoker == null) {
invoker = targetClass.getMethod(method.getName(),
method.getParameterTypes());
callInterfaceMethods.put(method, invoker);
}
return invoker.invoke(target, args);
}

private void prepareCallInterface() {
targetClass = target.getClass();
setThreadLocalHttpServletRequestMethod =
ClassEnhancer.Utils.querySetThreadLocalHttpServletRequestMethod(targetClass);
}
}


public interface ClassEnhancer {
final static public Class[]
SET_THREAD_LOCAL_HTTP_SERVLET_REQUEST_PARAMS =
{HttpServletRequest.class};
final static public String SET_THREAD_LOCAL_HTTP_SERVLET_REQUEST_METH
= "setThreadLocalHttpServletRequest";

public GWTSpringController createController(RemoteService delegate,
boolean unwrapGWTExceptions);


static public class Utils {
static public Method
querySetThreadLocalHttpServletRequestMethod(RemoteService rpcImpl) {
Class implClass = rpcImpl.getClass();
return querySetThreadLocalHttpServletRequestMethod(implClass);
}

static public Method
querySetThreadLocalHttpServletRequestMethod(Class implClass) {
Method ret = null;
try {
ret =
implClass.getDeclaredMethod(ClassEnhancer.SET_THREAD_LOCAL_HTTP_SERVLET_REQUEST_METH,
ClassEnhancer.SET_THREAD_LOCAL_HTTP_SERVLET_REQUEST_PARAMS);


} catch (NoSuchMethodException err) {
// its ok, not all rpc impls will declare one
}

return ret;
}
}
}

rgds ash
http://www.gworks.com.au

ash

unread,
Nov 5, 2006, 2:29:30 AM11/5/06
to Google Web Toolkit
RE: javassist impl

package org.gwtwidgets.server.spring.enhancer;

import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.LoaderClassPath;
import javassist.Modifier;
import javassist.NotFoundException;

import org.apache.commons.logging.Log;
import org.gwtwidgets.server.spring.GWTSpringController;
import org.gwtwidgets.server.spring.ReflectionUtils;
import org.springframework.aop.framework.Advised;

import com.google.gwt.user.client.rpc.RemoteService;

/**
* Class enhancer based on the Javassist instrumentation library.
* notes: refactored george's impl to support
rpcImp#setThreadLocalHttpServletRequest()
*


* @author Ashin Wimalajeewa (ash)
*
*/

public class JavassistEnhancer implements ClassEnhancer {
private Log logger;

public JavassistEnhancer(Log logger) {
this.logger = logger;
}

public synchronized GWTSpringController createController(RemoteService
delegate, boolean unwrapExceptions) {
try {
ControllerBuilder builder = new ControllerBuilder(delegate);
return builder.build();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}

static public RemoteService getRemoteServiceBase(RemoteService impl)
throws Exception{
RemoteService base = impl;
if (impl instanceof Advised) {
Advised advisedImpl = (Advised) impl;
base = (RemoteService) advisedImpl.getTargetSource().getTarget();
base = getRemoteServiceBase(base);
}
return base;
}

protected class ControllerBuilder {
static final public String DELEGATE_PREFIX = "__gwtHndlrDelegate";
static final public String BASE_DELEGATE = "__gwtHndlrBase";

private int delegateHashCode;
private RemoteService delegate, baseDelegate;
private Class baseClass;
private boolean isHttpServletRequestRequired;
private ClassPool pool;
private CtClass controllerCtClass, baseCtClass;
private Class[] baseInterfaces;

public ControllerBuilder(RemoteService impl) throws Exception {
delegate = impl;
delegateHashCode = delegate.hashCode();
baseDelegate = getRemoteServiceBase(delegate);
baseClass = baseDelegate.getClass();
baseInterfaces =
ReflectionUtils.getImplementedInterfaces(baseClass);
Method setMth =
ClassEnhancer.Utils.querySetThreadLocalHttpServletRequestMethod(baseClass);
isHttpServletRequestRequired = (setMth != null);
}

public GWTSpringDelegatingController build()
throws NotFoundException, NoSuchMethodException,
CannotCompileException, InstantiationException, IllegalAccessException
{
prepareClassPool();
constructControllerClass();
appendDelegateFields();
appendDelegateInitialiser();
appendRemoteServiceInterfaces();
return constructController();
}

private void prepareClassPool() throws NotFoundException {
pool = ClassPool.getDefault();
ClassLoader delegateClassLoader = baseClass.getClassLoader();
pool.insertClassPath(new LoaderClassPath(delegateClassLoader));
baseCtClass = pool.get(baseClass.getName());
if (logger.isDebugEnabled())
logger.debug(pool + " pool initialised");
}

private void constructControllerClass() throws NoSuchMethodException,
NotFoundException, CannotCompileException {
String superClassName = getControllerSuperClassname();
String className = superClassName + delegateHashCode;
controllerCtClass = pool.makeClass(className);
controllerCtClass.setSuperclass(pool.get(superClassName));
if (logger.isDebugEnabled())
logger.debug(controllerCtClass + " constructed");
}

private String getControllerSuperClassname() {
String superClassName =
GWTSpringDelegatingController.class.getName();
return superClassName;
}

private void appendRemoteServiceInterfaces() throws
NotFoundException, CannotCompileException {
for (int i = 0; i < baseInterfaces.length; i++) {
CtClass ctIntf = pool.get(baseInterfaces[i].getName());
appendRemoteService(ctIntf, i);
}
if (logger.isDebugEnabled())
logger.debug(controllerCtClass + " all interfaces added");
}

private void appendRemoteService(CtClass ctIntf, int idx) throws
CannotCompileException, NotFoundException {
controllerCtClass.addInterface(ctIntf);
CtMethod[] intfMthds = ctIntf.getDeclaredMethods();
for (CtMethod method : intfMthds)
appendInterfaceMethod(method, idx);
if (logger.isDebugEnabled())
logger.debug(controllerCtClass + " " + ctIntf);
}

private void appendInterfaceMethod(CtMethod intfMtd, int idx) throws
CannotCompileException, NotFoundException {
CtMethod toAppend = CtNewMethod.copy(intfMtd, controllerCtClass,
null);
int mods = toAppend.getModifiers();
mods ^= Modifier.ABSTRACT;
toAppend.setModifiers(mods);
String body = constructMethodBody(toAppend, idx);
toAppend.setBody(body);
controllerCtClass.addMethod(toAppend);
if (logger.isDebugEnabled())
logger.debug(controllerCtClass + " " + toAppend);
}

private String constructMethodBody(CtMethod intfMtd, int idx) throws
NotFoundException {
CtClass[] params = intfMtd.getParameterTypes();
boolean retSpec = !CtClass.voidType.equals(intfMtd.getReturnType());

StringBuilder body = new StringBuilder("{\r\n");
if (isHttpServletRequestRequired)
body.append(BASE_DELEGATE).append(".setThreadLocalHttpServletRequest(this.getThreadLocalRequest());\r\n");
if (retSpec)
body.append("return ");
body.append(DELEGATE_PREFIX).append(idx).append('.');
body.append(intfMtd.getName());
body.append('(');
for (int i = 0; i < params.length; i++) {
if (i > 0)
body.append(',');
body.append('$').append(i+1);
}
body.append(");\r\n}");
return body.toString();
}

private void appendDelegateFields() throws CannotCompileException,
NotFoundException {
for (int i = 0; i < baseInterfaces.length; i++) {
CtClass intf = pool.get(baseInterfaces[i].getName());
CtField delegate = new CtField(intf, DELEGATE_PREFIX + i,
controllerCtClass);
delegate.setModifiers(Modifier.PRIVATE);
controllerCtClass.addField(delegate);
}
if (isHttpServletRequestRequired) {
CtField base = new CtField(baseCtClass, BASE_DELEGATE,
controllerCtClass);
base.setModifiers(Modifier.PRIVATE);
controllerCtClass.addField(base);
}
if (logger.isDebugEnabled())
logger.debug(controllerCtClass);
}

private void appendDelegateInitialiser() throws
CannotCompileException {
StringBuilder meth = new StringBuilder();
// signature
meth.append("public void
__GWTSpringDelegatingController__setDelegate(").append(RemoteService.class.getName()).append("
p1)\r\n");

// body
meth.append("{\r\n");
for (int i = 0; i < baseInterfaces.length; i++)
meth.append(" ").append(DELEGATE_PREFIX).append(i).append("=
(").append(baseInterfaces[i].getName()).append(") p1;\r\n");
if (isHttpServletRequestRequired)
meth.append(" ").append(BASE_DELEGATE).append(" =
(").append(baseClass.getName()).append(")
").append(JavassistEnhancer.class.getName()).append(".getRemoteServiceBase(p1);\r\n");
meth.append('}');

CtMethod init = CtNewMethod.make(meth.toString(),
controllerCtClass);
controllerCtClass.addMethod(init);
if (logger.isDebugEnabled())
logger.debug(controllerCtClass + " " + init);
}

private GWTSpringDelegatingController constructController() throws
CannotCompileException, InstantiationException, IllegalAccessException
{
Class controllerClass = controllerCtClass.toClass();
GWTSpringDelegatingController ret = (GWTSpringDelegatingController)
controllerClass.newInstance();
ret.__GWTSpringDelegatingController__setDelegate(delegate);
if (logger.isDebugEnabled())
logger.debug("ctrl = " + ret);

George Georgovassilis

unread,
Nov 5, 2006, 3:05:21 AM11/5/06
to Google-We...@googlegroups.com
Hello Ash

I'll look into what's going wrong in hosted mode. I hoped to avoid that
because I consider the hosted server rather a toy than a tool - it's a
blank setup without any real-life value, for development I would use a
server with a similar setup to my production server. Just checking we
are talking about the same thing: it's not the hosted _browser_ you're
having trouble with but the hosted _server_, yes?

Heaven, why did you go through all that trouble? I already implemented
some time ago your request in the GWTSpringController.getRequest() and
GWTSpringController.getResponse(), have a look at the svn. Isn't it
better to add functionality to one class instead of two? I mean,
especially since behind the scenes your pojo services are encapsulated
in a GWTSpringController instance anyway by both the cglib and the
javassist implementations, so it is made sure that these two static
methods return the current request. If you don't like the dependency,
you can write a wrapper like a 'RequestProvider' around this invocation
and adapt it towards your needs. I see that the changes you made already
imply a threadlocal on your pojo services which, I presume, you also do
not access as properties but via getters - so you already have the
required abstraction and distance from the concrete implementation.

Does this solution not meet your demands? Is there a reason you want
specifically a thread local on your pojo to be instantiated instead of
using the static from GWTSpringController? If you in general want to
modify your bean based on method invocations, you might consider using
spring proxies; they are flexible, extensible and will always allow you
to do more than we ever could add to the GWTHandler in reasonable time
without sacrificing too much performance for the added complexity.

Tell me what you think so that we can decide where we must extend the
GWTHandler and where we can rely on what is already there.

Many thanks
G.

ash

unread,
Nov 5, 2006, 5:35:29 AM11/5/06
to Google Web Toolkit
hi george,

> I'll look into what's going wrong in hosted mode. I hoped to avoid that
> because I consider the hosted server rather a toy than a tool - it's a
> blank setup without any real-life value, for development I would use a
> server with a similar setup to my production server. Just checking we

yes, i know what u mean. i thought the same way until i got everything
working as i wanted in the embedded hosted mode tomat server.


> some time ago your request in the GWTSpringController.getRequest() and
> GWTSpringController.getResponse(), have a look at the svn. Isn't it

i know, i use GWTSpringController.getRequest() in the
DelegateCallaback.


> better to add functionality to one class instead of two? I mean,

if RemoteServiceServlet#getThreadLocalRequest() had greater visibility
or was statically scoped, then GWTSpringController would not have to
implement that feature.


> especially since behind the scenes your pojo services are encapsulated
> in a GWTSpringController instance anyway by both the cglib and the
> javassist implementations, so it is made sure that these two static

imho GWTSpringController.getRequest() is an unfortunate, but necessary
feature that is currently only leveraged by my cglib impl. however, in
my javassist i was able to use
RemoteServiceServlet#getThreadLocalRequest().


> methods return the current request. If you don't like the dependency,
> you can write a wrapper like a 'RequestProvider' around this invocation
> and adapt it towards your needs. I see that the changes you made already
> imply a threadlocal on your pojo services which, I presume, you also do
> not access as properties but via getters - so you already have the
> required abstraction and distance from the concrete implementation.
>
> Does this solution not meet your demands? Is there a reason you want
> specifically a thread local on your pojo to be instantiated instead of
> using the static from GWTSpringController? If you in general want to

my gwt applications have no compile-time dependency on either spring or
gwthandler. both of these element only present themselves within the
deployment & runtime contexts. the only way in which i thought i could
avoid such dependencies without refactoring your impls, was if the gwt
team made RemoteServiceServlet#getThreadLocalRequest(), public and
static.


> modify your bean based on method invocations, you might consider using
> spring proxies; they are flexible, extensible and will always allow you
> to do more than we ever could add to the GWTHandler in reasonable time
> without sacrificing too much performance for the added complexity.

pls send through a sample incl spring cfg & src which enables the http
servlet request to be injected prior to each rpc call for those impl
that request it; without violating the compile-time dependency rule.

btw your statistical report was enlightening. it encouraged me to reuse
your performance test suite. based on my performance test results, the
spring proxies are a dog. i currently only proxy the application
facades, not the rpc impls.


> Tell me what you think so that we can decide where we must extend the
> GWTHandler and where we can rely on what is already there.

i couldnt think of any other way to achieve my goals. i would really
appreciate your suggestions on alternatives:

here are typical rpc impls:

1. my test case sample
package com.mycompany.project.server;

import javax.servlet.http.HttpServletRequest;

import com.mycompany.project.client.TestRpc;

public class SpringTestRpcImpl implements TestRpc {
private ThreadLocal<HttpServletRequest> threadsHttpServletRequest =
new ThreadLocal<HttpServletRequest>();

public SpringTestRpcImpl() {
System.out.println("SpringTestRpcImpl created");
}

public String test() {
return "Hello World";
}

public void setThreadLocalHttpServletRequest(HttpServletRequest req) {
threadsHttpServletRequest.set(req); // this gets called prior to the
method

System.out.println("SpringTestRpcImpl::setThreadLocalHttpServletRequest");
}
}


2. your sample
package org.gwtwidgets.server.spring.test.serverimpl;

import javax.servlet.http.HttpServletRequest;

import org.gwtwidgets.server.spring.test.server.ServiceAdd;

import com.google.gwt.user.client.rpc.SerializableException;

public class ServiceAddImpl implements ServiceAdd {
public int add(int a, int b) {
return new Integer(a + b);
}

public void throwException() throws SerializableException {
throw new SerializableException("exception");
}

public void setThreadLocalHttpServletRequest(HttpServletRequest req) {
System.out.println("ServiceAddImpl::setThreadLocalHttpServletRequest");
}
}


This approach uses convention over configuration. hence, if the
developer specifies the setThreadLocalHttpServletRequest() method, then
it will be invoked prior to each rpc method impl. u will also notice in
both impls above that there is no compile-time dependency.

perhaps i need to re-consider my values regarding minimal compile-time
dependencies.

rgds ash
http://www.gworks.com.au

George Georgovassilis

unread,
Nov 6, 2006, 3:40:26 PM11/6/06
to Google-We...@googlegroups.com
Ash

that was actually a pretty neat idea which reminded me of the <bean ...
init="yourInitMethodNameHere"> syntax.
Here follows the Spring setup which I promised you, but you need a
further class (RequestInjection) from the svn.

The basic idea is that Spring lets you wrap via simple XML your own
methods around beans (it calls this Method Interceptors). So I just
wrote such a method interceptor, namely the RequestInjection class which
takes the http request/response from the GWTSpringController and calls
any setter you specify on your POJO service. The setters/getters must
accept ServletRequest and ServletResponse and must do the thread local
magic on its own... earlier on the thread you already demonstrated that
you go to great lengths to avoid dependencies, so this will certainly
not scare you.

The configuration is committed to the svn in the usual test case, it
looks somewhat verbose but hey, that's Spring. I also recommend [1] for
an excellent explanation of the grinds and wheels working under the hood.

The performance is probably not too good either because of the proxy
invocation, the reflective invocation of the target method, the two
lookups for the setters (on any method invocation, not just once on the
http invocation!) and can possibly be improved.

On the matter of whether it is advisable to avoid compile time
dependencies, I think it is a matter of taste and you do well in not
letting anyone spit into your soup. What you could do is maybe create a
RequestProvider interface and provide an implementation that gets the
request from the GWTSpringController which you pack then into a jar file
and treat it like a different library. The interface is not really a 3rd
party dependency (you can duplicate it in your project) and do the
binding via spring (by setting a RequestProvider implementation in the
xml configs).

Have a nice week everybody!
G.

[1]
http://static.springframework.org/spring/docs/2.0.x/reference/aop-api.html

ash

unread,
Nov 8, 2006, 6:42:16 AM11/8/06
to Google Web Toolkit
hi george,

thanks for going to the effort of committing the extra code and
creating a test-case. i really appreciate it.

> The configuration is committed to the svn in the usual test case, it
> looks somewhat verbose but hey, that's Spring. I also recommend [1] for
> an excellent explanation of the grinds and wheels working under the hood.
>
> The performance is probably not too good either because of the proxy
> invocation, the reflective invocation of the target method, the two
> lookups for the setters (on any method invocation, not just once on the
> http invocation!) and can possibly be improved.

i ran up your test-case and then proceeded to incorporate it into my
project...

hmm. im an old dog from the old school. i am an advocate of meyer's
open-closed princple (ocp) and martin's dependency inversion principle
(dip). but one thing that i am conscious of, is overdosing on spring or
other ioc container facilities. i often cringe at what i feel is an
abuse of inversion. I desire cohesiveness within subsystems and have
experienced spring inversion abuse render a subsystem overly complex
and over engineered.

your spring solution:
* 100% satisfies my requirements. you have achieved no compile-time
dependency
* is well abstracted and configurable

yet, to be honest, i prefer the other solution. i think this comes down
to a matter of taste, values and past experiences.

i know the other solution will significantly out perform the proxy,
after all its call is burnt into the method body. i also think its
important to strike a balance b/n convention and configuration.


> letting anyone spit into your soup. What you could do is maybe create a
> RequestProvider interface and provide an implementation that gets the

this is just another level of indirection that i would rather do
without.

it would be good if the gwthandler was more open to plugin enhancer
impl to override the defaults.

george, i really want to thank you for taking the time on this. i think
it is the solution that most people would prefer.

rgds ash
http://www.gworks.com.au

georgeuoa

unread,
Nov 10, 2006, 5:38:58 PM11/10/06
to Google Web Toolkit
Dear Ash et All

Apologies for the delay. In the svn you will find a new version which,
apart from minor refactorings allows you to optionally set your own
ClassEnhancer implementation on the GWTHandler which it will use to
proxy/weave/whatever services. For this I will be happy to include in
the gwl-sl as addons anything you would like to see included with the
next version, submitted by email to me under the Apache License 2 or,
for write svn access, please contact Robert Hanson.

I concur that RPC should be more open and accessible and filed a
petition for this [1].

Now, about problems with the hosted server... I shamefully admit that I
have not used it since the glorious 1.0.2x days. I gave it a short try
tonight and turned away in terror because of that peculiar ShellServlet
I don't understand. Are you using the hosted server with or without
this servlet? In any case, please do post a description of the error
you are observing. Could it be related to [2]?

And again, have a nice weekend everyone!

[1] http://code.google.com/p/google-web-toolkit/issues/detail?id=389
[2] http://code.google.com/p/google-web-toolkit/issues/detail?id=385

ash

unread,
Nov 14, 2006, 5:18:38 AM11/14/06
to Google Web Toolkit
hey george,

i apologise its taken so long to respond to this thread.

> In the svn you will find a new version which,
> apart from minor refactorings allows you to optionally set your own
> ClassEnhancer implementation on the GWTHandler which it will use to
> proxy/weave/whatever services. For this I will be happy to include in

nice job.


> the gwl-sl as addons anything you would like to see included with the
> next version, submitted by email to me under the Apache License 2 or,
> for write svn access, please contact Robert Hanson.

im using my enhancer impls in my current project. i would like to trial
the impls a bit longer before committing them to your distro. btw, this
is just my opinion but it would be great to see your codebase as part
of the greater spring distro (like caucho remoting).


> I concur that RPC should be more open and accessible and filed a
> petition for this [1].

i hope to start a thread with you on areas of gwt-rpc that can be
better opened up. i noticed that miguel and a few others from the gwt
team have woken up from the dead so hopefully we can discuss some of
our motivations.


> I don't understand. Are you using the hosted server with or without
> this servlet? In any case, please do post a description of the error

im using hosted mode with the servlet[1].

> you are observing. Could it be related to [2]?

i think this is a specific issue with javassist. ive seen it before
when i was injecting byte code into the gwt-compiler class files to
give me better error reporting. to think we survived those days - i
still remember your serialization defect that scared the hell out of
me, thinking that i was going to encounter yet another hurdle. i lost
atleast 10 years of life trying to deliver an application on 1.0.2x
<smile>.


btw, the stack trace that i get when using javassist is:
<b>root cause</b>
<pre>org.springframework.beans.factory.BeanCreationException: Error


creating bean with name 'urlMapping' defined in ServletContext resource

[/WEB-INF/GWTSpring-servlet.xml]: Invocation of init method failed;
nested exception is java.lang.NoClassDefFoundError: javassist/ClassPath
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:878)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:396)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:240)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:132)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:237)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:153)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:254)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:337)
org.springframework.web.context.support.AbstractRefreshableWebApplicationContext.refresh(AbstractRefreshableWebApplicationContext.java:156)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:308)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:252)
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:221)
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:114)
javax.servlet.GenericServlet.init(GenericServlet.java:211)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:118)
org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:799)
org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:705)
org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:577)
org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
java.lang.Thread.run(Thread.java:595)


1 -
http://gwtpetstore.googlecode.com/svn/tags/1.0.2/tomcat/webapps/ROOT/WEB-INF/web.xml

rgds ash
http://www.gworks.com.au

georgeuoa

unread,
Dec 5, 2006, 2:43:22 PM12/5/06
to Google Web Toolkit
Hello Ash

Apologies for the inappropriate long silence.
I think it has to do with the GWT classloader: the hosted mode tomcat
runs with the GWT classes in its bootstrap classloader, while javassist
is in the webapp classloader. I fear, even after all this time, that I
don't know of any workaround. Maybe it helps to move _all_ webapp jars
to the hosted server classpath, i.e. out of WEB-INF/lib

I am sorry to be so little of any help :(

ash

unread,
Dec 5, 2006, 5:43:28 PM12/5/06
to Google Web Toolkit
mate,

solved this a long time ago. i mentioned it in gwt-commons.

btw atm im not actively polling this group for discussion responses. if
u r waiting on a response from me, hit me a direct.

rgds ash
http://www.gworks.com.au

Pipe

unread,
Dec 19, 2006, 3:50:54 PM12/19/06
to Google Web Toolkit
Hello everyone, Im quite new to GWT and Spring, so forgive my
ignorance, but I still cant make my basic gwt example to run with
GWTHandler, I'v tried all kind of things but it seems to persist a
classpath error of some kind, it shows me:

[TRACE] The development shell servlet received a request for 'add.rpc'
in module 'cl.bluesoft.gwt.HomePage'

and

[WARN] Resource not found: add.rpc

My web.xml is this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/prototipo-servlet.xml</param-value>
</context-param>

<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<servlet>
<servlet-name>prototipo</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>prototipo</servlet-name>
<url-pattern>*.rpc</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>shell</servlet-name>
<servlet-class>com.google.gwt.dev.shell.GWTShellServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>shell</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

My gwt.xml is this:
<module>

<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>

<!-- Specify the app entry point class. -->
<entry-point class='cl.bluesoft.gwt.client.HomePage'/>

</module>

And the prototipo-servlet.xml (the one who config spring) is this:
<?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.gwtwidgets.server.spring.GWTHandler">
<property name="mapping">
<map>
<entry key="/add.rpc" value-ref="SumaUno"/>
</map>
</property>

</bean>

<bean id="SumaUno" class="cl.bluesoft.gwt.server.ModificaUnoImpl"/>
</beans>

Im invoking the service like in the example:
target.setServiceEntryPoint("/add.rpc");

Also I'v been trying to download the example posted at [1] but the
server disconect the download with no reason every time I try...

Can anybody post a complete example? so I can begin from there using
GWTHandler with spring?, I need to test it on hosted mode and web...

Thanks a lot.

Pipe,
felipe.p...@gmail.com

Pipe

unread,
Dec 19, 2006, 3:59:41 PM12/19/06
to Google Web Toolkit
Sorry forgot to post the [1] link:
http://g.georgovassilis.googlepages.com/usingthegwthandler

George already answer me about it, and he is helping me right now...
(Thanks a lot).

Any other help is wellcomed ;)

George Georgovassilis

unread,
Dec 19, 2006, 4:22:42 PM12/19/06
to Google-We...@googlegroups.com
Hello again

I hope my email reached you, it contains the WAR file. This one you have
to deploy to your webserver. If you use tomcat, just drop it to the
webapp directory and it will extract the war contents itself.
You then can go to http://localhost:8080/gwt-wl-sl/ and verify that the
four tests pass (it's not much of a test really, just four alerts you
can click and watch out that every one says 'success'). I am again sorry
for the inconvenience, Googlepages keeps corrupting the WAR files all
the time - I guess it's not much good for anything else than images.

Now, I see that you use the GWTShell servlet also in your setup. I must
confess to you that I absolutely hate it, just like I hate the inbuilt
hosted tomcat because it causes endless trouble, class loading issues
and weird configurations. Since I guess that you are writing your
application because you will eventually sell it to a customer - and he
is not running a hosted GWT environment but a real web server - I advise
you to gradually rid yourself of the GWTShell. Your current mapping in
the web.xml actually creates an ambiguity because you map RPC requests
to the Spring servlet - but everything else to the GWTShell which you
don't need anymore. That does at no point mean that you must abandon the
hosted mode browser (which I value as an cant-live-without part of
developing GWT applications!). In my post about the GWTHandler I provide
a setup for eclipse which you can use to run the hosted mode browser on
the sample application in the WAR file.

The hosted mode browser there uses the -noserver option, which connects
to an external web server instead of launching the inbuilt tomcat. And
you can provide it with the real URL (the one you would hit with your
browser in the production environment for example). That proves by the
way to be an invaluable tool, should your application ever cause trouble
on your customer's site - just connect with the hosted mode browser to
his web server and debug as calm & cool you like through your IDE debugger.

The client part of your application (the one that runs in the browser)
does not know that the server now runs Spring instead of the GWTShell -
and it should not care either. Your RPC URLs stay the same, just that
now they are served from Spring instead of the GWTShell.

I hope that helped somehow
G.

www.gtraffic.info

unread,
Dec 20, 2006, 10:54:50 AM12/20/06
to Google Web Toolkit
Hi Pipe. I am trying to do the same thing..run simple GWTHandler
example in hosted mode. Did you get this working?

Al.

www.gtraffic.info

unread,
Dec 20, 2006, 11:35:25 AM12/20/06
to Google Web Toolkit
George,

Let me get this straight in my head

- you are running a separate instance of Tomcat which has the
appropriate configuration files web.xml and GWTSpring-servlet.xml.

- you are running the hosted mode browser with the noserver option and
specifying the tomcat port to attach through instead '-port 8080'.

Are you building a war file with the 'ServiceAddImpl' in it which gets
deployed under your Tomcat instance? If not how is this setup.

Cheers,
Al.

George Georgovassilis

unread,
Dec 20, 2006, 2:49:31 PM12/20/06
to Google-We...@googlegroups.com
> - you are running a separate instance of Tomcat which has the
> appropriate configuration files web.xml and GWTSpring-servlet.xml.
Yes

> - you are running the hosted mode browser with the noserver option and
> specifying the tomcat port to attach through instead '-port 8080'.
Yes. Precisely:
-noserver -port 8080 -out src/test/webapp/static
gwt-wl-sl/static/org.gwtwidgets.server.spring.test.ClientApplication/ClientApplication.html

> Are you building a war file with the 'ServiceAddImpl' in it which gets
> deployed under your Tomcat instance? If not how is this setup.
Of course! If you download the war from the sample page you'll see only
two servlets in the web.xml:

<servlet>
<servlet-name>GWTSpring</servlet-name>


<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>GWTSpring</servlet-name>
<url-pattern>*.rpc</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>defaultservlet</servlet-name>

<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>defaultservlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

The GWTSpring servlet is responsible for RPC and the defaultservlet for
providing all the static content (GWT compiler output, html, images,
css...).

>
> Cheers,
> Al.
>
>
> >
>
>

Reply all
Reply to author
Forward
0 new messages