1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.orchestra.lib.jsf;
20
21 import java.util.List;
22 import java.util.ListIterator;
23
24 import javax.faces.context.ExternalContext;
25 import javax.faces.context.FacesContext;
26 import javax.faces.context.FacesContextWrapper;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
31
32 /**
33 * Convenient class to wrap the current FacesContext in portlet environment.
34 *
35 * @since 1.4
36 *
37 * @author Leonardo Uribe (latest modification by $Author: lu4242 $)
38 * @version $Revision: 798382 $ $Date: 2009-07-27 22:23:02 -0500 (lun, 27 jul 2009) $
39 */
40 public class _PortletFacesContextWrapper extends FacesContextWrapper
41 {
42 private final static String REQUEST_ADAPTER = "org.apache.myfaces.orchestra.REQUEST_ADAPTER";
43
44 //~ Instance fields -------------------------------------------------------
45
46 private final FacesContext _facesContext;
47 private final ExternalContext externalContextDelegate;
48 private final RequestHandler contextLockHandler;
49 private final List _handlers;
50 private final String _nextToken;
51
52 private final Log log = LogFactory
53 .getLog(_PortletFacesContextWrapper.class);
54
55 //~ Constructors ----------------------------------------------------------
56
57 /**
58 * The install parameter controls whether this object will be configured as
59 * the object returned from calls to FacesContext.getCurrentInstance() or not.
60 * <p>
61 * When only overriding the release() method, then install=false is ok as that
62 * is called directly by the FacesServlet on the instance returned by the
63 * FacesContextFactory. However all other methods are invoked on the object
64 * that is returned from FacesContext.getCurrentInstance, so install=true is
65 * needed in order for any other method overrides to have any effect.
66 * <p>
67 * <b>IMPORTANT</b>: install=true should not be used until MYFACES-1820 is fixed.
68 */
69 public _PortletFacesContextWrapper(final FacesContext facesContext,
70 final boolean install, boolean finit, String fnextToken, List fhandlers,
71 final RequestHandler fcontextLockHandler )
72 {
73 if (log.isDebugEnabled())
74 {
75 log.debug("getFacesContext: running inner constructor");
76 }
77
78 _facesContext = facesContext;
79
80 if (install)
81 {
82 FacesContext.setCurrentInstance(this);
83 }
84
85 externalContextDelegate = new PortletExternalContextWrapper(
86 _facesContext.getExternalContext());
87
88 _handlers = fhandlers;
89 _nextToken = fnextToken;
90 contextLockHandler = fcontextLockHandler;
91 if (finit)
92 {
93 ListIterator i = fhandlers.listIterator();
94 try
95 {
96 contextLockHandler.init(facesContext);
97 while (i.hasNext())
98 {
99 RequestHandler h = (RequestHandler) i.next();
100
101 if (log.isDebugEnabled())
102 {
103 log.debug("Running inithandler of type "
104 + h.getClass().getName());
105 }
106
107 h.init(facesContext);
108 }
109 }
110 catch (RuntimeException e)
111 {
112 log.error("Problem initialising RequestHandler", e);
113 _release(i);
114 contextLockHandler.deinit();
115 throw e;
116 }
117 }
118 else
119 {
120 try
121 {
122 contextLockHandler.init(facesContext);
123 }
124 catch (RuntimeException e)
125 {
126 contextLockHandler.deinit();
127 }
128
129 RequestType type = ExternalContextUtils.getRequestType(facesContext
130 .getExternalContext());
131
132 if (RequestType.RENDER.equals(type))
133 {
134 String handlersKey = (String) fnextToken;
135 FrameworkAdapter adapter = (FrameworkAdapter) getExternalContext()
136 .getApplicationMap().remove(
137 REQUEST_ADAPTER + handlersKey);
138 if (FrameworkAdapter.getCurrentInstance() == null)
139 {
140 FrameworkAdapter.setCurrentInstance(adapter);
141 }
142 }
143 }
144 }
145
146 //~ Non-Final Methods -----------------------------------------------------
147
148 public void release()
149 {
150 if (log.isDebugEnabled())
151 {
152 log.debug("Running release");
153 }
154 RequestType type = ExternalContextUtils
155 .getRequestType(getExternalContext());
156 if (RequestType.RENDER.equals(type) ||
157 RequestType.EVENT.equals(type) ||
158 RequestType.RESOURCE.equals(type) ||
159 this.getResponseComplete())
160 {
161 ListIterator i = _handlers.listIterator();
162 while (i.hasNext())
163 {
164 i.next();
165 }
166 _release(i);
167 }
168 if (RequestType.ACTION.equals(type))
169 {
170 if (this.getResponseComplete())
171 {
172 // If response is complete by some reason, we need to
173 // clean request handlers from application map. This is set
174 // before an instance of this class is created.
175 getExternalContext().getApplicationMap().remove(
176 PortletOrchestraFacesContextFactory.REQUEST_HANDLERS+_nextToken);
177 }
178 else
179 {
180 //Pass the current FrameworkAdapter through application map,
181 //to remove it later when rendering
182 FrameworkAdapter adapter = FrameworkAdapter.getCurrentInstance();
183 getExternalContext().getApplicationMap().put(
184 REQUEST_ADAPTER + _nextToken, adapter);
185
186 //Orchestra suppose the same thread handles the current request, but
187 //in portlets this is not necessary true. One thread could handle action
188 //requests and other render request. To keep code working we set it to
189 //null here, so other request don't mix it.
190 FrameworkAdapter.setCurrentInstance(null);
191 }
192 }
193
194 try
195 {
196 //Since in portlets the same thread does not handler both action and
197 //render phase for the same request contextLockHandler needs to
198 //be cleared and lock again
199 contextLockHandler.deinit();
200 }
201 catch (Exception e)
202 {
203 log.error("Problem deinitialising RequestHandler", e);
204 }
205 if (log.isDebugEnabled())
206 {
207 log.debug("Release completed");
208 }
209 getWrapped().release();
210 }
211
212 @Override
213 public FacesContext getWrapped()
214 {
215 return _facesContext;
216 }
217
218 private void _release(ListIterator i)
219 {
220 while (i.hasPrevious())
221 {
222 try
223 {
224 RequestHandler h = (RequestHandler) i.previous();
225 if (log.isDebugEnabled())
226 {
227 log.debug("Running deinithandler of type "
228 + h.getClass().getName());
229 }
230 h.deinit();
231 }
232 catch (Exception e)
233 {
234 log.error("Problem deinitialising RequestHandler", e);
235 }
236 }
237 }
238
239 //~ Final Methods ---------------------------------------------------------
240
241 public ExternalContext getExternalContext()
242 {
243 return externalContextDelegate == null ? getWrapped()
244 .getExternalContext() : externalContextDelegate;
245 }
246 }