JSF facelets template packaging
Asked Answered
T

1

12

As always, i'm a little confused.

Here https://community.jboss.org/wiki/ModularWebAppsWithJSF2 i've learned that it is easy and works out of the box to bundle templates in separate jars since JSF 2.0.

The only problem is: i can't get it working. I simply deploy a "page.xhtml" in all flavors (META-INF directory, resources directory, root; with and without faces-config.xml) in a jar that is included in the web application WEB-INF/lib and request something like http://host/demo/faces/page.xhtml or do an "include" or "decorate" on the template. I get an exception.

Here Java EE6> Packaging JSF facelets (xhtml) and ManagedBeans as JAR my favorite JSF teacher explains to use a custom ResourceResolver to do exactly this. As i debugged the resource resolving i have no doubt that this will work and will give it a try.

This is the question about the mechanics - what is the difference between the two approaches?

Which resources exactly are looked up in META-INF/resources automatically?

Treatise answered 15/2, 2012 at 9:7 Comment(0)
P
21

Facelets compositions (so, just plain *.xhtml pages, templates and include files) are resolved by ExternalContext#getResource() which delegates to ServletContext#getResource(). This requires a Servlet 3.x compatible container because /WEB-INF/lib/*.jar!/META-INF/resources resolving from is new since Servlet 3.0. If you aren't on Servlet 3.x yet, or want to put those JARs on a different location for some reason, then you'd need to create a custom ResourceResolver. See also How to create a modular JSF 2.0 application?

Facelets composite components and static resources (so, <cc:xxx> components and CSS/JS/image resources which are to be loaded by <h:outputStylesheet>, <h:outputScript> and <h:graphicImage>) are resolved from the classpath by ClassLoader#getResource(). To include the JAR file in the classpath scan of JSF, you'd need to include a JSF 2.x compatible faces-config.xml file in the /META-INF folder of the JAR file. The same story applies to @ManagedBean, @FacesValidator, @FacesConverter, @FacesComponent and other JSF artifacts.


When developing in Eclipse, you can choose Web > Web Fragment Project to create such a module project. It is not much different from a normal Java project, expect that it will implicitly include JavaScript facet and a targeted runtime, autocreate a /META-INF/web-fragment.xml file and get associated with an existing Dynamic Web Project by adding itself as a deployment assembly to that project.

You can also use an existing standard Java project with the right folder structure prepared. The /META-INF folder has to go in Java source folder. The web-fragment.xml file is by the way optional. You just have to manually add the Java project to the Deployment Assembly section of the main web project properties. Do not add it as another project in project's Build Path section.

When you're (manually) building a JAR file out of it, you need to make sure that the directory entries are added to the JAR, otherwise Facelets compositions can't be resolved. If you're building by build tools like Eclipse/Ant/Maven/etc, this has also to be taken into account. If this is not controllable, a custom ResourceResolver is the most reliable approach.

Photobathic answered 27/2, 2012 at 22:38 Comment(8)
Once again many thanks. Where the heck do you have always all this detail information from. Do you have an implementation of the spec of your own :-) The ResourceResolver is simple and up and running - now i will try to feed a web fragment to our maven monster...Treatise
Not working for me: I am using an existing standard shared Java project which I now removed from the Build Path of the implementing Project and now its only added as a deployment assembly. But still my ManagedProperty is ignored either in annotation or the faces-config.Chablis
@djmj: the JAR must have a JSF 2.0 compilant /META-INF/faces-config.xml and the main webapp's faces-config.xml shouldn't have a metadata-complete="true".Photobathic
I did not had metadata-complete="true" in it. I switched from faces-config declaration to annotations in that shared jar resulting in empty faces-config and now it works somehow, also managed properties. And it was not the first time today I cleared glassfish caches and deleted the deployed apps. Thanks for your help.Chablis
Something is working other with this ClassLoader.getResource() because normally it loads everything from the jar resources. But the library must be placed under META-INF/resources/ in the jar resources, so the full path must be so-ugly-as src/main/resources/META-INF/resources/my-lib (2-times resources eh...)Grabble
@lech: this structure is typical to Maven.Photobathic
Yes, but classloader loads directly from jar root anywayGrabble
Well, he is mister JSF, @mtraut. And father of OmniFaces. You can learn more if you want.Dasheen

© 2022 - 2024 — McMap. All rights reserved.