Advertisement
kurtz_mr

JSF dynamic include

Sep 27th, 2011
718
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 5 7.48 KB | None | 0 0
  1. package com.horus.hflow.web.commons.tag;
  2.  
  3. import java.io.IOException;
  4.  
  5. import javax.el.ELException;
  6. import javax.el.ValueExpression;
  7. import javax.faces.FacesException;
  8. import javax.faces.component.UIComponent;
  9. import javax.faces.view.facelets.*;
  10.  
  11. import com.horus.hflow.web.commons.component.DynamicInclude;
  12.  
  13. public final class DynamicIncludeHandler extends ComponentHandler {
  14.  
  15.   public DynamicIncludeHandler(ComponentConfig config) {
  16.     super(config);
  17.   }
  18.  
  19.   public void onComponentCreated(FaceletContext ctx, UIComponent component, UIComponent parent) {
  20.     DynamicInclude di = (DynamicInclude) component;
  21.     di.setFaceletContext(ctx);
  22.     TagAttribute[] vars = tag.getAttributes().getAll();
  23.     for (TagAttribute var : vars) {
  24.       String name = var.getQName();
  25.       String value = var.getValue();
  26.       final ValueExpression valueExpression =
  27.           ctx.getExpressionFactory().createValueExpression(
  28.               ctx.getFacesContext().getELContext(), value, Object.class);
  29.       di.addValueExpression(name, valueExpression);
  30.     }
  31.   }
  32.  
  33.   public boolean apply(FaceletContext ctx, UIComponent parent, String name)
  34.       throws IOException, FacesException, ELException {
  35.     if (name == null) {
  36.       this.nextHandler.apply(ctx, parent);
  37.       return true;
  38.     }
  39.     return false;
  40.   }
  41.  
  42. }
  43.  
  44.  
  45. package com.horus.hflow.web.commons.component;
  46.  
  47. import com.sun.faces.context.StateContext;
  48.  
  49. import javax.el.ValueExpression;
  50. import javax.faces.component.*;
  51. import javax.faces.context.FacesContext;
  52. import javax.faces.view.facelets.FaceletContext;
  53. import java.io.IOException;
  54. import java.util.*;
  55.  
  56. /**
  57.  * This component allows including facelets dynamically. It is using
  58.  * preserved FaceletContext to build component trees based on the view path.
  59.  * This FaceletContext is enriched with attributes passed to the
  60.  * dynamicInclude tag.
  61.  *
  62.  * Initially subtrees are built in the rendering phase. Then on postback
  63.  * request they are rebuilt in restoreView phase.
  64.  */
  65. public class DynamicInclude extends UIComponentBase {
  66.  
  67.   private static final String SRC_ATTRIBUTE = "src";
  68.  
  69.   private Map<String, ValueExpression> valueExpressions = Collections.emptyMap();
  70.   private List<String> renderedSources = new ArrayList<String>();
  71.   private List<String> restoredSources = Collections.emptyList();
  72.   // for ajax requests this will stay false
  73.   private boolean wasRendered = false;
  74.   private boolean wasPurged = false;
  75.   private FaceletContext faceletContext;
  76.   private String src;
  77.  
  78.   public DynamicInclude() {}
  79.  
  80.   public void addValueExpression(String key, ValueExpression valueExpression) {
  81.     if (valueExpressions == Collections.EMPTY_MAP)
  82.       valueExpressions = new HashMap<String, ValueExpression>();
  83.     valueExpressions.put(key, valueExpression);
  84.   }
  85.  
  86.   @SuppressWarnings("unchecked")
  87.   @Override
  88.   public void encodeBegin(FacesContext context) throws IOException {
  89.     wasRendered = true;
  90.     if (isRendered()) {
  91.       String src = getSrc();
  92.  
  93.       if (!renderedSources.contains(src))
  94.         // As soon as we detect the first inconsistency between restored and
  95.         // rendered views, we purge restored views. Otherwise we reuse restored
  96.         // view and mark is as rendered.
  97.         if (restoredSources.indexOf(src) == renderedSources.size())
  98.           renderedSources.add(src);
  99.         else if (!wasPurged)
  100.           purgeRestoredChildren(context);
  101.  
  102.       if (!renderedSources.contains(src)) {
  103.         buildView(context, src);
  104.         renderedSources.add(src);
  105.       }
  106.     }
  107.   }
  108.  
  109.   /**
  110.    * Remove all restored views except those marked as rendered.
  111.    */
  112.   private void purgeRestoredChildren(FacesContext context) {
  113.     StateContext stateContext = StateContext.getStateContext(context);
  114.     List<UIComponent> toRemove = new ArrayList<UIComponent>();
  115.     stateContext.setTrackViewModifications(false);
  116.     for (UIComponent c : getChildren())
  117.       if (!renderedSources.contains(((DynamicIncludeComponent)c).src))
  118.         toRemove.add(c);
  119.  
  120.     this.getChildren().removeAll(toRemove);
  121.     this.restoredSources = Collections.emptyList();
  122.     this.wasPurged = true;
  123.     stateContext.setTrackViewModifications(true);
  124.   }
  125.  
  126.   private void buildView(FacesContext context, String src) {
  127.     StateContext stateContext = StateContext.getStateContext(context);
  128.     try {
  129.       stateContext.setTrackViewModifications(false);
  130.       DynamicIncludeComponent panel = new DynamicIncludeComponent();
  131.       int index = findFreeIndex();
  132.       panel.src = src;
  133.       panel.index = index;
  134.       panel.setId(getId() + index);
  135.       this.getChildren().add(index, panel);
  136.       setAttributesInFaceletContext();
  137.       faceletContext.includeFacelet(panel, src);
  138.     } catch (IOException e) {
  139.       throw new RuntimeException(e);
  140.     } finally {
  141.       stateContext.setTrackViewModifications(true);
  142.     }
  143.   }
  144.  
  145.   private int findFreeIndex() {
  146.     for (int i = 0; i <= this.getChildCount(); i++) {
  147.       boolean free = true;
  148.       for (UIComponent c : this.getChildren())
  149.         if (i == ((DynamicIncludeComponent)c).index)
  150.           free = false;
  151.       if (free)
  152.         return i;
  153.     }
  154.     throw new IllegalStateException("Impossible! Could not find available index.");
  155.   }
  156.  
  157.   /**
  158.    * FaceletContext is used during creation of components from a facelet
  159.    * template. If these components have attributes with EL expressions
  160.    * referring to what's in dynamicInclude attributes, we have to make
  161.    * them available in FaceletContext.
  162.    */
  163.   private void setAttributesInFaceletContext() {
  164.     for (Map.Entry<String, ValueExpression> var : valueExpressions.entrySet())
  165.       faceletContext.getVariableMapper().setVariable(var.getKey(), var.getValue());
  166.   }
  167.  
  168.   @Override
  169.   public Object saveState(FacesContext context) {
  170.     Object values[] = new Object[2];
  171.     values[0] = super.saveState(context);
  172.     values[1] = wasRendered ? renderedSources : restoredSources;
  173.     return values;
  174.   }
  175.  
  176.   /**
  177.    * We rebuild subviews here. The children state will be restored
  178.    * by StateManagementStrategy because it first restores state of a node
  179.    * then processes its children.
  180.    */
  181.   @Override
  182.   public void restoreState(FacesContext context, Object state) {
  183.     Object values[] = (Object[]) state;
  184.     super.restoreState(context, values[0]);
  185.     this.restoredSources = (List<String>)values[1];
  186.  
  187.     for (String src : this.restoredSources)
  188.       buildView(context, src);
  189.   }
  190.  
  191.   /* getters and setters */
  192.   public String getFamily() {
  193.     return null;
  194.   }
  195.  
  196.   public void setSrc(String src) {
  197.     this.src = src;
  198.   }
  199.  
  200.   public String getSrc() {
  201.     if (src == null) {
  202.       ValueExpression ve = getValueExpression(SRC_ATTRIBUTE);
  203.       // Fast fix for poorly diagnosed error
  204.       if (ve == null)
  205.         ve = valueExpressions.get(SRC_ATTRIBUTE);
  206.       this.src = (String) ve.getValue(getFacesContext().getELContext());
  207.     }
  208.     return this.src;
  209.   }
  210.  
  211.   public void setFaceletContext(FaceletContext faceletContext) {
  212.     this.faceletContext = faceletContext;
  213.   }
  214.  
  215.   /**
  216.    * This serves as root for possible subviews included by DynamicInclude.
  217.    */
  218.   public static class DynamicIncludeComponent extends UIComponentBase implements NamingContainer {
  219.     // no need to preserve this, DynamicInclude restores this value
  220.     private String src;
  221.     private int index;
  222.  
  223.     @Override
  224.     public String getFamily() {
  225.       return null;
  226.     }
  227.  
  228.     @Override
  229.     public boolean isRendered() {
  230.       return src.equals(((DynamicInclude)getParent()).getSrc());
  231.     }
  232.   }
  233. }
  234.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement