1
2
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
25
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
128
129
130
131
132 }
133
134
135
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
148
149
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
342
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);
401
402 if (valueMustBeStored) {
403 ret[1] = UIComponentBase.saveAttachedState(facesContext,
404 value);
405 }
406
407 } else {
408 ret[1] = UIComponentBase.saveAttachedState(facesContext, 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 }