Dennis has posted 2 posts at DZone. View Full User Profile

JSF Anti-Patterns and Pitfalls

12.12.2008
| 42031 views |
  • submit to reddit
 

Code to Interface

JSF was designed to encourage an "embrace and extend" mindset. The JSF component model is consequently driven largely by interfaces. The ImplementationDependentManagedBean is an example of what happens when these interfaces are not observed; and yes, I have had to fix code like this.

import org.apache.myfaces.component.html.ext.HtmlInputHidden;
import org.apache.myfaces.component.html.ext.HtmlInputText;
import org.apache.myfaces.component.html.ext.HtmlOutputText;

public class ImplementationDependentManagedBean {

private HtmlInputText input ;
private HtmlInputHidden hidden ;
private HtmlOutputText output ;

/* getters & setters ommitted */

public boolean recordTotal(ActionEvent event) {

long total = ((Long)input.getValue()).longValue();
total += ((Long)hidden.getValue()).longValue();
total += ((Long)output.getValue()).longValue();

return new JmsUtil().broadcastTotal(total);
}

}

 

This managed bean has three component binding properties. Business logic is applied to each component in an action listener. Three classes from a MyFaces Tomahawk package have been imported. Notice the business logic only invokes the getValue method of each component. The getValue method is inherited from a superclass found in the core JSF API. By replacing these imports the class becomes interoperable.

import javax.faces.component.ValueHolder;

public class RefactoredManagedBean {

private ValueHolder input ;
private ValueHolder hidden ;
private ValueHolder output ;

/* getters & setters ommitted */

public boolean recordTotal(ActionEvent event) {

long total = 0;

for(ValueHolder valued : new ValueHolder[] {input, hidden, output})
total += ((Long)valued.getValue()).longValue();

return new JmsUtil().broadcastTotal(total);

}
}

 

ValueHolder is an interface implemented by a superclass of HtmlInputText, HtmlInputHidden and HtmlOutputText. By refactoring the class to use the ValueHolder interface, the managed bean can be used with the reference implementation as well as different ValueHolder component bindings (eg. HtmlOutputText, HtmlInputText, HtmlInputHidden, etc.). Polymorphism is used to clean up the business logic.

Remember, one of the beautiful things JSF provides is the freedom to express logic in POJOs. Application developers don't have to implement an interface or extend a class provided by the container. This doesn't mean it is alright to drop the principles of object oriented programming. When you see an opportunity to program to a standardized interface, do it.

Did you notice anything peculiar about the recordTotal action listener method? The JSF specification defines the return type of action listener methods to be void but the action listener has a return type of boolean. MyFaces allows this and ignores the method return type. Try to avoid this - it is acceptable for the reference implementation to throw an exception.
View State Encryption

A common misconception is that SSL excuses the need for view state encryption. Likewise, many developers assume using view state encryption means they have no need of SSL. Let the author be very clear: SSL and view state encryption have no common ground. They solve completely separate problems at different layers of the network protocol stack.

Consider the classic man in the middle attack. Manfred is a bank, Sean is an online customer, and Mike is an intermediary. Using plain HTTP, Mike can intercept the request from Sean to Manfred, record Sean's password, and forward the request to Manfred, unbeknownst to either party at each end.

By working at the transport layer of the network protocol stack, Manfred and Sean can use SSL to prevent Mike from using the intercepted information.

SSL provides point to point security, keeping Sean and Manfred safe from Mike; it does not keep Manfred safe from Sean if the application is using client side state saving. JSF builds a data structure to represent the component tree during the render response phase when using client side state saving. This data structure is called the view state. When using client side state saving, the view state is serialized, encoded, and slipped into the response via a hidden HTML field in the form.

When the HTML form is submitted it carries the view state value back to the server in the form of an HTTP parameter. JSF uses the value of this parameter to reconstruct the view during the restore view phase. The view is restored by reversing the process used to obtain the view state: it is decoded and deserialized. This poses a major security challenge to any JSF implementation because Sean has the freedom to change the view state. He can toggle the rendered attribute of UI controls that are not supposed to be available to him. He can point a commandButton to a method on any managed bean in the application. He can circumvent an action listener.

I strongly recommend view state encryption for public facing JSF applications using client side state saving in production because it prevents web clients from being able to tamper with the view state. I recommend disabling view state encryption for development and functional testing. Review the documentation for your JSF implementation in order to learn how you can enable view state encryption.
Portlet Issues

I feel sorry for Portlet developers. I really do. These people are always on the mailing lists and forums with problem after problem and it's never their fault. If any group of people has been bent over by the standards bodies, it is Portlet application developers.

Some parts of the JSF API behave different when inside a Portlet application. If your code is to run within a Portlet application and a regular Servlet container there are a few assumptions that need to be avoided. Here is some code assuming it will always run in a Servlet container.

FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext externalContext = ctx.getExternalContext();
ServletRequest request = (ServletRequest) externalContext.getRequest();
String id = request.getParameter("id");

 If your code will run in a Portlet application you must make not make explicit casts to javax.servlet.ServletRequest or javax.servlet.ServletResponse. If this code were used in a Portlet application, ExternalContext.getRequest would return a javax.portlet.PortletRequest, causing a ClassCastException. An interoperable way to obtain a value of a request attribute is to do the following.

FacesContext ctx = FacesContext.getCurrentInstance();
ExternalContext externalContext = ctx.getExternalContext();
externalContext.getRequestParameterMap().get("id");

Originally posted on TheServerSide.com


Author bio


Dennis Byrne currently works in the bay area for ThoughtWorks, a global consultancy with a focus on end-to-end agile software development of mission critical systems. Dennis is a committer and PMC member for Apache Myfaces. He is also a committer for JBoss JSFUnit. You can see Dennis' case study on JSF Anti-patterns this March at the 2008 TheServerSide Java Symposium in Las Vegas.

Published at DZone with permission of its author, Dennis Byrne.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Bruce Fancher replied on Mon, 2008/12/15 - 2:20am

Using JSF is itself an anti-pattern.

Manrico Corazzi replied on Tue, 2008/12/16 - 9:11am

So it turns out I'm not the only one utterly disliking JSF... :)

Marc Stock replied on Tue, 2008/12/16 - 2:06pm

+1 to Bruce Fancher

 Asking about JSF pitfalls is like sticking your hand in a fire and asking, "What are the pitfalls of sticking your hand in fire?" 

Omar Palomino S... replied on Thu, 2008/12/18 - 2:19pm in response to: Bruce Fancher

Wich alternatives do you propose that gets same tool support and ajax integration? I'm looking to speed-up time-to-develop projects and I really want to know about the alternatives to JSF-Ajax frameworks. Hope anyone could give a hand here.

Dzmitry Churbanau replied on Mon, 2008/12/22 - 11:46pm

Bruce Fancher, Manrico Corazzi and Marc Stock: everybody can criticize (read write this is bad and so on) but not everybody can give any valuable reason to it.
So, what is your reason? Can you give any reason, or it is just "i don't like it"? :)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.