GWT to EJB Bridging

I recently figured out that I could save myself a lot of hassle by implementing my GWT service/servlet in a bean. Once it’s a bean, all its methods are automatically wrapped in a transaction, which keeps my code really clean. Previously I didn’t think this was possible without having a ton of delegate methods in the servlet. However, I’ve discovered that I can just have my servlet dispatch client requests directly to a bean by overriding processCall().

To do this, don’t implement the GWT service’s interface in your RemoteServiceServlet. Instead, override processCall() like this:

 public String processCall(String payload) throws SerializationException {

 	try {

 		Object bean = getBean();

 		synchronized(bean) {

 			RPCRequest rpcRequest = RPC.decodeRequest(payload, bean.getClass());

 			return RPC.invokeAndEncodeResponse(bean, rpcRequest.getMethod(),

 					rpcRequest.getParameters());

 		}

 	} catch (IncompatibleRemoteServiceException ex) {

 		ex.printStackTrace();

 		return RPC.encodeResponseForFailure(null, ex);

 	} catch (NamingException ne) {

 		ne.printStackTrace();

 		return RPC.encodeResponseForFailure(null, ne);

 	}

 }

getBean() should use JNDI to get either a stateful or stateless bean, here’s an example of getting a stateful bean out of the HTTP session:

@EJB(name="ejb/booksService", beanInterface=BooksService.class)
public class BooksServiceServlet extends RemoteServiceServlet {

 public BooksService getBean() throws NamingException {

 	final HttpSession httpSession = getThreadLocalRequest().getSession();

 	BooksService bean = (BooksService) httpSession.getAttribute("booksService");

 	if(bean != null) try {

 		// Call a method to test whether the bean is still live; if it's dead, we'll re-create it

 		synchronized(bean) {

 			bean.isLoggedIn();

 		}

 	} catch(NoSuchEJBException ex) {

 		bean = null;

 		httpSession.removeAttribute("booksService");

 	}

 	if(bean == null) {

 		InitialContext ic = new InitialContext();

 		Object objRef = ic.lookup("java:comp/env/ejb/booksService");

 		bean = (BooksService)PortableRemoteObject.narrow(objRef, BooksService.class);

 		httpSession.setAttribute("booksService", bean);

 	}

 	return bean;

 }

// processCall(), from above, goes here
}

The bean has to implement the interface from your GWT client package, but it should also be defined in your EJB jar, not in the GWT war (I couldn’t get glassfish to recognize my bean definitions in the GWT war) which creates an annoying problem – you have to include the GWT jars in your classpath for the EJB jar project. Also, GWT needs the source code for all the objects used in the interface, so the interface itself still has to be defined in the GWT project. You can’t put annotations on the bean’s interface, so you’ll have to annotate the bean implementation, like this:

@Stateful
@Local(BooksService.class)
public class BooksServiceImpl implements BooksService {

Now your servlet will dispatch all the client calls straight to the bean, which means they’ll execute inside a transaction, and they’ll have easy access to any other EJB’s you need, which is great. I just wish I could de-couple the bean from GWT a bit more.

Advertisements

13 Responses to GWT to EJB Bridging

  1. Roman says:

    Hi man,
    would it be possible to publish a trivial example demonstrating the stuff described in your article “GWT to EJB Bridging”? I am going to have the same problem and because I am not very familiar with beans I would appreciate a trivial all-in-one example, despite the fact that your description is quite clear.

    Thanx.
    Roman

  2. dobes says:

    I’ll add it to my TODO list, although I might not get around to it in the short term.

    Thanks for your comment!

  3. roman says:

    Hi again,
    what do you think about GWT 1.4 final, is not that the solution how to simply call beans from GWT RPC and pass them to a client? Google says that

    “You can finally use java.lang.Serializable with GWT RPC, and the GWT RPC server-side subsystem is no longer intimately tied to servlets. You can easily wire it into any Java back-end infrastructure.”

    Or has your solution any other advantages? Thanks.

  4. dobes says:

    Hi Roman,

    I think they are saying that instead of using servlets to receive and process the GWT RPC requests, I could use a different kind of HTTP handler on the server side and still re-use most of the GWT servlet code.

    My solution is one way of calling beans directly via GWT RPC, I don’t really see that they’ve provided a new way to do so.

    Maybe you could clarify how you think the new code allows a GWT app to call directly to beans without a servlet to receive the HTTP requests and dispatch them to the bean?

  5. roman says:

    No, I do not mean it is now possible to call beans directly from GWT client, maybe one day in distant future.

    What I wanted to know is why is not possible to call beans directly from my server side servlet called by GWT RPC and pass them possibly back to a client. I have not try that yet, but I would say the only requirement now is to add the bean class (implementing java.io.Serializable) you want to pass to a client in the GWT client package.

    The only problem was, as far as I can see, that the bean had to implement GWT isSerializable until they released GWT 1.4 final. Now this obstruction should be removed.

    I do not have much experience with GWT, but I will have to, that is why I am asking. Hence I am sory for my maybe elementary questions. I just do not know why to override the processCall() method and implement the GWT service/servlet in a bean. Why is not possible (if it is not possible) to call beans directly and maybe pass bean objects back to a client using GWT RPC. Thanx for patience.

  6. dobes says:

    I suppose you’re thinking you could serialize the bean and send it to the client, at which point they would access the bean methods directly?

    One problem is that GWT doesn’t support Java 5 annotations, so my Java 5 beans won’t compile in GWT :-(. If it did support annotations, I think you’d have a better chance of adding bean support. Without annotations, the fact that something is a bean, and which other objects it is connected to, are all stored in xml files that GWT has no clue about.

    GWT’s means for generating special case subclasses for things (e.g. serialization and RPC) relies on having an identifiable interface or superclass, which the new EJB’s don’t have.

    Another issue I’ve noticed with GWT is that it only allows you to use classes and interfaces inside your GWT packages, except for the classes it provides. So third party beans are “right out” and your own beans have to go into a special package.

    That said, there’s probably some combination of interfaces and code generators that’ll make beans easier to use. In my case, though, and this probably applies to many, only one bean is needed anyway.

  7. roman says:

    Right,
    the problems you described are clear to me now. Actually I did not want to send a bean to a client and call its methods there, I know this cannot work, I just wanted to send an object containing data from my database to a client.

    If I am not mistaken, the simplest solution is to define an object implementing Serializable, somehow use a bean to get all the data I need from my database to the object and send it, using GWT RPC, to a client.

    And here I am not sure if your solution decribed above simplifies what I described in the previous paragraph or if it is intended only for calling methods of a server-side bean from your client application (e.g. write some data to a database e.t.c) without the possibility to send something back. Maybe both is possible, but I cannot figure out how to send a data object back to a client using your approach.

    I would say data from client for the bean you want to call are obtained using the rpcRequest.getParameters() method, but how to send something back, still not clear to me. Thanks for patience.

  8. dobes says:

    The bean methods are able to accept and return any serializable object (or array of serializable objects) , the same way that the servlet methods can when you implement the interface directly on the servlet. The main benefit of implementing the data access using a bean is that each method call is automatically wrapped in a database transaction, and provided with a database wrapper (EntityManager) by the EJB container.

    If you’re not interested in using J2EE features like that, this tip isn’t terribly useful, and you could just use a servlet to implement the interface, and handle transactions and database connection configuration your own way.

    In either case, you can certainly send serializable object to the client as long as they are part of your RPC interface, and they are inside the client package of the GWT application or part of the built-in library.

  9. dobes says:

    To be more clear … you just have to return the serializable object(s) from your servlet or bean method, using the standard java return statement. The GWT serialization system uses the return type of the method to decide if and how to transfer the return value.

  10. Roman says:

    Ok,
    thanks for the explanation. It’s clearer to me know.

  11. Ton says:

    Hello, I am trying to use RPC calls to access EJB components, I had success using remote interfaces, but could not make an application GWT (war) access an ejb (ear) through local interfaces.
    The two applications war and ear are running in the same container jboss.
    It is not even possible to do this or am I doing something wrong?

  12. dobes says:

    Hi Ton,

    I’m not yet an expert on Java EE, I’m building my first application. However, I think that in order to use the local interface, your war would have to be part of the same ear.

    I could be wrong, though. You definitely couldn’t access it by just using a plain @EJB annotation – you’d have to assign an JNDI name to the EJB somehow and reference that from the WAR, I think.

  13. I’ve released my base class which allows easy access to a Stateless (or stateful) EJB via GWT RPC as part of Kiyaa! Check out the announcement on my new blog – http://www.dobesland.com/2008/11/09/announcing-kiyaa/

%d bloggers like this: