View Javadoc

1   /*
2    * $Id: AbstractRenderContext.java,v 1.18 2011/06/16 09:29:41 jbmeslin Exp $
3    */
4   package org.rcfaces.core.internal.renderkit;
5   
6   import java.util.ArrayList;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.List;
10  import java.util.Map;
11  
12  import javax.faces.FacesException;
13  import javax.faces.component.NamingContainer;
14  import javax.faces.component.StateHolder;
15  import javax.faces.component.UIComponent;
16  import javax.faces.component.UIComponentBase;
17  import javax.faces.context.FacesContext;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  import org.rcfaces.core.internal.tools.BindingTools;
22  
23  /**
24   * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
25   * @version $Revision: 1.18 $ $Date: 2011/06/16 09:29:41 $
26   */
27  public abstract class AbstractRenderContext implements IRenderContext {
28      private static final String REVISION = "$Revision: 1.18 $";
29  
30      private static final Log LOG = LogFactory
31              .getLog(AbstractRenderContext.class);
32  
33      private static final int COMPONENT_STACK_INITIAL_DEPTH = 16;
34  
35      private static final int SCOPE_VAR_INITIAL_SIZE = 4;
36  
37      private final List stack = new ArrayList(COMPONENT_STACK_INITIAL_DEPTH * 3);
38  
39      private List scopeVars = null;
40  
41      private FacesContext facesContext;
42  
43      private Map attributes;
44  
45      private boolean transientState;
46  
47      protected AbstractRenderContext() {
48      }
49  
50      public final FacesContext getFacesContext() {
51          return facesContext;
52      }
53  
54      protected void initialize(FacesContext facesContext) {
55          this.facesContext = facesContext;
56      }
57  
58      public String getComponentClientId(UIComponent component) {
59          return component.getClientId(facesContext);
60      }
61  
62      public String computeBrotherComponentClientId(UIComponent brotherComponent,
63              String componentId) {
64  
65          if (componentId.length() > 0
66                  && componentId.charAt(0) == NamingContainer.SEPARATOR_CHAR) {
67              return componentId;
68          }
69  
70          String brotherClientId = getComponentClientId(brotherComponent);
71  
72          if (brotherClientId == null) {
73              return null;
74          }
75  
76          int idx = brotherClientId.lastIndexOf(NamingContainer.SEPARATOR_CHAR);
77          if (idx < 0) {
78              return componentId;
79          }
80  
81          brotherClientId = brotherClientId.substring(0, idx + 1);
82  
83          return brotherClientId + componentId;
84      }
85  
86      public void pushComponent(UIComponent component, String componentClientId) {
87          stack.add(component);
88          stack.add(componentClientId);
89          stack.add(Boolean.FALSE);
90  
91          if (LOG.isDebugEnabled()) {
92              StringBuffer sb = new StringBuffer();
93  
94              for (Iterator it = stack.iterator(); it.hasNext();) {
95                  it.next();
96                  sb.append(" / " + it.next());
97                  it.next();
98              }
99  
100             LOG.debug("Push component. stack=" + sb);
101         }
102     }
103 
104     public void popComponent(UIComponent component) {
105 
106         int level = getStackLevel();
107         stack.remove(level);
108         String componentClientId = (String) stack.remove(level);
109         Object componentContextAttributes = stack.remove(level);
110         if (componentContextAttributes != Boolean.FALSE) {
111             releaseMap((Map) componentContextAttributes);
112         }
113 
114         if (LOG.isDebugEnabled()) {
115             StringBuffer sb = new StringBuffer();
116 
117             for (Iterator it = stack.iterator(); it.hasNext();) {
118                 it.next();
119                 sb.append(" / " + it.next());
120                 it.next();
121             }
122 
123             LOG.debug("Pop component (" + componentClientId + "). stack=" + sb);
124         }
125 
126         /*
127          * On ne fait pas ca ... Car il y a peut etre d'autres composants
128          * "freres" Camelia
129          * 
130          * if (getStackLevel() < 0) { release(); }
131          */
132     }
133 
134     /*
135      * protected void releaseComponentAttributes(Map map) { map.clear(); }
136      */
137 
138     private void releaseMap(Map map) {
139         map.clear();
140     }
141 
142     protected int getStackLevel() {
143         return stack.size() - 3;
144     }
145 
146     /*
147      * (non-Javadoc)
148      * 
149      * @see org.rcfaces.core.internal.renderkit.IRenderContext#getComponentContext()
150      */
151     public final Object getComponentContextAttribute(String key) {
152         int componentContextLevel = getStackLevel() + 2;
153 
154         Object object = stack.get(componentContextLevel);
155         if (object == Boolean.FALSE) {
156             return null;
157         }
158 
159         Map map = (Map) object;
160 
161         return map.get(key);
162     }
163 
164     public final boolean containsComponentContextAttribute(String key) {
165         int componentContextLevel = getStackLevel() + 2;
166 
167         Object object = stack.get(componentContextLevel);
168         if (object == Boolean.FALSE) {
169             return false;
170         }
171 
172         Map map = (Map) object;
173 
174         return map.containsKey(key);
175     }
176 
177     public final Object setComponentContextAttribute(String key, Object value) {
178         int componentContextLevel = getStackLevel() + 2;
179 
180         Object object = stack.get(componentContextLevel);
181         if (object == Boolean.FALSE) {
182             object = new HashMap();
183             stack.set(componentContextLevel, object);
184         }
185 
186         Map map = (Map) object;
187 
188         return map.put(key, value);
189     }
190 
191     public final Object removeComponentContextAttribute(String key) {
192         int componentContextLevel = getStackLevel() + 2;
193 
194         Object object = stack.get(componentContextLevel);
195         if (object == Boolean.FALSE) {
196             return null;
197         }
198 
199         Map map = (Map) object;
200 
201         return map.remove(key);
202     }
203 
204     public final Object getAttribute(String key) {
205         if (attributes == null) {
206             return null;
207         }
208 
209         return attributes.get(key);
210     }
211 
212     public final Object setAttribute(String key, Object value) {
213         if (attributes == null) {
214             attributes = new HashMap();
215         }
216 
217         return attributes.put(key, value);
218     }
219 
220     public boolean containsAttribute(String key) {
221         if (attributes == null) {
222             return false;
223         }
224         return attributes.containsKey(key);
225     }
226 
227     public Object removeAttribute(String key) {
228         if (attributes == null) {
229             return null;
230         }
231 
232         return attributes.remove(key);
233     }
234 
235     public final UIComponent getComponent() {
236 
237         int level = getStackLevel();
238 
239         if (level < 0) {
240             throw new IllegalStateException("Empty stack of components !");
241         }
242 
243         return (UIComponent) stack.get(level);
244     }
245 
246     public final String getComponentClientId() {
247 
248         int level = getStackLevel();
249 
250         return (String) stack.get(level + 1);
251     }
252 
253     public final IComponentWriter getComponentWriter() {
254         return createWriter(getComponent());
255     }
256 
257     protected abstract IComponentWriter createWriter(UIComponent component);
258 
259     public void encodeEnd(IComponentWriter writer) throws WriterException {
260     }
261 
262     public void popScopeVar(String varName) {
263         if (scopeVars == null || scopeVars.isEmpty()) {
264             throw new FacesException("Scope var stack is empty");
265         }
266 
267         int level = scopeVars.size();
268         VarScopeState scope = (VarScopeState) scopeVars.remove(--level);
269 
270         if (varName.equals(scope.getVarName()) == false) {
271             throw new FacesException("Not the same varName ? (stackVarName="
272                     + scope.getVarName() + " varName=" + varName + ")");
273         }
274 
275         getFacesContext().getExternalContext().getRequestMap().remove(varName);
276     }
277 
278     public void pushScopeVar(String varName, Object scopeValue,
279             Object valueBinding, boolean valueMustBeStored) {
280 
281         pushScopeVar(new VarScopeState(varName, scopeValue, valueBinding,
282                 valueMustBeStored));
283     }
284 
285     protected void pushScopeVar(VarScopeState varScopeState) {
286 
287         FacesContext facesContext = getFacesContext();
288 
289         if (scopeVars == null) {
290             scopeVars = new ArrayList(SCOPE_VAR_INITIAL_SIZE);
291         }
292 
293         scopeVars.add(varScopeState);
294 
295         facesContext.getExternalContext().getRequestMap().put(
296                 varScopeState.getVarName(), varScopeState.getValue());
297     }
298 
299     public Object saveState(FacesContext facesContext) {
300         if (scopeVars == null || scopeVars.isEmpty()) {
301             return null;
302         }
303 
304         Object sv[] = new Object[scopeVars.size()];
305 
306         int idx = 0;
307         for (Iterator it = scopeVars.iterator(); it.hasNext();) {
308             VarScopeState varScopeState = (VarScopeState) it.next();
309 
310             sv[idx++] = varScopeState.saveState(facesContext);
311         }
312 
313         return sv;
314     }
315 
316     public void restoreState(FacesContext facesContext, Object object) {
317         Object sv[] = (Object[]) object;
318         if (sv == null) {
319             return;
320         }
321 
322         for (int i = 0; i < sv.length; i++) {
323             VarScopeState varScopeState = new VarScopeState();
324 
325             varScopeState.restoreState(facesContext, sv[i]);
326 
327             pushScopeVar(varScopeState);
328         }
329     }
330 
331     public boolean isTransient() {
332         return transientState;
333     }
334 
335     public void setTransient(boolean newTransientValue) {
336         this.transientState = newTransientValue;
337     }
338 
339     /**
340      * 
341      * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
342      * @version $Revision: 1.18 $ $Date: 2011/06/16 09:29:41 $
343      */
344     public static class VarScopeState implements StateHolder {
345         private static final String REVISION = "$Revision: 1.18 $";
346 
347         private String varName;
348 
349         private Object value;
350 
351         private Object valueBinding;
352 
353         private boolean valueMustBeStored;
354 
355         public VarScopeState() {
356         }
357 
358         public VarScopeState(String varName, Object scopeValue,
359                 Object valueBinding, boolean valueMustBeStored) {
360             this.varName = varName;
361             this.value = scopeValue;
362             this.valueBinding = valueBinding;
363             this.valueMustBeStored = valueMustBeStored;
364         }
365 
366         public void setTransient(boolean newTransientValue) {
367         }
368 
369         public boolean isTransient() {
370             return false;
371         }
372 
373         public void restoreState(FacesContext facesContext, Object state) {
374             Object ret[] = (Object[]) state;
375 
376             varName = (String) ret[0];
377 
378             valueMustBeStored = (ret[3] != null);
379 
380             valueBinding = UIComponentBase.restoreAttachedState(facesContext,
381                     ret[2]);
382 
383             if (valueMustBeStored || valueBinding == null) {
384                 value = UIComponentBase.restoreAttachedState(facesContext,
385                         ret[1]);
386 
387             } else if (valueBinding != null) {
388                 value = BindingTools.resolveBinding(facesContext, valueBinding);
389             }
390         }
391 
392         public Object saveState(FacesContext facesContext) {
393             Object ret[] = new Object[4];
394 
395             ret[0] = varName;
396             ret[3] = valueMustBeStored ? Boolean.TRUE : null;
397 
398             if (valueBinding != null) {
399                 ret[2] = UIComponentBase.saveAttachedState(facesContext,
400                         valueBinding); // ValueBindig
401 
402                 if (valueMustBeStored) {
403                     ret[1] = UIComponentBase.saveAttachedState(facesContext,
404                             value);
405                 }
406 
407             } else { // Pas de valueBinding, on enregistre la valeur
408                 ret[1] = UIComponentBase.saveAttachedState(facesContext, value); // Value
409             }
410 
411             return ret;
412         }
413 
414         public final String getVarName() {
415             return varName;
416         }
417 
418         public final Object getValue() {
419             return value;
420         }
421 
422         public final Object getValueBinding() {
423             return valueBinding;
424         }
425 
426         public final boolean isValueMustBeStored() {
427             return valueMustBeStored;
428         }
429     }
430 }