1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.view.facelets.pool.impl;
20
21 import java.util.ConcurrentModificationException;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.concurrent.ConcurrentHashMap;
25 import jakarta.faces.component.UIViewRoot;
26 import jakarta.faces.context.FacesContext;
27 import org.apache.myfaces.context.RequestViewContext;
28 import org.apache.myfaces.shared.util.WebConfigParamUtils;
29 import org.apache.myfaces.view.facelets.pool.RestoreViewFromPoolResult;
30 import org.apache.myfaces.view.facelets.pool.ViewPool;
31 import org.apache.myfaces.view.facelets.pool.ViewEntry;
32 import org.apache.myfaces.view.facelets.pool.ViewStructureMetadata;
33 import org.apache.myfaces.view.facelets.tag.jsf.FaceletState;
34
35
36
37
38
39 public class ViewPoolImpl extends ViewPool
40 {
41
42
43 private static final String SKIP_VIEW_MAP_SAVE_STATE = "oam.viewPool.SKIP_VIEW_MAP_SAVE_STATE";
44
45 private Map<MetadataViewKey, ViewPoolEntryHolder > staticStructureViewPool;
46
47 private Map<MetadataViewKey, Map<DynamicViewKey, ViewPoolEntryHolder>> dynamicStructureViewPool;
48
49 private Map<MetadataViewKey, ViewPoolEntryHolder > partialStructureViewPool;
50
51 private final int maxCount;
52 private final int dynamicPartialLimit;
53
54 private final boolean entryWeak;
55 private final boolean deferredNavigation;
56
57
58 private Map<MetadataViewKey, ViewStructureMetadata> staticStructureViewMetadataMap;
59 private Map<MetadataViewKey, Map<DynamicViewKey, ViewStructureMetadata>>
60 dynamicStructureViewMetadataMap;
61
62 public ViewPoolImpl(FacesContext facesContext, Map<String, String> parameters)
63 {
64 staticStructureViewPool = new ConcurrentHashMap<MetadataViewKey, ViewPoolEntryHolder>();
65 partialStructureViewPool = new ConcurrentHashMap<MetadataViewKey, ViewPoolEntryHolder>();
66 dynamicStructureViewPool = new ConcurrentHashMap<MetadataViewKey, Map<DynamicViewKey, ViewPoolEntryHolder>>();
67 maxCount = WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
68 INIT_PARAM_VIEW_POOL_MAX_POOL_SIZE,
69 parameters.containsKey(INIT_PARAM_VIEW_POOL_MAX_POOL_SIZE) ?
70 Integer.parseInt(parameters.get(INIT_PARAM_VIEW_POOL_MAX_POOL_SIZE)) :
71 INIT_PARAM_VIEW_POOL_MAX_POOL_SIZE_DEFAULT);
72 dynamicPartialLimit = WebConfigParamUtils.getIntegerInitParameter(facesContext.getExternalContext(),
73 INIT_PARAM_VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT,
74 parameters.containsKey(INIT_PARAM_VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT) ?
75 Integer.parseInt(parameters.get(INIT_PARAM_VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT)) :
76 INIT_PARAM_VIEW_POOL_MAX_DYNAMIC_PARTIAL_LIMIT_DEFAULT);
77 String entryMode = WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
78 INIT_PARAM_VIEW_POOL_ENTRY_MODE,
79 parameters.containsKey(INIT_PARAM_VIEW_POOL_ENTRY_MODE) ?
80 parameters.get(INIT_PARAM_VIEW_POOL_ENTRY_MODE) :
81 INIT_PARAM_VIEW_POOL_ENTRY_MODE_DEFAULT);
82 entryWeak = ENTRY_MODE_WEAK.equals(entryMode);
83 String deferredNavigationVal = WebConfigParamUtils.getStringInitParameter(facesContext.getExternalContext(),
84 INIT_PARAM_VIEW_POOL_DEFERRED_NAVIGATION,
85 parameters.containsKey(INIT_PARAM_VIEW_POOL_DEFERRED_NAVIGATION) ?
86 parameters.get(INIT_PARAM_VIEW_POOL_DEFERRED_NAVIGATION) :
87 "false");
88 deferredNavigation = Boolean.valueOf(deferredNavigationVal);
89
90 staticStructureViewMetadataMap = new ConcurrentHashMap<MetadataViewKey, ViewStructureMetadata>();
91 dynamicStructureViewMetadataMap = new ConcurrentHashMap<MetadataViewKey,
92 Map<DynamicViewKey, ViewStructureMetadata>>();
93 }
94
95 protected void pushStaticStructureView(FacesContext context, MetadataViewKey key, ViewEntry entry)
96 {
97 ViewPoolEntryHolder q = staticStructureViewPool.get(key);
98 if (q == null)
99 {
100 q = new ViewPoolEntryHolder(maxCount);
101 staticStructureViewPool.put(key, q);
102 }
103 q.add(entry);
104 }
105
106 protected ViewEntry popStaticStructureView(FacesContext context, MetadataViewKey key)
107 {
108 ViewPoolEntryHolder q = staticStructureViewPool.get(key);
109 if (q == null)
110 {
111 return null;
112 }
113 ViewEntry entry = q.poll();
114 if (entry == null)
115 {
116 return null;
117 }
118 do
119 {
120 if (entry.activate())
121 {
122 return entry;
123 }
124 entry = q.poll();
125 }
126 while (entry != null);
127 return null;
128 }
129
130 protected void pushPartialStructureView(FacesContext context, MetadataViewKey key, ViewEntry entry)
131 {
132 ViewPoolEntryHolder q = partialStructureViewPool.get(key);
133 if (q == null)
134 {
135 q = new ViewPoolEntryHolder(maxCount);
136 partialStructureViewPool.put(key, q);
137 }
138 q.add(entry);
139 }
140
141 protected ViewEntry popPartialStructureView(FacesContext context, MetadataViewKey key)
142 {
143 ViewPoolEntryHolder q = partialStructureViewPool.get(key);
144 if (q == null)
145 {
146 return null;
147 }
148 ViewEntry entry = q.poll();
149 if (entry == null)
150 {
151 return null;
152 }
153 do
154 {
155 if (entry.activate())
156 {
157 return entry;
158 }
159 entry = q.poll();
160 }while (entry != null);
161 return null;
162 }
163
164
165
166
167
168
169
170
171
172
173
174 protected MetadataViewKey deriveViewKey(FacesContext facesContext,
175 UIViewRoot root)
176 {
177 MetadataViewKey viewKey;
178 if (!facesContext.getResourceLibraryContracts().isEmpty())
179 {
180 String[] contracts = new String[facesContext.getResourceLibraryContracts().size()];
181 contracts = facesContext.getResourceLibraryContracts().toArray(contracts);
182 viewKey = new MetadataViewKeyImpl(root.getViewId(), root.getRenderKitId(), root.getLocale(), contracts);
183 }
184 else
185 {
186 viewKey = new MetadataViewKeyImpl(root.getViewId(), root.getRenderKitId(), root.getLocale());
187 }
188 return viewKey;
189 }
190
191 protected ViewEntry generateViewEntry(FacesContext facesContext,
192 UIViewRoot root)
193 {
194 return entryWeak ? new WeakViewEntry(root) : new SoftViewEntry(root);
195 }
196
197 protected DynamicViewKey generateDynamicStructureViewKey(FacesContext facesContext, UIViewRoot root,
198 FaceletState faceletDynamicState)
199 {
200 return new DynamicViewKey(faceletDynamicState);
201 }
202
203 protected void pushDynamicStructureView(FacesContext context, UIViewRoot root, DynamicViewKey key, ViewEntry entry)
204 {
205 MetadataViewKey ordinaryKey = deriveViewKey(context, root);
206 Map<DynamicViewKey, ViewPoolEntryHolder> map = dynamicStructureViewPool.get(ordinaryKey);
207 if (map == null)
208 {
209 map = new ConcurrentHashMap<DynamicViewKey, ViewPoolEntryHolder>();
210 dynamicStructureViewPool.put(ordinaryKey, map);
211 }
212 ViewPoolEntryHolder q = map.get(key);
213 if (q == null)
214 {
215 q = new ViewPoolEntryHolder(maxCount);
216 map.put(key, q);
217 }
218 if (!q.add(entry))
219 {
220 pushPartialStructureView(context, ordinaryKey, entry);
221 }
222 }
223
224 protected ViewEntry popDynamicStructureView(FacesContext context, UIViewRoot root, DynamicViewKey key)
225 {
226 MetadataViewKey ordinaryKey = deriveViewKey(context, root);
227 Map<DynamicViewKey, ViewPoolEntryHolder> map = dynamicStructureViewPool.get(ordinaryKey);
228 if (map == null)
229 {
230 return null;
231 }
232 ViewPoolEntryHolder q = map.get(key);
233 if (q == null)
234 {
235 return null;
236 }
237 ViewEntry entry = q.poll();
238 while (entry != null)
239 {
240 if (entry.activate())
241 {
242 return entry;
243 }
244 entry = q.poll();
245 }
246 return null;
247 }
248
249 @Override
250 public void pushStaticStructureView(FacesContext context, UIViewRoot root)
251 {
252 MetadataViewKey key = deriveViewKey(context, root);
253 if (staticStructureViewMetadataMap.containsKey(key))
254 {
255 ViewEntry value = generateViewEntry(context, root);
256 pushStaticStructureView(context, key, value);
257 }
258 }
259
260 @Override
261 public ViewEntry popStaticOrPartialStructureView(FacesContext context, UIViewRoot root)
262 {
263 MetadataViewKey key = deriveViewKey(context, root);
264 ViewEntry entry = popStaticStructureView(context, key);
265 if (entry != null)
266 {
267 entry.setResult(RestoreViewFromPoolResult.COMPLETE);
268 }
269 else
270 {
271 entry = popPartialStructureView(context, key);
272 if (entry != null)
273 {
274 entry.setResult(RestoreViewFromPoolResult.REFRESH_REQUIRED);
275 }
276 else
277 {
278 Map<DynamicViewKey, ViewPoolEntryHolder> map = dynamicStructureViewPool.get(key);
279 if (map != null)
280 {
281 try
282 {
283 ViewPoolEntryHolder maxEntry = null;
284 long max = -1;
285 for (Iterator<ViewPoolEntryHolder> it = map.values().iterator(); it.hasNext();)
286 {
287 ViewPoolEntryHolder e = it.next();
288 long count = e.getCount();
289 if (count > max && count > dynamicPartialLimit)
290 {
291 maxEntry = e;
292 max = count;
293 }
294 }
295 if (maxEntry != null)
296 {
297 entry = maxEntry.poll();
298 if (entry != null)
299 {
300 do
301 {
302 if (entry.activate())
303 {
304 break;
305 }
306 entry = maxEntry.poll();
307 }
308 while (entry != null);
309 if (entry != null)
310 {
311 entry.setResult(RestoreViewFromPoolResult.REFRESH_REQUIRED);
312 }
313 }
314 }
315 }
316 catch(ConcurrentModificationException ex)
317 {
318
319 }
320 }
321 }
322 }
323 return entry;
324 }
325
326 @Override
327 public void pushDynamicStructureView(FacesContext context, UIViewRoot root,
328 FaceletState faceletDynamicState)
329 {
330 DynamicViewKey key = (DynamicViewKey) generateDynamicStructureViewKey(context, root, faceletDynamicState);
331 MetadataViewKey ordinaryKey = deriveViewKey(context, root);
332 Map<DynamicViewKey, ViewStructureMetadata> map = dynamicStructureViewMetadataMap.get(ordinaryKey);
333 if (map != null)
334 {
335 ViewEntry value = generateViewEntry(context, root);
336 pushDynamicStructureView(context, root, key, value);
337 }
338 }
339
340 @Override
341 public ViewEntry popDynamicStructureView(FacesContext context, UIViewRoot root,
342 FaceletState faceletDynamicState)
343 {
344 DynamicViewKey key = generateDynamicStructureViewKey(context, root, faceletDynamicState);
345 ViewEntry entry = popDynamicStructureView(context, root, key);
346 if (entry != null)
347 {
348 entry.setResult(RestoreViewFromPoolResult.COMPLETE);
349 }
350 return entry;
351 }
352
353 @Override
354 public void pushPartialStructureView(FacesContext context, UIViewRoot root)
355 {
356 MetadataViewKey key = deriveViewKey(context, root);
357 ViewEntry value = generateViewEntry(context, root);
358 pushPartialStructureView(context, key, value);
359 }
360
361 @Override
362 public boolean isWorthToRecycleThisView(FacesContext context, UIViewRoot root)
363 {
364 MetadataViewKey key = deriveViewKey(context, root);
365 ViewPoolEntryHolder q = partialStructureViewPool.get(key);
366 if (q != null && q.isFull())
367 {
368 return false;
369 }
370 return true;
371 }
372
373 @Override
374 public void storeStaticViewStructureMetadata(FacesContext context, UIViewRoot root,
375 FaceletState faceletState)
376 {
377 MetadataViewKey key = deriveViewKey(context, root);
378 if (!staticStructureViewMetadataMap.containsKey(key))
379 {
380 RequestViewContext rvc = RequestViewContext.getCurrentInstance(context);
381 Object state = saveViewRootState(context, root);
382 ViewStructureMetadata metadata = new ViewStructureMetadataImpl(state,
383 rvc.getRequestViewMetadata().cloneInstance());
384 staticStructureViewMetadataMap.put(key, metadata);
385 }
386 }
387
388 @Override
389 public ViewStructureMetadata retrieveStaticViewStructureMetadata(FacesContext context, UIViewRoot root)
390 {
391 MetadataViewKey key = deriveViewKey(context, root);
392 return staticStructureViewMetadataMap.get(key);
393 }
394
395 private Object saveViewRootState(FacesContext context, UIViewRoot root)
396 {
397 Object state;
398 if (root.getViewMap(false) != null)
399 {
400 try
401 {
402 context.getAttributes().put(SKIP_VIEW_MAP_SAVE_STATE, Boolean.TRUE);
403 state = root.saveState(context);
404 }
405 finally
406 {
407 context.getAttributes().remove(SKIP_VIEW_MAP_SAVE_STATE);
408 }
409 }
410 else
411 {
412 state = root.saveState(context);
413 }
414 return state;
415 }
416
417 @Override
418 public void storeDynamicViewStructureMetadata(FacesContext context, UIViewRoot root,
419 FaceletState faceletDynamicState)
420 {
421 DynamicViewKey key = (DynamicViewKey) generateDynamicStructureViewKey(context, root, faceletDynamicState);
422 MetadataViewKey ordinaryKey = deriveViewKey(context, root);
423 if (!dynamicStructureViewMetadataMap.containsKey(ordinaryKey))
424 {
425
426 Map<DynamicViewKey, ViewStructureMetadata> map = dynamicStructureViewMetadataMap.get(ordinaryKey);
427 if (map == null)
428 {
429 map = new ConcurrentHashMap<DynamicViewKey, ViewStructureMetadata>();
430 dynamicStructureViewMetadataMap.put(ordinaryKey, map);
431 }
432 RequestViewContext rvc = RequestViewContext.getCurrentInstance(context);
433
434 Object state = saveViewRootState(context, root);
435
436 ViewStructureMetadata metadata = new ViewStructureMetadataImpl(state,
437 rvc.getRequestViewMetadata().cloneInstance());
438 map.put(key, metadata);
439 }
440 }
441
442 @Override
443 public ViewStructureMetadata retrieveDynamicViewStructureMetadata(FacesContext context, UIViewRoot root,
444 FaceletState faceletDynamicState)
445 {
446 DynamicViewKey key = (DynamicViewKey) generateDynamicStructureViewKey(context, root, faceletDynamicState);
447 MetadataViewKey ordinaryKey = deriveViewKey(context, root);
448 Map<DynamicViewKey, ViewStructureMetadata> map = dynamicStructureViewMetadataMap.get(ordinaryKey);
449 if (map != null)
450 {
451 return map.get(key);
452 }
453 return null;
454 }
455
456
457
458
459 @Override
460 public boolean isDeferredNavigationEnabled()
461 {
462 return deferredNavigation;
463 }
464
465 }