1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.flow.cdi;
20
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.logging.Level;
29 import java.util.logging.Logger;
30 import javax.annotation.PostConstruct;
31 import javax.annotation.PreDestroy;
32 import javax.enterprise.context.SessionScoped;
33 import javax.enterprise.inject.spi.BeanManager;
34 import javax.faces.context.ExceptionHandler;
35 import javax.faces.context.ExternalContext;
36 import javax.faces.context.FacesContext;
37 import javax.faces.flow.Flow;
38 import javax.faces.flow.FlowHandler;
39 import javax.faces.lifecycle.ClientWindow;
40 import javax.inject.Inject;
41 import javax.servlet.ServletContext;
42 import org.apache.myfaces.cdi.util.ContextualInstanceInfo;
43 import org.apache.myfaces.cdi.util.ContextualStorage;
44 import org.apache.myfaces.cdi.JsfApplicationArtifactHolder;
45 import org.apache.myfaces.context.ReleaseableExternalContext;
46 import org.apache.myfaces.context.servlet.StartupFacesContextImpl;
47 import org.apache.myfaces.context.servlet.StartupServletExternalContextImpl;
48 import org.apache.myfaces.flow.util.FlowUtils;
49 import org.apache.myfaces.shared.config.MyfacesConfig;
50 import org.apache.myfaces.shared.context.ExceptionHandlerImpl;
51
52
53
54
55
56
57
58
59
60
61 @SessionScoped
62 public class FlowScopeBeanHolder implements Serializable
63 {
64
65
66
67
68
69 private Map<String, ContextualStorage> storageMap;
70
71 private Map<String, List<String>> activeFlowMapKeys;
72
73 private FacesFlowClientWindowCollection windowCollection;
74
75 public static final String CURRENT_FLOW_SCOPE_MAP = "oam.CURRENT_FLOW_SCOPE_MAP";
76
77 private static final String FLOW_SCOPE_PREFIX = "oam.flow.SCOPE";
78
79 public static final String FLOW_SCOPE_PREFIX_KEY = FLOW_SCOPE_PREFIX+".KEY";
80
81 @Inject
82 JsfApplicationArtifactHolder applicationContextBean;
83
84 public FlowScopeBeanHolder()
85 {
86 }
87
88 @PostConstruct
89 public void init()
90 {
91 storageMap = new ConcurrentHashMap<String, ContextualStorage>();
92 activeFlowMapKeys = new ConcurrentHashMap<String, List<String>>();
93 windowCollection = null;
94
95 FacesContext facesContext = FacesContext.getCurrentInstance();
96 this.refreshClientWindow(facesContext);
97 facesContext.getExternalContext().getSessionMap().put(FLOW_SCOPE_PREFIX_KEY,
98 1);
99 }
100
101
102
103
104
105
106
107 public ContextualStorage getContextualStorage(BeanManager beanManager, String flowClientWindowId)
108 {
109 ContextualStorage contextualStorage = storageMap.get(flowClientWindowId);
110 if (contextualStorage == null)
111 {
112 synchronized (this)
113 {
114 contextualStorage = storageMap.get(flowClientWindowId);
115 if (contextualStorage == null)
116 {
117 contextualStorage = new ContextualStorage(beanManager, true, true);
118 storageMap.put(flowClientWindowId, contextualStorage);
119 }
120 }
121 }
122
123 return contextualStorage;
124 }
125
126 public ContextualStorage getContextualStorageNoCreate(BeanManager beanManager, String flowClientWindowId)
127 {
128 return storageMap.get(flowClientWindowId);
129 }
130
131 public Map<String, ContextualStorage> getStorageMap()
132 {
133 return storageMap;
134 }
135
136 public Map<Object, Object> getFlowScopeMap(
137 BeanManager beanManager, String flowClientWindowId, boolean create)
138 {
139 Map<Object, Object> map = null;
140 if (create)
141 {
142 ContextualStorage contextualStorage = getContextualStorage(
143 beanManager, flowClientWindowId);
144 ContextualInstanceInfo info = contextualStorage.getStorage().get(CURRENT_FLOW_SCOPE_MAP);
145 if (info == null)
146 {
147 info = new ContextualInstanceInfo<Object>();
148 contextualStorage.getStorage().put(CURRENT_FLOW_SCOPE_MAP, info);
149 }
150 map = (Map<Object, Object>) info.getContextualInstance();
151 if (map == null)
152 {
153 map = new HashMap<Object,Object>();
154 info.setContextualInstance(map);
155 }
156 }
157 else
158 {
159 ContextualStorage contextualStorage = getContextualStorageNoCreate(
160 beanManager, flowClientWindowId);
161 if (contextualStorage != null)
162 {
163 ContextualInstanceInfo info = contextualStorage.getStorage().get(CURRENT_FLOW_SCOPE_MAP);
164 if (info != null)
165 {
166 map = (Map<Object, Object>) info.getContextualInstance();
167 }
168 }
169 }
170 return map;
171 }
172
173
174
175
176
177
178
179
180
181
182
183 public Map<String, ContextualStorage> forceNewStorage()
184 {
185 Map<String, ContextualStorage> oldStorageMap = storageMap;
186 storageMap = new ConcurrentHashMap<String, ContextualStorage>();
187 return oldStorageMap;
188 }
189
190
191
192
193
194
195
196
197
198 public void destroyBeans()
199 {
200
201
202 Map<String, ContextualStorage> oldWindowContextStorages = forceNewStorage();
203
204 for (ContextualStorage contextualStorage : oldWindowContextStorages.values())
205 {
206 FlowScopedContextImpl.destroyAllActive(contextualStorage);
207 }
208 }
209
210
211
212
213 @PreDestroy
214 public void destroyBeansOnPreDestroy()
215 {
216 Map<String, ContextualStorage> oldWindowContextStorages = forceNewStorage();
217 if (!oldWindowContextStorages.isEmpty())
218 {
219 FacesContext facesContext = FacesContext.getCurrentInstance();
220 ServletContext servletContext = null;
221 if (facesContext == null)
222 {
223 try
224 {
225 servletContext = applicationContextBean.getServletContext();
226 }
227 catch (Throwable e)
228 {
229 Logger.getLogger(FlowScopeBeanHolder.class.getName()).log(Level.WARNING,
230 "Cannot locate servletContext to create FacesContext on @PreDestroy flow scope beans. "
231 + "The beans will be destroyed without active FacesContext instance.");
232 servletContext = null;
233 }
234 }
235 if (facesContext == null &&
236 servletContext != null)
237 {
238 try
239 {
240 ExternalContext externalContext = new StartupServletExternalContextImpl(servletContext, false);
241 ExceptionHandler exceptionHandler = new ExceptionHandlerImpl();
242 facesContext = new StartupFacesContextImpl(externalContext,
243 (ReleaseableExternalContext) externalContext, exceptionHandler, false);
244 for (ContextualStorage contextualStorage : oldWindowContextStorages.values())
245 {
246 FlowScopedContextImpl.destroyAllActive(contextualStorage);
247 }
248 }
249 finally
250 {
251 facesContext.release();
252 }
253 }
254 else
255 {
256 for (ContextualStorage contextualStorage : oldWindowContextStorages.values())
257 {
258 FlowScopedContextImpl.destroyAllActive(contextualStorage);
259 }
260 }
261 }
262 }
263
264 public void refreshClientWindow(FacesContext facesContext)
265 {
266 if (windowCollection == null)
267 {
268 Integer ft = MyfacesConfig.getCurrentInstance(facesContext.getExternalContext()).
269 getNumberOfFacesFlowClientWindowIdsInSession();
270 windowCollection = new FacesFlowClientWindowCollection(new ClientWindowFacesFlowLRUMap(ft));
271 }
272 ClientWindow cw = facesContext.getExternalContext().getClientWindow();
273 if (cw != null && cw.getId() != null)
274 {
275 windowCollection.setFlowScopeBeanHolder(this);
276 windowCollection.put(cw.getId(), "");
277 }
278 }
279
280 public void clearFlowMap(String clientWindowId)
281 {
282 List<String> activeFlowKeys = activeFlowMapKeys.remove(clientWindowId);
283 if (activeFlowKeys != null && !activeFlowKeys.isEmpty())
284 {
285 for (String flowMapKey : activeFlowKeys)
286 {
287 ContextualStorage contextualStorage = storageMap.remove(flowMapKey);
288 if (contextualStorage != null)
289 {
290 FlowScopedContextImpl.destroyAllActive(contextualStorage);
291 }
292 }
293 }
294 }
295
296 public List<String> getActiveFlowMapKeys(FacesContext facesContext)
297 {
298 ClientWindow cw = facesContext.getExternalContext().getClientWindow();
299 String baseKey = cw.getId();
300 List<String> activeFlowKeys = activeFlowMapKeys.get(baseKey);
301 if (activeFlowKeys == null)
302 {
303 return Collections.emptyList();
304 }
305 else
306 {
307 return activeFlowKeys;
308 }
309 }
310
311 public void createCurrentFlowScope(FacesContext facesContext)
312 {
313 ClientWindow cw = facesContext.getExternalContext().getClientWindow();
314 String baseKey = cw.getId();
315
316 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
317 Flow flow = flowHandler.getCurrentFlow(facesContext);
318 String flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
319
320 List<String> activeFlowKeys = activeFlowMapKeys.get(baseKey);
321 if (activeFlowKeys == null)
322 {
323 activeFlowKeys = new ArrayList<String>();
324
325 }
326 activeFlowKeys.add(0, flowMapKey);
327 activeFlowMapKeys.put(baseKey, activeFlowKeys);
328 refreshClientWindow(facesContext);
329 }
330
331 public void destroyCurrentFlowScope(FacesContext facesContext)
332 {
333 ClientWindow cw = facesContext.getExternalContext().getClientWindow();
334 String baseKey = cw.getId();
335
336 FlowHandler flowHandler = facesContext.getApplication().getFlowHandler();
337 Flow flow = flowHandler.getCurrentFlow(facesContext);
338 String flowMapKey = FlowUtils.getFlowMapKey(facesContext, flow);
339
340 ContextualStorage contextualStorage = storageMap.remove(flowMapKey);
341 if (contextualStorage != null)
342 {
343 FlowScopedContextImpl.destroyAllActive(contextualStorage);
344 }
345
346 List<String> activeFlowKeys = activeFlowMapKeys.get(baseKey);
347 if (activeFlowKeys != null && !activeFlowKeys.isEmpty())
348 {
349 activeFlowKeys.remove(flowMapKey);
350 }
351 }
352 }