Your SlideShare is downloading. ×
0
JavaServer Faces Anti-Patterns Dennis Byrne - ThoughtWorks [email_address] http://notdennisbyrne.blogspot.com
Validating Setter <ul><ul><li><managed-bean> </li></ul></ul><ul><ul><li><managed-bean-name>iterationBean</managed-bean-nam...
Validating Setter <ul><li>public class Iteration { </li></ul><ul><li>private Calendar start, end; // injected </li></ul><u...
Validating Setter Solutions <ul><li><application> </li></ul><ul><li><variable-resolver> </li></ul><ul><li>org.springframew...
The Map Trick <ul><li>#{requestScopedMap.key}  // calls get(‘key’) </li></ul><ul><li>#{requestScopedMap[‘key’]} </li></ul>...
déjà vu PhaseListener <ul><ul><li><context-param> </li></ul></ul><ul><ul><li><description> </li></ul></ul><ul><ul><li>comm...
XML Hell <ul><ul><li><navigation-rule> <from-view-id>/home.xhtml</from-view-id> </li></ul></ul><ul><ul><li><navigation-cas...
Thread Safety <ul><ul><ul><li>javax.faces.event.PhaseListener  </li></ul></ul></ul><ul><ul><ul><li>javax.faces.render.Rend...
Thread Safety <ul><li><h:inputText value=&quot;#{managedBean.value}&quot; converter=&quot;#{threadUnsafe}&quot; /> </li></...
Facelets Migration <ul><li>public class WidgetTag extends UIComponentELTag{ </li></ul><ul><li>private String title, styleC...
Law of Demeter <ul><li>A “Train Wreck” - sensitive to changes in domain model </li></ul><ul><li>employee. getDepartment()....
Vendor Lock-in <ul><li>import org.apache.myfaces.component.html.ext.HtmlInputHidden; </li></ul><ul><li>import org.apache.m...
Vendor Lock-in Solution <ul><li>import javax.faces.component.ValueHolder; </li></ul><ul><li>public class RefactoredManaged...
Portlet ClassCastException <ul><li>FacesContext ctx = FacesContext.getCurrentInstance(); </li></ul><ul><li>ExternalContext...
OpenTransactionInViewFilter   <ul><ul><li>public void doFilter(ServletRequest request,  </li></ul></ul><ul><li>ServletResp...
N + 1 <ul><ul><li><!-- One trip to the database for the master record ... --> </li></ul></ul><ul><ul><li><h:dataTable valu...
N + 1- N <ul><li>public class OpenTransactionInApplicationPhaseListener  </li></ul><ul><li>implements PhaseListener { </li...
Thanks <ul><li>Dennis Byrne - ThoughtWorks </li></ul><ul><li>[email_address] </li></ul><ul><li>http://notdennisbyrne.blogs...
Upcoming SlideShare
Loading in...5
×

JavaServer Faces Anti-Patterns and Pitfalls

2,663

Published on

Here are my slides from ApacheCon 2007

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,663
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
92
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Transcript of "JavaServer Faces Anti-Patterns and Pitfalls"

  1. 1. JavaServer Faces Anti-Patterns Dennis Byrne - ThoughtWorks [email_address] http://notdennisbyrne.blogspot.com
  2. 2. Validating Setter <ul><ul><li><managed-bean> </li></ul></ul><ul><ul><li><managed-bean-name>iterationBean</managed-bean-name> </li></ul></ul><ul><ul><li><managed-bean-class> com.thoughtworks.Iteration </li></ul></ul><ul><ul><li> </managed-bean-class> </li></ul></ul><ul><ul><li><managed-bean-scope> request </managed-bean-scope> </li></ul></ul><ul><ul><li><managed-property> </li></ul></ul><ul><ul><li> <property-name> start </property-name> </li></ul></ul><ul><ul><li> <value> #{sprintBean.currentStart} </value> </li></ul></ul><ul><ul><li></managed-property> </li></ul></ul><ul><ul><li><managed-property> </li></ul></ul><ul><ul><li> <property-name> end </property-name> </li></ul></ul><ul><ul><li> <value> #{sprintBean.currentEnd} </value> </li></ul></ul><ul><ul><li></managed-property> </li></ul></ul><ul><ul><li><managed-property> </li></ul></ul><ul><ul><li> <property-name>last</property-name> </li></ul></ul><ul><ul><li> <value>hack</value> </li></ul></ul><ul><ul><li></managed-property> </li></ul></ul><ul><ul><li></managed-bean> </li></ul></ul>
  3. 3. Validating Setter <ul><li>public class Iteration { </li></ul><ul><li>private Calendar start, end; // injected </li></ul><ul><li>// sans setters and getters for start, end </li></ul><ul><li>public void setLast(String last) { </li></ul><ul><li>if(start == null) </li></ul><ul><li>throw new NullPointerException(&quot;start&quot;); </li></ul><ul><li>if(end == null) </li></ul><ul><li>throw new NullPointerException(&quot;end&quot;); </li></ul><ul><li>if(start.after(end)) </li></ul><ul><li>throw new IllegalStateException(&quot;start > end&quot;); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  4. 4. Validating Setter Solutions <ul><li><application> </li></ul><ul><li><variable-resolver> </li></ul><ul><li>org.springframework.web.jsf.DelegatingVariableResolver </li></ul><ul><li></variable-resolver> </li></ul><ul><li></application> </li></ul><ul><li><application> <el-resolver> </li></ul><ul><li>org.apache.myfaces.el.unified.resolver.GuiceResolver </li></ul><ul><li></el-resolver> </li></ul><ul><li></application> </li></ul><ul><li>public class Iteration { </li></ul><ul><li>private Calendar start, end; // injected </li></ul><ul><li>@PostConstruct </li></ul><ul><li>public void initialize() { </li></ul><ul><li>// domain validation logic here ... </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  5. 5. The Map Trick <ul><li>#{requestScopedMap.key} // calls get(‘key’) </li></ul><ul><li>#{requestScopedMap[‘key’]} </li></ul><ul><li>public class MapTrick implements java.util.Map { </li></ul><ul><li>public Object get(Object key) { </li></ul><ul><li>return new BusinessLogic().doSomething(key); </li></ul><ul><li>} </li></ul><ul><li>public void clear() { } </li></ul><ul><li>public boolean containsKey(Object arg) { return false; } </li></ul><ul><li>public boolean isEmpty() { return false; } </li></ul><ul><li>public Set keySet() { return null; } </li></ul><ul><li>public Object put(Object key, Object value) { return null; } </li></ul><ul><li>public void putAll(Map arg) { } </li></ul><ul><li>public Object remove(Object arg) { return null; } </li></ul><ul><li>public int size() { return 0; } </li></ul><ul><li>} </li></ul>
  6. 6. déjà vu PhaseListener <ul><ul><li><context-param> </li></ul></ul><ul><ul><li><description> </li></ul></ul><ul><ul><li>comma separated list of JSF conf files </li></ul></ul><ul><ul><li></description> </li></ul></ul><ul><ul><li><param-name> javax.faces.CONFIG_FILES </param-name> </li></ul></ul><ul><ul><li><param-value> </li></ul></ul><ul><ul><li>/WEB-INF/faces-config.xml </li></ul></ul><ul><ul><li></param-value> </li></ul></ul><ul><ul><li></context-param> </li></ul></ul><ul><ul><li><lifecycle> </li></ul></ul><ul><ul><li><phase-listener> </li></ul></ul><ul><ul><li>com.thoughtworks.PhaseListenerImpl </li></ul></ul><ul><ul><li></phase-listener> </li></ul></ul><ul><ul><li></lifecycle> </li></ul></ul>
  7. 7. XML Hell <ul><ul><li><navigation-rule> <from-view-id>/home.xhtml</from-view-id> </li></ul></ul><ul><ul><li><navigation-case> </li></ul></ul><ul><ul><li><from-outcome>contact_us</from-outcome> </li></ul></ul><ul><ul><li><to-view-id>/contact.xhtml</to-view-id> </li></ul></ul><ul><ul><li></navigation-case> </li></ul></ul><ul><ul><li></navigation-rule> </li></ul></ul><ul><ul><li><navigation-rule> <from-view-id>/site_map.xhtml</from-view-id> </li></ul></ul><ul><ul><li><navigation-case> </li></ul></ul><ul><ul><li><from-outcome>contact_us</from-outcome> </li></ul></ul><ul><ul><li><to-view-id>/contact.xhtml</to-view-id> </li></ul></ul><ul><ul><li></navigation-case> </li></ul></ul><ul><ul><li></navigation-rule> </li></ul></ul><ul><ul><li><navigation-rule><from-view-id> * </from-view-id> </li></ul></ul><ul><ul><li><navigation-case> <!-- global nav rule --> </li></ul></ul><ul><ul><li><from-outcome>contact_us</from-outcome> </li></ul></ul><ul><ul><li><to-view-id>/contact.xhtml</to-view-id> </li></ul></ul><ul><ul><li></navigation-case> </li></ul></ul><ul><ul><li></navigation-rule> </li></ul></ul>
  8. 8. Thread Safety <ul><ul><ul><li>javax.faces.event.PhaseListener </li></ul></ul></ul><ul><ul><ul><li>javax.faces.render.Renderer </li></ul></ul></ul><ul><ul><ul><li>Managed Beans </li></ul></ul></ul><ul><ul><ul><li>javax.faces.convert.Converter </li></ul></ul></ul><ul><ul><ul><li>javax.faces.validator.Validator </li></ul></ul></ul><ul><ul><ul><li>javax.faces.FacesContext </li></ul></ul></ul><ul><ul><ul><li>JSF Tags </li></ul></ul></ul>
  9. 9. Thread Safety <ul><li><h:inputText value=&quot;#{managedBean.value}&quot; converter=&quot;#{threadUnsafe}&quot; /> </li></ul><ul><li><managed-bean> </li></ul><ul><li><managed-bean-name>threadUnsafe</managed-bean-name> </li></ul><ul><li><managed-bean-class> </li></ul><ul><li>org.apache.myfaces.book.ThreadUnsafeConverter </li></ul><ul><li></managed-bean-class> </li></ul><ul><li><managed-bean-scope> session </managed-bean-scope> </li></ul><ul><li></managed-bean> </li></ul><ul><li><h:inputText value=&quot;#{managedBean.value}&quot; > </li></ul><ul><li><f:converter converterId=&quot;threadUnsafe&quot; > <!-- Always Safe --> </li></ul><ul><li></h:inputText> </li></ul><ul><li><converter> </li></ul><ul><li><converter-id>threadUnsafe</converter-id> </li></ul><ul><li><converter-class>org.apache.myfaces.book.ThreadUnsafeConverter </li></ul><ul><li></converter-class> </li></ul><ul><li></converter> </li></ul>
  10. 10. Facelets Migration <ul><li>public class WidgetTag extends UIComponentELTag{ </li></ul><ul><li>private String title, styleClass = &quot;default_class&quot;; </li></ul><ul><li>protected void setProperties(UIComponent component) { </li></ul><ul><li>super.setProperties(component); </li></ul><ul><li>Widget span = (Widget) component; </li></ul><ul><li>span.setStyleClass(styleClass); </li></ul><ul><li>span.setTitle(title == null ? &quot;no title&quot; : title); </li></ul><ul><li>FacesContext ctx = FacesContext.getCurrentInstance(); </li></ul><ul><li>Map session = ctx.getExternalContext().getSessionMap(); </li></ul><ul><li>span.setStyle((String) session.get(&quot;style&quot;)); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  11. 11. Law of Demeter <ul><li>A “Train Wreck” - sensitive to changes in domain model </li></ul><ul><li>employee. getDepartment().getManager() </li></ul><ul><li>.getOffice().getAddress().getZip(); </li></ul><ul><li>An EL “Train Wreck” - sensitive to changes in domain model </li></ul><ul><li>#{employee. department.manager.office.address.zip } </li></ul><ul><li>Encapsulated, insensitive to changes in domain model </li></ul><ul><li>#{employee.officeManagersZipCode} </li></ul>
  12. 12. Vendor Lock-in <ul><li>import org.apache.myfaces.component.html.ext.HtmlInputHidden; </li></ul><ul><li>import org.apache.myfaces.component.html.ext.HtmlInputText; </li></ul><ul><li>import org.apache.myfaces.component.html.ext.HtmlOutputText; </li></ul><ul><li>public class ImplementationDependentManagedBean { </li></ul><ul><ul><li>private HtmlInputText input ; </li></ul></ul><ul><ul><li>private HtmlInputHidden hidden ; </li></ul></ul><ul><ul><li>private HtmlOutputText output ; </li></ul></ul><ul><ul><li>/* getters and setters omitted */ </li></ul></ul><ul><ul><li>public boolean recordTotal(ActionEvent event) { </li></ul></ul><ul><ul><li> long total = ((Long)input.getValue()).longValue(); </li></ul></ul><ul><ul><li> total += ((Long)hidden.getValue()).longValue(); </li></ul></ul><ul><ul><li> total += ((Long)output.getValue()).longValue(); </li></ul></ul><ul><ul><li> return new JmsUtil().broadcastTotal(total); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>} </li></ul>
  13. 13. Vendor Lock-in Solution <ul><li>import javax.faces.component.ValueHolder; </li></ul><ul><li>public class RefactoredManagedBean { </li></ul><ul><li>private ValueHolder input ; </li></ul><ul><li>private ValueHolder hidden ; </li></ul><ul><li>private ValueHolder output ; </li></ul><ul><li>/* getters & setters ommitted */ </li></ul><ul><li>public boolean recordTotal(ActionEvent event) { </li></ul><ul><li>long total = 0; </li></ul><ul><li>ValueHolder[] vh = new ValueHolder[] {input, hidden, output}; </li></ul><ul><li>for(ValueHolder valued : vh) </li></ul><ul><li>total += ((Long)valued.getValue()).longValue(); </li></ul><ul><li>return new JmsUtil().broadcastTotal(total); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  14. 14. Portlet ClassCastException <ul><li>FacesContext ctx = FacesContext.getCurrentInstance(); </li></ul><ul><li>ExternalContext ectx = ctx.getExternalContext(); </li></ul><ul><li>ServletRequest request = ( ServletRequest )ectx .getRequest(); </li></ul><ul><li>String id = request.getParameter(&quot;id&quot;); </li></ul><ul><li>FacesContext ctx = FacesContext.getCurrentInstance(); </li></ul><ul><li>ExternalContext ectx = ctx.getExternalContext(); </li></ul><ul><li>String id = ectx.getRequestParameterMap().get(&quot;id&quot;); </li></ul>
  15. 15. OpenTransactionInViewFilter <ul><ul><li>public void doFilter(ServletRequest request, </li></ul></ul><ul><li>ServletResponse response, FilterChain chain){ </li></ul><ul><ul><li>try { </li></ul></ul><ul><ul><li> ObjectRelationalUtility.startTransaction(); </li></ul></ul><ul><ul><li> chain.doFilter(request, response); </li></ul></ul><ul><ul><li> ObjectRelationalUtility.commitTransaction(); </li></ul></ul><ul><ul><li>} catch (Throwable throwable) { </li></ul></ul><ul><ul><li> try { </li></ul></ul><ul><ul><li>ObjectRelationalUtility.rollbackTransaction(); </li></ul></ul><ul><ul><li> } catch (Throwable _throwable) { </li></ul></ul><ul><ul><li>/* sans error handling */ </li></ul></ul><ul><ul><li> } </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
  16. 16. N + 1 <ul><ul><li><!-- One trip to the database for the master record ... --> </li></ul></ul><ul><ul><li><h:dataTable value=&quot;#{projectBean.projects}&quot; var=&quot;project&quot;> </li></ul></ul><ul><ul><li><h:column> </li></ul></ul><ul><ul><li> <h:commandLink action=&quot;#{projectBean.viewProject}&quot; </li></ul></ul><ul><ul><li>value=&quot;view project&quot;/> </li></ul></ul><ul><ul><li></h:column> </li></ul></ul><ul><ul><li><h:column> </li></ul></ul><ul><ul><li> <!-- ... and + N trips for each child record --> </li></ul></ul><ul><ul><li> <f:facet name=&quot;header&quot;>Project Manager</f:facet> </li></ul></ul><ul><ul><li> #{project .manager.name } </li></ul></ul><ul><ul><li></h:column> </li></ul></ul><ul><ul><li><h:column> </li></ul></ul><ul><ul><li> <f:facet name=&quot;header&quot;>Project Name</f:facet> </li></ul></ul><ul><ul><li> #{project.name} </li></ul></ul><ul><ul><li></h:column> </li></ul></ul><ul><ul><li></h:dataTable> </li></ul></ul>
  17. 17. N + 1- N <ul><li>public class OpenTransactionInApplicationPhaseListener </li></ul><ul><li>implements PhaseListener { </li></ul><ul><li>public void beforePhase(PhaseEvent event) { </li></ul><ul><li>try { </li></ul><ul><li>ObjectRelationalUtility.startTransaction(); </li></ul><ul><li>} catch (Throwable throwable) { /* sans error handling */ } </li></ul><ul><li>} </li></ul><ul><li>public void afterPhase(PhaseEvent event) { </li></ul><ul><li>try { </li></ul><ul><li>ObjectRelationalUtility.commitTransaction(); </li></ul><ul><li>} catch (Throwable throwable) { </li></ul><ul><li>ObjectRelationalUtility.rollbackTransaction(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>public PhaseId getPhaseId(){return PhaseId.INVOKE_APPLICATION ;} </li></ul><ul><li>} </li></ul>
  18. 18. Thanks <ul><li>Dennis Byrne - ThoughtWorks </li></ul><ul><li>[email_address] </li></ul><ul><li>http://notdennisbyrne.blogspot.com </li></ul>
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×