A couple of weeks ago I was asked to create a web application to run on Google Cloud Platform (SDK v1.9.48 by the time this post was typed in). After configuring AppEngine settings (creating account, project, cloud database, source code repository, etc, etc, etc...), I was ready to develop my first webapp using GAE Eclipse Plugin.
It was huge my dissapointment when I found out that GAE only brings along by default support for JSP and servlets.
Then I said: "May God help me! Back to J2EE's stone age again? I'm used to JSF and (C)DI for the UI. How am I going to integrate in a GAE webapp these 3 J2EE standards and make it run smoothly (if such a thing is possible)?":
- JSF 2.x
- (C)DI 1.x
- JPA 2.x
Just keep reading this post and you'll know how!
Well, I decided not to give up so easily and get into the problem. After a couple of weeks of hard researching and trial-error coding, I found the solution to this mess.
Before beginning with the post, I'll give you some great resources that can help you to pull this together:
Frameworks:
This is how I got it to work:
The most important configuration is in web.xml. The JSF initialization MUST RUN FIRST: I found out that
com.sun.faces.config.ConfigureListener
is in charge of that step and it always looks for theFacesServlet
declaration. Since JSF requests MUST be served by Guice with aFacesHttpServlet
wrapper (which I'll post later) in order to enable DI, then:I declared the
FacesServlet
WITHOUT<servlet-mapping>
s (I figured out that step by trial-error coding).It's only declared to initialize the
FacesContextFactory
. This is the MUST-HAVE structure of the web.xml:Second, I'm not trying to inject a managed bean instance into another anymore. Instead, I'm injecting a bound business logic instance into the beans (in other words, emulating EJB behavior). This is what I did:
I defined a
@BindingAnnotation
for the business logic implementation:I defined a business logic interface with its implementation and annotated both with the
@BusinessLogic
annotation (This is an example that registers a visit made to the page. The fields are: the visit number, the source IP and the timestamp):and its implementation:
To avoid reinstantiation of the business logic objects, I defined a single instance for the DI binding:
Now, the Guice module with the object bindings:
The
businessLogicBindings()
method associates the business logic interface with the implementation instance. On the other hand, you can see on this line:serve(urlPattern).with(FacesHttpServlet.class);
, Guice will reroute JSF requests to a HttpServlet wrapper with an injectedFacesServlet
instance:Now, the listener that initializes the injector:
Last, but not least, Mojarra must register our DI implementation as its DI provider (see the
<context-param>
com.sun.faces.injectionProvider
value):All of this working altogether (yet ommitting the JPA part, which is not relevant at this point):
ExampleBean
:Now, you can create a *.xhtml file as your inxdex and put this testing code on it:
JPA feature is easier since its configuration neither depends on JSF nor DI.
PersistenceManagerSetupListener
:All the persistence init properties are defined in
app-engine.xml
. Its basic structure:You must define at least one persistence unit (in "persistence.xml"):
and some initialize and shutdown methods in your persistence manager object(s) to create and destroy the EntityManagerFactory and the EntityManager(s). Something like this:
The "Visit" class is just an Entity class which maps the 3 fields (Number of visit, source IP and timestamp) and it's registered in the "persistence.xml" file.
I wrote this post as a tutorial that shows, step-by-step, how I managed to run these technologies on GAE (SDK 1.9.48 by the time I typed these lines in). It's taken me weeks of researching and trial-error coding, and I expect with this guide to help other Java programmers not to go through that mess as I did.
Hope this guide can help others to create great J2EE apps in GAE.