JSF 2.0 with Spring 3 and Spring Security 3 on Google Application Engine




In this post I'm going to show a simple fully integrated CRUD style application working on Google Application Engine.

The technologies used are :
  • JSF 2.0 - Mojarra 2.0.2
  • Spring 3.0.0.RELEASE
  • Spring Security 3.0.0.RELEASE
  • Hibernate Validator 4.0.2.GA as reference implementation of JSR 303: Bean Validation
  • AspectJ 1.6.7
  • Groovy and the gmaven-plugin

You can see a live demo at : http://sandcode.appspot.com
UPDATE(22 August 2010)
You can compare with : http://deltaset-demo.appspot.com
and see the project created based on the ideas in that post : http://www.deltaset.org


The application is build with Maven 2.2.1
For local execution you would need Google App Engine SDK 1.3.0 1.3.1

The archetype was updated on 11 February 2010, so that works for latest Google App Engine - 1.3.1

If you want to play and customize it you would need to have installed and configured Java, Maven and Google App Engine SDK

Choose gae-archetype after running :

mvn archetype:generate -DarchetypeCatalog=http://sandcode.googlecode.com/svn/maven2/


build the application :

mvn install


run it :

dev_appserver target/YOUR_ARTIFACT_ID


type in your browser: http://localhost:8080

enjoy :)

If you want to extend the application you can use the small generation utility coming with it :

mvn -Pcrud -Ddomain=Book -Dfields=title,author,remarks


The generator will create for you :

src/main/java/YOUR_EXAMPLE_PACKAGE_NAME/app/domain/Book.java
src/main/java/YOUR_EXAMPLE_PACKAGE_NAME/app/repository/BookRepository.java
src/main/java/YOUR_EXAMPLE_PACKAGE_NAME/app/web/BookController.java
src/main/webapp/secured/book/list.xhtml
src/main/webapp/secured/book/detail.xhtml
src/main/webapp/secured/book/form.xhtml


It will also extend the menu :

src/main/webapp/resources/app/menu.xhtml

with :

<app:menu-group groupname="GEN ADDED - Book ">
<app:menu-item itemoutcome="/secured/book/list" itemvalue="#{msg['book.view.list']}">
<app:menu-item itemoutcome="/secured/book/form" itemvalue="#{msg['book.view.form']}">
</app:menu-item>


Extend the application default Messages bundle :

src/main/resources/Messages.properties

with:

#labels generated for Book
book.view.detail=GEN Book detail
book.view.form=GEN Book form
book.view.list=GEN Book list
book.title=GEN Title
book.author=GEN Author
book.remarks=GEN Remarks


This was the 2 min intro.. depending on your internet connection you can have a nicely running GAE application for about 2-5 min :)

If you want to deploy it on your account of Google Application Engine you will have to edit by hand :

src/main/webapp/WEB-INF/appengine-web.xml

and then type :

appcfg update target/YOUR_ARTIFACT_ID


And... Some more... :

The application is having the following features :
layerd architecture - domain, service, controller
'request' based crud for JSF
localized - currently supports English and Bulgarian. To add another language you need to :
1. create a translated copy of Message.properties
2. edit faces-config.xml
3. download from http://www.famfamfam.com/lab/icons/flags/ the correct flag ;) and add it to src/main/webapp/resources/img/flag with the right name.
4. create a translated copy of ValidationMessages.properties (needed by Bean Validation)

Basic UI customization - the user can change the preffered language, the position of the menu and the colors of the application.
Using of JSF 2.0 custom components, templating.
Using of "JSR 303: Bean Validation".
Using of "JSR 330: Dependency Injection for Java" annotations with Spring 3 ( javax.annotation.ManagedBean , @Inject, @Named ).
Using of Java Config style for Spring 3 ( @Configuration ).
Using of @Bean annotation with inplace implementation of an interface, directly in the @Configuration bean.
Using of @RolesAllowed (javax.annotation.security.RolesAllowed) with Spring Security 3 for securing your application.
Using of 2 distinct roles ROLE_USER and ROLE_ADMIN, securing of methods called with h:commandLink (or h:commandButton)
'Native' integration between Spring Security and JSF : app/web/LoginBean.java ; src/main/webapp/login.xhtml
Almost NO xml configuration for spring : src/main/webapp/WEB-INF/applicationContext.xml
AspectJ for logging app/aspect/TimeExecutionLoggingAspect.java (well.. by default it is swithced off, but you can take a look in the pom.xml )
AspectJ and the Spring stereotype annotations (Repository, Service, etc..) can help you easy log only what you need : app/aspect/SystemArchitecture.java
AspectJ for static weaving of 3rd party jar files (in our case this is jsf-impl , because of a bug in the local Google App SDK ) : common/aspect/FixWebConfigurationAspect.java
Groovy gmaven-plugin and Groovy Templates for generation of files..
Using of box-shadow and border-radius css properties for IE : src/main/webapp/resources/css/gray.css

Enjoy :)
And I'm definitly waiting for your feedback, questions and proposals ;)

Comments

  1. I accidentally took a look at the applicationContext.xml at http://sandcode.googlecode.com/svn/tags/BLOG_JAN2010/crud-jpa-spring-gae/src/main/webapp/WEB-INF/applicationContext.xml and the schema is for Spring 2.5???

    ReplyDelete
  2. Много добро много добро :Д

    Супер :Д

    ReplyDelete
  3. RE: Toy
    you are right , the schema is the one for Spring 2.5 . But, that is one of the great things about Spring - they are backward compatible. Also the configuration of beans with annotations is available exactly since version 2.5. Spring 3.0 adds the support for JSR 330 - "Dependency Injection for Java" , and not only that.. Thanks for the interest in the post :)

    ReplyDelete
  4. Hi Dimitar,

    superb post, nice recipe with fresh ingredients!
    The use of aspects is fantastic just as Chris Richardson lesson.
    Among the others I've appreciate very much this snippet in pom
    UTF-8
    Regards

    ReplyDelete
  5. Hi Domenico,
    thanks a lot for the good words :)
    I'm happy that you have enjoyed the post.

    ReplyDelete
  6. Hi,
    Thanks for this really good post.
    I try to start from scratch without Maven, and i have a problem.
    When i try to access a managedbean, i have a null error. I see a log at Jetty startup :
    JSF1027: [null] The ELResolvers for JSF were not registered with the JSP
    If you have a solution, thanks.

    ReplyDelete
  7. Hi, what is the startup time of the app? I have similar setup with jsf2 and it took about 15s to render first page. Thanks Luba

    ReplyDelete
  8. Hi Luba,
    the "cold" startup time for that app is between 18-23 sec according to the log files, which shouldn't worry you at all. If you are having enough users, it will stay "warm" and the response times are round 180ms to 500ms depending on the executed back-end logic. If you want to keep the application "warm" you can implement some "cron" task, but this is not needed if you have enough users.

    ReplyDelete
  9. Hi Richard,
    the problem with your app could be anywhere - versions of jar files, web.xml, faces-config.xml . I would recommend you to take some of the existing maven archetypes, or just working sample, and then to modify it to fit your needs.

    ReplyDelete
  10. Hi Makariev,
    Thanks for your answer.
    I have found my error. I have used a bad @ManagedBean (javax.faces), instead of javax.annotation. So spring cant make this job ;)
    Now, application works but, yes there is a but ;)
    I have a managed bean whith a list. When the list is called by some XHTML, my logger show me that getter is called 8 times ...
    I'm beginner on JSF2, but i think is not a normal lifecycle ?
    Thanks

    ReplyDelete
  11. Excellent post!!, i enjoy read it.
    Kernelman, Montreal(CA)

    ReplyDelete
  12. Hi Makariev,
    when I deploy it, error appears:
    No persistence unit with name 'person-pu' found

    but when I move the configuration to application-context.xml and append this line "" on pulEntityManagerFactory, it works fine.

    any idea how POJO configuration cannot find the persistence.xml?

    ReplyDelete
  13. the line appended is persistenceXmlLocation in application-context, it works fine, but on POJO it doesn't work as if it cannot find the path of persistence.

    ReplyDelete
  14. Hi Kahlil,
    no idea what might be wrong with your deployment. The live demo application on the top of the post is exactly what I've described here.. and it works :) If the problem is on your local system, that could be something with the local environment : jdk version, gae version..

    ReplyDelete
  15. Bravo, Makariev!

    I especially adore how you do this:

    "AspectJ for static weaving of 3rd party jar files (in our case this is jsf-impl , because of a bug in the local Google App SDK ) : common/aspect/FixWebConfigurationAspect.java"

    This is a very good use of AspectJ, and I'm glad you used it!

    No more monkey-patching sources... (although that AOP is exactly monkeypatching, but what I mean is no need to change the original JAR)

    Keep up the good work! Waiting for more of your quality posts.

    P.S.: can you add in PrimeFaces 2.0 please??

    ReplyDelete
  16. You should disable snapshots for the repository definitions.

    ReplyDelete
  17. Hi Hendy,
    Thanks for the good words :),
    I've added your proposal for disabling snapshots - definitely important for faster build :)

    ReplyDelete
  18. This is by far the most useful post concerning Spring and App Engine I have found to date. And everything using the most recent version.. A true dream come true. Thank you SO much for giving back to the community!

    ReplyDelete
  19. Hello Makariev,
    What a great post you have with every piece of technology that're current today. Not only that but with the right layering architecture implementation example. Thank you so much!

    However, I am trying to run it since this morning in the following environment:
    1. Glassfish v3
    2. JDK 1.6

    But I get the following errors:

    Start Up Error
    ===================

    INFO: com.jsfdemo_jsfdemo_war_1 was successfully deployed in 9,302 milliseconds.
    INFO: JSF1027: [/jsfdemo] The ELResolvers for JSF were not registered with the JSP container.
    INFO: 18:51:09,065 WARN [org.springframework.web.context.request.FacesRequestAttributes] - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@492f0b] for attribute 'preferencesBean' because FacesRequestAttributes does not support such callbacks

    The following errors are when I try to log in with user1/user1
    ================================================
    INFO: 18:51:09,065 WARN [org.springframework.web.context.request.FacesRequestAttributes] - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@492f0b] for attribute 'preferencesBean' because FacesRequestAttributes does not support such callbacks

    INFO: 18:52:43,089 WARN [org.springframework.web.context.request.FacesRequestAttributes] - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@711d75] for attribute 'loginBean' because FacesRequestAttributes does not support such callbacks

    INFO: 18:52:51,039 WARN [org.springframework.web.context.request.FacesRequestAttributes] - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@e996af] for attribute 'loginBean' because FacesRequestAttributes does not support such callbacks

    INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
    INFO: 18:52:51,068 WARN [org.springframework.security.authentication.event.LoggerListener] - Authentication event AuthenticationSuccessEvent: user1; details: null

    INFO: 18:52:53,264 WARN [org.springframework.web.context.request.FacesRequestAttributes] - Could not register destruction callback [org.springframework.beans.factory.support.DisposableBeanAdapter@74e65f] for attribute 'person' because FacesRequestAttributes does not support such callbacks

    SEVERE: Error Rendering View[/secured/person/list.xhtml]
    javax.faces.FacesException: javax.el.ELException: /secured/person/list.xhtml @10,56 pageInfo="#{person.pageInfo}": java.lang.NullPointerException: No API environment is registered for this thread.
    ...
    ...
    Caused by: javax.el.ELException: /secured/person/list.xhtml @10,56 pageInfo="#{person.pageInfo}": java.lang.NullPointerException: No API environment is registered for this thread.
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:107)
    at javax.faces.component.UIComponentBase$AttributesMap.get(UIComponentBase.java:2166)
    ... 86 more
    Caused by: java.lang.NullPointerException: No API environment is registered for this thread.
    at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppId(DatastoreApiHelper.java:67)
    at com.google.appengine.api.datastore.DatastoreApiHelper.getCurrentAppIdNamespace(DatastoreApiHelper.java:77)
    at com.google.appengine.api.datastore.Query.(Query.java:84)

    I would really appreicate if you could help me figure out what's causing this?
    Thank you.
    T

    ReplyDelete
  20. Hi Dimitar,

    Thank you for doing this. Getting Spring & GAE running through Maven is awesome. However I would like to ask if you could add Eclipse integration to your archetype. I tried it by simply using mvn eclipse:eclipse, but when I imported the project into eclipse, it was not recognized as a GAE application. Would you know how to make this work? Thanks for your help.

    Regards,
    Mitch

    ReplyDelete
  21. Very nice post...thanks for saving hell lot time of mine...

    ReplyDelete
  22. Hi.. I loved the sample.. I am studying these technologies and your sample is completed.
    =)

    What did you describe in the start is how access the code? There is other way to access? because I never use maven .. so.. if possible tell us =]

    ReplyDelete
  23. What would Spring Web Flow do for this project?

    ReplyDelete

Popular posts from this blog

Extreme productivity with JSF 2.0 and Deltaset

JSF 2.0 with Maven 2 plugins for Glassfish v3, Jetty and Tomcat