It's been a while since my last post, as I've gone through a significant career change. I am now working for Red Hat, as a core developer on the RichFaces project. I am also representing Red hat on the JSR-344: JSF 2.2 Expert Group, and will continue in my role as Seam Faces module lead.
As such, I'll be presenting at JAXConf/JSF Summit on the topic of Seam Faces. I really like this presentation, as I not only go into the features provided by Seam Faces, but I show how some of those features are implemented taking advantage of the platform extension points built into CDI and JSF. I'll also introduce how we are using Arquillian, Shrinkwrap, and JSFUnit to test Seam Faces, and how you can use the same toolset to test your own applications with independent and isolated in-container tests.
So if you are at JAXConf/JSF Summit, be sure to come see my talk, or grab me at any time to share your thoughts on where you would like to see Seam Faces going in the future - I'll be more than happy to discuss solutions, and point you to the git repository!
Friday, June 17, 2011
Monday, April 18, 2011
Seam Module Spotlight: Seam Faces
This is a blog entry I wrote for in.relation.to. I'm including it here to keep a personal record of the post.
In this entry for the Seam Module Spotlight series, we will take a close look at the “view configuration” feature of Seam Faces.
Seam Faces aims to provide JSF developers with a truly worthy framework for web development by ironing out some of JSF’s pain points, integrating tightly with CDI, and offering out of the box integration with the other Seam Modules and third party libraries. Part of achieving this goal involves providing a means to centrally configure each of these seemingly disparate concerns, without having to create any JSF Phase listeners, nor maintain a bunch XML files.
Adhering to the CDI core tenet of type safety, Seam Faces offers a type-safe mechanism to configure the behaviour of your JSF views. So far these configurable behaviors include:
Lets take a closer look at the View configuration from the Seam Faces example “faces-viewconfig”:
The properties of the enum are annotated with a @ViewPattern annotation, specifying to which views the adjacent annotations apply. ViewPatterns support wildcards, and matches are made to a particular view weighted by the specificity of the match; therefore, if two annotations paired with different @ViewPatterns conflict for a given view, the annotation paired with the more specific @ViewPattern takes precedence.
Seam Security via the @ViewConfig
Now let’s look at the Seam Security annotations @Admin and @Owner. These annotations are user-provided, meaning they were built solely for this example, and are qualified with the Seam Security qualifier: @SecurityBindingType. When a view is requested that matches a pattern in the @ViewConfig annotated with such an annotation, Seam Faces invokes Seam Security to determine if access should be granted. Authorization is evaluated with the following class:
In this way, views annotated with the @Owner annotation are secured by the @Secures method annotated with the same @Owner annotation. Coupled with parameter injection, this is truly a declarative syntax for securing view access.
Furthermore, the @Admin annotation is defined with an additional qualifier:
URL rewriting via the @ViewConfig
The view config also let’s us configure URL rewriting for a view using the @UrlMapping annotation. In the above @ViewConfig, the URL /item.jsf?item =1 would get mapped into /item/1/, courtesy of PrettyFaces and the annotation: @UrlMapping(“/item/#{id}”). In this mapping, “#{id}” tells the rewriting-engine to treat the last portion of the URL as the value of the the query-parameter named “id”. By integrating the configuration of rewriting URLs alongside the rest of the view configuration, Seam Faces attempts to make this powerful technology more accessible, and a core part of JSF application development.
Setting faces-redirect=true
A seemingly simple annotation, @FacesRedirect is a surprisingly useful one. When this annotation is present with a @ViewPattern, any navigation to a matching view is intercepted, and the faces-redirect attribute is activated. In the provided example the @FacesRedirect annotation is applied once to the pattern “/*”, which applies the configuration to all views. One could optionally override this catch all setting on a more specific pattern, or on an individual view, with the annotation @FacesRedirect(false). This annotation has a special place close to my heart - no more “?faces-redirect=true” peppered throughout any more applications!
Seam Persistence via the @ViewConfig
Last, but not least, there is the SeamManagedTransaction annotation that can be applied in the @ViewConfig. This allows transactional behaviour to be defined on a per view basis. Exploring the possibilities here will be the subject matter for a subsequent post.
The future for the @ViewConfig component of Seam Faces is bright, with many more capabilities to be added. In addition, the @ViewConfig presented here is merely a front-end to an internal store of the view configuration data. This opens up the possibility of providing alternate means of populating the view config data store, writing extensions to perform custom operations on view config data for your individual application, and more. One solution being explored is to introduce child tags to the f:metadata tag, which will allow view related concerns to be defined from within the view itself. Additionally, configuration sources like xml and database persistence could be incorporated to provide developers with more options.
Seam Faces provides a centralised, type safe way of configuring the behaviour of your JSF views. Try the ViewConfig out and be sure to send in your feedback. This is still early days for the feature, and all feedback is very much appreciated!
In this entry for the Seam Module Spotlight series, we will take a close look at the “view configuration” feature of Seam Faces.
Seam Faces aims to provide JSF developers with a truly worthy framework for web development by ironing out some of JSF’s pain points, integrating tightly with CDI, and offering out of the box integration with the other Seam Modules and third party libraries. Part of achieving this goal involves providing a means to centrally configure each of these seemingly disparate concerns, without having to create any JSF Phase listeners, nor maintain a bunch XML files.
Adhering to the CDI core tenet of type safety, Seam Faces offers a type-safe mechanism to configure the behaviour of your JSF views. So far these configurable behaviors include:
- Restricting view access by integrating with Seam Security
- Configuring URL rewriting by integrating with PrettyFaces (or any other pluggable URL rewriting framework)
- Configuring Transactions via Seam Persistence
- And a personal favorite: setting “?faces-redirect=true” when navigating to a view.
Lets take a closer look at the View configuration from the Seam Faces example “faces-viewconfig”:
@ViewConfig
public interface Pages {
static enum Pages1 {
@ViewPattern("/admin.xhtml")
@Admin
ADMIN,
@ViewPattern("/item.xhtml")
@UrlMapping(pattern="/item/#{id}/")
@Owner
ITEM,
@ViewPattern("/*")
@FacesRedirect
@AccessDeniedView("/list.xhtml")
@LoginView("/login.xhtml")
ALL;
}
}
At first glance, the structure of the above configuration might appear odd. The @ViewConfig annotation is on the interface, and the interface is nothing more than a container for a static enum. This arrangement is unfortunately required by the current CDI specification for the view configuration annotations to be scanned, and will hopefully be corrected in future iterations of the CDI spec.The properties of the enum are annotated with a @ViewPattern annotation, specifying to which views the adjacent annotations apply. ViewPatterns support wildcards, and matches are made to a particular view weighted by the specificity of the match; therefore, if two annotations paired with different @ViewPatterns conflict for a given view, the annotation paired with the more specific @ViewPattern takes precedence.
Seam Security via the @ViewConfig
Now let’s look at the Seam Security annotations @Admin and @Owner. These annotations are user-provided, meaning they were built solely for this example, and are qualified with the Seam Security qualifier: @SecurityBindingType. When a view is requested that matches a pattern in the @ViewConfig annotated with such an annotation, Seam Faces invokes Seam Security to determine if access should be granted. Authorization is evaluated with the following class:
public class SecurityRules {
public @Secures @Owner boolean ownerChecker(Identity identity, @Current Item item) {
if (item == null || identity.getUser() == null) {
return false;
} else {
return item.getOwner().equals(identity.getUser().getId());
}
}
public @Secures @Admin boolean adminChecker(Identity identity) {
if (identity.getUser() == null) {
return false;
} else {
return "admin".equals(identity.getUser().getId());
}
}
}
In this way, views annotated with the @Owner annotation are secured by the @Secures method annotated with the same @Owner annotation. Coupled with parameter injection, this is truly a declarative syntax for securing view access.
Furthermore, the @Admin annotation is defined with an additional qualifier:
@RestrictAtPhase(PhaseIdType.RESTORE_VIEW)This annotation causes the security restriction to be applied at the “Restore View” phase, rather than the default phases: “Invoke Application” and “Render Response”. These default phases were chosen in order for application data to be present and allow access restrictions to be contextual. The default phases also mean that the security restrictions are evaluated twice per lifecycle, as the view often changes at the end of the “Invoke Application” phase.
URL rewriting via the @ViewConfig
The view config also let’s us configure URL rewriting for a view using the @UrlMapping annotation. In the above @ViewConfig, the URL /item.jsf?item =1 would get mapped into /item/1/, courtesy of PrettyFaces and the annotation: @UrlMapping(“/item/#{id}”). In this mapping, “#{id}” tells the rewriting-engine to treat the last portion of the URL as the value of the the query-parameter named “id”. By integrating the configuration of rewriting URLs alongside the rest of the view configuration, Seam Faces attempts to make this powerful technology more accessible, and a core part of JSF application development.
Setting faces-redirect=true
A seemingly simple annotation, @FacesRedirect is a surprisingly useful one. When this annotation is present with a @ViewPattern, any navigation to a matching view is intercepted, and the faces-redirect attribute is activated. In the provided example the @FacesRedirect annotation is applied once to the pattern “/*”, which applies the configuration to all views. One could optionally override this catch all setting on a more specific pattern, or on an individual view, with the annotation @FacesRedirect(false). This annotation has a special place close to my heart - no more “?faces-redirect=true” peppered throughout any more applications!
Seam Persistence via the @ViewConfig
Last, but not least, there is the SeamManagedTransaction annotation that can be applied in the @ViewConfig. This allows transactional behaviour to be defined on a per view basis. Exploring the possibilities here will be the subject matter for a subsequent post.
The future for the @ViewConfig component of Seam Faces is bright, with many more capabilities to be added. In addition, the @ViewConfig presented here is merely a front-end to an internal store of the view configuration data. This opens up the possibility of providing alternate means of populating the view config data store, writing extensions to perform custom operations on view config data for your individual application, and more. One solution being explored is to introduce child tags to the f:metadata tag, which will allow view related concerns to be defined from within the view itself. Additionally, configuration sources like xml and database persistence could be incorporated to provide developers with more options.
Seam Faces provides a centralised, type safe way of configuring the behaviour of your JSF views. Try the ViewConfig out and be sure to send in your feedback. This is still early days for the feature, and all feedback is very much appreciated!
Sunday, April 3, 2011
RichFaces Plugin for Seam Forge
If you haven't yet heard about it, Seam Forge is a fantastic new tool from JBoss for rapid application development of standards based applications. Forge allows a developer to quickly set up the scaffolding for an application, and quickly get to the matter of solving domain problems.
What makes Forge particularly interesting, from my perspective, is the way it was built with plugins in mind as a defining way in which the platform is meant to be extended. To take this new tool for a spin, I created a Forge plugin for RichFaces - the killer component kit for JSF 2.
For instructions on installing Forge, refer to the Forge Documentation. The following guide assumes you have Forge installed and functional.
** The instructions in this blog are for the 0.1.0 version of the RichFaces plugin for Seam Forge. See the project's README.txt for update usage instructions. **
First, lets install the RichFaces plugin for forge (installing from git!):
Forge makes it easy to create a new project:
Next, make the project a Java EE wep app, by installing the "servlet facet":
Now, we can run the "richfaces" command, with no arguments to see the options available:
Running "richfaces install" duplicates the behaviour of the existing RichFaces maven archetype. If you have an existing project, and you just want to use forge to add the RichFaces dependencies and setup the web.xml, run "richfaces isntall-base". For our vanilla application, we'll run the full install, and see a simple facelet page with an input component "ajaxified" with RichFaces.
This new RichFaces enabled maven project is ready to be opened up in your favorite IDE (I used Netbeans) and run in your preferred run-time container (I used Glassfish 3.1).
This is early days for this plugin. I achieved my initial goal of being functionally equivalent to the maven archetype, but there is plenty of room for improvement. Some of my ideas are:
Fork away, lets show the power of Seam Forge with the RichFaces plugin!
What makes Forge particularly interesting, from my perspective, is the way it was built with plugins in mind as a defining way in which the platform is meant to be extended. To take this new tool for a spin, I created a Forge plugin for RichFaces - the killer component kit for JSF 2.
For instructions on installing Forge, refer to the Forge Documentation. The following guide assumes you have Forge installed and functional.
** The instructions in this blog are for the 0.1.0 version of the RichFaces plugin for Seam Forge. See the project's README.txt for update usage instructions. **
First, lets install the RichFaces plugin for forge (installing from git!):
$ forge git-plugin git://github.com/bleathem/richfaces-forge-plugin.git
Forge makes it easy to create a new project:
$ new-project --named richfacesApp --topLevelPackage ca.bleathem.richfaces.test --projectFolder richfacesApp
Next, make the project a Java EE wep app, by installing the "servlet facet":
$ project install-facet forge.spec.servlet
Now, we can run the "richfaces" command, with no arguments to see the options available:
$ richfaces Use the install commands to install: install-base: maven dependencies, and web.xml configuration install-example-facelet: a sample RichFaces enabled facelet file with backing bean install: both base and example-facelet
Running "richfaces install" duplicates the behaviour of the existing RichFaces maven archetype. If you have an existing project, and you just want to use forge to add the RichFaces dependencies and setup the web.xml, run "richfaces isntall-base". For our vanilla application, we'll run the full install, and see a simple facelet page with an input component "ajaxified" with RichFaces.
$ richfaces install ***SUCCESS*** RichFaces BOM dependency has been installed. ***SUCCESS*** org.richfaces.ui:richfaces-components-ui:4.0.0.Final dependency has been installed. ***SUCCESS*** org.richfaces.core:richfaces-core-impl:4.0.0.Final dependency has been installed. ***SUCCESS*** javax.servlet:servlet-api dependency has been installed. ***SUCCESS*** javax.servlet.jsp:jsp-api dependency has been installed. ***SUCCESS*** javax.servlet:jstl dependency has been installed. ***SUCCESS*** net.sf.ehcache:ehcache dependency has been installed. ***SUCCESS*** javax.faces.PROJECT_STAGE context-param has been installed. ***SUCCESS*** javax.faces.SKIP_COMMENTS context-param has been installed. ***SUCCESS*** Faces Servlet mapping has been installed. Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/webapp/WEB-INF/web.xml Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/webapp/templates/template.xhtml ***SUCCESS*** template.xhtml file has been installed. Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/webapp/index.xhtml ***SUCCESS*** index.xhtml file has been installed. Wrote /home/bleathem/NetBeansProjects/richfaces/richfacesApp/src/main/java/ca/bleathem/richfaces/test/RichBean.java ***SUCCESS*** RichBean class has been installed.
This new RichFaces enabled maven project is ready to be opened up in your favorite IDE (I used Netbeans) and run in your preferred run-time container (I used Glassfish 3.1).
This is early days for this plugin. I achieved my initial goal of being functionally equivalent to the maven archetype, but there is plenty of room for improvement. Some of my ideas are:
- Make the sample facelet page more attractive, and showcase more of RichFaces capabilities
- Test and support the generated application in more containers - including Servlet 2.5
- Scan and convert vanilla facelet tags (or tags from other frameworks) converting them to RichFaces components. I'm thinking specifically dataTables, but I'm sure this would work well for other components.
Fork away, lets show the power of Seam Forge with the RichFaces plugin!
Sunday, March 27, 2011
View Configuration with Seam 3 Faces - the Introduction
In Seam Faces we've provided JSF developers with a mechanism to centrally configure various aspects of their JSF views. Concerns like transaction control and view security are currently supported, and support for URL rewriting, XSRF attack prevention, and JSF navigation is in the planning stage.
The end-goal is to support view configuration via multiple sources (including some support for <f:metadata> child tags). For now we provide type-safe configuration using annotations on enums. The benefit of type-safety for page configuration is a tremendous benefit, and will become evident in the following code examples.
In this post I will cover the @ViewConfig security annotations supported in the Seam 3.0 release. This view configuration feature is still considered "beta" and the @ViewConfig API is subject to change in upcoming releases - based on the feedback we get from you, our community of Seam developers!
(Note: Seam Faces delegates authorization checks to Seam Security, which must be included in your project for the security annotations to have any effect)
Consider this @ViewConfig interface:
The following annotations are available:
The secret sauce is in the annotations qualified with the @SecureBindingType qualifier.
These annotations are mapped to methods that check for appropriate authorization, functionality provided by the Seam Security module. The authorization methods themselves are annotated with @Secure and the corresponding @SecureBindingType qualified annotation, as in the class below:
So how do these pieces fit together? Consider a request for the view /list.xhtml. This would match the view pattern, "/*" and access would be granted, as no SecureBindingType qualified annotation is present. On the other hand, a request to the view /item.xhtml is matched by the more specific pattern "/item.xhtml", and the request would be intercepted. Authorization would be checked according to the method annotated by @Secures, and @Owner, and the user redirected to the login view /login.xhtml. If the user was already logged in, and authorization still failed, the user would be instead redirected to the access denied view. If these views are not defined by their respective annotations, a 401 response is returned.
The enforcement of security restrictions is highly tuned to the JSF life-cycle. By default, authorization is checked before the Invoke Application and Render Response phases (because the view requested may change between these phases). However, by including a "restrictAtPhase" method on SecureBindingType qualified annotation, the phases at which that restriction is applied can be fine tuned. Additionally, the @RestrictAtPhase annotation can be applied to an enum value to change the default phase for all SecureBindingType qualified annotations on enums values that match that pattern. In the example above, the @Admin restriction would be checked at the RestoreView phase, and the @Admin annotation is defined as follows:
While there are a lot of controls to fine tune your security requirements, the defaults are sensible (we hope!) and your security configuration can be quite straight forward. Of course one still has to configure Seam Security to perform the authentication - see the Seam 3 Security module page for further details.
In an upcoming blog series, I'll examine use cases, and propose how we can build more annotations into the view configuration to further centralize application configuration. The @ViewConfig API will also be further refined, based on community feedback. Feel free to leave comments here, or in one of the many communication avenues of the Seam framework with any ideas you have on how this feature can be refined. And of course, we're always looking for more developers to jump in and contribute!
The end-goal is to support view configuration via multiple sources (including some support for <f:metadata> child tags). For now we provide type-safe configuration using annotations on enums. The benefit of type-safety for page configuration is a tremendous benefit, and will become evident in the following code examples.
In this post I will cover the @ViewConfig security annotations supported in the Seam 3.0 release. This view configuration feature is still considered "beta" and the @ViewConfig API is subject to change in upcoming releases - based on the feedback we get from you, our community of Seam developers!
(Note: Seam Faces delegates authorization checks to Seam Security, which must be included in your project for the security annotations to have any effect)
Consider this @ViewConfig interface:
@ViewConfig
public interface Pages {
static enum Pages1 {
@ViewPattern("/*")
@LoginView("/login.xhtml")
@AccessDeniedView("/item/list.xhtml")
ALL,
@ViewPattern("/admin/*")
@Admin(restrictAtPhase=RESTORE_VIEW)
ADMIN,
@ViewPattern("/item.xhtml")
@Owner
ITEM;
}
}
The following annotations are available:
- @ViewConfig
- This marker annotation identifies this interface as containing view configuration annotated enums.
- @ViewPattern
- This contains the view pattern to which these annotations apply. Notice the use of wildcards in the view
- @LoginView, @AccessDeniedView
- The viewIds to redirect to for for authentication, and authorization failure
- @Admin, @Owner
- These "security" annotations are qualified with @SecureBindingType from Seam Security. The authorization methods themselves are each annotated with both the @Secures annotation and the corresponding "security" annotation
- @RestrictAtPhase
- Specify the phases at which the security restrictions will be applied. Default phases are the Invoke Application and Render Response phases
The secret sauce is in the annotations qualified with the @SecureBindingType qualifier.
@SecurityBindingType
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface Owner {
}
These annotations are mapped to methods that check for appropriate authorization, functionality provided by the Seam Security module. The authorization methods themselves are annotated with @Secure and the corresponding @SecureBindingType qualified annotation, as in the class below:
public class SecurityRules {
private transient final Logger logger = Logger.getLogger(SecurityRules.class.getName());
public @Secures @Owner boolean ownerCheck(Identity identity) {
if (identity == null || identity.getUser() == null) {
logger.info("Identity/User is null");
return false;
} else {
String id = identity.getUser().getId();
logger.infof("Username is: %s", id);
return "demo".equals(id);
}
}
public @Secures @Admin boolean adminCheck() {
return false; // No one is an admin!
}
}
So how do these pieces fit together? Consider a request for the view /list.xhtml. This would match the view pattern, "/*" and access would be granted, as no SecureBindingType qualified annotation is present. On the other hand, a request to the view /item.xhtml is matched by the more specific pattern "/item.xhtml", and the request would be intercepted. Authorization would be checked according to the method annotated by @Secures, and @Owner, and the user redirected to the login view /login.xhtml. If the user was already logged in, and authorization still failed, the user would be instead redirected to the access denied view. If these views are not defined by their respective annotations, a 401 response is returned.
The enforcement of security restrictions is highly tuned to the JSF life-cycle. By default, authorization is checked before the Invoke Application and Render Response phases (because the view requested may change between these phases). However, by including a "restrictAtPhase" method on SecureBindingType qualified annotation, the phases at which that restriction is applied can be fine tuned. Additionally, the @RestrictAtPhase annotation can be applied to an enum value to change the default phase for all SecureBindingType qualified annotations on enums values that match that pattern. In the example above, the @Admin restriction would be checked at the RestoreView phase, and the @Admin annotation is defined as follows:
@SecurityBindingType
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface Admin {
public PhaseIdType[] restrictAtPhase();
}
While there are a lot of controls to fine tune your security requirements, the defaults are sensible (we hope!) and your security configuration can be quite straight forward. Of course one still has to configure Seam Security to perform the authentication - see the Seam 3 Security module page for further details.
In an upcoming blog series, I'll examine use cases, and propose how we can build more annotations into the view configuration to further centralize application configuration. The @ViewConfig API will also be further refined, based on community feedback. Feel free to leave comments here, or in one of the many communication avenues of the Seam framework with any ideas you have on how this feature can be refined. And of course, we're always looking for more developers to jump in and contribute!
Wednesday, February 16, 2011
Updating Weld in Glassfish 3.1
Like any piece of software, Weld, the reference implementation for JSR-299, is continually improving as bugs are discovered, and performance is optimized. However, since Weld is tightly coupled with your application server of choice, using the latest weld is slightly more complicated than just bundling a weld release with your web application. This post outlines the relatively painless process of updating the Weld implementation of Glassfish 3.1 to use the latest SNAPSHOT, or any later release for that matter.
A quick search of the Glassfish folder structure identifies the Weld implementation:
The weld-osgi-bundle.jar is the file we have to replace. But how does one go about creating such an OSGI bundle? I for one am not an OSGI expert, and I'm sure I'm not alone :P
Update: The Weld OSGI bundle is now published to the maven repository. Instead of building it yourself, you can download it via:
Not to worry, the weld guys have this in hand. The OSGI bundle is built as an artifact during the weld build. To begin, proceed to the Weld core github page, and checkout the project:
I had a bit of trouble building the entire project, due to the requirement of some deprecated artifacts. So just build the impl module in core:
Next, build the OSGI bundle:
Now take that newly created Weld OSGI bundle, and use it to replace the Glassfish weld-osgi-bundle.jar file we located earlier.
Restart Glassfish, and you should see a message in the log file along the lines of:
And there you have it, Glassfish 3.1 running with the latest Weld. Thanks to Stuart Douglas who guided me through the process!
Note: this will not work to get Weld 1.1+ to run on Glassfish 3.0.1, as the interface between Glassfish and Weld changed considerably with Weld 1.1/Glassfish 3.1. However that interface is for the most part stable, so we can use newer releases of Weld on Glassfish 3.1.
A quick search of the Glassfish folder structure identifies the Weld implementation:
$ find /opt/sun/glassfish/ -iname '*weld*' /opt/sun/glassfish/glassfish/modules/weld-integration-fragment.jar /opt/sun/glassfish/glassfish/modules/weld-integration.jar /opt/sun/glassfish/glassfish/modules/weld-osgi-bundle.jar
The weld-osgi-bundle.jar is the file we have to replace. But how does one go about creating such an OSGI bundle? I for one am not an OSGI expert, and I'm sure I'm not alone :P
Update: The Weld OSGI bundle is now published to the maven repository. Instead of building it yourself, you can download it via:
Not to worry, the weld guys have this in hand. The OSGI bundle is built as an artifact during the weld build. To begin, proceed to the Weld core github page, and checkout the project:
git clone https://github.com/weld/core.git cd core
I had a bit of trouble building the entire project, due to the requirement of some deprecated artifacts. So just build the impl module in core:
cd impl mvn clean install
Next, build the OSGI bundle:
cd ../bundles/osgi/ mvn clean install
Now take that newly created Weld OSGI bundle, and use it to replace the Glassfish weld-osgi-bundle.jar file we located earlier.
cp target/weld-osgi-bundle-1.1.0-SNAPSHOT.jar /opt/sun/glassfish/glassfish/modules/weld-osgi-bundle.jar
Restart Glassfish, and you should see a message in the log file along the lines of:
INFO: Updated bundle 75 from /opt/sun/glassfish-3.1-b41/glassfish/modules/weld-osgi-bundle.jar
And there you have it, Glassfish 3.1 running with the latest Weld. Thanks to Stuart Douglas who guided me through the process!
Note: this will not work to get Weld 1.1+ to run on Glassfish 3.0.1, as the interface between Glassfish and Weld changed considerably with Weld 1.1/Glassfish 3.1. However that interface is for the most part stable, so we can use newer releases of Weld on Glassfish 3.1.
Saturday, January 29, 2011
RESTful URLs, with JSF 2
JSF 2 introduced the ability to create RESTful URLs with the introduction of the <f:viewParam> tag. The tag is easy enough to use, you simply place it in the <f:metadate> tag, and configure the attributes to decode the url.
There are no words to explain how great a feature this is for JSF. The old "every request is a POST" theory didn't pan out. RESTful URLs are bookmarkable, and meaningful to end-users. Unfortunately they are still a bit tricky to use in vanilla JSF, as there are only three backing bean scopes in "vanilla" Java EE 6 that are capable of dealing with business transactions/conversations, and each currently has it's own set of limitations. They are the Session, Conversation, and View scopes
First the Session scope - don't use it! The Session scope is essentially global for your user as they interact with your web application; there is no concept of a business conversation. In short, you'll end up with a scalability issue as your session fills up with business objects that are no longer relevant to the current user task.
The second scope to consider is the Conversation scope introduced in Java EE 6 with CDI. It can span multiple requests, but is shorter lived than the Session. It at first seems great, but if you're not careful, it breaks the concept of RESTful URLs by tagging the nasty little "cid=#" parameter to your query string. If the user bookmarks, or otherwise shares the URL, a conversation expired exception will be thrown when the URL is later reloaded. This quickly becomes a burden to try and deal with. This *is* something that is fixed with Weld 1.1, but I've got apps to write today!
Finally, this leaves the View scope introduced with JSF 2. The lifetime of the bean is tied to the JSF view - ie. your bean falls out of scope when you navigate to a new view. The short, well defined nature of this scope means you don't have the memory leak problems of the Session scope, and it doesn't mess up your RESTful URLs the way the Conversation scope does. However, the only way to get View scoped beans to to share information between views is by using viewParams. So if you store your business data in View scoped beans, you have to persist your data before moving on to the next view. This is how I currently build my applications, but the views are becoming too cluttered with javascript panels and popup boxes, as I try to fit a complete business conversation in a single view.
I'm very hopeful that with Weld 1.1, and the fix of issue WELD-549, that I will be able to make better use of Conversation scoped beans. I will the be able to navigate between URLs (with faces-redirect=false) with conversation scoped beans, and not have to worry about the "cid=#" parameter showing up in my URLs when the user performs navigations not relevant to the current conversation. At least hopefully this will be the case!
Additionally and/or alternatively, we need more scopes. Something like the ViewAccess scope I last blogged about, where the developer doesn't have to think about bean scope so much. Just write your app, and have the framework do the right thing.
Please share your thoughts if you've got another way of working with RESTful URLs in your JSF apps, I would love to hear about it!
<f:metadata>
<f:viewParam />
</f:metadata>
There are no words to explain how great a feature this is for JSF. The old "every request is a POST" theory didn't pan out. RESTful URLs are bookmarkable, and meaningful to end-users. Unfortunately they are still a bit tricky to use in vanilla JSF, as there are only three backing bean scopes in "vanilla" Java EE 6 that are capable of dealing with business transactions/conversations, and each currently has it's own set of limitations. They are the Session, Conversation, and View scopes
First the Session scope - don't use it! The Session scope is essentially global for your user as they interact with your web application; there is no concept of a business conversation. In short, you'll end up with a scalability issue as your session fills up with business objects that are no longer relevant to the current user task.
The second scope to consider is the Conversation scope introduced in Java EE 6 with CDI. It can span multiple requests, but is shorter lived than the Session. It at first seems great, but if you're not careful, it breaks the concept of RESTful URLs by tagging the nasty little "cid=#" parameter to your query string. If the user bookmarks, or otherwise shares the URL, a conversation expired exception will be thrown when the URL is later reloaded. This quickly becomes a burden to try and deal with. This *is* something that is fixed with Weld 1.1, but I've got apps to write today!
Finally, this leaves the View scope introduced with JSF 2. The lifetime of the bean is tied to the JSF view - ie. your bean falls out of scope when you navigate to a new view. The short, well defined nature of this scope means you don't have the memory leak problems of the Session scope, and it doesn't mess up your RESTful URLs the way the Conversation scope does. However, the only way to get View scoped beans to to share information between views is by using viewParams. So if you store your business data in View scoped beans, you have to persist your data before moving on to the next view. This is how I currently build my applications, but the views are becoming too cluttered with javascript panels and popup boxes, as I try to fit a complete business conversation in a single view.
I'm very hopeful that with Weld 1.1, and the fix of issue WELD-549, that I will be able to make better use of Conversation scoped beans. I will the be able to navigate between URLs (with faces-redirect=false) with conversation scoped beans, and not have to worry about the "cid=#" parameter showing up in my URLs when the user performs navigations not relevant to the current conversation. At least hopefully this will be the case!
Additionally and/or alternatively, we need more scopes. Something like the ViewAccess scope I last blogged about, where the developer doesn't have to think about bean scope so much. Just write your app, and have the framework do the right thing.
Please share your thoughts if you've got another way of working with RESTful URLs in your JSF apps, I would love to hear about it!
Friday, December 17, 2010
ViewAccessScope - why it's useful
At first the conversation scope introduced with CDI seemed like it would be incredibly useful. Unfortunately, working with conversations ended up being more difficult than expected. Details of why this is, is fodder for another post.
I ended up often using the JSF ViewScope, exposed as a CDI scope though the Seam Faces CDI extension. When used in conjunction with JSF viewParams to propagate information between pages, the result is a book-markable end user experience.
The problem with this is that the "business conversation" is now restricted to a single page. JSF components that provide a tabbed interfaces allow one to pack a lot into a single page, in a clear and structured way, but there are times when it just makes more sense to navigate to a new page (or view in JSF speak).
This is where the ViewAccessScope comes in. It's a scope defined in MyFaces CODI (a CDI extension). The ViewAccessScope is like a long-lived conversation, where the conversation ends as soon as you use a view that does not reference the ViewAccessScoped bean.
The pattern I see as being incredibly useful, is to initiate a "business conversation" by passing viewParams to a page, then navigate through appropriate views to complete the process. When we come to a page that no longer references the ViewAccessScoped bean, the business conversation is over. This is a perfect fit with how I think of structuring my apps.
Now to try it out, and see how well it works!
I ended up often using the JSF ViewScope, exposed as a CDI scope though the Seam Faces CDI extension. When used in conjunction with JSF viewParams to propagate information between pages, the result is a book-markable end user experience.
The problem with this is that the "business conversation" is now restricted to a single page. JSF components that provide a tabbed interfaces allow one to pack a lot into a single page, in a clear and structured way, but there are times when it just makes more sense to navigate to a new page (or view in JSF speak).
This is where the ViewAccessScope comes in. It's a scope defined in MyFaces CODI (a CDI extension). The ViewAccessScope is like a long-lived conversation, where the conversation ends as soon as you use a view that does not reference the ViewAccessScoped bean.
The pattern I see as being incredibly useful, is to initiate a "business conversation" by passing viewParams to a page, then navigate through appropriate views to complete the process. When we come to a page that no longer references the ViewAccessScoped bean, the business conversation is over. This is a perfect fit with how I think of structuring my apps.
Now to try it out, and see how well it works!
Subscribe to:
Posts (Atom)
