Last updated by steyze 2 months ago
Following JSF-ICEfaces plugin...
Based on
icefaces plugin work. It prepares the background for ICEfaces 2 plugin but I preferred to split implementation from standard in order to allow developper to make their own JSF framework integration.
JSF-2 integration
- Bean By convention (no need for faces-config)
- Bean access to controller parameters (session,request,params...)
- Beans dynamic methods for navigation redirect(action?,bean?,view?,uri?,url?) and render(action?,view?,bean?),
- Automatic bean and service properties resolution
- 'void init()' called at bean initialization if present
- 'void dispose()' called at bean destruction if present
- JSF Extended request scope ('view')
- Access to web.xml configuration via Jsf2Config.groovy
- Access to faces-config generated in web-app/faces-config.xml
- Converters for Locale, Closure, Currency, Timezone
- i18n ready, fast access with #{m['key']}
- create-bean script
- Hibernate session managed from view rendering to view response
- Execute groovy code in EL expression ( #{gtag.groov[' def i = 2; 3.times{ i++ }; i; ']} )
- Support JSF2 Components - @ManagedBean ...
Extra methods for beans :
- Support tagLibraries methods
- Support controllers properties
- redirect(action?,bean?,view?,uri?,url?),
- render(action?,view?,bean?)
- facesMessage(summary?, details?, severity?)
Sample code
Use of create-bean package.Class will do this :
package appclass DummyBean{ def static scope = 'view' //['view' (jsf2special request scope),'request','session','globalSession' (portlet),'conversation'(swf),'flow'(swf)] def property = "hi"
def oldProperty = "bye" //def otherBean (autowired bean) void init(){
//called when bean starts
} void dispose(){
//called when bean stop
} /*String action() {
}*/
void say(javax.faces.event.ActionEvent ae) {
// render "test2.xhtml" change view
// redirect "test.xhtml" redirect view, forcing page scoped bean clean
} void change(javax.faces.event.ActionEvent ae) {
def changed = property
property = oldProperty
oldProperty = changed
}
}
Here the text.xhtml page (called via configured extension, by default .xhtml)
<?xml version='1.0' encoding='utf-8'?>
<f:view xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core">
<html>
<h:head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
</h:head>
<h:body>
<h:outputScript name="jsf.js" library="javax.faces" target="body" />
<h:form>
<h:panelGroup id="prop">
<h:outputText value="#{dummyBean.property}"/>
<h:commandButton value="say #{dummyBean.property}" actionListener="#{dummyBean.say}"/>
<h:commandButton value="prepare #{dummyBean.oldProperty}" actionListener="#{dummyBean.change}">
<f:ajax render="prop"/>
</h:commandButton>
</h:panelGroup>
</h:form>
</h:body>
</html>
</f:view>
Navigation by convention
Here some equivalents methods
<h:commandLink action="/bean/test.iface" />
<h:commandLink action="/bean/test" />
<h:commandLink action="test" />
<h:commandLink action="test.xhtml" />
From bean you can use
render action:"/bean/test.xhtml" //and the equivalents seen before
render "/bean/test.xhtml" // == render action:*
render view:"test" // == /bean/test.xhtml
render bean:"bean2" // /bean2/index.xhtml
render bean:"bean2",view:"test" :// /bean2/test.xhtml
Sample redirect convention
redirect url:"www.google.fr"
redirect action:"test"
render action:"test?faces-redirect=true"
<h:commandLink action="test?faces-redirect=true" />
Greets
Success story: using jsf plugin with PrimeFaces and Grails 1.3.7
Update dependencies
These informations are for the plugin version 0.1
!You have to update the dependencies of the plugin to get your project running:
dependencies {
provided 'org.hibernate:hibernate-core:3.3.1.GA',
'javax.servlet:servlet-api:2.5',
'com.sun.faces:jsf-api:2.1.2',
'com.sun.faces:jsf-impl:2.1.2' compile 'javax.servlet:jstl:1.2'
}With this settings you use the current Mojarra JSF implementation as a basis.
Patches
These informations are for the plugin version 0.1
!To use the plugin in the grails default environment you have to patch some code.
GrailsResourceResolver
There is a small bug using this plugin and install a deployable WAR.
The implementation uses the default GroovyPageResourceLoader which is not available creating and deploy the WAR file.
Try this fix in the constructor of GrailsResourceResolver of the plugin:
public GrailsResourceResolver() {
System.out.println("GrailsResourceResolver: constructor"); // Bugfix: ResourceResolver only during Development, SB, 2011-11-24
if (ApplicationHolder.getApplication().getMainContext()
.containsBean(GroovyPageResourceLoader.BEAN_ID)) {
System.out.println("GrailsResourceResolver: get groovyPageResourceLoader"); this.resourceLoader = (GroovyPageResourceLoader) ApplicationHolder
.getApplication().getMainContext()
.getBean(GroovyPageResourceLoader.BEAN_ID); } else if (ApplicationHolder.getApplication().getMainContext()
.containsBean("groovyPageResourceLoaderJSF")) {
System.out.println("GrailsResourceResolver: get groovyPageResourceLoaderJSF"); this.resourceLoader = (GroovyPageResourceLoader) ApplicationHolder
.getApplication().getMainContext()
.getBean("groovyPageResourceLoaderJSF");
}
}After this create a new bean instance of the page resolver in the applicationContext.xml:
<bean id="groovyPageResourceLoaderJSF"
class="org.codehaus.groovy.grails.web.pages.GroovyPageResourceLoader">
<property name="baseResource">
<value>/WEB-INF/grails-app/views</value>
</property>
</bean>
Debug resource resolver
If you have problems receiving resources on your JSF pages like images or stylesheets try to debug the GrailsResourceResolver:
/**
* Bugfix: Get Resource through resourceLoader OR servletContextLoader
*
* @param uri
* @return
*/
private Resource getResourceWithinContext(String uri) {
System.out.println("GrailsResourceResolver: getResourceWithinContext: " + uri); if (resourceLoader != null) {
System.out.println("GrailsResourceResolver: GroovyPageResourceLoader is active"); if (Environment.getCurrent().isReloadEnabled()
&& Metadata.getCurrent().isWarDeployed()) { return resourceLoader.getResource(uri);
} Resource r = servletContextLoader.getResource(uri); if (r.exists())
return r; return resourceLoader.getResource(uri);
} else {
System.out.println("GrailsResourceResolver: trying to get resource through context"); Resource r = servletContextLoader.getResource(uri); if (r.exists()) {
return r;
}
} System.out.println("GrailsResourceResolver: trying Spring MainContext"); Resource r = ApplicationHolder.getApplication().getMainContext().getResource(uri); if (r.exists()) {
return r;
} System.out.println("GrailsResourceResolver: trying fixed base path with Spring MainContext"); r = ApplicationHolder.getApplication().getMainContext().getResource("/WEB-INF/grails-app/views" + uri); if (r.exists()) {
return r;
} System.out.println("GrailsResourceResolver: couldn't get resource"); throw new IllegalStateException(
"ResourceResolver not initialised correctly, no [resourceLoader] specified!");
}Using message bundles
JSF was not able to resolve the grails bundles.
Use this workaround:
Place the bundles in the src/java folder of your project.
e.g.<grails-project>/src/java/i18n/message_en_GB.properties
Configure faces-config.xml for this bundle location:
<application>
…
<locale-config>
<default-locale>en_GB</default-locale>
</locale-config>
<resource-bundle>
<base-name>i18n.messages</base-name>
<var>msg</var>
</resource-bundle>
…
</application>Now you can access the bundle in the JSF pages via msg.
<h:outputText value="#{msg['site.title']}" />Using PrimeFaces
Add the dependecy to your grails configuration:
e.g.compile 'org.primefaces:primefaces:3.0.1'
After the small fixes and this configuraton you can create JSF2 pages.
Pages are placed under
grails-app/views.
Beans are placed under
grails-app/beans.
Tips and Tricks
Default Index
To set the default start to a JSF page I used a simple grails controller with a redirect:
class HomeController {
def index = {
redirect(uri:"/login.xhtml")
}
}The config in UrlMappings.groovy:
"/"(controller: 'home', action: 'index')
Last updated by smaldini 2 years ago
What is a bean by convention ?
A groovy/java class placed in grails-app/beans using XxxxBean.java/.groovy conventionnal name.
How can I access to these beans from EL expression ?
Simply use property styled name : XxxBean becomes #{xxxBean}
Where do I put my jspx ?
In grails-app views or in web-app.
Can I still use faces-config.xml ?
Yes, you find it in web-app/web-inf/faces-config.xml. Update already established parameters if you know what you do :) Note the old managed bean are not resolved automatically. Use FacesContext at init method to set these ones.