JavaServer Faces Anti-Patterns and Pitfalls
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

JavaServer Faces Anti-Patterns and Pitfalls

  • 4,182 views
Uploaded on

Here are my slides from ApacheCon 2007

Here are my slides from ApacheCon 2007

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
4,182
On Slideshare
4,174
From Embeds
8
Number of Embeds
4

Actions

Shares
Downloads
91
Comments
0
Likes
3

Embeds 8

https://www.linkedin.com 3
http://www.slideshare.net 2
http://www.linkedin.com 2
http://localhost 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

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