referencing an EJB from RemoteServiceServlet

45 views
Skip to first unread message

danbot

unread,
Jul 3, 2006, 9:06:06 AM7/3/06
to Google Web Toolkit
Hi All,

I am trying to talk to a stateless session bean from my ServiceImpl on
the server side (the one that extends my service interface and extends
RemoteServiceServlet) . Anyway.. I'm wondering if anyone has a working
example of this?

I tried to run this application in the hosted client and go a whole lot
of "cannot be resolved" type errors but it just occured to me that this
is prob because my Session Bean is not deployed to the same instance of
tomcat. right?

This leads me to my next issue.. has anyone successfully packaged and
deployed one of these gwt applications to jboss?

Thanks
Dan

Dave

unread,
Jul 3, 2006, 3:39:38 PM7/3/06
to Google Web Toolkit
You are correct, the servlet is running on the wrong server. You want
the servlet to run in the JBoss container, not the embedded Tomcat
engine.

There are a few steps to make this work. We're using Weblogic, but the
steps are similar.

1) Build a web app that contains your servlet for your RPC call.

a) Make sure the gwt-user JAR is on the classpath for your servlet.
In our case we put it in the APP-INF\lib directory of our EAR
file. It could also go in WEB-INF\lib

b) Note: GWT includes some javax.servlet.* classes in the gwt-user
JAR. We unzipped the JAR and removed the extra classes.

2) Map your servlet using the GWT module name in the URL pattern. If
your app is com.cool.CoolApplication and has an RPC service called
beanService then register the URL as
/com.cool.CoolApplication/beanService in web.xml. Use the same URL in
your main module GWT file.

3) In the source code of your GWT-based widget that needs to call the
Bean service do the lookup as follows.

BeanRPCServiceAsync beanProxy= (BeanRPCServiceAsync)GWT.create(
BeanRPCService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) beanProxy;
String url = GWT.getModuleBaseURL() + "/beanService";

// MAGIC IF statement
if (!GWT.isScript()) {
url = "http://localhost/ritmWeb" + url;
}

endpoint.setServiceEntryPoint(url);

The trick is in using the GWT module name and the MAGIC IF statement.
If you are in hosted mode, the RPC code will try to connect to a URL
running on localhost. If you are in script mode the code will connect
to the URL that the script was downloaded from.

The other problem area is how to share classes between GWT javascript
code and business tier code. For example value objects that are
populated by the Session bean and shown via the GWT widgets. The
problem is one of compilation order since the EJB tier usually does not
depend on a class in the web tier for compilation.

What we did is the following
1) We created a second GWT module in our application. The GWT file has
an empty <module> tag. In our case we created a second set of code,
outside of the web application. At runtime this shows up as a class
library in the EAR's classpath. The package must end in .client as with
all GWT code. We called our second module reuse.gwt.xml and the package
might be something like com.cool.reuse.client

2) In the main GWT module, add an <inherits> tag that references your
second GWT module <inherits name='com.cool.reuse'/>. Think of a GWT
inherits tag as being similar to the an import tag in Java.

3) Change your Eclipse launch configuration so that the the source code
in your reuse package is on the classpath of the launch configuration.
GWT needs to see the Java source code on the classpath so it can do the
Java -> Javascript compilation.

If you do this correctly then you will be able to use the classes in
the reuse package inside of a session bean and inside of your GWT code.

You can also use the same classpath tricks in the ANT script so that
when you run your ant build the classes will be visible to the GWT
compiler.

Hope this helps, if notm then we will try again.

Dave

unread,
Jul 3, 2006, 8:47:12 PM7/3/06
to Google Web Toolkit
A point of clarification. The magic if statement needs to have

http://localhost/webAppName. In our case the name of the web app was
ritmWeb

edmik

unread,
Jul 4, 2006, 7:41:08 AM7/4/06
to Google Web Toolkit
Hi Dan,
GWT works fine under JBoss Tomcat service. My prototype
app called a Message Bean via a JMS queue message.
Just use a standard InitialContext() e.g.
context = new InitialContext();
obj = (<Your Cast>)context.lookup("java:/<...>");

Hope this helps.
Malcolm

danbot

unread,
Jul 4, 2006, 8:17:59 AM7/4/06
to Google Web Toolkit
Thanks for that guys,

Dave , I might get you to go over that again. I swear i'm going to
create a tutorial once i've figured this out.

I'll go through how I've set things up so far. I've included examples
of code showing how i've set this up.

1. Get Rid of the javax.servlet jars from gwt-user.jar
2. Make sure gwt-user.jar gets packaged into WEB-INF/lib
3. Map servlet in web.xml like below
<web-app>
<servlet>
<servlet-class>myapplication.gwt.client.MyApp/MyAppService</servlet-class>
<servlet-name>MyAppService</servlet-name>
</servlet>
</web-app>
4. Create another gwt.xml file that is a reference for my bean
package >> myapplication.mybean.gwt.client
>>mybean.gwt.xml (has nothing set in module tag)


5. add <inherits name='myapplication.gwt.mybean'/> to the main gwt.xml
file.

So on point 4. do I add classes for the data objects in my bean
application here? For example "MyObject" ?
I'm not sure what you mean by "In our case we created a second set of


code, outside of the web application."

Also what would my Web app name be below?

String url = GWT.getModuleBaseURL() + "/MyAppService";

// MAGIC IF statement
if (!GWT.isScript()) {

url = "http://localhost/????" + url;
}

endpoint.setServiceEntryPoint(url);

----------------------------------

>> the client class where all the cool stuff happens

package myapplication.gwt.client;

public class MyApp implements EntryPoint
{

MyAppServiceAsync service;

public void onModuleLoad ()
{
service = (MyAppServiceAsync) GWT.create(MyAppService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) service;
endpoint.setServiceEntryPoint("/MyAppService");

.... cool stuff happens here

}
}

----------------------------------

>> client side interface for service

package myapplication.gwt.client;

public interface MyAppService extends RemoteService
{
public MyObject getMyObject();
}

----------------------------------

>> client side async interface

package myapplication.gwt.client;

public interface MyAppServiceAsync
{
public MyObject getMyObject();
}

----------------------------------

>> server side implementation of the Service, acts as a kindof proxy to MyBean

package myapplication.gwt.server;

import myapplication.gwt.client.MyAppService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

public class MyAppServiceImpl
extends RemoteServiceServlet
implements MyAppService
{

private MyBean lookupMyBean() throws MyException
{
try {
InitialContext jndiContext = new InitialContext();
return (MyBean) jndiContext.lookup("MyBean");
} catch (NamingException e) {
Logger logger = Logger.getLogger(e.getExplanation());
throw new MyException("Lookup of MyBean Object failed");
}
}

public MyObject getMyObject() throws MyException {
return lookupMyBean().getMyObject();
}

}

Dave

unread,
Jul 4, 2006, 2:05:10 PM7/4/06
to Google Web Toolkit
You are close, but not quite there.

Steps 1-2 as listed are correct.
Step 3, Change web.xml to look like this. Note: the leading slashes are
important.
<web-app>
<servlet>
<servlet-class>myapplication.gwt.client.MyApp.MyAppService</servlet-class>
<servlet-name>MyAppService</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>MyAppService</servlet-name>
<url-pattern>/myapplication.gwt.client.MyApp/appService</url-pattern>
</servlet-mapping>
</web-app>

Step 3a (new) In the main GWT xml file register your servlet for your
RPC using the GWT module name as a prefix

<servlet path="/myapplication.gwt.client.MyApp/appService"
class="myapplication.gwt.client.MyApp.MyAppService"/>

Now, to look up your RPC service in your GWT client code, use the
following. Replace the ???? with the name of your web app when it is
deployed on the server. It would be the same URL you would type into a
browser to open a JSP or HTML file in the web app. Ex.
http://localhost/myWebApp. Also, add a port # if your development
server is not listening on port 80, etc.

String url = GWT.getModuleBaseURL() + "/MyAppService";

// MAGIC IF statement. This code only runs in hosted mode. In
Javascript this code is not executed
if (!GWT.isScript()) {
url = "http://localhost/myWebApp" + url;
}

endpoint.setServiceEntryPoint(url);

Compile and package your web app, start JBoss, and test the client
using either GWT hosted mode or the Javascript code, (Note: you have to
copy the generated JS files into the web app at the correct relative
paths.
If you try a simple service, you should be able to get the RPC call to
work in both modes (if you add the generated Javascript to the web app.

In our case we use Ant and we run the GWT compiler as part of the build
process. Here are exerpts from our ant build script that will get your
started. The URL to test the JS code would be

http://localhost/myWebApp/myapplication.gwt.client.MyApp/MyApp.html

<path id="gwt.classpath">
<pathelement location="${webApp.src}"/> <!-- Path to GWT client source
code -->
<pathelement location="${gwt.lib.dir}/gwt-user-1-0-21.jar"/>
<pathelement location="${gwt.lib.dir}/gwt-dev-windows-1-0-21.jar"/>
</path>

<target name="compile-javascript">
<java classpathref="gwt.classpath"
classname="com.google.gwt.dev.GWTCompiler"
fork="true">
<arg value="-out"/>
<arg value="${webApp.out}"/> <!-- Path to root directory of web app
-->
<arg value="myapplication.gwt.client.MyApp"/> <!-- GWT module name
-->
</java>
</target>

Now the fun part is if you want to use a GWT isSerializable class in
both the GWT code and inside of your J2EE server side code. One example
would be a value object class that is populated by a session bean and
used by the GWT client code. In a typical J2EE app where the value
objects are used by JSP/servlet code you would have the following
compilation dependencies

VO source code
EJB tier source code
Web tier source code

To make this work with GWT, you need to remember that the VO classes
are running in both Java and Javascript versions at runtime. To make
this work, you need to tell GWT about the extra source so it can build
the Javascript versions. To make things easier it is helpful to put all
of the GWT VOs in their own source code folder. That way you don't have
to worry about filtering out classes that would not make it thru the
GWT compiler.

So our directory structure looks like this (We use the BEA split
development directory structure, see the Weblogic 8.1 server docs on
e-docs.bea.com for an explanation)

project-root
src
ear-root
META-INF - EAR xml deployment descriptors
APP-INF - Shared JAR files (Weblogic adds these to the EAR class
path)
clientVO
myapplication
gwt
client - Source code for VO (1)
session
META-INF - EJB deployment descriptors
myapplication
gwt
business - EJB source code for session beans
myWebApp
myapplication.gwt.client.MyApp - Compiled Javascript code goes here
WEB-INF - Web deployment descriptor
lib - JAR files needed by the web app
src
myapplication
gwt
client
MyApp - Main GWT file goes here
client - Source code for GWT code goes here
server - Source code for servlet goes here

So, to make the clientVO classes visible to GWT you would need to do
the following.

1) Add a new GWT file called myapplication.gwt.client.clientVO.gwt.xml
in the directory marked (1) above
The contents are simply
<module></module>

2) Add the following line to the main GWT XML file. This tells GWT that
there is more source code somewhere on the classpath that it will need
to look at.
<inherits name='myapplication.gwt.client.clientVO'/>

3) Change the build script (and by extension the classpath in Eclipse
in the Run/Debug launch configuration) to include the source code
directory for the clientVO stuff.

<path id="gwt.classpath">
<pathelement location="${clientVO.src}"/> <!-- Path to clientVO source
code -->
<pathelement location="${webApp.src}"/> <!-- Path to GWT client source
code -->
<pathelement location="${gwt.lib.dir}/gwt-user-1-0-21.jar"/>
<pathelement location="${gwt.lib.dir}/gwt-dev-windows-1-0-21.jar"/>
</path>

You might have to tweak the paths a little bit, I'm typing this in, it
is not a running sample. But it is pretty close.

Good luck

Dave

Nathanael

unread,
Jul 26, 2006, 3:24:18 AM7/26/06
to Google Web Toolkit
Thanks a lot Dave for these informations.
Perhaps some people will feel the need of a tutorial.
I will take the time for a try before saying me :).

Nathanael.

tomcat5

unread,
Jul 27, 2006, 9:01:09 AM7/27/06
to Google Web Toolkit
You have discribed it in too hard way.
I'd probed it and the thing is much simple.

At first: not need "another gwt.xml" and <inherit it and so on.

Look at that common code on Jboss 4.0.4 GA (EJB3.0) &
gwt-windows-1.0.21


=========Persistence container===========
---------------------------------------------------
@Table(name = "TABLE-1")
public class Bean {
private Integer id ;

@Id
@Column(name = "ID")
public Integer getId() {
return id;
}
...
}
--------------------------------------------------
@Local
public interface BeanService {
// interface methods
}
----------------------------------------------------
@Stateless(name = "BeanServiceName")
public class BeanServiceImpl implements BeanService {
// there is EntityManager, query code & so on
}


============Web container ================
-------------GWT servlet method (RPC)--------------
public class RequestServiceImpl extends RemoteServiceServlet implements
RequestService {

public String rpc_method(String input) {
Context context = new InitialContext();
BeanService beanService =
(BeanService)context.lookup("<global JNDI name of BeanServiceImpl>");
}
}

-----------------------------------------------------------
rpc_method calls in EntryPoint class and it works, but how about
transaction and other not simple things I dont Known.

in my case string <global JNDI name of BeanServiceImpl> is
"<earfilename>/BeanServiceName/local"

Reply all
Reply to author
Forward
0 new messages