The core of my app is some tricky Hibernate and EJB3 persistence code
(it's technically a peer-to-peer replicated object/relational
persistence layer). I would ideally like to have a GWT server-side
service that could interact with my EJB3 persistence code.
I could go one of two ways:
1) Integrate GWT on top of the G4JSF project, to enable me to keep the
Seam/JSF server-side stack but use GWT as the client side. Pro: could
still use JSF to organize my navigation. Con: Seam isn't really buying
much at that point, I don't know how well G4JSF integrates with Seam,
and the overall stack is a lot taller than it really has reason to be.
2) Build a server-side service using straightforward servlets, perhaps
integrating with the JBoss embedded EJB3 container (which is how Seam's
examples work). Pro: shorter stack, less pieces to go wrong. Con: I
don't know how to build a servlet that interfaces with the JBoss
embedded EJB3 container.
So my questions are:
- Has anyone built any GWT apps that interface with Seam?
- Has anyone built any GWT apps that interface with EJB3 server
components?
- Are there any public examples of doing either?
Thanks!
Cheers,
Rob
Also, is anyone actually using G4JSF? Any experiences to report?
Right now it looks like a bit of an abandoned project -- no mentions of
use on any of the ajax4jsf lists or here, and no updates since
mid-August....
Even if there was no full support for 1.5, in my opinion it would be
helpful if GWT simply ignored things like annotations so that code that
contained them could be used in both server and client side (allowing
the server side to benefit from the annotations).
Regards,
Ismael
[1] http://code.google.com/p/google-web-toolkit/issues/detail?id=168
> So my questions are:
> - Has anyone built any GWT apps that interface with Seam?
I haven't used Seam yet, no.
> - Has anyone built any GWT apps that interface with EJB3 server
> components?
Sure, I use JBoss 4.whatever and Hibernate with EJB3 annotations. My
java code is compiled using java 1.5.
Now, there are some issues that you'll encounter.
First, your annotated server side persistent objects cannot be sent
directly to the client. You'll have to create DTOs for that.
Your DTOs will have to implement the GWT interface IsSerializable.
Shared code (DTOs, and service interfaces) must not contain any java
1.5 specific features. (no annotations, or generics for instance)
> - Are there any public examples of doing either?
Not yet.
-jason
http://www.jroller.com/page/vprise/20060808
Thanks Shai for writing it up in all that detail.
I'm also more excited about G4JSF now than I was, after reading the
writeup on that technology on theserverside:
http://www.theserverside.com/tt/articles/article.tss?l=GWTandJSF
The more I think about it, the more I'm starting to see why a joint JSF
and GWT site could be a big win. I'm working on (Yet Another) blogging
platform. JSF for the "REST-ful" parts of the site (the bookmarkable
individual posts, the Atom feed, etc.) would be good, and then GWT +
JSF for the post editor tool (or the advanced RSS-reader-like tool).
It's a very lightweight use of JSF, but I'd still rather do JSF +
Facelets than any other toolkit for the web pieces, even if all the
interactivity is GWT. And even if I'm not using Seam's conversations
(because all the conversational flows happen on the client in the GWT
app), Seam's still a nice clean way to create session and application
components wired to my business logic.
After looking at some of the Seam Remoting code, it seems like talking
to Seam from G4JSF *might* not be too tough after all. If I get it
working, I will definitely post a sample.
My name is Sergey Smirnov and I am the author of the article you
mentioned above. We just have completed the support for JBoss Seam in
the scope of the Ajax4jsf project. So, we are pretty confident with
Seam's architecture and conversation context now. Your usecase sounds
very interesting for us.
Additional to the features shown in the article, Alexander added the
support for form base interaction with GWT. I.e. it works similar to
the regular JSF request/response cycle (in Ajax or non-Ajax mode).
Therefore, using Seam's conversational flows might not be a
unrealizable dream like it seems now.
So, If you are interested, we are ready to help you with you project by
making some improvement on the level of G4jsf.
Regards,
Sergey : G4jsf Team
One quick question, though: how do you plan to preserve the
conversation ID across GWT invocations? From briefly looking at G4JSF,
it seems that you're using GWT's native serialization mechanism, which
doesn't seem to have a way to extend it to pass out-of-band state
information (such as the Seam conversation ID). In Seam remoting, the
conversation ID is passed back and forth to the client Javascript code
in the serialized message. If you're not altering GWT's serialization
protocol at all, how do you propose to preserve the conversation
context across multiple GWT round-trips?
Again, I don't see this as a critical issue, since most of the use
cases for Seam conversations are covered by GWT's purely client-side
application model. In other words, I probably wouldn't need Seam
conversations even if G4JSF supported them, since most of what I'd want
to do with Seam conversations is more naturally done with rich client
application logic in GWT. But nonetheless I'm curious to know what you
were thinking....
Glad to see you're reading here :-)
Cheers!
Rob
Now that GWT 1.2 RC1 is out, the G4JSF build script needed a couple of
mods (three to be precise - search for 'OS X addition' to find them).
This version of
/g4jsf-cdk/template/ant/build.xml
works for what I have done so far. You can probably do a better job but
if anyone needs this now - here tis,
<?xml version="1.0" encoding="utf-8" ?>
<project name="org.ajax4jsf.gwt.sample.Components" default="war"
basedir="..">
<description>
org.ajax4jsf.gwt.sample.Components build file. This is used to
package up your project as a jar,
if you want to distribute it. This isn't needed for normal
operation.
</description>
<!-- Load user property definition overrides -->
<property environment="env"/>
<property file="user.properties" />
<property file="build.properties"/>
<property file="${user.home}/build.properties"/>
<!-- Establish property definition defaults -->
<property name="compile.debug" value="true"/>
<property name="compile.deprecation" value="false"/>
<property name="compile.optimize" value="true"/>
<property name="compile.source" value="1.4"/>
<property name="compile.target" value="1.4"/>
<!-- Project directories -->
<property name="build.dir" value="${basedir}/build"/>
<property name="tests.src.dir" value="${basedir}/tests"/>
<property name="tests.classes.dir" value="${build.dir}/tests"/>
<property name="module.src.dir" value="${basedir}/JavaSource"/>
<property name="module.classes.dir" value="${build.dir}/classes"/>
<property name="gwt.home" value="@GWT_HOME@"/>
<property name="junit.home"
value="${eclipse.home}/plugins/org.junit_3.8.1"/>
<property name="htmlunit.home" value=""/>
<property name="shale.test.lib" value=""/>
<property name="gwt.module" value="@PACKAGE@.@Component@"/>
<property name="gwt.test.module" value="@PACKAGE@.TestCase"/>
<target name="init">
<mkdir dir="${build.dir}"/>
<condition property="gwt.dev.lib"
value="${gwt.home}/gwt-dev-windows.jar">
<os family="windows"/>
</condition>
<condition property="gwt.dev.lib"
value="${gwt.home}/gwt-dev-linux.jar">
<equals arg1="${os.name}" arg2="Linux"/>
</condition>
<!-- OS X addition -->
<condition property="gwt.dev.lib"
value="${gwt.home}/gwt-dev-mac.jar">
<os family="mac"/>
</condition>
<!-- OS X addition
- the first condition here is just a do nothing placeholder for
the jvm argument when the OS is not OS X (-Xmixed is the default
execution mode)
-->
<condition property="jvm.arg1" value="-Xmixed">
<not>
<os family="mac"/>
</not>
</condition>
<condition property="jvm.arg1" value="-XstartOnFirstThread">
<os family="mac"/>
</condition>
</target>
<!-- set classpath -->
<path id="project.class.path">
<pathelement path="${java.class.path}/"/>
<pathelement path="${gwt.home}/gwt-user.jar"/>
<!-- Additional dependencies (such as junit) go here -->
<fileset dir="WebContent/WEB-INF/lib" id="weblibs">
<include name="*.jar"/>
<exclude name="gwt-*.jar"/>
</fileset>
</path>
<path id="test.hosted.class.path">
<!--path refid="project.class.path" /-->
<pathelement path="${gwt.home}/gwt-user.jar"/>
<pathelement path="${junit.home}/junit.jar"/>
<pathelement path="WebContent/WEB-INF/lib/gwtjsf.jar"/>
</path>
<path id="test.class.path">
<path refid="project.class.path" />
<fileset dir="${htmlunit.home}/lib">
<include name="*.jar"/>
</fileset>
<pathelement path="${junit.home}/junit.jar"/>
<pathelement path="${shale.test.lib}"/>
</path>
<target name="compile-sample" description="Compile src to bin"
depends="init" >
<mkdir dir="${module.classes.dir}"/>
<javac srcdir="${module.src.dir}" destdir="${module.classes.dir}"
includes="**" debug="${compile.debug}" debuglevel="lines,vars,source"
source="${compile.source}" target="${compile.target}"
optimize="${compile.optimize}" deprecation="${compile.deprecation}">
<classpath refid="project.class.path"/>
</javac>
</target>
<target name="compile-tests" description="Compile src to bin"
depends="init" >
<mkdir dir="${tests.classes.dir}"/>
<javac srcdir="${tests.src.dir}" destdir="${tests.classes.dir}"
includes="**" debug="${compile.debug}" debuglevel="lines,vars,source"
source="${compile.source}" target="${compile.target}"
optimize="${compile.optimize}" deprecation="${compile.deprecation}">
<classpath refid="project.class.path"/>
</javac>
</target>
<!-- =================================
target: compile.js
================================= -->
<target name="compile.js" depends="compile-sample" description="-->
Compile google widgets">
<java fork="true" dir="${basedir}"
classname="com.google.gwt.dev.GWTCompiler" >
<arg value="-out"/>
<arg value="${module.src.dir}/META-INF/gwt"/>
<arg value="${gwt.module}"/>
<classpath path="${module.src.dir}" />
<classpath path="${module.classes.dir}" />
<classpath location="${gwt.dev.lib}"></classpath>
<classpath refid="project.class.path"></classpath>
</java>
</target>
<!-- =================================
target: hosted mode shell
================================= -->
<target name="shell" depends="compile-sample" description="-->
Compile google widgets hosted mode shell ">
<delete dir="${build.dir}/tomcat/work" failonerror="false"/>
<java fork="true" dir="${build.dir}"
classname="com.google.gwt.dev.GWTShell" >
<!-- OS X addition -->
<jvmarg value="${jvm.arg1}"/>
<arg value="-out"/>
<arg value="WebContent"/>
<arg value="${gwt.module}/index.html"/>
<classpath path="${module.src.dir}" />
<classpath path="${module.classes.dir}" />
<classpath location="${gwt.dev.lib}"></classpath>
<classpath refid="project.class.path"></classpath>
<env key="LD_LIBRARY_PATH"
value="${gwt.home}${path.separator}${env.LD_LIBRARY_PATH}"/>
<env key="PATH"
value="${gwt.home}${path.separator}${env.PATH}"/>
<env key="LANG" value="en_US" />
</java>
</target>
<!-- =================================
target: tests
================================= -->
<target name="tests" depends="compile-tests" description="-->
Junit test cases">
<mkdir dir="${build.dir}/testreports"/>
<delete dir="${build.dir}/tomcat/work" failonerror="false"/>
<!-- Hosted mode JUnit tests ( client part ) -->
<junit fork="true" forkmode="once" dir="${build.dir}"
printsummary="true" showoutput="true" filtertrace="false">
<classpath path="${tests.src.dir}" />
<classpath path="${tests.classes.dir}" />
<classpath path="${gwt.dev.lib}"></classpath>
<classpath refid="test.hosted.class.path"></classpath>
<env key="LD_LIBRARY_PATH"
value="${gwt.home}${path.separator}${env.LD_LIBRARY_PATH}"/>
<env key="PATH"
value="${gwt.home}${path.separator}${env.PATH}"/>
<env key="LANG" value="en_US" />
<formatter type="plain"/>
<batchtest todir="${build.dir}/testreports">
<fileset dir="${tests.src.dir}">
<include name="**/client/*Test*.java"/>
<exclude name="**/AllTests.java"/>
</fileset>
</batchtest>
</junit>
<!-- Server part tests -->
<junit fork="true" dir="${build.dir}" printsummary="true"
showoutput="true" filtertrace="false">
<classpath path="${tests.src.dir}" />
<classpath path="${tests.classes.dir}" />
<classpath refid="test.class.path"></classpath>
<formatter type="plain"/>
<batchtest todir="${build.dir}/testreports">
<fileset dir="${tests.src.dir}">
<exclude name="**/client/*Test*.java"/>
<include name="**/*Test*.java"/>
<exclude name="**/AllTests.java"/>
</fileset>
</batchtest>
</junit>
</target>
<target name="package" depends="compile.js" description="Package up
the project as a jar">
<jar destfile="${build.dir}/${gwt.module}.jar">
<fileset dir="${module.classes.dir}">
<exclude name="**/*.cache.xml"/>
<exclude name="**/gwt.js"/>
</fileset>
<fileset dir="${module.src.dir}">
<exclude name="**/*.java"/>
</fileset>
</jar>
</target>
<!-- =================================
target: war
================================= -->
<target name="war" depends="package" description="--> Create sample
war">
<war destfile="${build.dir}/@PROJECT@.war" webxml="ant/web.xml">
<fileset dir="WebContent">
<exclude name="WEB-INF/classes/**"/>
</fileset>
<lib dir="${build.dir}" >
<include name="*.jar"/>
</lib>
</war>
</target>
<target name="clean">
<!-- Delete the bin directory tree -->
<delete dir="${build.dir}" failonerror="false"/>
</target>
</project>
Have you experienced any other issues with g4jsf and GWT 1.2 since
posting your build.xml tweaks above? It looks like g4jsf is on the
ajax4jsf guys' back burner again (no releases since August 15)... is it
working OK for you? Any examples to share?