Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package pl.horus.wf.web.commons.component;
- import com.sun.faces.context.StateContext;
- import javax.el.ValueExpression;
- import javax.faces.component.*;
- import javax.faces.context.FacesContext;
- import javax.faces.view.facelets.FaceletContext;
- import java.io.IOException;
- import java.util.*;
- /**
- * This component allows including facelets dynamically. It is using
- * preserved FaceletContext to build component trees based on the view path.
- * This FaceletContext is enriched with attributes passed to the
- * dynamicInclude tag.
- *
- * Initially subtrees are built in the rendering phase. Then on postback
- * request they are rebuilt in restoreView phase.
- */
- public class DynamicInclude extends UIComponentBase {
- private static final String SRC_ATTRIBUTE = "src";
- private Map<String, ValueExpression> valueExpressions = Collections.emptyMap();
- private List<String> renderedSources = new ArrayList<String>();
- private List<String> restoredSources = Collections.emptyList();
- // for ajax requests this will stay false
- private boolean wasRendered = false;
- private boolean wasPurged = false;
- private FaceletContext faceletContext;
- private String src;
- public DynamicInclude() {}
- public void addValueExpression(String key, ValueExpression valueExpression) {
- if (valueExpressions == Collections.EMPTY_MAP)
- valueExpressions = new HashMap<String, ValueExpression>();
- valueExpressions.put(key, valueExpression);
- }
- @Override
- public void encodeBegin(FacesContext context) throws IOException {
- wasRendered = true;
- this.src = calculateSrc();
- if (isRendered()) {
- String src = getSrc();
- if (!renderedSources.contains(src))
- // As soon as we detect the first inconsistency between restored and
- // rendered views, we purge restored views. Otherwise we reuse restored
- // view and mark it as rendered.
- if (restoredSources.indexOf(src) == renderedSources.size())
- renderedSources.add(src);
- else if (!wasPurged)
- purgeRestoredChildren(context);
- if (!renderedSources.contains(src)) {
- buildView(context, src);
- renderedSources.add(src);
- }
- }
- }
- /**
- * Remove all restored views except those marked as rendered.
- */
- private void purgeRestoredChildren(FacesContext context) {
- StateContext stateContext = StateContext.getStateContext(context);
- List<UIComponent> toRemove = new ArrayList<UIComponent>();
- stateContext.setTrackViewModifications(false);
- for (UIComponent c : getChildren())
- if (!renderedSources.contains(((DynamicIncludeComponent)c).src))
- toRemove.add(c);
- this.getChildren().removeAll(toRemove);
- this.restoredSources = Collections.emptyList();
- this.wasPurged = true;
- stateContext.setTrackViewModifications(true);
- }
- private void buildView(FacesContext context, String src) {
- StateContext stateContext = StateContext.getStateContext(context);
- try {
- stateContext.setTrackViewModifications(false);
- DynamicIncludeComponent panel = new DynamicIncludeComponent();
- int index = findFreeIndex();
- panel.src = src;
- panel.index = index;
- panel.setId(getId() + index);
- this.getChildren().add(index, panel);
- setAttributesInFaceletContext();
- faceletContext.includeFacelet(panel, src);
- } catch (IOException e) {
- throw new RuntimeException(e);
- } finally {
- stateContext.setTrackViewModifications(true);
- }
- }
- private int findFreeIndex() {
- for (int i = 0; i <= this.getChildCount(); i++) {
- boolean free = true;
- for (UIComponent c : this.getChildren())
- if (i == ((DynamicIncludeComponent)c).index)
- free = false;
- if (free)
- return i;
- }
- throw new IllegalStateException("Impossible! Could not find available index.");
- }
- /**
- * FaceletContext is used during creation of components from a facelet
- * template. If these components have attributes with EL expressions
- * referring to what's in dynamicInclude attributes, we have to make
- * them available in FaceletContext.
- */
- private void setAttributesInFaceletContext() {
- for (Map.Entry<String, ValueExpression> var : valueExpressions.entrySet())
- faceletContext.getVariableMapper().setVariable(var.getKey(), var.getValue());
- }
- @Override
- public Object saveState(FacesContext context) {
- Object values[] = new Object[2];
- values[0] = super.saveState(context);
- values[1] = wasRendered ? renderedSources : restoredSources;
- return values;
- }
- /**
- * We rebuild subviews here. The children state will be restored
- * by StateManagementStrategy because it first restores state of a node
- * then processes its children.
- */
- @Override
- public void restoreState(FacesContext context, Object state) {
- Object values[] = (Object[]) state;
- super.restoreState(context, values[0]);
- this.restoredSources = (List<String>)values[1];
- for (String src : this.restoredSources)
- buildView(context, src);
- }
- /* getters and setters */
- public String getFamily() {
- return null;
- }
- public void setSrc(String src) {
- this.src = src;
- }
- public String getSrc() {
- if (src == null)
- this.src = calculateSrc();
- return this.src;
- }
- private String calculateSrc() {
- ValueExpression ve = getValueExpression(SRC_ATTRIBUTE);
- // Fast fix for poorly diagnosed error
- if (ve == null)
- ve = valueExpressions.get(SRC_ATTRIBUTE);
- return (String) ve.getValue(getFacesContext().getELContext());
- }
- public void setFaceletContext(FaceletContext faceletContext) {
- this.faceletContext = faceletContext;
- }
- /**
- * This serves as root for possible subviews included by DynamicInclude.
- */
- public static class DynamicIncludeComponent extends UIComponentBase implements NamingContainer {
- // no need to preserve this, DynamicInclude restores this value
- private String src;
- private int index;
- @Override
- public String getFamily() {
- return null;
- }
- @Override
- public boolean isRendered() {
- return src.equals(((DynamicInclude)getParent()).getSrc());
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement