SeesionID in Generator?

40 views
Skip to first unread message

Den Ga

unread,
Aug 16, 2006, 6:27:12 PM8/16/06
to Google Web Toolkit
Is it possible to access Session ID in Generator? To maintain state or
receive an argument from a client (besides class name)?

bruciadmin

unread,
Aug 16, 2006, 7:17:58 PM8/16/06
to Google Web Toolkit
Hmmm, my curiousity is piqued, what is this "Generator" you're
referring to?

>From the sounds of it, there are posts which deal with getting cookies
from the browser. Some people have even posted up Java code to be run
from your GWT client which wraps cookies for your retrieval. If you set
the session in a cookie, your client side code could get it this way.

A non GWT specific method I've used in the past (for good or ill) is to
put the session ID as a global javascript page variable. You could then
grab that via JSNI to get the session ID.

Or maybe I've missed the point completely and your talking about
something like the some sort of session created when the code is
generated... though that sounds kinda silly.

Den Ga

unread,
Aug 16, 2006, 7:46:26 PM8/16/06
to Google Web Toolkit
Generator is the abstract class that allows you to generate classes on
the fly (and compite them into JavaScript) using GWT.create.

Hence GWT.create(MyClass.class) will connect to the server, invoke
Generator registered for this class, generate Java code, compile it
into JavaScript, pass to the client, instantiate and return an instance
to you. (Of course the point here is to generate some subclass that
overrides some methods in MyClass). Or am I wrong?

Being lazy bastard I want to be able to send a snippet of code from
server to client. This snippet might be different for different clients
or different states.

bruciadmin

unread,
Aug 16, 2006, 8:55:34 PM8/16/06
to Google Web Toolkit
Whoa... I just did some reading on generator. I initially thought you
were trying to do something wacky and against the grain from GWT. I
just deleted a huge post asking whether or not you were sure you knew
what you were doing and there might be a better way. Then I did some
research before posting (just to be sure) and realised that what you
are doing is completely within the current trend of where GWT is moving
to. I guess I just hadn't seen many posts on this issue.

So with my new found understanding of what you're trying to do, if you
do want to use session information from your generator, I'd use the
following algorithm:

1.) Server side call is made to the GWT servlet, but beforehand, you've
used some sort of filtering process to get the session and put it in a
thread local variable.
2.) The GWT specific calls are made which eventually find and invoke
the generate call on your generator.
3.) Your generator grabs the session out of the thread local variable.

This is a perfect solution for something like a thread local variable,
to hold the session after the request cycle has started. It's also a
nice way to avoid having to pass the session as a variable on every
method call.

Den Ga

unread,
Aug 17, 2006, 1:22:19 PM8/17/06
to Google Web Toolkit
Well, that's cute but who is to guarantee that the server-side call
using RPC and the call to produce the class will use the same thread?
Moreover, usually http servers employ thread-caching that means that
user requests will be processed on random threads.

Or maybe tomcat assigns a thread per session? Doubt it.

Google, where r u?

bruciadmin

unread,
Aug 17, 2006, 8:01:02 PM8/17/06
to Google Web Toolkit
Umm, no, that's not correct.

I like this definition of ThreadLocal usage
(http://crazybob.org/2006/07/hard-core-java-threadlocal.html):
"Use a thread local variable (where each thread has a separate value)
when you want to carry a value along without explicitly passing it from
method to method down the call stack"

As long as the ThreadLocal variable gets the session variable
overwritten at the start of the request - no matter what - then you are
guaranteed that different request instances hitting different server
threads will get access to the same session object. Have you used a
ThreadLocal variable before? There are certain givens you have to allow
for, like always ensuring you overwrite the variable at the start of
the request, but I can guarantee you that this is a solid solution and
has worked for me many times previously.

As long as you always intercept the start of the request and get the
session into the ThreadLocal variable, the later call to your generate
method will always get the same session for the given request.

Trust me on this - read up on ThreadLocal variables and their usage in
a servlet environment:
http://www.javalobby.org/articles/thread-safe/index.jsp
http://forum.java.sun.com/thread.jspa?threadID=610109

Specifically, check out the following thread where someone tries to
point out not to use ThreadLocal's for a thread-safe servlet and gets
quite an accurate response as to why they are fine:
http://www.jguru.com/faq/view.jsp?EID=150

Scott Blum

unread,
Aug 18, 2006, 11:10:29 AM8/18/06
to Google-We...@googlegroups.com
Hi all,

> Generator is the abstract class that allows you to generate classes on
> the fly (and compite them into JavaScript) using GWT.create.
>
> Hence GWT.create(MyClass.class) will connect to the server, invoke
> Generator registered for this class, generate Java code, compile it
> into JavaScript, pass to the client, instantiate and return an instance
> to you. (Of course the point here is to generate some subclass that
> overrides some methods in MyClass). Or am I wrong?

The Generator subsystem hasn't been well-documented yet, so you're a
little on your own at the moment, though I think good examples can be
found a few "rebind" packages in gwt-user.jar.

But I need to clear up a fundamental misunderstanding. There are
three major GWT contexts under which code can run. There's client
runtime, which is where all translated client-side code runs. There's
server runtime, which is where service implementations run. (Any
objects that are serialized back and forth will exist in both the
client and server runtime.) Finally, there's *compile* time. This is
code that runs only when the GWTCompiler is running (*1). Generators
run ONLY at compile time. They never run in the server or client
runtimes. The intuition you described above is useful, but incorrect.
By the time your code is through compiling, all of the GWT.create()
calls have been replaced with hard-coded new() operations.

This is why we generate multiple scripts as compiled output. We
generate a script for every possible permutation of "rebind results",
if you will. Most of the time, the only variability is in what
browser is running. That's why you often end up with four to five
scripts (IE, Mozilla (and maybe older Mozilla), Safari, and Opera) --
this is the result of GWTCompiler producing a script for each browser,
which is implemented with GWT.create() calls in DOM. Which concrete
browser class is selected depends on the results of a "user.agent"
property. The value of this property is computed within your
*.nocache.html file; that file in turn chooses the correct
pre-compiled script that matches the results of the property
evaluation. But the fundamental assumption is that all *possible*
property result values have to be known ahead of time-- which means a
finite and predetermined set of values.

It would be possible, in theory, to use a session ID inside of the
nocache.html to map onto one of a predetermined set of property
values, but the general case of using an arbitrary session ID (and
having that value available to a Generator) is impossible.

Hope this clears things up,
Scott

Scott Blum

unread,
Aug 18, 2006, 11:15:20 AM8/18/06
to Google-We...@googlegroups.com
On 8/18/06, I wrote:
> Finally, there's *compile* time. This is code that runs only when the
> GWTCompiler is running (*1).

*1) In addition to running under GWTCompiler, Generators also run
during "hosted mode compile time", which occurs when your client-side
Java code is being prepped to run under the hosted browser. The fact
that everything seems to happen all at once in hosted mode makes it
easy to misinterpret what's really going on. I didn't want to confuse
the issue by mentioning this inline.

claude

unread,
Aug 18, 2006, 3:36:18 PM8/18/06
to Google Web Toolkit
Hey Scott,

I wonder if this thread is a good place to ask a little about how we
can use the generators ourselves. The package(s) ...gwt.core.ext.* are
lightly documented and difficult to interpret correctly. I've fished
around and suspected that they were part of the compilation cycle but I
presume they are exposed as part of the API so that others can generate
different target code.

Experimenting with these would lead to new insights, but it's not at
all clear what the correct entry point is. The key method is clearly:

public abstract String generate(TreeLogger logger,
GeneratorContext context, String typeName);

The typeName is the class name argument used in GWT.create() call, yes?
The return value is the qualified class name to be substituted?
The logger makes sense and the context clearly has more depth.

I presume the generated code is actually written in JavaScript via the
GeneratorContext tryCreate method. Is that right?

The oracles are a way of accessing CompilationUnit elements at
compilation time or for generating target code?

What I'd love to see, is a super simple 'hello world' example that adds
a new generator to the compilation cycle. Maybe all it generates is a
single JS function (that says hello?). I can see that this
functionality was intended to be exposed or it wouldn't be in the API,
but what conditions was it designed to address and what kind of
extensions might I want to write with it?

PS: The TreeLogger is a hiearchical logger that prints either to the
console or (in hosted mode) to the GWT console, right?

I realize that we want to focus on the GUI set and client/server model,
but I would very much like to implement something that works like GWT's
RCP with a more pluggable protocol model. I'd rather work along with
the grain than against it. Any information that can put me on the road
to fruitful exploration would be greatly appreciated.

Scott Blum

unread,
Aug 18, 2006, 7:15:25 PM8/18/06
to Google-We...@googlegroups.com
> I wonder if this thread is a good place to ask a little about how we
> can use the generators ourselves. The package(s) ...gwt.core.ext.* are
> lightly documented and difficult to interpret correctly. I've fished
> around and suspected that they were part of the compilation cycle but I
> presume they are exposed as part of the API so that others can generate
> different target code.

Yes, the ultimate intent is that people will be able to tie into our
deferred binding system to do all sorts of cool things at compile
time. The GWT team has a strong belief in, "Why put off until runtime
what you can do at compile time?" We hope that ultimately people will
find deferred binding to be as useful as (and more appropriate to the
browser than) reflection.

However, this is really more of an advanced feature, and one we don't
expect to see wide use of until the product as a whole is a little
more mature. So we have not yet spent a lot of cycles on thoroughly
documenting and supporting it.

> Experimenting with these would lead to new insights, but it's not at
> all clear what the correct entry point is. The key method is clearly:
>
> public abstract String generate(TreeLogger logger,
> GeneratorContext context, String typeName);
>
> The typeName is the class name argument used in GWT.create() call, yes?
> The return value is the qualified class name to be substituted?
> The logger makes sense and the context clearly has more depth.

Yes, yes, and yes. Actually, I believe the return value can also be a
semicolon-delimited list of classes if you generate more than one.

> I presume the generated code is actually written in JavaScript via the
> GeneratorContext tryCreate method. Is that right?

The generated code should actually be Java, also you're free to use
JSNI in generated classes (RPC does this, in fact).

> The oracles are a way of accessing CompilationUnit elements at
> compilation time or for generating target code?

TypeOracle is a lot like using reflection. It exposes a full model of
the entire client code base that's available. PropertyOracle exposes
the current value of all of the deferred binding properties (such as
user.agent). Both of these can provide useful information to a
Generator.

> What I'd love to see, is a super simple 'hello world' example that adds
> a new generator to the compilation cycle. Maybe all it generates is a
> single JS function (that says hello?). I can see that this
> functionality was intended to be exposed or it wouldn't be in the API,
> but what conditions was it designed to address and what kind of
> extensions might I want to write with it?

Indeed, it was designed to be exposed so that people could do all the
useful things in client code that are presently being done via
reflection in Java server code. The possibilities are pretty
limitless.

If you want to get sense of how it works, I would start with
JUnitTestCaseStubGenerator, which is probably the simplest shipping
Generator.

Get a JUnit test set up (junitCreator is useful here), and add the
following JVM arg to the command line: -Dgwt.args="-gen gen". The gen
flag tells the compiler to dump all generated files onto the file
system. (The gwt.args system property lets you pass options to the
shell in a JUnit run as if you were invoking GWTShell directly with
those command line args). Map the newly created "gen" folder into
your project, and find the generated subclass of your base test case.
This class was produced by JUnitTestCaseStubGenerator, so you can use
it as a reference when examining the code for the generator. You can
even set a break point and step through it to watch it in action.

For more complicated examples, check out com.google.gwt.i18n.rebind or
com.google.gwt.user.rebind.rpc. The RPC stuff really demonstrates the
full power of what you can do.


> PS: The TreeLogger is a hiearchical logger that prints either to the
> console or (in hosted mode) to the GWT console, right?

Exactly.

> I realize that we want to focus on the GUI set and client/server model,
> but I would very much like to implement something that works like GWT's
> RCP with a more pluggable protocol model. I'd rather work along with
> the grain than against it. Any information that can put me on the road
> to fruitful exploration would be greatly appreciated.

Hope this helps, I'll be happy to answer furthur questions.
Scott

claude

unread,
Aug 19, 2006, 11:34:35 AM8/19/06
to Google Web Toolkit
I was able to get the JUnit code generated (-gen option) and I've been
looking at various examples I could find (BTW: The docs for JUnit
module definition fails to mention the need to inherit
com.google.gwt.junit.JUnit, which could cause someone less familiar
with the toolkit no end of heartache).

I've come up with a Hello World-type proxy generator (which I hope to
expand later). What I need to know is how to apply it. I will examine
the RPC code next.

Here's my example:

package com.claudeduguay.gwt.generator.rebind;

import java.io.*;

import com.google.gwt.core.ext.*;
import com.google.gwt.core.ext.typeinfo.*;

import com.google.gwt.user.rebind.*;

public class ProxyGenerator extends Generator
{
public String generate(


TreeLogger logger, GeneratorContext context, String typeName)

throws UnableToCompleteException
{
try
{
TypeOracle typeOracle = context.getTypeOracle();
JClassType requestedClass = typeOracle.getType(typeName);
String packageName = requestedClass.getPackage().getName();
String proxyClassName =
requestedClass.getSimpleSourceName() + "Proxy";
String qualifiedProxyClassName =
packageName + "." + proxyClassName;
String qualifiedSourceName =
requestedClass.getQualifiedSourceName();
SourceWriter writer = getSourceWriter(logger, context,
packageName, proxyClassName, qualifiedSourceName);
writeToStringMethod(proxyClassName, writer);
return qualifiedProxyClassName;
}
catch (NotFoundException e)
{
logger.log(TreeLogger.ERROR,
"Class '" + typeName + "' Not Found", e);
throw new UnableToCompleteException();
}
}

protected SourceWriter getSourceWriter(
TreeLogger logger, GeneratorContext context,
String packageName, String className, String superclassName)
{
PrintWriter printWriter = context.tryCreate(
logger, packageName, className);
if (printWriter == null) return null;
ClassSourceFileComposerFactory composerFactory =
new ClassSourceFileComposerFactory(packageName, className);
composerFactory.setSuperclass(superclassName);
return composerFactory.createSourceWriter(context, printWriter);
}

protected void writeToStringMethod(
String proxyClassName, SourceWriter writer)
{
writer.println();
writer.println("public String toString()");
writer.println("{");
writer.indent();
writer.println("return \"Hello, from " + proxyClassName);
writer.outdent();
writer.println("}");
}
}

I've collapsed things as much as possible to create a viable test and,
hopefull, something that can be used to explain this feature in simple
terms. I just have no idea how I can tigger this now ;-), though my
first thought it that there has to be a registry or factory that the
GWT compiler relies on. I will begin my hunt for this in the RCP
source...

I am starting to see how the type oracle can be used to inspect a class
and generate suitable wrappers that do much more... very nice!

Message has been deleted

nik

unread,
Aug 19, 2006, 2:02:33 PM8/19/06
to Google Web Toolkit
<generate-with
class="com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator">
<when-type-assignable
class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>

I guess this is the key Generator binding configuration
(I've found it in
gwt-user.jar/com/google/gwt/user/RemoteService.gwt.xml)

Scott Blum

unread,
Aug 19, 2006, 2:19:49 PM8/19/06
to Google-We...@googlegroups.com
On 8/19/06, claude <claude....@gmail.com> wrote:
> I was able to get the JUnit code generated (-gen option) and I've been
> looking at various examples I could find (BTW: The docs for JUnit
> module definition fails to mention the need to inherit
> com.google.gwt.junit.JUnit, which could cause someone less familiar
> with the toolkit no end of heartache).

Actually, we removed this requirement in 1.1.0 to make things simpler.
You no longer have to inherit from the JUnit module; JUnitShell makes
you inherit it automatically when you're running a JUnit test. So
we're kind of "cheating" here. :)

> I've collapsed things as much as possible to create a viable test and,
> hopefull, something that can be used to explain this feature in simple
> terms. I just have no idea how I can tigger this now ;-), though my
> first thought it that there has to be a registry or factory that the
> GWT compiler relies on.

To kick things off, you have to setup a rebind rule. This is a rule,
somewhere in your module definition (or inherited modules) that tells
GWT to look for a specific sort of type, and invoke your Generator if
that type is found. Usually the trigger is that the requested type is
a subclass or implementor of some marker type. Take a look at
JUnit.gwt.xml and RemoteService.gwt.xml for examples.

Scott

claude

unread,
Aug 19, 2006, 2:36:01 PM8/19/06
to Google Web Toolkit
Oooooooo, you beat me!

I just figured this out and was able to get a generator working. Three
quick caveats, should anybody try to use the code I posted.

1) The posted code needs to call writer.commit(logger) just before
returning from the generate class.

2) There are syntax errors in my generated code that needs to be
corrected, a missing end quote and semicolon.

3) There are apparently multiple calls made into this code, durring
which the print writer may be null, so defensive programming is called
for. It appears that bypassing write calls when the writer is null,
does not cause an overall failure, and the output is correctly written
to file (use -gen), so I am presuming that multiple calls are made. In
any case, null writers need to be accounted for and writing skipped in
those cases.

Also - You must call GWT.create(SourceClassName.class); before the
compiler is invoked and the class must implement (or I presume extend)
the interface (or class?) declared in the 'when-type-assignable' XML
tag.

All the fixes are trivial and documented in this thread, so I probably
won't re-post the corrected class .

Item 3 may be a bug. It would be good to know if this code nees to be
re-entrant and whether null writers are expected, or whether I'm doing
something wrong and could fix it.

I'm very impressed, as I almost always am by Google code and products.
I can totally buy into the compile it in advance if you can and I can
see that in most cases reflection is not important (though I'm certain
that some cases exist, they probably very rare).

And now, I can try to create something useful with this new-found magic
incantation ;-).

claude

unread,
Aug 19, 2006, 2:39:55 PM8/19/06
to Google Web Toolkit
Thanks Scott.

Our messages must have crossed paths. The next thing I need to learn
are the oracles, I'll probably build something simple first, but I may
have more questions. I'll post them under a new thread.

nik

unread,
Aug 19, 2006, 2:56:11 PM8/19/06
to Google Web Toolkit
Your posts helped a lot

I have a plan of using this for Bean2JSON and JSON2Bean serialization
and RPC calls.

p.s. But I have some second thoughts. (I'll rather sleep on it)

Thanks to you and Scott

Scott Blum

unread,
Aug 19, 2006, 7:56:32 PM8/19/06
to Google-We...@googlegroups.com
On 8/19/06, claude <claude....@gmail.com> wrote:
> 3) There are apparently multiple calls made into this code, durring
> which the print writer may be null, so defensive programming is called
> for. It appears that bypassing write calls when the writer is null,
> does not cause an overall failure, and the output is correctly written
> to file (use -gen), so I am presuming that multiple calls are made. In
> any case, null writers need to be accounted for and writing skipped in
> those cases.

> Item 3 may be a bug. It would be good to know if this code nees to be


> re-entrant and whether null writers are expected, or whether I'm doing
> something wrong and could fix it.

This is the intended design. When your Generator tries to create a
class that already exists in the current compile, trying to get a
source writer returns null to let you know the class already exists.
The code that calls your Generator has no idea what classes you're
going to generate, so it calls your Generator even if you don't need
to generate anything.

Scott

Reply all
Reply to author
Forward
0 new messages